11.2Sjmcneill/* $NetBSD: si.c,v 1.2 2025/12/11 01:13:49 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.2Sjmcneill__KERNEL_RCSID(0, "$NetBSD: si.c,v 1.2 2025/12/11 01:13:49 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.2Sjmcneill void *ch_si; 1161.1Sjmcneill}; 1171.1Sjmcneill 1181.1Sjmcneillstruct si_softc { 1191.1Sjmcneill device_t sc_dev; 1201.1Sjmcneill bus_space_tag_t sc_bst; 1211.1Sjmcneill bus_space_handle_t sc_bsh; 1221.1Sjmcneill 1231.1Sjmcneill struct si_channel sc_chan[SI_NUM_CHAN]; 1241.1Sjmcneill}; 1251.1Sjmcneill 1261.1Sjmcneill#define RD4(sc, reg) \ 1271.1Sjmcneill bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 1281.1Sjmcneill#define WR4(sc, reg, val) \ 1291.1Sjmcneill bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 1301.1Sjmcneill 1311.1Sjmcneillstatic int si_match(device_t, cfdata_t, void *); 1321.1Sjmcneillstatic void si_attach(device_t, device_t, void *); 1331.1Sjmcneill 1341.1Sjmcneillstatic int si_intr(void *); 1351.2Sjmcneillstatic void si_softintr(void *); 1361.1Sjmcneill 1371.1Sjmcneillstatic int si_rescan(device_t, const char *, const int *); 1381.1Sjmcneillstatic int si_print(void *, const char *); 1391.1Sjmcneill 1401.1Sjmcneillstatic void si_get_report_desc(void *, void **, int *); 1411.1Sjmcneillstatic int si_open(void *, void (*)(void *, void *, unsigned), void *); 1421.1Sjmcneillstatic void si_stop(void *); 1431.1Sjmcneillstatic void si_close(void *); 1441.1Sjmcneillstatic usbd_status si_set_report(void *, int, void *, int); 1451.1Sjmcneillstatic usbd_status si_get_report(void *, int, void *, int); 1461.1Sjmcneillstatic usbd_status si_write(void *, void *, int); 1471.1Sjmcneill 1481.1SjmcneillCFATTACH_DECL_NEW(si, sizeof(struct si_softc), 1491.1Sjmcneill si_match, si_attach, NULL, NULL); 1501.1Sjmcneill 1511.1Sjmcneillstatic int 1521.1Sjmcneillsi_match(device_t parent, cfdata_t cf, void *aux) 1531.1Sjmcneill{ 1541.1Sjmcneill struct mainbus_attach_args *maa = aux; 1551.1Sjmcneill 1561.1Sjmcneill return strcmp(maa->maa_name, "si") == 0; 1571.1Sjmcneill} 1581.1Sjmcneill 1591.1Sjmcneillstatic void 1601.1Sjmcneillsi_attach(device_t parent, device_t self, void *aux) 1611.1Sjmcneill{ 1621.1Sjmcneill struct mainbus_attach_args * const maa = aux; 1631.1Sjmcneill struct si_softc * const sc = device_private(self); 1641.1Sjmcneill unsigned chan; 1651.1Sjmcneill void *ih; 1661.1Sjmcneill 1671.1Sjmcneill KASSERT(device_unit(self) == 0); 1681.1Sjmcneill 1691.1Sjmcneill aprint_naive("\n"); 1701.1Sjmcneill aprint_normal(": Serial Interface\n"); 1711.1Sjmcneill 1721.1Sjmcneill sc->sc_dev = self; 1731.1Sjmcneill sc->sc_bst = maa->maa_bst; 1741.1Sjmcneill if (bus_space_map(sc->sc_bst, maa->maa_addr, SI_SIZE, 0, 1751.1Sjmcneill &sc->sc_bsh) != 0) { 1761.1Sjmcneill aprint_error_dev(self, "couldn't map registers\n"); 1771.1Sjmcneill return; 1781.1Sjmcneill } 1791.1Sjmcneill 1801.1Sjmcneill for (chan = 0; chan < SI_NUM_CHAN; chan++) { 1811.1Sjmcneill struct si_channel *ch; 1821.1Sjmcneill struct hidev_tag *t; 1831.1Sjmcneill 1841.1Sjmcneill ch = &sc->sc_chan[chan]; 1851.1Sjmcneill ch->ch_sc = sc; 1861.1Sjmcneill ch->ch_index = chan; 1871.1Sjmcneill mutex_init(&ch->ch_lock, MUTEX_DEFAULT, IPL_VM); 1881.1Sjmcneill cv_init(&ch->ch_cv, "sich"); 1891.2Sjmcneill ch->ch_si = softint_establish(SOFTINT_SERIAL, 1901.2Sjmcneill si_softintr, ch); 1911.2Sjmcneill KASSERT(ch->ch_si != NULL); 1921.1Sjmcneill 1931.1Sjmcneill t = &ch->ch_hidev; 1941.1Sjmcneill t->_cookie = &sc->sc_chan[chan]; 1951.1Sjmcneill t->_get_report_desc = si_get_report_desc; 1961.1Sjmcneill t->_open = si_open; 1971.1Sjmcneill t->_stop = si_stop; 1981.1Sjmcneill t->_close = si_close; 1991.1Sjmcneill t->_set_report = si_set_report; 2001.1Sjmcneill t->_get_report = si_get_report; 2011.1Sjmcneill t->_write = si_write; 2021.1Sjmcneill } 2031.1Sjmcneill 2041.1Sjmcneill WR4(sc, SIPOLL, 2051.1Sjmcneill __SHIFTIN(7, SIPOLL_X) | 2061.1Sjmcneill __SHIFTIN(1, SIPOLL_Y)); 2071.1Sjmcneill WR4(sc, SICOMCSR, SICOMCSR_RDSTINT | SICOMCSR_RDSTINTMSK); 2081.1Sjmcneill 2091.1Sjmcneill ih = intr_establish_xname(maa->maa_irq, IST_LEVEL, IPL_VM, si_intr, sc, 2101.1Sjmcneill device_xname(self)); 2111.1Sjmcneill KASSERT(ih != NULL); 2121.1Sjmcneill 2131.1Sjmcneill si_rescan(self, NULL, NULL); 2141.1Sjmcneill} 2151.1Sjmcneill 2161.1Sjmcneillstatic int 2171.1Sjmcneillsi_rescan(device_t self, const char *ifattr, const int *locs) 2181.1Sjmcneill{ 2191.1Sjmcneill struct si_softc * const sc = device_private(self); 2201.1Sjmcneill struct si_attach_args saa; 2211.1Sjmcneill unsigned chan; 2221.1Sjmcneill 2231.1Sjmcneill for (chan = 0; chan < SI_NUM_CHAN; chan++) { 2241.1Sjmcneill struct si_channel *ch = &sc->sc_chan[chan]; 2251.1Sjmcneill 2261.1Sjmcneill if (ch->ch_dev == NULL) { 2271.1Sjmcneill saa.saa_hidev = &ch->ch_hidev; 2281.1Sjmcneill saa.saa_index = ch->ch_index; 2291.1Sjmcneill 2301.1Sjmcneill ch->ch_dev = config_found(self, &saa, si_print, 2311.1Sjmcneill CFARGS(.submatch = config_stdsubmatch, 2321.1Sjmcneill .locators = locs)); 2331.1Sjmcneill } 2341.1Sjmcneill } 2351.1Sjmcneill 2361.1Sjmcneill return 0; 2371.1Sjmcneill} 2381.1Sjmcneill 2391.1Sjmcneillstatic int 2401.1Sjmcneillsi_print(void *aux, const char *pnp) 2411.1Sjmcneill{ 2421.1Sjmcneill struct si_attach_args *saa = aux; 2431.1Sjmcneill 2441.1Sjmcneill if (pnp != NULL) { 2451.1Sjmcneill aprint_normal("uhid at %s", pnp); 2461.1Sjmcneill } 2471.1Sjmcneill 2481.1Sjmcneill /* 2491.1Sjmcneill * The Wii Operations Manual for RVL-001 refers to the controller 2501.1Sjmcneill * ports as "Nintendo GameCube Controller Sockets". 2511.1Sjmcneill */ 2521.1Sjmcneill aprint_normal(" socket %d", saa->saa_index + 1); 2531.1Sjmcneill 2541.1Sjmcneill return UNCONF; 2551.1Sjmcneill} 2561.1Sjmcneill 2571.1Sjmcneillstatic void 2581.1Sjmcneillsi_make_report(struct si_softc *sc, unsigned chan, void *report, bool with_rid) 2591.1Sjmcneill{ 2601.1Sjmcneill uint32_t inbuf[2]; 2611.1Sjmcneill uint8_t *iptr = (uint8_t *)inbuf; 2621.1Sjmcneill uint8_t *optr = report; 2631.1Sjmcneill unsigned off = 0; 2641.1Sjmcneill 2651.1Sjmcneill inbuf[0] = RD4(sc, SICINBUFH(chan)); 2661.1Sjmcneill inbuf[1] = RD4(sc, SICINBUFL(chan)); 2671.1Sjmcneill 2681.1Sjmcneill if (with_rid) { 2691.1Sjmcneill optr[off++] = chan + 1; 2701.1Sjmcneill } 2711.1Sjmcneill 2721.1Sjmcneill optr[off] = 0; 2731.1Sjmcneill optr[off] |= GCPAD_X(iptr) ? 0x01 : 0; 2741.1Sjmcneill optr[off] |= GCPAD_A(iptr) ? 0x02 : 0; 2751.1Sjmcneill optr[off] |= GCPAD_B(iptr) ? 0x04 : 0; 2761.1Sjmcneill optr[off] |= GCPAD_Y(iptr) ? 0x08 : 0; 2771.1Sjmcneill optr[off] |= GCPAD_LCLICK(iptr) ? 0x10 : 0; 2781.1Sjmcneill optr[off] |= GCPAD_RCLICK(iptr) ? 0x20 : 0; 2791.1Sjmcneill optr[off] |= GCPAD_Z(iptr) ? 0x80 : 0; 2801.1Sjmcneill off++; 2811.1Sjmcneill 2821.1Sjmcneill optr[off] = 0; 2831.1Sjmcneill optr[off] |= GCPAD_START(iptr) ? 0x02 : 0; 2841.1Sjmcneill optr[off] |= GCPAD_UP(iptr) ? 0x10 : 0; 2851.1Sjmcneill optr[off] |= GCPAD_RIGHT(iptr) ? 0x20 : 0; 2861.1Sjmcneill optr[off] |= GCPAD_DOWN(iptr) ? 0x40 : 0; 2871.1Sjmcneill optr[off] |= GCPAD_LEFT(iptr) ? 0x80 : 0; 2881.1Sjmcneill off++; 2891.1Sjmcneill 2901.1Sjmcneill memcpy(&optr[off], &iptr[2], 6); 2911.1Sjmcneill off += 6; 2921.1Sjmcneill 2931.1Sjmcneill optr[off++] = 0; 2941.1Sjmcneill} 2951.1Sjmcneill 2961.2Sjmcneillstatic void 2971.2Sjmcneillsi_softintr(void *priv) 2981.2Sjmcneill{ 2991.2Sjmcneill struct si_channel *ch = priv; 3001.2Sjmcneill 3011.2Sjmcneill if (ISSET(ch->ch_state, SI_STATE_OPEN)) { 3021.2Sjmcneill ch->ch_intr(ch->ch_intrarg, ch->ch_buf, sizeof(ch->ch_buf)); 3031.2Sjmcneill } 3041.2Sjmcneill} 3051.2Sjmcneill 3061.1Sjmcneillstatic int 3071.1Sjmcneillsi_intr(void *priv) 3081.1Sjmcneill{ 3091.1Sjmcneill struct si_softc *sc = priv; 3101.1Sjmcneill unsigned chan; 3111.1Sjmcneill uint32_t comcsr, sr; 3121.1Sjmcneill int ret = 0; 3131.1Sjmcneill 3141.1Sjmcneill comcsr = RD4(sc, SICOMCSR); 3151.1Sjmcneill sr = RD4(sc, SISR); 3161.1Sjmcneill 3171.1Sjmcneill if (ISSET(comcsr, SICOMCSR_TCINT)) { 3181.1Sjmcneill WR4(sc, SICOMCSR, comcsr | SICOMCSR_TCINT); 3191.1Sjmcneill } 3201.1Sjmcneill 3211.1Sjmcneill if (ISSET(comcsr, SICOMCSR_RDSTINT)) { 3221.1Sjmcneill for (chan = 0; chan < SI_NUM_CHAN; chan++) { 3231.1Sjmcneill struct si_channel *ch = &sc->sc_chan[chan]; 3241.1Sjmcneill 3251.1Sjmcneill if (ISSET(sr, SISR_RDST(chan))) { 3261.1Sjmcneill /* Reading INBUF[HL] de-asserts RDSTINT. */ 3271.1Sjmcneill si_make_report(sc, chan, ch->ch_buf, false); 3281.1Sjmcneill 3291.1Sjmcneill if (ISSET(ch->ch_state, SI_STATE_OPEN)) { 3301.2Sjmcneill softint_schedule(ch->ch_si); 3311.1Sjmcneill } 3321.1Sjmcneill } 3331.1Sjmcneill 3341.1Sjmcneill ret = 1; 3351.1Sjmcneill } 3361.1Sjmcneill } 3371.1Sjmcneill 3381.1Sjmcneill WR4(sc, SISR, sr & SISR_ERROR_ACK_ALL); 3391.1Sjmcneill 3401.1Sjmcneill return ret; 3411.1Sjmcneill} 3421.1Sjmcneill 3431.1Sjmcneillstatic void 3441.1Sjmcneillsi_get_report_desc(void *cookie, void **desc, int *size) 3451.1Sjmcneill{ 3461.1Sjmcneill *desc = gcpad_report_descr; 3471.1Sjmcneill *size = sizeof(gcpad_report_descr); 3481.1Sjmcneill} 3491.1Sjmcneill 3501.1Sjmcneillstatic int 3511.1Sjmcneillsi_open(void *cookie, void (*intr)(void *, void *, u_int), void *arg) 3521.1Sjmcneill{ 3531.1Sjmcneill struct si_channel *ch = cookie; 3541.1Sjmcneill struct si_softc *sc = ch->ch_sc; 3551.1Sjmcneill int error; 3561.1Sjmcneill 3571.1Sjmcneill mutex_enter(&ch->ch_lock); 3581.1Sjmcneill 3591.1Sjmcneill if (ISSET(ch->ch_state, SI_STATE_OPEN)) { 3601.1Sjmcneill error = EBUSY; 3611.1Sjmcneill goto unlock; 3621.1Sjmcneill } 3631.1Sjmcneill 3641.1Sjmcneill ch->ch_intr = intr; 3651.1Sjmcneill ch->ch_intrarg = arg; 3661.1Sjmcneill ch->ch_state |= SI_STATE_OPEN; 3671.1Sjmcneill 3681.1Sjmcneill (void)RD4(sc, SICINBUFH(ch->ch_index)); 3691.1Sjmcneill (void)RD4(sc, SICINBUFL(ch->ch_index)); 3701.1Sjmcneill 3711.1Sjmcneill /* Init controller */ 3721.1Sjmcneill WR4(sc, SICOUTBUF(ch->ch_index), 0x00400300); 3731.1Sjmcneill 3741.1Sjmcneill /* Enable polling */ 3751.1Sjmcneill WR4(sc, SIPOLL, RD4(sc, SIPOLL) | SIPOLL_EN(ch->ch_index)); 3761.1Sjmcneill 3771.1Sjmcneill WR4(sc, SISR, SISR_WR(ch->ch_index)); 3781.1Sjmcneill WR4(sc, SICOMCSR, RD4(sc, SICOMCSR) | SICOMCSR_TSTART); 3791.1Sjmcneill 3801.1Sjmcneill error = 0; 3811.1Sjmcneill 3821.1Sjmcneillunlock: 3831.1Sjmcneill mutex_exit(&ch->ch_lock); 3841.1Sjmcneill 3851.1Sjmcneill return error; 3861.1Sjmcneill} 3871.1Sjmcneill 3881.1Sjmcneillstatic void 3891.1Sjmcneillsi_stop(void *cookie) 3901.1Sjmcneill{ 3911.1Sjmcneill struct si_channel *ch = cookie; 3921.1Sjmcneill 3931.1Sjmcneill mutex_enter(&ch->ch_lock); 3941.1Sjmcneill 3951.1Sjmcneill ch->ch_state |= SI_STATE_STOPPED; 3961.1Sjmcneill 3971.1Sjmcneill cv_broadcast(&ch->ch_cv); 3981.1Sjmcneill mutex_exit(&ch->ch_lock); 3991.1Sjmcneill} 4001.1Sjmcneill 4011.1Sjmcneillstatic void 4021.1Sjmcneillsi_close(void *cookie) 4031.1Sjmcneill{ 4041.1Sjmcneill struct si_channel *ch = cookie; 4051.1Sjmcneill struct si_softc *sc = ch->ch_sc; 4061.1Sjmcneill 4071.1Sjmcneill mutex_enter(&ch->ch_lock); 4081.1Sjmcneill 4091.1Sjmcneill /* Diable polling */ 4101.1Sjmcneill WR4(sc, SIPOLL, RD4(sc, SIPOLL) & ~SIPOLL_EN(ch->ch_index)); 4111.1Sjmcneill 4121.1Sjmcneill ch->ch_state &= ~(SI_STATE_OPEN | SI_STATE_STOPPED); 4131.1Sjmcneill ch->ch_intr = NULL; 4141.1Sjmcneill ch->ch_intrarg = NULL; 4151.1Sjmcneill 4161.1Sjmcneill cv_broadcast(&ch->ch_cv); 4171.1Sjmcneill mutex_exit(&ch->ch_lock); 4181.1Sjmcneill} 4191.1Sjmcneill 4201.1Sjmcneillstatic usbd_status 4211.1Sjmcneillsi_set_report(void *cookie, int type, void *data, int len) 4221.1Sjmcneill{ 4231.1Sjmcneill return USBD_INVAL; 4241.1Sjmcneill} 4251.1Sjmcneill 4261.1Sjmcneillstatic usbd_status 4271.1Sjmcneillsi_get_report(void *cookie, int type, void *data, int len) 4281.1Sjmcneill{ 4291.1Sjmcneill struct si_channel *ch = cookie; 4301.1Sjmcneill struct si_softc *sc = ch->ch_sc; 4311.1Sjmcneill uint32_t *inbuf = data; 4321.1Sjmcneill 4331.1Sjmcneill if (len != GCPAD_REPORT_SIZE + 1) { 4341.1Sjmcneill return USBD_IOERROR; 4351.1Sjmcneill } 4361.1Sjmcneill 4371.1Sjmcneill mutex_enter(&ch->ch_lock); 4381.1Sjmcneill si_make_report(sc, ch->ch_index, inbuf, true); 4391.1Sjmcneill mutex_exit(&ch->ch_lock); 4401.1Sjmcneill 4411.1Sjmcneill return USBD_NORMAL_COMPLETION; 4421.1Sjmcneill} 4431.1Sjmcneill 4441.1Sjmcneillstatic usbd_status 4451.1Sjmcneillsi_write(void *cookie, void *data, int len) 4461.1Sjmcneill{ 4471.1Sjmcneill return USBD_INVAL; 4481.1Sjmcneill} 449