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