si.c revision 1.1
11.1Sjmcneill/* $NetBSD: si.c,v 1.1 2025/12/08 23:00:22 jmcneill Exp $ */ 21.1Sjmcneill 31.1Sjmcneill/*- 41.1Sjmcneill * Copyright (c) 2025 Jared McNeill <jmcneill@invisible.ca> 51.1Sjmcneill * All rights reserved. 61.1Sjmcneill * 71.1Sjmcneill * Redistribution and use in source and binary forms, with or without 81.1Sjmcneill * modification, are permitted provided that the following conditions 91.1Sjmcneill * are met: 101.1Sjmcneill * 1. Redistributions of source code must retain the above copyright 111.1Sjmcneill * notice, this list of conditions and the following disclaimer. 121.1Sjmcneill * 2. Redistributions in binary form must reproduce the above copyright 131.1Sjmcneill * notice, this list of conditions and the following disclaimer in the 141.1Sjmcneill * documentation and/or other materials provided with the distribution. 151.1Sjmcneill * 161.1Sjmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 171.1Sjmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 181.1Sjmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 191.1Sjmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 201.1Sjmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 211.1Sjmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 221.1Sjmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 231.1Sjmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 241.1Sjmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 251.1Sjmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 261.1Sjmcneill * SUCH DAMAGE. 271.1Sjmcneill */ 281.1Sjmcneill 291.1Sjmcneill#include <sys/cdefs.h> 301.1Sjmcneill__KERNEL_RCSID(0, "$NetBSD: si.c,v 1.1 2025/12/08 23:00:22 jmcneill Exp $"); 311.1Sjmcneill 321.1Sjmcneill#include <sys/param.h> 331.1Sjmcneill#include <sys/bus.h> 341.1Sjmcneill#include <sys/device.h> 351.1Sjmcneill#include <sys/systm.h> 361.1Sjmcneill#include <sys/bitops.h> 371.1Sjmcneill#include <sys/mutex.h> 381.1Sjmcneill#include <sys/tty.h> 391.1Sjmcneill#include <uvm/uvm_extern.h> 401.1Sjmcneill 411.1Sjmcneill#include <machine/wii.h> 421.1Sjmcneill#include <machine/pio.h> 431.1Sjmcneill 441.1Sjmcneill#include <dev/hid/hidev.h> 451.1Sjmcneill 461.1Sjmcneill#include "locators.h" 471.1Sjmcneill#include "mainbus.h" 481.1Sjmcneill#include "si.h" 491.1Sjmcneill#include "gcpad_rdesc.h" 501.1Sjmcneill 511.1Sjmcneill#define SI_NUM_CHAN 4 521.1Sjmcneill 531.1Sjmcneill#define SICOUTBUF(n) ((n) * 0xc + 0x00) 541.1Sjmcneill#define SICINBUFH(n) ((n) * 0xc + 0x04) 551.1Sjmcneill#define SICINBUFL(n) ((n) * 0xc + 0x08) 561.1Sjmcneill#define SIPOLL 0x30 571.1Sjmcneill#define SIPOLL_X __BITS(25, 16) 581.1Sjmcneill#define SIPOLL_Y __BITS(15, 8) 591.1Sjmcneill#define SIPOLL_EN(n) (__BIT(7 - n)) 601.1Sjmcneill#define SICOMCSR 0x34 611.1Sjmcneill#define SICOMCSR_TCINT __BIT(31) 621.1Sjmcneill#define SICOMCSR_TCINTMSK __BIT(30) 631.1Sjmcneill#define SICOMCSR_RDSTINT __BIT(28) 641.1Sjmcneill#define SICOMCSR_RDSTINTMSK __BIT(27) 651.1Sjmcneill#define SICOMCSR_OUTLNGTH __BITS(22, 16) 661.1Sjmcneill#define SICOMCSR_INLNGTH __BITS(14, 8) 671.1Sjmcneill#define SICOMCSR_TSTART __BIT(0) 681.1Sjmcneill#define SISR 0x38 691.1Sjmcneill#define SISR_OFF(n) ((3 - (n)) * 8) 701.1Sjmcneill#define SISR_WR(n) __BIT(SISR_OFF(n) + 7) 711.1Sjmcneill#define SISR_RDST(n) __BIT(SISR_OFF(n) + 5) 721.1Sjmcneill#define SISR_WRST(n) __BIT(SISR_OFF(n) + 4) 731.1Sjmcneill#define SISR_NOREP(n) __BIT(SISR_OFF(n) + 3) 741.1Sjmcneill#define SISR_COLL(n) __BIT(SISR_OFF(n) + 2) 751.1Sjmcneill#define SISR_OVRUN(n) __BIT(SISR_OFF(n) + 1) 761.1Sjmcneill#define SISR_UNRUN(n) __BIT(SISR_OFF(n) + 0) 771.1Sjmcneill#define SISR_ERROR_MASK(n) (SISR_NOREP(n) | SISR_COLL(n) | \ 781.1Sjmcneill SISR_OVRUN(n) | SISR_UNRUN(n)) 791.1Sjmcneill#define SISR_ERROR_ACK_ALL (SISR_ERROR_MASK(0) | SISR_ERROR_MASK(1) | \ 801.1Sjmcneill SISR_ERROR_MASK(2) | SISR_ERROR_MASK(3)) 811.1Sjmcneill#define SIEXILK 0x3c 821.1Sjmcneill#define SIIOBUF 0x80 831.1Sjmcneill 841.1Sjmcneill#define GCPAD_REPORT_SIZE 9 851.1Sjmcneill#define GCPAD_START(_buf) ISSET((_buf)[0], 0x10) 861.1Sjmcneill#define GCPAD_Y(_buf) ISSET((_buf)[0], 0x08) 871.1Sjmcneill#define GCPAD_X(_buf) ISSET((_buf)[0], 0x04) 881.1Sjmcneill#define GCPAD_B(_buf) ISSET((_buf)[0], 0x02) 891.1Sjmcneill#define GCPAD_A(_buf) ISSET((_buf)[0], 0x01) 901.1Sjmcneill#define GCPAD_LCLICK(_buf) ISSET((_buf)[1], 0x40) 911.1Sjmcneill#define GCPAD_RCLICK(_buf) ISSET((_buf)[1], 0x20) 921.1Sjmcneill#define GCPAD_Z(_buf) ISSET((_buf)[1], 0x10) 931.1Sjmcneill#define GCPAD_UP(_buf) ISSET((_buf)[1], 0x08) 941.1Sjmcneill#define GCPAD_DOWN(_buf) ISSET((_buf)[1], 0x04) 951.1Sjmcneill#define GCPAD_RIGHT(_buf) ISSET((_buf)[1], 0x02) 961.1Sjmcneill#define GCPAD_LEFT(_buf) ISSET((_buf)[1], 0x01) 971.1Sjmcneill 981.1Sjmcneillstruct si_softc; 991.1Sjmcneill 1001.1Sjmcneillstruct si_channel { 1011.1Sjmcneill struct si_softc *ch_sc; 1021.1Sjmcneill device_t ch_dev; 1031.1Sjmcneill unsigned ch_index; 1041.1Sjmcneill struct hidev_tag ch_hidev; 1051.1Sjmcneill kmutex_t ch_lock; 1061.1Sjmcneill kcondvar_t ch_cv; 1071.1Sjmcneill uint8_t ch_state; 1081.1Sjmcneill#define SI_STATE_OPEN __BIT(0) 1091.1Sjmcneill#define SI_STATE_STOPPED __BIT(1) 1101.1Sjmcneill void (*ch_intr)(void *, void *, u_int); 1111.1Sjmcneill void *ch_intrarg; 1121.1Sjmcneill uint8_t ch_buf[GCPAD_REPORT_SIZE]; 1131.1Sjmcneill void *ch_desc; 1141.1Sjmcneill int ch_descsize; 1151.1Sjmcneill}; 1161.1Sjmcneill 1171.1Sjmcneillstruct si_softc { 1181.1Sjmcneill device_t sc_dev; 1191.1Sjmcneill bus_space_tag_t sc_bst; 1201.1Sjmcneill bus_space_handle_t sc_bsh; 1211.1Sjmcneill 1221.1Sjmcneill struct si_channel sc_chan[SI_NUM_CHAN]; 1231.1Sjmcneill}; 1241.1Sjmcneill 1251.1Sjmcneill#define RD4(sc, reg) \ 1261.1Sjmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 1271.1Sjmcneill#define WR4(sc, reg, val) \ 1281.1Sjmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 1291.1Sjmcneill 1301.1Sjmcneillstatic int si_match(device_t, cfdata_t, void *); 1311.1Sjmcneillstatic void si_attach(device_t, device_t, void *); 1321.1Sjmcneill 1331.1Sjmcneillstatic int si_intr(void *); 1341.1Sjmcneill 1351.1Sjmcneillstatic int si_rescan(device_t, const char *, const int *); 1361.1Sjmcneillstatic int si_print(void *, const char *); 1371.1Sjmcneill 1381.1Sjmcneillstatic void si_get_report_desc(void *, void **, int *); 1391.1Sjmcneillstatic int si_open(void *, void (*)(void *, void *, unsigned), void *); 1401.1Sjmcneillstatic void si_stop(void *); 1411.1Sjmcneillstatic void si_close(void *); 1421.1Sjmcneillstatic usbd_status si_set_report(void *, int, void *, int); 1431.1Sjmcneillstatic usbd_status si_get_report(void *, int, void *, int); 1441.1Sjmcneillstatic usbd_status si_write(void *, void *, int); 1451.1Sjmcneill 1461.1SjmcneillCFATTACH_DECL_NEW(si, sizeof(struct si_softc), 1471.1Sjmcneill si_match, si_attach, NULL, NULL); 1481.1Sjmcneill 1491.1Sjmcneillstatic int 1501.1Sjmcneillsi_match(device_t parent, cfdata_t cf, void *aux) 1511.1Sjmcneill{ 1521.1Sjmcneill struct mainbus_attach_args *maa = aux; 1531.1Sjmcneill 1541.1Sjmcneill return strcmp(maa->maa_name, "si") == 0; 1551.1Sjmcneill} 1561.1Sjmcneill 1571.1Sjmcneillstatic void 1581.1Sjmcneillsi_attach(device_t parent, device_t self, void *aux) 1591.1Sjmcneill{ 1601.1Sjmcneill struct mainbus_attach_args * const maa = aux; 1611.1Sjmcneill struct si_softc * const sc = device_private(self); 1621.1Sjmcneill unsigned chan; 1631.1Sjmcneill void *ih; 1641.1Sjmcneill 1651.1Sjmcneill KASSERT(device_unit(self) == 0); 1661.1Sjmcneill 1671.1Sjmcneill aprint_naive("\n"); 1681.1Sjmcneill aprint_normal(": Serial Interface\n"); 1691.1Sjmcneill 1701.1Sjmcneill sc->sc_dev = self; 1711.1Sjmcneill sc->sc_bst = maa->maa_bst; 1721.1Sjmcneill if (bus_space_map(sc->sc_bst, maa->maa_addr, SI_SIZE, 0, 1731.1Sjmcneill &sc->sc_bsh) != 0) { 1741.1Sjmcneill aprint_error_dev(self, "couldn't map registers\n"); 1751.1Sjmcneill return; 1761.1Sjmcneill } 1771.1Sjmcneill 1781.1Sjmcneill for (chan = 0; chan < SI_NUM_CHAN; chan++) { 1791.1Sjmcneill struct si_channel *ch; 1801.1Sjmcneill struct hidev_tag *t; 1811.1Sjmcneill 1821.1Sjmcneill ch = &sc->sc_chan[chan]; 1831.1Sjmcneill ch->ch_sc = sc; 1841.1Sjmcneill ch->ch_index = chan; 1851.1Sjmcneill mutex_init(&ch->ch_lock, MUTEX_DEFAULT, IPL_VM); 1861.1Sjmcneill cv_init(&ch->ch_cv, "sich"); 1871.1Sjmcneill 1881.1Sjmcneill t = &ch->ch_hidev; 1891.1Sjmcneill t->_cookie = &sc->sc_chan[chan]; 1901.1Sjmcneill t->_get_report_desc = si_get_report_desc; 1911.1Sjmcneill t->_open = si_open; 1921.1Sjmcneill t->_stop = si_stop; 1931.1Sjmcneill t->_close = si_close; 1941.1Sjmcneill t->_set_report = si_set_report; 1951.1Sjmcneill t->_get_report = si_get_report; 1961.1Sjmcneill t->_write = si_write; 1971.1Sjmcneill } 1981.1Sjmcneill 1991.1Sjmcneill WR4(sc, SIPOLL, 2001.1Sjmcneill __SHIFTIN(7, SIPOLL_X) | 2011.1Sjmcneill __SHIFTIN(1, SIPOLL_Y)); 2021.1Sjmcneill WR4(sc, SICOMCSR, SICOMCSR_RDSTINT | SICOMCSR_RDSTINTMSK); 2031.1Sjmcneill 2041.1Sjmcneill ih = intr_establish_xname(maa->maa_irq, IST_LEVEL, IPL_VM, si_intr, sc, 2051.1Sjmcneill device_xname(self)); 2061.1Sjmcneill KASSERT(ih != NULL); 2071.1Sjmcneill 2081.1Sjmcneill si_rescan(self, NULL, NULL); 2091.1Sjmcneill} 2101.1Sjmcneill 2111.1Sjmcneillstatic int 2121.1Sjmcneillsi_rescan(device_t self, const char *ifattr, const int *locs) 2131.1Sjmcneill{ 2141.1Sjmcneill struct si_softc * const sc = device_private(self); 2151.1Sjmcneill struct si_attach_args saa; 2161.1Sjmcneill unsigned chan; 2171.1Sjmcneill 2181.1Sjmcneill for (chan = 0; chan < SI_NUM_CHAN; chan++) { 2191.1Sjmcneill struct si_channel *ch = &sc->sc_chan[chan]; 2201.1Sjmcneill 2211.1Sjmcneill if (ch->ch_dev == NULL) { 2221.1Sjmcneill saa.saa_hidev = &ch->ch_hidev; 2231.1Sjmcneill saa.saa_index = ch->ch_index; 2241.1Sjmcneill 2251.1Sjmcneill ch->ch_dev = config_found(self, &saa, si_print, 2261.1Sjmcneill CFARGS(.submatch = config_stdsubmatch, 2271.1Sjmcneill .locators = locs)); 2281.1Sjmcneill } 2291.1Sjmcneill } 2301.1Sjmcneill 2311.1Sjmcneill return 0; 2321.1Sjmcneill} 2331.1Sjmcneill 2341.1Sjmcneillstatic int 2351.1Sjmcneillsi_print(void *aux, const char *pnp) 2361.1Sjmcneill{ 2371.1Sjmcneill struct si_attach_args *saa = aux; 2381.1Sjmcneill 2391.1Sjmcneill if (pnp != NULL) { 2401.1Sjmcneill aprint_normal("uhid at %s", pnp); 2411.1Sjmcneill } 2421.1Sjmcneill 2431.1Sjmcneill /* 2441.1Sjmcneill * The Wii Operations Manual for RVL-001 refers to the controller 2451.1Sjmcneill * ports as "Nintendo GameCube Controller Sockets". 2461.1Sjmcneill */ 2471.1Sjmcneill aprint_normal(" socket %d", saa->saa_index + 1); 2481.1Sjmcneill 2491.1Sjmcneill return UNCONF; 2501.1Sjmcneill} 2511.1Sjmcneill 2521.1Sjmcneillstatic void 2531.1Sjmcneillsi_make_report(struct si_softc *sc, unsigned chan, void *report, bool with_rid) 2541.1Sjmcneill{ 2551.1Sjmcneill uint32_t inbuf[2]; 2561.1Sjmcneill uint8_t *iptr = (uint8_t *)inbuf; 2571.1Sjmcneill uint8_t *optr = report; 2581.1Sjmcneill unsigned off = 0; 2591.1Sjmcneill 2601.1Sjmcneill inbuf[0] = RD4(sc, SICINBUFH(chan)); 2611.1Sjmcneill inbuf[1] = RD4(sc, SICINBUFL(chan)); 2621.1Sjmcneill 2631.1Sjmcneill if (with_rid) { 2641.1Sjmcneill optr[off++] = chan + 1; 2651.1Sjmcneill } 2661.1Sjmcneill 2671.1Sjmcneill optr[off] = 0; 2681.1Sjmcneill optr[off] |= GCPAD_X(iptr) ? 0x01 : 0; 2691.1Sjmcneill optr[off] |= GCPAD_A(iptr) ? 0x02 : 0; 2701.1Sjmcneill optr[off] |= GCPAD_B(iptr) ? 0x04 : 0; 2711.1Sjmcneill optr[off] |= GCPAD_Y(iptr) ? 0x08 : 0; 2721.1Sjmcneill optr[off] |= GCPAD_LCLICK(iptr) ? 0x10 : 0; 2731.1Sjmcneill optr[off] |= GCPAD_RCLICK(iptr) ? 0x20 : 0; 2741.1Sjmcneill optr[off] |= GCPAD_Z(iptr) ? 0x80 : 0; 2751.1Sjmcneill off++; 2761.1Sjmcneill 2771.1Sjmcneill optr[off] = 0; 2781.1Sjmcneill optr[off] |= GCPAD_START(iptr) ? 0x02 : 0; 2791.1Sjmcneill optr[off] |= GCPAD_UP(iptr) ? 0x10 : 0; 2801.1Sjmcneill optr[off] |= GCPAD_RIGHT(iptr) ? 0x20 : 0; 2811.1Sjmcneill optr[off] |= GCPAD_DOWN(iptr) ? 0x40 : 0; 2821.1Sjmcneill optr[off] |= GCPAD_LEFT(iptr) ? 0x80 : 0; 2831.1Sjmcneill off++; 2841.1Sjmcneill 2851.1Sjmcneill memcpy(&optr[off], &iptr[2], 6); 2861.1Sjmcneill off += 6; 2871.1Sjmcneill 2881.1Sjmcneill optr[off++] = 0; 2891.1Sjmcneill} 2901.1Sjmcneill 2911.1Sjmcneillstatic int 2921.1Sjmcneillsi_intr(void *priv) 2931.1Sjmcneill{ 2941.1Sjmcneill struct si_softc *sc = priv; 2951.1Sjmcneill unsigned chan; 2961.1Sjmcneill uint32_t comcsr, sr; 2971.1Sjmcneill int ret = 0; 2981.1Sjmcneill 2991.1Sjmcneill comcsr = RD4(sc, SICOMCSR); 3001.1Sjmcneill sr = RD4(sc, SISR); 3011.1Sjmcneill 3021.1Sjmcneill if (ISSET(comcsr, SICOMCSR_TCINT)) { 3031.1Sjmcneill WR4(sc, SICOMCSR, comcsr | SICOMCSR_TCINT); 3041.1Sjmcneill } 3051.1Sjmcneill 3061.1Sjmcneill if (ISSET(comcsr, SICOMCSR_RDSTINT)) { 3071.1Sjmcneill for (chan = 0; chan < SI_NUM_CHAN; chan++) { 3081.1Sjmcneill struct si_channel *ch = &sc->sc_chan[chan]; 3091.1Sjmcneill 3101.1Sjmcneill if (ISSET(sr, SISR_RDST(chan))) { 3111.1Sjmcneill /* Reading INBUF[HL] de-asserts RDSTINT. */ 3121.1Sjmcneill si_make_report(sc, chan, ch->ch_buf, false); 3131.1Sjmcneill 3141.1Sjmcneill if (ISSET(ch->ch_state, SI_STATE_OPEN)) { 3151.1Sjmcneill ch->ch_intr(ch->ch_intrarg, ch->ch_buf, 3161.1Sjmcneill sizeof(ch->ch_buf)); 3171.1Sjmcneill } 3181.1Sjmcneill } 3191.1Sjmcneill 3201.1Sjmcneill ret = 1; 3211.1Sjmcneill } 3221.1Sjmcneill } 3231.1Sjmcneill 3241.1Sjmcneill WR4(sc, SISR, sr & SISR_ERROR_ACK_ALL); 3251.1Sjmcneill 3261.1Sjmcneill return ret; 3271.1Sjmcneill} 3281.1Sjmcneill 3291.1Sjmcneillstatic void 3301.1Sjmcneillsi_get_report_desc(void *cookie, void **desc, int *size) 3311.1Sjmcneill{ 3321.1Sjmcneill *desc = gcpad_report_descr; 3331.1Sjmcneill *size = sizeof(gcpad_report_descr); 3341.1Sjmcneill} 3351.1Sjmcneill 3361.1Sjmcneillstatic int 3371.1Sjmcneillsi_open(void *cookie, void (*intr)(void *, void *, u_int), void *arg) 3381.1Sjmcneill{ 3391.1Sjmcneill struct si_channel *ch = cookie; 3401.1Sjmcneill struct si_softc *sc = ch->ch_sc; 3411.1Sjmcneill int error; 3421.1Sjmcneill 3431.1Sjmcneill mutex_enter(&ch->ch_lock); 3441.1Sjmcneill 3451.1Sjmcneill if (ISSET(ch->ch_state, SI_STATE_OPEN)) { 3461.1Sjmcneill error = EBUSY; 3471.1Sjmcneill goto unlock; 3481.1Sjmcneill } 3491.1Sjmcneill 3501.1Sjmcneill ch->ch_intr = intr; 3511.1Sjmcneill ch->ch_intrarg = arg; 3521.1Sjmcneill ch->ch_state |= SI_STATE_OPEN; 3531.1Sjmcneill 3541.1Sjmcneill (void)RD4(sc, SICINBUFH(ch->ch_index)); 3551.1Sjmcneill (void)RD4(sc, SICINBUFL(ch->ch_index)); 3561.1Sjmcneill 3571.1Sjmcneill /* Init controller */ 3581.1Sjmcneill WR4(sc, SICOUTBUF(ch->ch_index), 0x00400300); 3591.1Sjmcneill 3601.1Sjmcneill /* Enable polling */ 3611.1Sjmcneill WR4(sc, SIPOLL, RD4(sc, SIPOLL) | SIPOLL_EN(ch->ch_index)); 3621.1Sjmcneill 3631.1Sjmcneill WR4(sc, SISR, SISR_WR(ch->ch_index)); 3641.1Sjmcneill WR4(sc, SICOMCSR, RD4(sc, SICOMCSR) | SICOMCSR_TSTART); 3651.1Sjmcneill 3661.1Sjmcneill error = 0; 3671.1Sjmcneill 3681.1Sjmcneillunlock: 3691.1Sjmcneill mutex_exit(&ch->ch_lock); 3701.1Sjmcneill 3711.1Sjmcneill return error; 3721.1Sjmcneill} 3731.1Sjmcneill 3741.1Sjmcneillstatic void 3751.1Sjmcneillsi_stop(void *cookie) 3761.1Sjmcneill{ 3771.1Sjmcneill struct si_channel *ch = cookie; 3781.1Sjmcneill 3791.1Sjmcneill mutex_enter(&ch->ch_lock); 3801.1Sjmcneill 3811.1Sjmcneill ch->ch_state |= SI_STATE_STOPPED; 3821.1Sjmcneill 3831.1Sjmcneill cv_broadcast(&ch->ch_cv); 3841.1Sjmcneill mutex_exit(&ch->ch_lock); 3851.1Sjmcneill} 3861.1Sjmcneill 3871.1Sjmcneillstatic void 3881.1Sjmcneillsi_close(void *cookie) 3891.1Sjmcneill{ 3901.1Sjmcneill struct si_channel *ch = cookie; 3911.1Sjmcneill struct si_softc *sc = ch->ch_sc; 3921.1Sjmcneill 3931.1Sjmcneill mutex_enter(&ch->ch_lock); 3941.1Sjmcneill 3951.1Sjmcneill /* Diable polling */ 3961.1Sjmcneill WR4(sc, SIPOLL, RD4(sc, SIPOLL) & ~SIPOLL_EN(ch->ch_index)); 3971.1Sjmcneill 3981.1Sjmcneill ch->ch_state &= ~(SI_STATE_OPEN | SI_STATE_STOPPED); 3991.1Sjmcneill ch->ch_intr = NULL; 4001.1Sjmcneill ch->ch_intrarg = NULL; 4011.1Sjmcneill 4021.1Sjmcneill cv_broadcast(&ch->ch_cv); 4031.1Sjmcneill mutex_exit(&ch->ch_lock); 4041.1Sjmcneill} 4051.1Sjmcneill 4061.1Sjmcneillstatic usbd_status 4071.1Sjmcneillsi_set_report(void *cookie, int type, void *data, int len) 4081.1Sjmcneill{ 4091.1Sjmcneill return USBD_INVAL; 4101.1Sjmcneill} 4111.1Sjmcneill 4121.1Sjmcneillstatic usbd_status 4131.1Sjmcneillsi_get_report(void *cookie, int type, void *data, int len) 4141.1Sjmcneill{ 4151.1Sjmcneill struct si_channel *ch = cookie; 4161.1Sjmcneill struct si_softc *sc = ch->ch_sc; 4171.1Sjmcneill uint32_t *inbuf = data; 4181.1Sjmcneill 4191.1Sjmcneill if (len != GCPAD_REPORT_SIZE + 1) { 4201.1Sjmcneill return USBD_IOERROR; 4211.1Sjmcneill } 4221.1Sjmcneill 4231.1Sjmcneill mutex_enter(&ch->ch_lock); 4241.1Sjmcneill si_make_report(sc, ch->ch_index, inbuf, true); 4251.1Sjmcneill mutex_exit(&ch->ch_lock); 4261.1Sjmcneill 4271.1Sjmcneill return USBD_NORMAL_COMPLETION; 4281.1Sjmcneill} 4291.1Sjmcneill 4301.1Sjmcneillstatic usbd_status 4311.1Sjmcneillsi_write(void *cookie, void *data, int len) 4321.1Sjmcneill{ 4331.1Sjmcneill return USBD_INVAL; 4341.1Sjmcneill} 435