From 2a8222bf45c910f907e2a386dac0ca3b382f839f Mon Sep 17 00:00:00 2001 From: zac brown Date: Fri, 24 Apr 2026 18:06:42 +0000 Subject: [PATCH 01/35] working si_identify method --- sys/arch/evbppc/nintendo/dev/joybus.h | 58 +++++++++++++++++++++ sys/arch/evbppc/nintendo/dev/si.c | 73 ++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 sys/arch/evbppc/nintendo/dev/joybus.h diff --git a/sys/arch/evbppc/nintendo/dev/joybus.h b/sys/arch/evbppc/nintendo/dev/joybus.h new file mode 100644 index 0000000000000..95ad7bf2de03e --- /dev/null +++ b/sys/arch/evbppc/nintendo/dev/joybus.h @@ -0,0 +1,58 @@ +/*- + * Copyright (c) 2025 Zac Brown + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +#define JB_WIRELESS __BIT(15) +#define JB_WIRELESS_RECV __BIT(14) +#define JB_RUMBLE __BIT(13) +#define JB_CONTROLLER __BIT(11) +#define JB_WIRELESS_TYPE __BIT(10) +#define JB_WIRELESS_STATE __BIT(9) +#define JB_DOLPHIN __BIT(8) +#define JB_WIRELESS_ORIGIN __BIT(5) +#define JB_WIRELESS_FIXID __BIT(4) +#define JB_WIRELESS_NONCTRL __BIT(3) +#define JB_WIRELESS_LITE __BIT(2) + +#define SI_NONE 0x0000 +#define SI_N64 0x0500 +#define SI_N64MIC 0x0001 +#define SI_N64KB 0x0002 +#define SI_N64MS 0x0200 +#define SI_GBA 0x0004 +#define SI_GBABIOS 0x0800 +#define SI_GC 0x0900 +#define SI_WAVEBRD_RECV 0xe960 +#define SI_WAVEBRD JB_WIRELESS & JB_RUMBLE & JB_CONTROLLER +#define SI_GCKB 0x0802 +#define SI_GCSTEER 0x0800 // TODO - steering wheel and gba bios are the + // same. risk of misidentification + +#define IS_DOLPHIN(n) ISSET(n, JB_CONTROLLER) +#define IS_N64(n) !ISSET(n, JB_CONTROLLER) +#define IS_GCPAD(n) (((n) & (JB_CONTROLLER | JB_DOLPHIN)) == SI_GC) || ISSET(n, JB_WIRELESS) +#define IS_GBA(n) (n == SI_GBA || n == SI_GBABIOS) diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index d55c06cfae1cf..ca90376aea8e2 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -47,10 +47,13 @@ __KERNEL_RCSID(0, "$NetBSD: si.c,v 1.1 2026/01/09 22:54:30 jmcneill Exp $"); #include "mainbus.h" #include "si.h" #include "gcpad_rdesc.h" +#include "joybus.h" #define SI_NUM_CHAN 4 #define SICOUTBUF(n) ((n) * 0xc + 0x00) +#define SIIDENTIFY 0x00000000 +#define SIINIT 0x00400300 #define SICINBUFH(n) ((n) * 0xc + 0x04) #define SICINBUFL(n) ((n) * 0xc + 0x08) #define SIPOLL 0x30 @@ -60,10 +63,14 @@ __KERNEL_RCSID(0, "$NetBSD: si.c,v 1.1 2026/01/09 22:54:30 jmcneill Exp $"); #define SICOMCSR 0x34 #define SICOMCSR_TCINT __BIT(31) #define SICOMCSR_TCINTMSK __BIT(30) +#define SICOMCSR_COMERR __BIT(29) #define SICOMCSR_RDSTINT __BIT(28) #define SICOMCSR_RDSTINTMSK __BIT(27) +#define SICOMCSR_CH_EN __BIT(24) #define SICOMCSR_OUTLNGTH __BITS(22, 16) #define SICOMCSR_INLNGTH __BITS(14, 8) +#define SICOMCSR_CMD_EN __BIT(7) +#define SICOMCSR_CHANNEL __BITS(2, 1) #define SICOMCSR_TSTART __BIT(0) #define SISR 0x38 #define SISR_OFF(n) ((3 - (n)) * 8) @@ -105,6 +112,8 @@ struct si_channel { kmutex_t ch_lock; kcondvar_t ch_cv; uint8_t ch_state; + uint16_t ch_id; + uint16_t ch_id_extra; #define SI_STATE_OPEN __BIT(0) #define SI_STATE_STOPPED __BIT(1) void (*ch_intr)(void *, void *, u_int); @@ -128,6 +137,12 @@ struct si_softc { #define WR4(sc, reg, val) \ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) +#define AWAIT_SISR(sc, chan) \ + do { while (RD4(sc, SISR) & SISR_WRST(chan)); } while (0) +#define AWAIT_SICOMCSR(sc) \ + do { while (RD4(sc, SICOMCSR) & SICOMCSR_TSTART); } while (0) + + static int si_match(device_t, cfdata_t, void *); static void si_attach(device_t, device_t, void *); @@ -136,6 +151,7 @@ static void si_softintr(void *); static int si_rescan(device_t, const char *, const int *); static int si_print(void *, const char *); +static int si_identify(device_t, unsigned); static void si_get_report_desc(void *, void **, int *); static int si_open(void *, void (*)(void *, void *, unsigned), void *); @@ -190,6 +206,8 @@ si_attach(device_t parent, device_t self, void *aux) si_softintr, ch); KASSERT(ch->ch_si != NULL); + si_identify(self, chan); + t = &ch->ch_hidev; t->_cookie = &sc->sc_chan[chan]; t->_get_report_desc = si_get_report_desc; @@ -223,7 +241,7 @@ si_rescan(device_t self, const char *ifattr, const int *locs) for (chan = 0; chan < SI_NUM_CHAN; chan++) { struct si_channel *ch = &sc->sc_chan[chan]; - if (ch->ch_dev == NULL) { + if (ch->ch_dev == NULL && (IS_GCPAD(ch->ch_id))) { saa.saa_hidev = &ch->ch_hidev; saa.saa_index = ch->ch_index; @@ -254,6 +272,56 @@ si_print(void *aux, const char *pnp) return UNCONF; } + +/* + * Identify the device on the specified channel + * + * Disables Polling and uses the SI I/O Buffer directly to communicate with the + * device. The Identify Response is always a 2-byte identifier and 1-byte of + * extra data. + * + * TODO decide if i need mutex in here. kinda seems like you want to lock + * down the whole siiobuf whenever you are operating on it. i think it might + * need a mutex different than the channel level ones + * + * I think i will probably make an internal method that handles the communiction + * on the iobuffer and that can maintain the lock + */ +static int +si_identify(device_t self, unsigned chan) +{ + uint32_t comcsr, siio; + struct si_softc * const sc = device_private(self); + struct si_channel *ch; + + ch = &sc->sc_chan[chan]; + + WR4(sc, SIPOLL, RD4(sc, SIPOLL) & ~SIPOLL_EN(chan)); + WR4(sc, SIIOBUF, SIIDENTIFY); + WR4(sc, SISR, SISR_WR(chan)); + AWAIT_SISR(sc, chan); + + WR4(sc, SICOMCSR, + SICOMCSR_CH_EN | + SICOMCSR_CMD_EN | + __SHIFTIN(0, SICOMCSR_TCINTMSK) | + __SHIFTIN(1, SICOMCSR_OUTLNGTH) | + __SHIFTIN(3, SICOMCSR_INLNGTH) | + __SHIFTIN(chan, SICOMCSR_CHANNEL) | + SICOMCSR_TSTART + ); + AWAIT_SICOMCSR(sc); + comcsr = RD4(sc, SICOMCSR); + WR4(sc, SICOMCSR, comcsr | SICOMCSR_TCINT); + + siio = RD4(sc, SIIOBUF); + ch->ch_id = siio >> 16; + ch->ch_id_extra = siio & 0x0000FFFF; + aprint_normal("si_identify: Identified chan%d as 0x%08X / 0x%08X\n", chan, ch->ch_id, ch->ch_id_extra); + + return 0; +} + static void si_make_report(struct si_softc *sc, unsigned chan, void *report, bool with_rid) { @@ -369,7 +437,7 @@ si_open(void *cookie, void (*intr)(void *, void *, u_int), void *arg) (void)RD4(sc, SICINBUFL(ch->ch_index)); /* Init controller */ - WR4(sc, SICOUTBUF(ch->ch_index), 0x00400300); + WR4(sc, SICOUTBUF(ch->ch_index), SIINIT); /* Enable polling */ WR4(sc, SIPOLL, RD4(sc, SIPOLL) | SIPOLL_EN(ch->ch_index)); @@ -377,6 +445,7 @@ si_open(void *cookie, void (*intr)(void *, void *, u_int), void *arg) WR4(sc, SISR, SISR_WR(ch->ch_index)); WR4(sc, SICOMCSR, RD4(sc, SICOMCSR) | SICOMCSR_TSTART); + // TODO - AWAIT_SICOMCSR and figure out error error = 0; unlock: From 1b4f43816de4fa988fe440586f17cfdfb90831d1 Mon Sep 17 00:00:00 2001 From: zac brown Date: Fri, 24 Apr 2026 22:03:49 +0000 Subject: [PATCH 02/35] got a char driver for gba to work - moved common stuff to si.h - use the identity of the device in match for uhid/gba - very basic char driver for gba right now can be initialized with mknod /dev/gba0 c gba 0 --- sys/arch/evbppc/conf/NINTENDO | 1 + sys/arch/evbppc/conf/majors.evbppc | 2 + sys/arch/evbppc/nintendo/dev/files.dev | 4 + sys/arch/evbppc/nintendo/dev/gba_si.c | 126 +++++++++++++++++++++++++ sys/arch/evbppc/nintendo/dev/si.c | 95 +------------------ sys/arch/evbppc/nintendo/dev/si.h | 93 ++++++++++++++++++ sys/arch/evbppc/nintendo/dev/uhid_si.c | 12 ++- 7 files changed, 238 insertions(+), 95 deletions(-) create mode 100644 sys/arch/evbppc/nintendo/dev/gba_si.c diff --git a/sys/arch/evbppc/conf/NINTENDO b/sys/arch/evbppc/conf/NINTENDO index 03672719ce36e..ce7521a30ea30 100644 --- a/sys/arch/evbppc/conf/NINTENDO +++ b/sys/arch/evbppc/conf/NINTENDO @@ -133,6 +133,7 @@ options WSDISPLAY_MULTICONS ahb0 at mainbus0 irq 14 si0 at mainbus0 addr 0x0d006400 irq 3 # Serial interface uhid* at si0 +gba* at si0 exi0 at mainbus0 addr 0x0d006800 irq 4 # External interface rtcsram0 at exi0 # RTC/SRAM chip gecko0 at exi0 # USB Gecko diff --git a/sys/arch/evbppc/conf/majors.evbppc b/sys/arch/evbppc/conf/majors.evbppc index 10f9eb8bf8427..2814d96aecc60 100644 --- a/sys/arch/evbppc/conf/majors.evbppc +++ b/sys/arch/evbppc/conf/majors.evbppc @@ -83,6 +83,8 @@ device-major twe char 76 twe #device-major obsolete char 98 obsolete (nsmb) device-major xlcom char 99 xlcom +device-major gba char 100 + # Majors up to 143 are reserved for machine-dependent drivers. # New machine-independent driver majors are assigned in # sys/conf/majors. diff --git a/sys/arch/evbppc/nintendo/dev/files.dev b/sys/arch/evbppc/nintendo/dev/files.dev index cd053d28aadb2..65e7e28c87075 100644 --- a/sys/arch/evbppc/nintendo/dev/files.dev +++ b/sys/arch/evbppc/nintendo/dev/files.dev @@ -37,6 +37,10 @@ file arch/evbppc/nintendo/dev/si.c si attach uhid at si with uhid_si file arch/evbppc/nintendo/dev/uhid_si.c uhid_si +device gba +attach gba at si with gba_si +file arch/evbppc/nintendo/dev/gba_si.c gba_si + define ahb { [addr=-1], [irq=-1] } device ahb: ahb attach ahb at mainbus diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.c b/sys/arch/evbppc/nintendo/dev/gba_si.c new file mode 100644 index 0000000000000..4bb68506f271b --- /dev/null +++ b/sys/arch/evbppc/nintendo/dev/gba_si.c @@ -0,0 +1,126 @@ +/*- + * Copyright (c) 2025 ZacBrown + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/04/24 15:07:30 gummybuns Exp $"); + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "si.h" +#include "joybus.h" + +static int gba_si_match(device_t, cfdata_t, void *); +static void gba_si_attach(device_t, device_t, void *); + +dev_type_open(gba_open); +dev_type_close(gba_close); +dev_type_ioctl(gba_ioctl); + +const struct cdevsw gba_cdevsw = { + .d_open = gba_open, + .d_close = gba_close, + .d_ioctl = noioctl, + .d_read = noread, + .d_write = nowrite, + .d_stop = nostop, + .d_tty = notty, + .d_poll = nopoll, + .d_mmap = nommap, + .d_kqfilter = nokqfilter, + .d_discard = nodiscard, + .d_flag = D_OTHER +}; + +struct gba_softc { + device_t sc_dev; + struct si_channel *ch; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; +}; + +CFATTACH_DECL_NEW(gba_si, sizeof(struct gba_softc), + gba_si_match, gba_si_attach, NULL, NULL); + +static int +gba_si_match(device_t parent, cfdata_t cf, void *aux) +{ + struct si_softc * const sc = device_private(parent); + struct si_attach_args * const saa = aux; + struct si_channel *ch; + + ch = &sc->sc_chan[saa->saa_index]; + aprint_normal("gba: checking 0x%08X...", ch->ch_id); + if (IS_GBA(ch->ch_id)) { + aprint_normal(" is is a gba!\n"); + return 1; + } + + aprint_normal(" is not a gba\n"); + return 0; +} + +static void +gba_si_attach(device_t parent, device_t self, void *aux) +{ + struct si_softc * const psc = device_private(parent); + struct si_attach_args * const saa = aux; + struct gba_softc * const sc = device_private(self); + struct si_channel *ch = &psc->sc_chan[saa->saa_index]; + + aprint_normal("gba: inside attach\n"); + sc->sc_dev = self; + sc->ch = ch; + sc->sc_bst = psc->sc_bst; + sc->sc_bsh = psc->sc_bsh; +} + +int +gba_open(dev_t dev, int flag, int mode, struct lwp *l) +{ + return 0; +} + +int +gba_close(dev_t dev, int flag, int mode, struct lwp *l) +{ + return 0; +} + +/* +int +gba_read(dev_t dev, struct uio *uio, int flags) +{ + return 0; +} +*/ diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index ca90376aea8e2..d100c52916908 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -49,99 +49,6 @@ __KERNEL_RCSID(0, "$NetBSD: si.c,v 1.1 2026/01/09 22:54:30 jmcneill Exp $"); #include "gcpad_rdesc.h" #include "joybus.h" -#define SI_NUM_CHAN 4 - -#define SICOUTBUF(n) ((n) * 0xc + 0x00) -#define SIIDENTIFY 0x00000000 -#define SIINIT 0x00400300 -#define SICINBUFH(n) ((n) * 0xc + 0x04) -#define SICINBUFL(n) ((n) * 0xc + 0x08) -#define SIPOLL 0x30 -#define SIPOLL_X __BITS(25, 16) -#define SIPOLL_Y __BITS(15, 8) -#define SIPOLL_EN(n) (__BIT(7 - n)) -#define SICOMCSR 0x34 -#define SICOMCSR_TCINT __BIT(31) -#define SICOMCSR_TCINTMSK __BIT(30) -#define SICOMCSR_COMERR __BIT(29) -#define SICOMCSR_RDSTINT __BIT(28) -#define SICOMCSR_RDSTINTMSK __BIT(27) -#define SICOMCSR_CH_EN __BIT(24) -#define SICOMCSR_OUTLNGTH __BITS(22, 16) -#define SICOMCSR_INLNGTH __BITS(14, 8) -#define SICOMCSR_CMD_EN __BIT(7) -#define SICOMCSR_CHANNEL __BITS(2, 1) -#define SICOMCSR_TSTART __BIT(0) -#define SISR 0x38 -#define SISR_OFF(n) ((3 - (n)) * 8) -#define SISR_WR(n) __BIT(SISR_OFF(n) + 7) -#define SISR_RDST(n) __BIT(SISR_OFF(n) + 5) -#define SISR_WRST(n) __BIT(SISR_OFF(n) + 4) -#define SISR_NOREP(n) __BIT(SISR_OFF(n) + 3) -#define SISR_COLL(n) __BIT(SISR_OFF(n) + 2) -#define SISR_OVRUN(n) __BIT(SISR_OFF(n) + 1) -#define SISR_UNRUN(n) __BIT(SISR_OFF(n) + 0) -#define SISR_ERROR_MASK(n) (SISR_NOREP(n) | SISR_COLL(n) | \ - SISR_OVRUN(n) | SISR_UNRUN(n)) -#define SISR_ERROR_ACK_ALL (SISR_ERROR_MASK(0) | SISR_ERROR_MASK(1) | \ - SISR_ERROR_MASK(2) | SISR_ERROR_MASK(3)) -#define SIEXILK 0x3c -#define SIIOBUF 0x80 - -#define GCPAD_REPORT_SIZE 9 -#define GCPAD_START(_buf) ISSET((_buf)[0], 0x10) -#define GCPAD_Y(_buf) ISSET((_buf)[0], 0x08) -#define GCPAD_X(_buf) ISSET((_buf)[0], 0x04) -#define GCPAD_B(_buf) ISSET((_buf)[0], 0x02) -#define GCPAD_A(_buf) ISSET((_buf)[0], 0x01) -#define GCPAD_LCLICK(_buf) ISSET((_buf)[1], 0x40) -#define GCPAD_RCLICK(_buf) ISSET((_buf)[1], 0x20) -#define GCPAD_Z(_buf) ISSET((_buf)[1], 0x10) -#define GCPAD_UP(_buf) ISSET((_buf)[1], 0x08) -#define GCPAD_DOWN(_buf) ISSET((_buf)[1], 0x04) -#define GCPAD_RIGHT(_buf) ISSET((_buf)[1], 0x02) -#define GCPAD_LEFT(_buf) ISSET((_buf)[1], 0x01) - -struct si_softc; - -struct si_channel { - struct si_softc *ch_sc; - device_t ch_dev; - unsigned ch_index; - struct hidev_tag ch_hidev; - kmutex_t ch_lock; - kcondvar_t ch_cv; - uint8_t ch_state; - uint16_t ch_id; - uint16_t ch_id_extra; -#define SI_STATE_OPEN __BIT(0) -#define SI_STATE_STOPPED __BIT(1) - void (*ch_intr)(void *, void *, u_int); - void *ch_intrarg; - uint8_t ch_buf[GCPAD_REPORT_SIZE]; - void *ch_desc; - int ch_descsize; - void *ch_si; -}; - -struct si_softc { - device_t sc_dev; - bus_space_tag_t sc_bst; - bus_space_handle_t sc_bsh; - - struct si_channel sc_chan[SI_NUM_CHAN]; -}; - -#define RD4(sc, reg) \ - bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) -#define WR4(sc, reg, val) \ - bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) - -#define AWAIT_SISR(sc, chan) \ - do { while (RD4(sc, SISR) & SISR_WRST(chan)); } while (0) -#define AWAIT_SICOMCSR(sc) \ - do { while (RD4(sc, SICOMCSR) & SICOMCSR_TSTART); } while (0) - static int si_match(device_t, cfdata_t, void *); static void si_attach(device_t, device_t, void *); @@ -241,7 +148,7 @@ si_rescan(device_t self, const char *ifattr, const int *locs) for (chan = 0; chan < SI_NUM_CHAN; chan++) { struct si_channel *ch = &sc->sc_chan[chan]; - if (ch->ch_dev == NULL && (IS_GCPAD(ch->ch_id))) { + if (ch->ch_dev == NULL) { saa.saa_hidev = &ch->ch_hidev; saa.saa_index = ch->ch_index; diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index fa7ccb037f8d3..981ff77875262 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -31,6 +31,99 @@ #include +#define SI_NUM_CHAN 4 + +#define SICOUTBUF(n) ((n) * 0xc + 0x00) +#define SIIDENTIFY 0x00000000 +#define SIINIT 0x00400300 +#define SICINBUFH(n) ((n) * 0xc + 0x04) +#define SICINBUFL(n) ((n) * 0xc + 0x08) +#define SIPOLL 0x30 +#define SIPOLL_X __BITS(25, 16) +#define SIPOLL_Y __BITS(15, 8) +#define SIPOLL_EN(n) (__BIT(7 - n)) +#define SICOMCSR 0x34 +#define SICOMCSR_TCINT __BIT(31) +#define SICOMCSR_TCINTMSK __BIT(30) +#define SICOMCSR_COMERR __BIT(29) +#define SICOMCSR_RDSTINT __BIT(28) +#define SICOMCSR_RDSTINTMSK __BIT(27) +#define SICOMCSR_CH_EN __BIT(24) +#define SICOMCSR_OUTLNGTH __BITS(22, 16) +#define SICOMCSR_INLNGTH __BITS(14, 8) +#define SICOMCSR_CMD_EN __BIT(7) +#define SICOMCSR_CHANNEL __BITS(2, 1) +#define SICOMCSR_TSTART __BIT(0) +#define SISR 0x38 +#define SISR_OFF(n) ((3 - (n)) * 8) +#define SISR_WR(n) __BIT(SISR_OFF(n) + 7) +#define SISR_RDST(n) __BIT(SISR_OFF(n) + 5) +#define SISR_WRST(n) __BIT(SISR_OFF(n) + 4) +#define SISR_NOREP(n) __BIT(SISR_OFF(n) + 3) +#define SISR_COLL(n) __BIT(SISR_OFF(n) + 2) +#define SISR_OVRUN(n) __BIT(SISR_OFF(n) + 1) +#define SISR_UNRUN(n) __BIT(SISR_OFF(n) + 0) +#define SISR_ERROR_MASK(n) (SISR_NOREP(n) | SISR_COLL(n) | \ + SISR_OVRUN(n) | SISR_UNRUN(n)) +#define SISR_ERROR_ACK_ALL (SISR_ERROR_MASK(0) | SISR_ERROR_MASK(1) | \ + SISR_ERROR_MASK(2) | SISR_ERROR_MASK(3)) +#define SIEXILK 0x3c +#define SIIOBUF 0x80 + +#define GCPAD_REPORT_SIZE 9 +#define GCPAD_START(_buf) ISSET((_buf)[0], 0x10) +#define GCPAD_Y(_buf) ISSET((_buf)[0], 0x08) +#define GCPAD_X(_buf) ISSET((_buf)[0], 0x04) +#define GCPAD_B(_buf) ISSET((_buf)[0], 0x02) +#define GCPAD_A(_buf) ISSET((_buf)[0], 0x01) +#define GCPAD_LCLICK(_buf) ISSET((_buf)[1], 0x40) +#define GCPAD_RCLICK(_buf) ISSET((_buf)[1], 0x20) +#define GCPAD_Z(_buf) ISSET((_buf)[1], 0x10) +#define GCPAD_UP(_buf) ISSET((_buf)[1], 0x08) +#define GCPAD_DOWN(_buf) ISSET((_buf)[1], 0x04) +#define GCPAD_RIGHT(_buf) ISSET((_buf)[1], 0x02) +#define GCPAD_LEFT(_buf) ISSET((_buf)[1], 0x01) + +#define RD4(sc, reg) \ + bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) +#define WR4(sc, reg, val) \ + bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) + +#define AWAIT_SISR(sc, chan) \ + do { while (RD4(sc, SISR) & SISR_WRST(chan)); } while (0) +#define AWAIT_SICOMCSR(sc) \ + do { while (RD4(sc, SICOMCSR) & SICOMCSR_TSTART); } while (0) + +struct si_softc; + +struct si_channel { + struct si_softc *ch_sc; + device_t ch_dev; + unsigned ch_index; + struct hidev_tag ch_hidev; + kmutex_t ch_lock; + kcondvar_t ch_cv; + uint8_t ch_state; + uint16_t ch_id; + uint16_t ch_id_extra; +#define SI_STATE_OPEN __BIT(0) +#define SI_STATE_STOPPED __BIT(1) + void (*ch_intr)(void *, void *, u_int); + void *ch_intrarg; + uint8_t ch_buf[GCPAD_REPORT_SIZE]; + void *ch_desc; + int ch_descsize; + void *ch_si; +}; + +struct si_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + + struct si_channel sc_chan[SI_NUM_CHAN]; +}; + struct si_attach_args { struct hidev_tag *saa_hidev; int saa_index; diff --git a/sys/arch/evbppc/nintendo/dev/uhid_si.c b/sys/arch/evbppc/nintendo/dev/uhid_si.c index 61ff6914aec8b..d0191b0f332e1 100644 --- a/sys/arch/evbppc/nintendo/dev/uhid_si.c +++ b/sys/arch/evbppc/nintendo/dev/uhid_si.c @@ -39,6 +39,7 @@ __KERNEL_RCSID(0, "$NetBSD: uhid_si.c,v 1.1 2026/01/09 22:54:30 jmcneill Exp $") #include #include "si.h" +#include "joybus.h" #define UHID_SI_VENDOR 0x057e /* Nintendo */ #define UHID_SI_PRODUCT 0x0337 /* GameCube adapter */ @@ -55,7 +56,16 @@ CFATTACH_DECL_NEW(uhid_si, sizeof(struct uhid_softc), static int uhid_si_match(device_t parent, cfdata_t cf, void *aux) { - return 1; + struct si_softc * const sc = device_private(parent); + struct si_attach_args * const saa = aux; + struct si_channel *ch; + + ch = &sc->sc_chan[saa->saa_index]; + if (IS_GCPAD(ch->ch_id)) { + return 1; + } + + return 0; } static void From 03ded0a25f0cbf9a47bdaf13eaaeb6d2be3e435d Mon Sep 17 00:00:00 2001 From: zac brown Date: Tue, 28 Apr 2026 20:11:15 +0000 Subject: [PATCH 03/35] refactored to have a common send for siiobuf --- sys/arch/evbppc/nintendo/dev/gba_si.c | 64 +++++++++++++++++++++++---- sys/arch/evbppc/nintendo/dev/si.c | 37 +++++++--------- sys/arch/evbppc/nintendo/dev/si.h | 53 ++++++++++++++++++++++ 3 files changed, 126 insertions(+), 28 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.c b/sys/arch/evbppc/nintendo/dev/gba_si.c index 4bb68506f271b..e7dd1d9a35769 100644 --- a/sys/arch/evbppc/nintendo/dev/gba_si.c +++ b/sys/arch/evbppc/nintendo/dev/gba_si.c @@ -30,6 +30,7 @@ __KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/04/24 15:07:30 gummybuns Exp $") #include #include #include +#include #include #include #include @@ -50,7 +51,7 @@ dev_type_ioctl(gba_ioctl); const struct cdevsw gba_cdevsw = { .d_open = gba_open, .d_close = gba_close, - .d_ioctl = noioctl, + .d_ioctl = gba_ioctl, .d_read = noread, .d_write = nowrite, .d_stop = nostop, @@ -62,6 +63,8 @@ const struct cdevsw gba_cdevsw = { .d_flag = D_OTHER }; +extern struct cfdriver gba_cd; + struct gba_softc { device_t sc_dev; struct si_channel *ch; @@ -106,21 +109,66 @@ gba_si_attach(device_t parent, device_t self, void *aux) } int -gba_open(dev_t dev, int flag, int mode, struct lwp *l) +gba_open(dev_t dev, int flags, int mode, struct lwp *l) { - return 0; + struct gba_softc * const sc = device_lookup_private(&gba_cd, minor(dev)); + struct si_channel *ch = sc->ch; + int error; + + mutex_enter(&ch->ch_lock); + + if (ISSET(ch->ch_state, SI_STATE_OPEN)) { + error = EBUSY; + goto unlock; + } + + ch->ch_state |= SI_STATE_OPEN; +unlock: + mutex_exit(&ch->ch_lock); + return error; } int -gba_close(dev_t dev, int flag, int mode, struct lwp *l) +gba_close(dev_t dev, int flags, int mode, struct lwp *l) { + struct gba_softc * const sc = device_lookup_private(&gba_cd, minor(dev)); + struct si_channel *ch = sc->ch; + + mutex_enter(&ch->ch_lock); + ch->ch_state &= ~(SI_STATE_OPEN | SI_STATE_STOPPED); + + /* cv_init is called in parent's si_attach */ + cv_broadcast(&ch->ch_cv); + + mutex_exit(&ch->ch_lock); return 0; } -/* +/** + * TODO: + * + * i dont really want to touch the other guys code at all if i dont have to. + * i dont think that i do. according to the docs you should never set + * TSTART if you are in the middle of a transaction. i can add the AWAIT to + * one or two of his lines np. + * + * then it says you should never change OUTLENGTH / INLENGTH / CHANNEL in the + * middle of a transaction. these are only things used for the siiobuf, which + * no one is using but me. so i can define my own mutex for that purpose. + */ int -gba_read(dev_t dev, struct uio *uio, int flags) +gba_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { - return 0; + //struct gba_softc * const sc = device_lookup_private(&gba_cd, minor(dev)); + int err; + + switch(cmd) { +// case SI_SEND: +// break; + default: + err = EINVAL; + break; + } + + return err; } -*/ diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index d100c52916908..19ce79fcc3d48 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -68,6 +68,8 @@ static usbd_status si_set_report(void *, int, void *, int); static usbd_status si_get_report(void *, int, void *, int); static usbd_status si_write(void *, void *, int); +kmutex_t sicomcsr_lock; + CFATTACH_DECL_NEW(si, sizeof(struct si_softc), si_match, si_attach, NULL, NULL); @@ -99,6 +101,7 @@ si_attach(device_t parent, device_t self, void *aux) aprint_error_dev(self, "couldn't map registers\n"); return; } + mutex_init(&sicomcsr_lock, MUTEX_DEFAULT, IPL_VM); for (chan = 0; chan < SI_NUM_CHAN; chan++) { struct si_channel *ch; @@ -197,34 +200,29 @@ si_print(void *aux, const char *pnp) static int si_identify(device_t self, unsigned chan) { - uint32_t comcsr, siio; + uint32_t comcsr; struct si_softc * const sc = device_private(self); struct si_channel *ch; + struct siio_send data; + uint8_t in[0]; + uint8_t out[3]; + + data.cmd = SIIDENTIFY; + data.chan = chan; + data.send_size = 0; + data.recv_size = 3; + data.inbuf = in; + data.outbuf = out; ch = &sc->sc_chan[chan]; WR4(sc, SIPOLL, RD4(sc, SIPOLL) & ~SIPOLL_EN(chan)); - WR4(sc, SIIOBUF, SIIDENTIFY); - WR4(sc, SISR, SISR_WR(chan)); - AWAIT_SISR(sc, chan); - - WR4(sc, SICOMCSR, - SICOMCSR_CH_EN | - SICOMCSR_CMD_EN | - __SHIFTIN(0, SICOMCSR_TCINTMSK) | - __SHIFTIN(1, SICOMCSR_OUTLNGTH) | - __SHIFTIN(3, SICOMCSR_INLNGTH) | - __SHIFTIN(chan, SICOMCSR_CHANNEL) | - SICOMCSR_TSTART - ); - AWAIT_SICOMCSR(sc); + __si_send(sc, &data); comcsr = RD4(sc, SICOMCSR); WR4(sc, SICOMCSR, comcsr | SICOMCSR_TCINT); - siio = RD4(sc, SIIOBUF); - ch->ch_id = siio >> 16; - ch->ch_id_extra = siio & 0x0000FFFF; - aprint_normal("si_identify: Identified chan%d as 0x%08X / 0x%08X\n", chan, ch->ch_id, ch->ch_id_extra); + ch->ch_id = (uint16_t)out[0] << 8; + aprint_normal("si_identify: Identified chan%d as 0x%08X\n", chan, ch->ch_id); return 0; } @@ -352,7 +350,6 @@ si_open(void *cookie, void (*intr)(void *, void *, u_int), void *arg) WR4(sc, SISR, SISR_WR(ch->ch_index)); WR4(sc, SICOMCSR, RD4(sc, SICOMCSR) | SICOMCSR_TSTART); - // TODO - AWAIT_SICOMCSR and figure out error error = 0; unlock: diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 981ff77875262..cff0e82d323e7 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -69,6 +69,7 @@ SISR_ERROR_MASK(2) | SISR_ERROR_MASK(3)) #define SIEXILK 0x3c #define SIIOBUF 0x80 +#define SIIOBUF_SIZE 128 #define GCPAD_REPORT_SIZE 9 #define GCPAD_START(_buf) ISSET((_buf)[0], 0x10) @@ -95,6 +96,7 @@ do { while (RD4(sc, SICOMCSR) & SICOMCSR_TSTART); } while (0) struct si_softc; +extern kmutex_t sicomcsr_lock; struct si_channel { struct si_softc *ch_sc; @@ -129,4 +131,55 @@ struct si_attach_args { int saa_index; }; +struct siio_send { + uint8_t cmd; + unsigned chan; + uint8_t send_size; + uint8_t recv_size; + uint8_t *inbuf; + uint8_t *outbuf; +}; + +static inline int +__si_send(struct si_softc *sc, struct siio_send *data) +{ + uint32_t comcsr, sisr; + unsigned chan; + + chan = data->chan; + + bus_space_set_region_1(sc->sc_bst, sc->sc_bsh, SIIOBUF, 0, SIIOBUF_SIZE); + WR4(sc, SISR, SISR_ERROR_MASK(chan)); + + WR4(sc, SIIOBUF, data->cmd); + bus_space_write_region_1(sc->sc_bst, sc->sc_bsh, SIIOBUF+1, + data->inbuf, data->send_size); + + AWAIT_SICOMCSR(sc); + WR4(sc, SICOMCSR, + SICOMCSR_CH_EN | + SICOMCSR_CMD_EN | + __SHIFTIN(0, SICOMCSR_TCINTMSK) | + __SHIFTIN(data->send_size + 1, SICOMCSR_OUTLNGTH) | + __SHIFTIN(data->recv_size, SICOMCSR_INLNGTH) | + __SHIFTIN(chan, SICOMCSR_CHANNEL) | + SICOMCSR_TSTART + ); + AWAIT_SICOMCSR(sc); + + bus_space_read_region_1(sc->sc_bst, sc->sc_bsh, SIIOBUF, + data->outbuf, data->recv_size); + + comcsr = RD4(sc, SICOMCSR); + if (ISSET(comcsr, SICOMCSR_COMERR)) { + sisr = RD4(sc, SISR); + // TODO figure out the bit shifting here + //(sisr & SISR_ERROR_MASK(chan)) >> (NUM_CHANS - chan); + return sisr & SISR_ERROR_MASK(chan); + } + + return 0; +} + + #endif /* _WII_DEV_SI_H_ */ From 9a69c81934760abd6396adb64c83d2b05aec4eb3 Mon Sep 17 00:00:00 2001 From: zac brown Date: Wed, 29 Apr 2026 02:16:31 +0000 Subject: [PATCH 04/35] refactor __siiobuf_send --- sys/arch/evbppc/nintendo/dev/si.c | 45 +++++++++++-------------------- sys/arch/evbppc/nintendo/dev/si.h | 42 ++++++++++++++++------------- 2 files changed, 38 insertions(+), 49 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index 19ce79fcc3d48..601cff1ec2277 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -183,46 +183,31 @@ si_print(void *aux, const char *pnp) } -/* - * Identify the device on the specified channel - * - * Disables Polling and uses the SI I/O Buffer directly to communicate with the - * device. The Identify Response is always a 2-byte identifier and 1-byte of - * extra data. - * - * TODO decide if i need mutex in here. kinda seems like you want to lock - * down the whole siiobuf whenever you are operating on it. i think it might - * need a mutex different than the channel level ones - * - * I think i will probably make an internal method that handles the communiction - * on the iobuffer and that can maintain the lock - */ static int si_identify(device_t self, unsigned chan) { - uint32_t comcsr; struct si_softc * const sc = device_private(self); struct si_channel *ch; struct siio_send data; - uint8_t in[0]; - uint8_t out[3]; + uint8_t out[1]; + uint8_t in[3]; + int res; - data.cmd = SIIDENTIFY; + /* identify always expects 3 bytes back although id is only 2 bytes */ + out[0] = SIIDENTIFY; data.chan = chan; - data.send_size = 0; - data.recv_size = 3; - data.inbuf = in; - data.outbuf = out; + data.out = out; + data.outsize = 1; + data.in = in; + data.insize = 3; - ch = &sc->sc_chan[chan]; - - WR4(sc, SIPOLL, RD4(sc, SIPOLL) & ~SIPOLL_EN(chan)); - __si_send(sc, &data); - comcsr = RD4(sc, SICOMCSR); - WR4(sc, SICOMCSR, comcsr | SICOMCSR_TCINT); + if ((res = __si_send(sc, &data)) != 0) { + aprint_normal("si_identify: chan%d sisr - 0x%08X\n", chan, res); + } - ch->ch_id = (uint16_t)out[0] << 8; - aprint_normal("si_identify: Identified chan%d as 0x%08X\n", chan, ch->ch_id); + ch = &sc->sc_chan[chan]; + ch->ch_id = (uint16_t)in[0] << 8; + aprint_normal("si_identify: chan%d id - 0x%08X\n", chan, ch->ch_id); return 0; } diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index cff0e82d323e7..eeade3fd686c4 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -89,6 +89,13 @@ bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) #define WR4(sc, reg, val) \ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) +#define SIIOBUF_CLEAR(sc) \ + bus_space_set_region_1((sc)->sc_bst, (sc)->sc_bsh, SIIOBUF, 0, \ + SIIOBUF_SIZE) +#define SIIOBUF_WR(sc, buf, sz) \ + bus_space_write_region_1((sc)->sc_bst, (sc)->sc_bsh, SIIOBUF, buf, sz) +#define SIIOBUF_RD(sc, buf, sz) \ + bus_space_read_region_1((sc)->sc_bst, (sc)->sc_bsh, SIIOBUF, buf, sz) #define AWAIT_SISR(sc, chan) \ do { while (RD4(sc, SISR) & SISR_WRST(chan)); } while (0) @@ -132,50 +139,47 @@ struct si_attach_args { }; struct siio_send { - uint8_t cmd; - unsigned chan; - uint8_t send_size; - uint8_t recv_size; - uint8_t *inbuf; - uint8_t *outbuf; + unsigned chan; /* which controller port */ + uint8_t insize; /* size of in buffer - max 128 */ + uint8_t outsize; /* size of out buffer - max 128 */ + uint8_t *in; /* buffer to store response */ + uint8_t *out; /* buffer to send out to ext device */ }; static inline int __si_send(struct si_softc *sc, struct siio_send *data) { - uint32_t comcsr, sisr; + uint32_t comcsr, sisr, shift_amt; unsigned chan; chan = data->chan; - bus_space_set_region_1(sc->sc_bst, sc->sc_bsh, SIIOBUF, 0, SIIOBUF_SIZE); + SIIOBUF_CLEAR(sc); + SIIOBUF_WR(sc, data->out, data->outsize); WR4(sc, SISR, SISR_ERROR_MASK(chan)); - WR4(sc, SIIOBUF, data->cmd); - bus_space_write_region_1(sc->sc_bst, sc->sc_bsh, SIIOBUF+1, - data->inbuf, data->send_size); - AWAIT_SICOMCSR(sc); WR4(sc, SICOMCSR, SICOMCSR_CH_EN | SICOMCSR_CMD_EN | __SHIFTIN(0, SICOMCSR_TCINTMSK) | - __SHIFTIN(data->send_size + 1, SICOMCSR_OUTLNGTH) | - __SHIFTIN(data->recv_size, SICOMCSR_INLNGTH) | + __SHIFTIN(data->outsize, SICOMCSR_OUTLNGTH) | + __SHIFTIN(data->insize, SICOMCSR_INLNGTH) | __SHIFTIN(chan, SICOMCSR_CHANNEL) | SICOMCSR_TSTART ); AWAIT_SICOMCSR(sc); - bus_space_read_region_1(sc->sc_bst, sc->sc_bsh, SIIOBUF, - data->outbuf, data->recv_size); + comcsr = RD4(sc, SICOMCSR); + WR4(sc, SICOMCSR, comcsr | SICOMCSR_TCINT); + + SIIOBUF_RD(sc, data->in, data->insize); comcsr = RD4(sc, SICOMCSR); if (ISSET(comcsr, SICOMCSR_COMERR)) { sisr = RD4(sc, SISR); - // TODO figure out the bit shifting here - //(sisr & SISR_ERROR_MASK(chan)) >> (NUM_CHANS - chan); - return sisr & SISR_ERROR_MASK(chan); + shift_amt = 8 * (SI_NUM_CHAN - 1 - chan); + return ((sisr & SISR_ERROR_MASK(chan)) >> shift_amt) & 0x3F; } return 0; From 119611a4365ccab6d110fa52fe2f0054aed59a99 Mon Sep 17 00:00:00 2001 From: zac brown Date: Tue, 12 May 2026 00:56:36 +0000 Subject: [PATCH 05/35] wip playing with multiboot --- sys/arch/evbppc/nintendo/dev/gba_si.c | 32 ++++++++++++++++++++++ sys/arch/evbppc/nintendo/dev/si.c | 8 +++--- sys/arch/evbppc/nintendo/dev/si.h | 38 ++++++++++++++++++++------- 3 files changed, 64 insertions(+), 14 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.c b/sys/arch/evbppc/nintendo/dev/gba_si.c index e7dd1d9a35769..db047e99dd592 100644 --- a/sys/arch/evbppc/nintendo/dev/gba_si.c +++ b/sys/arch/evbppc/nintendo/dev/gba_si.c @@ -96,16 +96,48 @@ gba_si_match(device_t parent, cfdata_t cf, void *aux) static void gba_si_attach(device_t parent, device_t self, void *aux) { + uint32_t siiobuf; struct si_softc * const psc = device_private(parent); struct si_attach_args * const saa = aux; struct gba_softc * const sc = device_private(self); struct si_channel *ch = &psc->sc_chan[saa->saa_index]; + struct siio_send data; + int res; + uint8_t out[3]; + uint16_t in[1]; aprint_normal("gba: inside attach\n"); sc->sc_dev = self; sc->ch = ch; sc->sc_bst = psc->sc_bst; sc->sc_bsh = psc->sc_bsh; + + for(;;) { + for (int i = 0; i < 15; i++) { + aprint_normal("trying to send handshake\n"); + // this is wong + out[0] = 0x15; + out[1] = 0x62; + out[2] = 0x02; + //out[0] = 0x6202; + data.chan = saa->saa_index; + data.out = out; + data.in = in; + data.outsize = 3; + data.insize = 2; + siiobuf = RD4(psc, SIIOBUF); + aprint_normal("handshake: before - siiobuf - 0x%08X\n", siiobuf); + if ((res = __si_send(psc, &data)) != 0) { + aprint_normal("handshake: sisr - 0x%08X\n", res); + } + + siiobuf = RD4(psc, SIIOBUF); + aprint_normal("handshake: after - siiobuf - 0x%08X\n", siiobuf); + if (in[0] != 0) break; + } + if (in[0] != 0) break; + delay(62500); /* 1/16 of a second */ + } } int diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index 601cff1ec2277..f848ccae9b0c8 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -189,16 +189,16 @@ si_identify(device_t self, unsigned chan) struct si_softc * const sc = device_private(self); struct si_channel *ch; struct siio_send data; - uint8_t out[1]; - uint8_t in[3]; + uint32_t out[1]; + uint32_t in[1]; int res; /* identify always expects 3 bytes back although id is only 2 bytes */ out[0] = SIIDENTIFY; data.chan = chan; data.out = out; - data.outsize = 1; data.in = in; + data.outsize = 1; data.insize = 3; if ((res = __si_send(sc, &data)) != 0) { @@ -206,7 +206,7 @@ si_identify(device_t self, unsigned chan) } ch = &sc->sc_chan[chan]; - ch->ch_id = (uint16_t)in[0] << 8; + ch->ch_id = (uint16_t)(in[0] >> 16); aprint_normal("si_identify: chan%d id - 0x%08X\n", chan, ch->ch_id); return 0; diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index eeade3fd686c4..15855180963b1 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -92,10 +92,10 @@ #define SIIOBUF_CLEAR(sc) \ bus_space_set_region_1((sc)->sc_bst, (sc)->sc_bsh, SIIOBUF, 0, \ SIIOBUF_SIZE) -#define SIIOBUF_WR(sc, buf, sz) \ - bus_space_write_region_1((sc)->sc_bst, (sc)->sc_bsh, SIIOBUF, buf, sz) -#define SIIOBUF_RD(sc, buf, sz) \ - bus_space_read_region_1((sc)->sc_bst, (sc)->sc_bsh, SIIOBUF, buf, sz) +#define SIIOBUF_WR(sc, buf, cnt) \ + bus_space_write_region_4((sc)->sc_bst, (sc)->sc_bsh, SIIOBUF, buf, cnt) +#define SIIOBUF_RD(sc, buf, cnt) \ + bus_space_read_region_1((sc)->sc_bst, (sc)->sc_bsh, SIIOBUF, buf, cnt) #define AWAIT_SISR(sc, chan) \ do { while (RD4(sc, SISR) & SISR_WRST(chan)); } while (0) @@ -140,22 +140,39 @@ struct si_attach_args { struct siio_send { unsigned chan; /* which controller port */ - uint8_t insize; /* size of in buffer - max 128 */ - uint8_t outsize; /* size of out buffer - max 128 */ - uint8_t *in; /* buffer to store response */ - uint8_t *out; /* buffer to send out to ext device */ + uint32_t insize; /* number of bytes for in buffer */ + uint32_t outsize; /* number of bytes for out buffer */ + void *in; /* buffer to store response */ + void *out; /* buffer to send out to ext device */ }; static inline int __si_send(struct si_softc *sc, struct siio_send *data) { - uint32_t comcsr, sisr, shift_amt; + uint32_t comcsr, sisr, shift_amt, cnt; //, i, val; unsigned chan; chan = data->chan; + aprint_normal("\n"); + aprint_normal("__si_send: chan %d siiobuf before clear is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); SIIOBUF_CLEAR(sc); - SIIOBUF_WR(sc, data->out, data->outsize); + aprint_normal("__si_send: chan %d siiobuf after clear is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); + + /* siiobuf must to be written in increments of 4 bytes */ + cnt = ((data->outsize+3)/4); + aprint_normal("__si_send: chan %d out buf (outsize %d / cnt %d):", chan, data->outsize, cnt); + SIIOBUF_WR(sc, data->out, cnt); + /* + for (i = 0; i < cnt; i++) { + val = 0; + size_t sz = MIN(4, data->outsize - (i * 4)); + memcpy(&val, ((uint8_t *)data->out) + (i * 4), sz); + WR4(sc, SIIOBUF + i, val); + } + */ + + aprint_normal("__si_send: chan %d siiobuf after write is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); WR4(sc, SISR, SISR_ERROR_MASK(chan)); AWAIT_SICOMCSR(sc); @@ -173,6 +190,7 @@ __si_send(struct si_softc *sc, struct siio_send *data) comcsr = RD4(sc, SICOMCSR); WR4(sc, SICOMCSR, comcsr | SICOMCSR_TCINT); + aprint_normal("__si_send: chan %d siiobuf after command is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); SIIOBUF_RD(sc, data->in, data->insize); comcsr = RD4(sc, SICOMCSR); From ecdb2658eecb6343d57d5c8eaab924ad6fe4ac52 Mon Sep 17 00:00:00 2001 From: gummybuns Date: Tue, 12 May 2026 21:00:41 -0400 Subject: [PATCH 06/35] trying to implement ioctl --- sys/arch/evbppc/nintendo/dev/gba_si.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.c b/sys/arch/evbppc/nintendo/dev/gba_si.c index db047e99dd592..f732ac2e98162 100644 --- a/sys/arch/evbppc/nintendo/dev/gba_si.c +++ b/sys/arch/evbppc/nintendo/dev/gba_si.c @@ -30,6 +30,7 @@ __KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/04/24 15:07:30 gummybuns Exp $") #include #include #include +#include #include #include #include @@ -41,6 +42,8 @@ __KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/04/24 15:07:30 gummybuns Exp $") #include "si.h" #include "joybus.h" +#define SI_SEND _IOWR(0, 1, struct siio_send) + static int gba_si_match(device_t, cfdata_t, void *); static void gba_si_attach(device_t, device_t, void *); @@ -191,12 +194,14 @@ gba_close(dev_t dev, int flags, int mode, struct lwp *l) int gba_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { - //struct gba_softc * const sc = device_lookup_private(&gba_cd, minor(dev)); + struct gba_softc * const gbasc = device_lookup_private(&gba_cd, minor(dev)); + struct si_softc * const sc = gbasc->ch->ch_sc; int err; switch(cmd) { -// case SI_SEND: -// break; + case SI_SEND: + err = __si_send(sc, (struct siio_send *) data); + break; default: err = EINVAL; break; From 2d5705121d0b8050696b5bb50b1ee15675012abd Mon Sep 17 00:00:00 2001 From: zac brown Date: Wed, 13 May 2026 03:01:24 +0000 Subject: [PATCH 07/35] return 0 --- sys/arch/evbppc/nintendo/dev/gba_si.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.c b/sys/arch/evbppc/nintendo/dev/gba_si.c index f732ac2e98162..4b819d5bb71d9 100644 --- a/sys/arch/evbppc/nintendo/dev/gba_si.c +++ b/sys/arch/evbppc/nintendo/dev/gba_si.c @@ -139,7 +139,7 @@ gba_si_attach(device_t parent, device_t self, void *aux) if (in[0] != 0) break; } if (in[0] != 0) break; - delay(62500); /* 1/16 of a second */ + delay(62500); // 1/16 of a second } } @@ -158,6 +158,7 @@ gba_open(dev_t dev, int flags, int mode, struct lwp *l) } ch->ch_state |= SI_STATE_OPEN; + error = 0; unlock: mutex_exit(&ch->ch_lock); return error; From 716db9c2b07a8345959b8794213537c795aee11e Mon Sep 17 00:00:00 2001 From: zac brown Date: Thu, 14 May 2026 00:48:44 +0000 Subject: [PATCH 08/35] actually got userland program with ioctl to work --- sys/arch/evbppc/nintendo/dev/gba_si.c | 55 ++++++++++++++++++++++++--- sys/arch/evbppc/nintendo/dev/si.h | 14 +++---- 2 files changed, 56 insertions(+), 13 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.c b/sys/arch/evbppc/nintendo/dev/gba_si.c index 4b819d5bb71d9..3855791d6411a 100644 --- a/sys/arch/evbppc/nintendo/dev/gba_si.c +++ b/sys/arch/evbppc/nintendo/dev/gba_si.c @@ -31,10 +31,12 @@ __KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/04/24 15:07:30 gummybuns Exp $") #include #include #include +#include #include #include #include #include +#include #include #include @@ -42,7 +44,15 @@ __KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/04/24 15:07:30 gummybuns Exp $") #include "si.h" #include "joybus.h" -#define SI_SEND _IOWR(0, 1, struct siio_send) +struct gba_send { + uint32_t status; + uint32_t insize; + uint32_t outsize; + void *in; + void *out; +}; + +#define SI_SEND _IOWR(0, 1, struct gba_send) static int gba_si_match(device_t, cfdata_t, void *); static void gba_si_attach(device_t, device_t, void *); @@ -86,7 +96,7 @@ gba_si_match(device_t parent, cfdata_t cf, void *aux) struct si_channel *ch; ch = &sc->sc_chan[saa->saa_index]; - aprint_normal("gba: checking 0x%08X...", ch->ch_id); + aprint_normal("gba: checking 0x%08X...\n", ch->ch_id); if (IS_GBA(ch->ch_id)) { aprint_normal(" is is a gba!\n"); return 1; @@ -114,6 +124,7 @@ gba_si_attach(device_t parent, device_t self, void *aux) sc->ch = ch; sc->sc_bst = psc->sc_bst; sc->sc_bsh = psc->sc_bsh; + aprint_normal("gba: channel is set to %d\n", sc->ch->ch_index); for(;;) { for (int i = 0; i < 15; i++) { @@ -195,14 +206,46 @@ gba_close(dev_t dev, int flags, int mode, struct lwp *l) int gba_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { - struct gba_softc * const gbasc = device_lookup_private(&gba_cd, minor(dev)); - struct si_softc * const sc = gbasc->ch->ch_sc; + struct gba_softc * const gbasc = device_lookup_private(&gba_cd, minor(dev)); + struct si_channel *ch = gbasc->ch; + struct si_softc * const sc = ch->ch_sc; + struct siio_send sd; int err; switch(cmd) { case SI_SEND: - err = __si_send(sc, (struct siio_send *) data); - break; + err = 0; + struct gba_send *gbs = (struct gba_send *)data; + if (gbs->outsize > SIIOBUF_SIZE || gbs->insize > SIIOBUF_SIZE) { + return EINVAL; + } + + sd.chan = ch->ch_index; + sd.outsize = gbs->outsize; + sd.insize = gbs->insize; + sd.out = kmem_alloc(gbs->outsize, KM_SLEEP); + sd.in = kmem_alloc(gbs->insize, KM_SLEEP); + + aprint_normal("gba_ioctl: gbs--outsize%d insize%d\n", gbs->outsize, gbs->insize); + aprint_normal("gba_ioctl: sd--chan:%d\t outsize%d insize%d\n", sd.chan, sd.outsize, sd.insize); + + if ((err = copyin(gbs->out, sd.out, sd.outsize)) != 0) { + goto si_send_cleanup; + } + + if ((err = __si_send(sc, &sd)) != 0) { + goto si_send_cleanup; + } + + if ((err = copyout(sd.in, gbs->in, sd.insize)) != 0) { + goto si_send_cleanup; + } + + gbs->status = sd.status; +si_send_cleanup: + kmem_free(sd.out, sd.outsize); + kmem_free(sd.in, sd.insize); + break; default: err = EINVAL; break; diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 15855180963b1..b72f17a515932 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -140,6 +140,7 @@ struct si_attach_args { struct siio_send { unsigned chan; /* which controller port */ + uint32_t status; /* the sisr result for this channel */ uint32_t insize; /* number of bytes for in buffer */ uint32_t outsize; /* number of bytes for out buffer */ void *in; /* buffer to store response */ @@ -161,16 +162,15 @@ __si_send(struct si_softc *sc, struct siio_send *data) /* siiobuf must to be written in increments of 4 bytes */ cnt = ((data->outsize+3)/4); - aprint_normal("__si_send: chan %d out buf (outsize %d / cnt %d):", chan, data->outsize, cnt); - SIIOBUF_WR(sc, data->out, cnt); - /* - for (i = 0; i < cnt; i++) { - val = 0; + aprint_normal("__si_send: chan %d out buf (outsize %d / cnt %d)\n", chan, data->outsize, cnt); + //SIIOBUF_WR(sc, data->out, cnt); + for (uint32_t i = 0; i < cnt; i++) { + uint32_t val = 0; size_t sz = MIN(4, data->outsize - (i * 4)); memcpy(&val, ((uint8_t *)data->out) + (i * 4), sz); + aprint_normal("__si_send: chan %d is copying %d bytes: 0x%X\n", chan,sz, val); WR4(sc, SIIOBUF + i, val); } - */ aprint_normal("__si_send: chan %d siiobuf after write is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); WR4(sc, SISR, SISR_ERROR_MASK(chan)); @@ -197,7 +197,7 @@ __si_send(struct si_softc *sc, struct siio_send *data) if (ISSET(comcsr, SICOMCSR_COMERR)) { sisr = RD4(sc, SISR); shift_amt = 8 * (SI_NUM_CHAN - 1 - chan); - return ((sisr & SISR_ERROR_MASK(chan)) >> shift_amt) & 0x3F; + data->status = ((sisr & SISR_ERROR_MASK(chan)) >> shift_amt) & 0x3F; } return 0; From e44cc2ec0898fd7b6b22aa157ed25e6c16c1df71 Mon Sep 17 00:00:00 2001 From: zac brown Date: Sun, 17 May 2026 14:36:32 +0000 Subject: [PATCH 09/35] got a multiboot solution to actually work --- sys/arch/evbppc/nintendo/dev/gba_multiboot.h | 209 +++++++++++++++++++ sys/arch/evbppc/nintendo/dev/gba_si.c | 57 ++--- sys/arch/evbppc/nintendo/dev/gba_si.h | 177 ++++++++++++++++ sys/arch/evbppc/nintendo/dev/si.h | 36 +++- 4 files changed, 434 insertions(+), 45 deletions(-) create mode 100644 sys/arch/evbppc/nintendo/dev/gba_multiboot.h create mode 100644 sys/arch/evbppc/nintendo/dev/gba_si.h diff --git a/sys/arch/evbppc/nintendo/dev/gba_multiboot.h b/sys/arch/evbppc/nintendo/dev/gba_multiboot.h new file mode 100644 index 0000000000000..e4063f375c8e7 --- /dev/null +++ b/sys/arch/evbppc/nintendo/dev/gba_multiboot.h @@ -0,0 +1,209 @@ +#ifndef _GBA_MULTIBOOT_H_ +#define _GBA_MULTIBOOT_H_ + +#include "si.h" + +#define GBA_READ 0x14 +#define GBA_WRITE 0x15 +#define SI_TRANS_DELAY 1236 //36450 // 50us * 24.375 + +static uint32_t status; + +struct gba_multiboot { + long size; + void *rom; +}; + +static inline uint32_t +gba_reset(struct si_softc *sc, unsigned chan) +{ + struct siio_send data; + uint32_t out[1]; + uint32_t in[1]; + out[0] = 0xFF000000; + data.chan = chan; + data.outsize = 1; + data.insize = 3; + data.in = in; + data.out = out; + + delay(SI_TRANS_DELAY); + __si_send(sc, &data); + return in[0]; +} + +static inline uint32_t +gba_identify(struct si_softc *sc, unsigned chan) +{ + struct siio_send data; + uint32_t out[1]; + uint32_t in[1]; + out[0] = 0x00000000; + data.chan = chan; + data.outsize = 1; + data.insize = 3; + data.in = in; + data.out = out; + + delay(SI_TRANS_DELAY); + __si_send(sc, &data); + return in[0]; +} + +static inline uint32_t +gba_read32(struct si_softc *sc, unsigned chan) +{ + struct siio_send data; + uint8_t out[1]; + uint8_t in[5]; + + out[0] = GBA_READ; + data.chan = chan; + data.outsize = 1; + data.insize = 5; + data.in = in; + data.out = out; + + delay(SI_TRANS_DELAY); + __si_send(sc, &data); + status = data.status; + /* first four bytes are the data. 5th is status */ + return *(uint32_t *)in; +} + +static inline uint32_t +gba_send32(struct si_softc *sc, unsigned chan, uint32_t msg) +{ + struct siio_send data; + uint8_t out[5]; + uint8_t in[1]; + + out[0] = GBA_WRITE; + out[1] = (msg>>0)&0xFF; + out[2] = (msg>>8)&0xFF; + out[3] = (msg>>16)&0xFF; + out[4] = (msg>>24)&0xFF; + + data.chan = chan; + data.outsize = 5; + data.insize = 1; + data.in = in; + data.out = out; + + delay(SI_TRANS_DELAY); + __si_send(sc, &data); + status = data.status; + return (uint32_t)in[0]; +} + +static unsigned int +calckey(unsigned int size) +{ + unsigned int ret = 0; + size=(size-0x200) >> 3; + int res1 = (size&0x3F80) << 1; + res1 |= (size&0x4000) << 2; + res1 |= (size&0x7F); + res1 |= 0x380000; + int res2 = res1; + res1 = res2 >> 0x10; + int res3 = res2 >> 8; + res3 += res1; + res3 += res2; + res3 <<= 24; + res3 |= res2; + res3 |= 0x80808080; + + if((res3&0x200) == 0) { + ret |= (((res3)&0xFF)^0x4B)<<24; + ret |= (((res3>>8)&0xFF)^0x61)<<16; + ret |= (((res3>>16)&0xFF)^0x77)<<8; + ret |= (((res3>>24)&0xFF)^0x61); + } else { + ret |= (((res3)&0xFF)^0x73)<<24; + ret |= (((res3>>8)&0xFF)^0x65)<<16; + ret |= (((res3>>16)&0xFF)^0x64)<<8; + ret |= (((res3>>24)&0xFF)^0x6F); + } + return ret; +} + +/* no idea what this is doing. all i guess is some sort of signing */ +static unsigned int +docrc(uint32_t crc, uint32_t val) +{ + int i; + for(i = 0; i < 0x20; i++) + { + if((crc^val)&1) + { + crc>>=1; + crc^=0xa1c1; + } + else + crc>>=1; + val>>=1; + } + return crc; +} + +static unsigned int +__gba_multiboot(struct si_softc *sc, unsigned chan, unsigned char *rom, long size) +{ + uint32_t res; + int count, i; + + count = 0; + for (;;) { + if (count == 500) { + aprint_normal("GIVING UP\n"); + return -1; // TODO better return val + } + + gba_reset(sc, chan); + res = gba_identify(sc, chan); + aprint_normal("res is 0x%08X\n", res); + if (res & 0x00001000) { + aprint_normal("WE FOUND OUR MATCH!\n"); + break; + } + count++; + } + + unsigned int sendsize = ((size+7)&~7); + unsigned int ourkey = calckey(sendsize); + + uint32_t sessionkeyraw = gba_read32(sc, chan); + uint32_t sessionkey = bswap32(sessionkeyraw^0x7365646F); // No idea this magic number + gba_send32(sc, chan, bswap32(ourkey)); + unsigned int fcrc = 0x15A0; // i have no idea this one either.. + aprint_normal("SENDING HEADER\n"); + /* send header */ + for (i = 0; i < 0xC0; i += 4) { + gba_send32(sc, chan, bswap32(*(uint32_t*)(rom+i))); + } + + aprint_normal("SENDING ROM\n"); + for (i = 0xC0; i < sendsize; i += 4) { + uint32_t enc = ((rom[i+3]<<24)|(rom[i+2]<<16)|(rom[i+1]<<8)|(rom[i])); + fcrc = docrc(fcrc, enc); + sessionkey = (sessionkey*0x6177614B)+1; + enc^=sessionkey; + enc^=((~(i+(0x20<<20)))+1); + enc^=0x20796220; + gba_send32(sc, chan, enc); + } + + fcrc |= (sendsize<<16); + sessionkey = (sessionkey*0x6177614B)+1; + fcrc^=sessionkey; + fcrc^=((~(i+(0x20<<20)))+1); + fcrc^=0x20796220; + + gba_send32(sc, chan, fcrc); + gba_read32(sc, chan); + + return 0; +} + +#endif diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.c b/sys/arch/evbppc/nintendo/dev/gba_si.c index 3855791d6411a..632f7625f63a0 100644 --- a/sys/arch/evbppc/nintendo/dev/gba_si.c +++ b/sys/arch/evbppc/nintendo/dev/gba_si.c @@ -43,6 +43,7 @@ __KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/04/24 15:07:30 gummybuns Exp $") #include "si.h" #include "joybus.h" +#include "gba_multiboot.h" struct gba_send { uint32_t status; @@ -52,7 +53,9 @@ struct gba_send { void *out; }; -#define SI_SEND _IOWR(0, 1, struct gba_send) + +#define SI_SEND _IOWR(0, 1, struct gba_send) +#define MULTIBOOT _IOWR(0, 2, struct gba_multiboot) static int gba_si_match(device_t, cfdata_t, void *); static void gba_si_attach(device_t, device_t, void *); @@ -109,15 +112,10 @@ gba_si_match(device_t parent, cfdata_t cf, void *aux) static void gba_si_attach(device_t parent, device_t self, void *aux) { - uint32_t siiobuf; struct si_softc * const psc = device_private(parent); struct si_attach_args * const saa = aux; struct gba_softc * const sc = device_private(self); struct si_channel *ch = &psc->sc_chan[saa->saa_index]; - struct siio_send data; - int res; - uint8_t out[3]; - uint16_t in[1]; aprint_normal("gba: inside attach\n"); sc->sc_dev = self; @@ -125,33 +123,10 @@ gba_si_attach(device_t parent, device_t self, void *aux) sc->sc_bst = psc->sc_bst; sc->sc_bsh = psc->sc_bsh; aprint_normal("gba: channel is set to %d\n", sc->ch->ch_index); - - for(;;) { - for (int i = 0; i < 15; i++) { - aprint_normal("trying to send handshake\n"); - // this is wong - out[0] = 0x15; - out[1] = 0x62; - out[2] = 0x02; - //out[0] = 0x6202; - data.chan = saa->saa_index; - data.out = out; - data.in = in; - data.outsize = 3; - data.insize = 2; - siiobuf = RD4(psc, SIIOBUF); - aprint_normal("handshake: before - siiobuf - 0x%08X\n", siiobuf); - if ((res = __si_send(psc, &data)) != 0) { - aprint_normal("handshake: sisr - 0x%08X\n", res); - } - - siiobuf = RD4(psc, SIIOBUF); - aprint_normal("handshake: after - siiobuf - 0x%08X\n", siiobuf); - if (in[0] != 0) break; - } - if (in[0] != 0) break; - delay(62500); // 1/16 of a second - } + aprint_normal("gba: ch%d - disabling SIPOLL\n", saa->saa_index); + //WR4(psc, SIPOLL, RD4(psc, SIPOLL) & ~SIPOLL_EN(saa->saa_index)); + WR4(psc, SIPOLL, 0); + aprint_normal("gba: SIPOLL is now 0x%08X\n", RD4(psc, SIPOLL)); } int @@ -213,6 +188,18 @@ gba_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) int err; switch(cmd) { + case MULTIBOOT: + err = 0; + struct gba_multiboot *gbm = (struct gba_multiboot *)data; + void *rom = kmem_alloc(gbm->size, KM_SLEEP); + if ((err = copyin(gbm->rom, rom, gbm->size)) != 0) { + goto multiboot_cleanup; + } + + err = __gba_multiboot(sc, ch->ch_index, (unsigned char *)rom, gbm->size); +multiboot_cleanup: + kmem_free(rom, gbm->size); + break; case SI_SEND: err = 0; struct gba_send *gbs = (struct gba_send *)data; @@ -226,8 +213,8 @@ gba_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) sd.out = kmem_alloc(gbs->outsize, KM_SLEEP); sd.in = kmem_alloc(gbs->insize, KM_SLEEP); - aprint_normal("gba_ioctl: gbs--outsize%d insize%d\n", gbs->outsize, gbs->insize); - aprint_normal("gba_ioctl: sd--chan:%d\t outsize%d insize%d\n", sd.chan, sd.outsize, sd.insize); + //aprint_normal("gba_ioctl: gbs--outsize%d insize%d\n", gbs->outsize, gbs->insize); + //aprint_normal("gba_ioctl: sd--chan:%d\t outsize%d insize%d\n", sd.chan, sd.outsize, sd.insize); if ((err = copyin(gbs->out, sd.out, sd.outsize)) != 0) { goto si_send_cleanup; diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.h b/sys/arch/evbppc/nintendo/dev/gba_si.h new file mode 100644 index 0000000000000..06c34c879f4cd --- /dev/null +++ b/sys/arch/evbppc/nintendo/dev/gba_si.h @@ -0,0 +1,177 @@ +#ifndef _GBA_SI_H +#define _GBA_SI_H + +#define SI_DELAY 50 + +struct gba_send { + uint32_t status; + uint32_t insize; + uint32_t outsize; + void *in; + void *out; +}; + +struct gba_multiboot { + unsigned long len; + unsigned char *rom; +} + +static inline uint32_t +__gba_reset(struct si_softc *sc, unsigned chan) +{ + struct siio_send data; + uint32_t out[1]; + uint32_t in[1]; + out[0] = 0xFF000000; + data.outsize = 1; + data.insize = 3; + data.out = out; + data.in = in; + data.chan = chan; + + delay(SI_DELAY); + __si_send(sc, &data); + return in[0]; +} + + +static inline uint32_t +__gba_status(struct si_softc *sc, unsigned chan) +{ + struct siio_send data; + uint32_t out[1]; + uint32_t in[1]; + out[0] = 0x00000000; + data.outsize = 1; + data.insize = 3; + data.out = out; + data.in = in; + data.chan = chan; + + delay(SI_DELAY); + __si_send(sc, &data); + return in[0]; +} + +static inline uint32_t +__gba_recv(struct si_softc *sc, unsigned chan) +{ + struct siio_send data; + uint8_t out[1]; + uint8_t in[5]; + + out[0] = 0x14; + data.outsize = 1; + data.insize = 5; + data.out = out; + data.in = in; + data.chan = chan; + + delay(SI_DELAY); + __si_send(sc, &data); + return *(uint32_t *)in; +} + +static inline uint32_t +__gba_send(struct si_softc *sc, unsigned chan, uint32_t msg) +{ + struct siio_send data; + uint8_t out[5]; + uint8_t in[1]; + + out[0] = 0x15; + out[1] = (msg>>0)&0xFF; + out[2] = (msg>>8)&0xFF; + out[3] = (msg>>16)&0xFF; + out[4] = (msg>>24)&0xFF; + + data.outsize = 5; + data.insize = 1; + data.out = out; + data.in = in; + data.chan = chan; + + delay(SI_DELAY); + __si_send(sc, &data); + return (uint32_t)in[0]; +} + +static unsigned int +__calckey(unsigned int size) +{ + unsigned int ret = 0; + size=(size-0x200) >> 3; + int res1 = (size&0x3F80) << 1; + res1 |= (size&0x4000) << 2; + res1 |= (size&0x7F); + res1 |= 0x380000; + int res2 = res1; + res1 = res2 >> 0x10; + int res3 = res2 >> 8; + res3 += res1; + res3 += res2; + res3 <<= 24; + res3 |= res2; + res3 |= 0x80808080; + + if((res3&0x200) == 0) { + ret |= (((res3)&0xFF)^0x4B)<<24; + ret |= (((res3>>8)&0xFF)^0x61)<<16; + ret |= (((res3>>16)&0xFF)^0x77)<<8; + ret |= (((res3>>24)&0xFF)^0x61); + } else { + ret |= (((res3)&0xFF)^0x73)<<24; + ret |= (((res3>>8)&0xFF)^0x65)<<16; + ret |= (((res3>>16)&0xFF)^0x64)<<8; + ret |= (((res3>>24)&0xFF)^0x6F); + } + return ret; +} + +static unsigned int +__docrc(uint32_t crc, uint32_t val) +{ + int i; + for(i = 0; i < 0x20; i++) + { + if((crc^val)&1) + { + crc>>=1; + crc^=0xa1c1; + } + else + crc>>=1; + val>>=1; + } + return crc; +} + +static void +__gba_multiboot(struct si_softc *sc, unsigned chan, unsigned char *rom, long len) +{ + int count = 0; + uint32_t res; + for (;;) { + if (count > 500) { + // giving up + return; + } + + __gba_reset(sc, chan); + res = __gba_status(sc, chan); + if (res & 0x00001000) { + aprint_normal("FOUND A MATCH\n"); + break; + } + count++; + } + + unsigned int sendsize = ((rom.size+7)&~7); + unsigned int ourkey = __calckey(sendsize); + uint32_t sessionkeyraw = __gba_recv(sc, chan); + uint32_t sessionkey = bswap32(sessionkeyraw^0x7365646F); // No idea this magic number + gba_send32(fd, ourkey); + +} + + #endif diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index b72f17a515932..84bbf881fef1f 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -41,7 +41,7 @@ #define SIPOLL 0x30 #define SIPOLL_X __BITS(25, 16) #define SIPOLL_Y __BITS(15, 8) -#define SIPOLL_EN(n) (__BIT(7 - n)) +#define SIPOLL_EN(n) (__BIT(4 + (n))) #define SICOMCSR 0x34 #define SICOMCSR_TCINT __BIT(31) #define SICOMCSR_TCINTMSK __BIT(30) @@ -155,15 +155,17 @@ __si_send(struct si_softc *sc, struct siio_send *data) chan = data->chan; - aprint_normal("\n"); - aprint_normal("__si_send: chan %d siiobuf before clear is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); + //aprint_normal("\n"); + //aprint_normal("__si_send: chan %d siiobuf before clear is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); + //aprint_normal("SIPOLL state: 0x%08X\n", RD4(sc, SIPOLL)); SIIOBUF_CLEAR(sc); - aprint_normal("__si_send: chan %d siiobuf after clear is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); + //aprint_normal("__si_send: chan %d siiobuf after clear is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); /* siiobuf must to be written in increments of 4 bytes */ cnt = ((data->outsize+3)/4); - aprint_normal("__si_send: chan %d out buf (outsize %d / cnt %d)\n", chan, data->outsize, cnt); - //SIIOBUF_WR(sc, data->out, cnt); + //aprint_normal("__si_send: chan %d out buf (outsize %d / cnt %d)\n", chan, data->outsize, cnt); + SIIOBUF_WR(sc, data->out, cnt); + /* for (uint32_t i = 0; i < cnt; i++) { uint32_t val = 0; size_t sz = MIN(4, data->outsize - (i * 4)); @@ -171,9 +173,14 @@ __si_send(struct si_softc *sc, struct siio_send *data) aprint_normal("__si_send: chan %d is copying %d bytes: 0x%X\n", chan,sz, val); WR4(sc, SIIOBUF + i, val); } + */ - aprint_normal("__si_send: chan %d siiobuf after write is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); + //aprint_normal("__si_send: chan %d siiobuf after write is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); WR4(sc, SISR, SISR_ERROR_MASK(chan)); + sisr = RD4(sc, SISR); + if ((sisr & SISR_ERROR_MASK(chan)) != 0) { + //aprint_normal("tried to clear sisr but it is currently %08x\n", sisr); + } AWAIT_SICOMCSR(sc); WR4(sc, SICOMCSR, @@ -182,24 +189,33 @@ __si_send(struct si_softc *sc, struct siio_send *data) __SHIFTIN(0, SICOMCSR_TCINTMSK) | __SHIFTIN(data->outsize, SICOMCSR_OUTLNGTH) | __SHIFTIN(data->insize, SICOMCSR_INLNGTH) | - __SHIFTIN(chan, SICOMCSR_CHANNEL) | - SICOMCSR_TSTART + __SHIFTIN(chan, SICOMCSR_CHANNEL) ); + comcsr = RD4(sc, SICOMCSR); + //aprint_normal("__side_send: chan %d sicomcsr is 0x%08X\n", chan, comcsr); + WR4(sc, SICOMCSR, comcsr | SICOMCSR_TSTART); AWAIT_SICOMCSR(sc); comcsr = RD4(sc, SICOMCSR); WR4(sc, SICOMCSR, comcsr | SICOMCSR_TCINT); - aprint_normal("__si_send: chan %d siiobuf after command is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); + //aprint_normal("__si_send: chan %d siiobuf after command is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); SIIOBUF_RD(sc, data->in, data->insize); comcsr = RD4(sc, SICOMCSR); if (ISSET(comcsr, SICOMCSR_COMERR)) { sisr = RD4(sc, SISR); + //aprint_normal("__si_send: chan %d sisr is set to 0x%08X\n", chan, sisr); shift_amt = 8 * (SI_NUM_CHAN - 1 - chan); data->status = ((sisr & SISR_ERROR_MASK(chan)) >> shift_amt) & 0x3F; + if (data->status == 0xC) { + aprint_normal("!!!!!!!!!!!!!\n"); + } } + //aprint_normal("Running delay(36450)\n"); + //delay(36450); + return 0; } From 725badc4e17f759582267a2486ad783917e9ea13 Mon Sep 17 00:00:00 2001 From: zac brown Date: Mon, 18 May 2026 16:08:50 +0000 Subject: [PATCH 10/35] starting to clean up - still need to figure out why SI_RESET and SI_IDENTIFY require uint32_t when we are only sending 1 byte --- sys/arch/evbppc/nintendo/dev/gba_multiboot.h | 27 +-- sys/arch/evbppc/nintendo/dev/gba_si.c | 80 +++++---- sys/arch/evbppc/nintendo/dev/gba_si.h | 177 ------------------- sys/arch/evbppc/nintendo/dev/joybus.h | 10 +- sys/arch/evbppc/nintendo/dev/si.c | 7 +- sys/arch/evbppc/nintendo/dev/si.h | 7 +- 6 files changed, 73 insertions(+), 235 deletions(-) delete mode 100644 sys/arch/evbppc/nintendo/dev/gba_si.h diff --git a/sys/arch/evbppc/nintendo/dev/gba_multiboot.h b/sys/arch/evbppc/nintendo/dev/gba_multiboot.h index e4063f375c8e7..7a394385a3f2a 100644 --- a/sys/arch/evbppc/nintendo/dev/gba_multiboot.h +++ b/sys/arch/evbppc/nintendo/dev/gba_multiboot.h @@ -3,15 +3,15 @@ #include "si.h" -#define GBA_READ 0x14 -#define GBA_WRITE 0x15 -#define SI_TRANS_DELAY 1236 //36450 // 50us * 24.375 +#define SI_TRANS_DELAY 1236 static uint32_t status; -struct gba_multiboot { - long size; - void *rom; +struct gba_multiboot_p { + long size; + unsigned chan; + unsigned char *rom; + struct si_softc *sc; }; static inline uint32_t @@ -20,7 +20,7 @@ gba_reset(struct si_softc *sc, unsigned chan) struct siio_send data; uint32_t out[1]; uint32_t in[1]; - out[0] = 0xFF000000; + out[0] = SI_RESET; data.chan = chan; data.outsize = 1; data.insize = 3; @@ -38,7 +38,7 @@ gba_identify(struct si_softc *sc, unsigned chan) struct siio_send data; uint32_t out[1]; uint32_t in[1]; - out[0] = 0x00000000; + out[0] = SI_IDENTIFY; data.chan = chan; data.outsize = 1; data.insize = 3; @@ -57,7 +57,7 @@ gba_read32(struct si_softc *sc, unsigned chan) uint8_t out[1]; uint8_t in[5]; - out[0] = GBA_READ; + out[0] = SI_GBARD; data.chan = chan; data.outsize = 1; data.insize = 5; @@ -78,7 +78,7 @@ gba_send32(struct si_softc *sc, unsigned chan, uint32_t msg) uint8_t out[5]; uint8_t in[1]; - out[0] = GBA_WRITE; + out[0] = SI_GBAWR; out[1] = (msg>>0)&0xFF; out[2] = (msg>>8)&0xFF; out[3] = (msg>>16)&0xFF; @@ -128,7 +128,6 @@ calckey(unsigned int size) return ret; } -/* no idea what this is doing. all i guess is some sort of signing */ static unsigned int docrc(uint32_t crc, uint32_t val) { @@ -148,10 +147,14 @@ docrc(uint32_t crc, uint32_t val) } static unsigned int -__gba_multiboot(struct si_softc *sc, unsigned chan, unsigned char *rom, long size) +__gba_multiboot(struct gba_multiboot_p *gbm) { uint32_t res; int count, i; + unsigned chan = gbm->chan; + unsigned char *rom = gbm->rom; + long size = gbm->size; + struct si_softc *sc = gbm->sc; count = 0; for (;;) { diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.c b/sys/arch/evbppc/nintendo/dev/gba_si.c index 632f7625f63a0..c26a543cdf042 100644 --- a/sys/arch/evbppc/nintendo/dev/gba_si.c +++ b/sys/arch/evbppc/nintendo/dev/gba_si.c @@ -1,5 +1,7 @@ +/* $NetBSD: gba_si.c,v 1.0 2026/05/18 22:54:30 gummybuns Exp $ */ + /*- - * Copyright (c) 2025 ZacBrown + * Copyright (c) 2026 ZacBrown * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -25,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/04/24 15:07:30 gummybuns Exp $"); +__KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/05/18 22:53:30 gummybuns Exp $"); #include #include @@ -46,16 +48,29 @@ __KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/04/24 15:07:30 gummybuns Exp $") #include "gba_multiboot.h" struct gba_send { - uint32_t status; - uint32_t insize; - uint32_t outsize; - void *in; - void *out; + uint32_t status; /* sisr status for this channel */ + uint32_t insize; /* bytes to receive. max 128 */ + uint32_t outsize; /* bytes to send. max 128 */ + void *in; /* buffer to store response */ + void *out; /* buffer to send out to gba */ +}; + +struct gba_multiboot { + long size; + void *rom; +}; + +extern struct cfdriver gba_cd; +struct gba_softc { + device_t sc_dev; + struct si_channel *ch; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; }; -#define SI_SEND _IOWR(0, 1, struct gba_send) -#define MULTIBOOT _IOWR(0, 2, struct gba_multiboot) +#define GBA_SEND _IOWR(0, 1, struct gba_send) +#define GBA_MULTIBOOT _IOWR(0, 2, struct gba_multiboot) static int gba_si_match(device_t, cfdata_t, void *); static void gba_si_attach(device_t, device_t, void *); @@ -79,15 +94,6 @@ const struct cdevsw gba_cdevsw = { .d_flag = D_OTHER }; -extern struct cfdriver gba_cd; - -struct gba_softc { - device_t sc_dev; - struct si_channel *ch; - bus_space_tag_t sc_bst; - bus_space_handle_t sc_bsh; -}; - CFATTACH_DECL_NEW(gba_si, sizeof(struct gba_softc), gba_si_match, gba_si_attach, NULL, NULL); @@ -97,15 +103,16 @@ gba_si_match(device_t parent, cfdata_t cf, void *aux) struct si_softc * const sc = device_private(parent); struct si_attach_args * const saa = aux; struct si_channel *ch; + unsigned chan; - ch = &sc->sc_chan[saa->saa_index]; + chan = saa->saa_index; + ch = &sc->sc_chan[chan]; aprint_normal("gba: checking 0x%08X...\n", ch->ch_id); if (IS_GBA(ch->ch_id)) { - aprint_normal(" is is a gba!\n"); + aprint_normal("gba: identified ch%d as a gba device\n", chan); return 1; } - aprint_normal(" is not a gba\n"); return 0; } @@ -117,16 +124,12 @@ gba_si_attach(device_t parent, device_t self, void *aux) struct gba_softc * const sc = device_private(self); struct si_channel *ch = &psc->sc_chan[saa->saa_index]; - aprint_normal("gba: inside attach\n"); sc->sc_dev = self; sc->ch = ch; sc->sc_bst = psc->sc_bst; sc->sc_bsh = psc->sc_bsh; - aprint_normal("gba: channel is set to %d\n", sc->ch->ch_index); - aprint_normal("gba: ch%d - disabling SIPOLL\n", saa->saa_index); - //WR4(psc, SIPOLL, RD4(psc, SIPOLL) & ~SIPOLL_EN(saa->saa_index)); - WR4(psc, SIPOLL, 0); - aprint_normal("gba: SIPOLL is now 0x%08X\n", RD4(psc, SIPOLL)); + // TODO - i dont know if i need to disable polling or not + //WR4(psc, SIPOLL, 0); } int @@ -153,7 +156,8 @@ gba_open(dev_t dev, int flags, int mode, struct lwp *l) int gba_close(dev_t dev, int flags, int mode, struct lwp *l) { - struct gba_softc * const sc = device_lookup_private(&gba_cd, minor(dev)); + struct gba_softc * const sc = device_lookup_private(&gba_cd, + minor(dev)); struct si_channel *ch = sc->ch; mutex_enter(&ch->ch_lock); @@ -181,27 +185,34 @@ gba_close(dev_t dev, int flags, int mode, struct lwp *l) int gba_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { - struct gba_softc * const gbasc = device_lookup_private(&gba_cd, minor(dev)); + struct gba_softc * const gbasc = device_lookup_private(&gba_cd, + minor(dev)); struct si_channel *ch = gbasc->ch; struct si_softc * const sc = ch->ch_sc; - struct siio_send sd; int err; switch(cmd) { - case MULTIBOOT: + case GBA_MULTIBOOT: err = 0; struct gba_multiboot *gbm = (struct gba_multiboot *)data; + struct gba_multiboot_p gbmp; void *rom = kmem_alloc(gbm->size, KM_SLEEP); if ((err = copyin(gbm->rom, rom, gbm->size)) != 0) { goto multiboot_cleanup; } - err = __gba_multiboot(sc, ch->ch_index, (unsigned char *)rom, gbm->size); + gbmp.sc = sc; + gbmp.chan = ch->ch_index; + gbmp.rom = (unsigned char *)rom; + gbmp.size = gbm->size; + + err = __gba_multiboot(&gbmp); multiboot_cleanup: kmem_free(rom, gbm->size); break; - case SI_SEND: + case GBA_SEND: err = 0; + struct siio_send sd; struct gba_send *gbs = (struct gba_send *)data; if (gbs->outsize > SIIOBUF_SIZE || gbs->insize > SIIOBUF_SIZE) { return EINVAL; @@ -213,9 +224,6 @@ gba_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) sd.out = kmem_alloc(gbs->outsize, KM_SLEEP); sd.in = kmem_alloc(gbs->insize, KM_SLEEP); - //aprint_normal("gba_ioctl: gbs--outsize%d insize%d\n", gbs->outsize, gbs->insize); - //aprint_normal("gba_ioctl: sd--chan:%d\t outsize%d insize%d\n", sd.chan, sd.outsize, sd.insize); - if ((err = copyin(gbs->out, sd.out, sd.outsize)) != 0) { goto si_send_cleanup; } diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.h b/sys/arch/evbppc/nintendo/dev/gba_si.h deleted file mode 100644 index 06c34c879f4cd..0000000000000 --- a/sys/arch/evbppc/nintendo/dev/gba_si.h +++ /dev/null @@ -1,177 +0,0 @@ -#ifndef _GBA_SI_H -#define _GBA_SI_H - -#define SI_DELAY 50 - -struct gba_send { - uint32_t status; - uint32_t insize; - uint32_t outsize; - void *in; - void *out; -}; - -struct gba_multiboot { - unsigned long len; - unsigned char *rom; -} - -static inline uint32_t -__gba_reset(struct si_softc *sc, unsigned chan) -{ - struct siio_send data; - uint32_t out[1]; - uint32_t in[1]; - out[0] = 0xFF000000; - data.outsize = 1; - data.insize = 3; - data.out = out; - data.in = in; - data.chan = chan; - - delay(SI_DELAY); - __si_send(sc, &data); - return in[0]; -} - - -static inline uint32_t -__gba_status(struct si_softc *sc, unsigned chan) -{ - struct siio_send data; - uint32_t out[1]; - uint32_t in[1]; - out[0] = 0x00000000; - data.outsize = 1; - data.insize = 3; - data.out = out; - data.in = in; - data.chan = chan; - - delay(SI_DELAY); - __si_send(sc, &data); - return in[0]; -} - -static inline uint32_t -__gba_recv(struct si_softc *sc, unsigned chan) -{ - struct siio_send data; - uint8_t out[1]; - uint8_t in[5]; - - out[0] = 0x14; - data.outsize = 1; - data.insize = 5; - data.out = out; - data.in = in; - data.chan = chan; - - delay(SI_DELAY); - __si_send(sc, &data); - return *(uint32_t *)in; -} - -static inline uint32_t -__gba_send(struct si_softc *sc, unsigned chan, uint32_t msg) -{ - struct siio_send data; - uint8_t out[5]; - uint8_t in[1]; - - out[0] = 0x15; - out[1] = (msg>>0)&0xFF; - out[2] = (msg>>8)&0xFF; - out[3] = (msg>>16)&0xFF; - out[4] = (msg>>24)&0xFF; - - data.outsize = 5; - data.insize = 1; - data.out = out; - data.in = in; - data.chan = chan; - - delay(SI_DELAY); - __si_send(sc, &data); - return (uint32_t)in[0]; -} - -static unsigned int -__calckey(unsigned int size) -{ - unsigned int ret = 0; - size=(size-0x200) >> 3; - int res1 = (size&0x3F80) << 1; - res1 |= (size&0x4000) << 2; - res1 |= (size&0x7F); - res1 |= 0x380000; - int res2 = res1; - res1 = res2 >> 0x10; - int res3 = res2 >> 8; - res3 += res1; - res3 += res2; - res3 <<= 24; - res3 |= res2; - res3 |= 0x80808080; - - if((res3&0x200) == 0) { - ret |= (((res3)&0xFF)^0x4B)<<24; - ret |= (((res3>>8)&0xFF)^0x61)<<16; - ret |= (((res3>>16)&0xFF)^0x77)<<8; - ret |= (((res3>>24)&0xFF)^0x61); - } else { - ret |= (((res3)&0xFF)^0x73)<<24; - ret |= (((res3>>8)&0xFF)^0x65)<<16; - ret |= (((res3>>16)&0xFF)^0x64)<<8; - ret |= (((res3>>24)&0xFF)^0x6F); - } - return ret; -} - -static unsigned int -__docrc(uint32_t crc, uint32_t val) -{ - int i; - for(i = 0; i < 0x20; i++) - { - if((crc^val)&1) - { - crc>>=1; - crc^=0xa1c1; - } - else - crc>>=1; - val>>=1; - } - return crc; -} - -static void -__gba_multiboot(struct si_softc *sc, unsigned chan, unsigned char *rom, long len) -{ - int count = 0; - uint32_t res; - for (;;) { - if (count > 500) { - // giving up - return; - } - - __gba_reset(sc, chan); - res = __gba_status(sc, chan); - if (res & 0x00001000) { - aprint_normal("FOUND A MATCH\n"); - break; - } - count++; - } - - unsigned int sendsize = ((rom.size+7)&~7); - unsigned int ourkey = __calckey(sendsize); - uint32_t sessionkeyraw = __gba_recv(sc, chan); - uint32_t sessionkey = bswap32(sessionkeyraw^0x7365646F); // No idea this magic number - gba_send32(fd, ourkey); - -} - - #endif diff --git a/sys/arch/evbppc/nintendo/dev/joybus.h b/sys/arch/evbppc/nintendo/dev/joybus.h index 95ad7bf2de03e..cfba56e1fbc35 100644 --- a/sys/arch/evbppc/nintendo/dev/joybus.h +++ b/sys/arch/evbppc/nintendo/dev/joybus.h @@ -1,5 +1,7 @@ +/* $NetBSD: joybus.h,v 1.0 2026/05/18 22:54:30 gummybuns Exp $ */ + /*- - * Copyright (c) 2025 Zac Brown + * Copyright (c) 2026 Zac Brown * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,6 +26,9 @@ * SUCH DAMAGE. */ +#include +__KERNEL_RCSID(0, "$NetBSD: joybus.h,v 1.0 2026/05/18 22:54:30 gummybuns Exp $"); + #include #define JB_WIRELESS __BIT(15) @@ -49,8 +54,7 @@ #define SI_WAVEBRD_RECV 0xe960 #define SI_WAVEBRD JB_WIRELESS & JB_RUMBLE & JB_CONTROLLER #define SI_GCKB 0x0802 -#define SI_GCSTEER 0x0800 // TODO - steering wheel and gba bios are the - // same. risk of misidentification +#define SI_GCSTEER 0x0800 /* risk: steering wheel + gbabios identical. */ #define IS_DOLPHIN(n) ISSET(n, JB_CONTROLLER) #define IS_N64(n) !ISSET(n, JB_CONTROLLER) diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index f848ccae9b0c8..2b0e0575a7d9c 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -193,8 +193,7 @@ si_identify(device_t self, unsigned chan) uint32_t in[1]; int res; - /* identify always expects 3 bytes back although id is only 2 bytes */ - out[0] = SIIDENTIFY; + out[0] = SI_IDENTIFY; data.chan = chan; data.out = out; data.in = in; @@ -207,8 +206,6 @@ si_identify(device_t self, unsigned chan) ch = &sc->sc_chan[chan]; ch->ch_id = (uint16_t)(in[0] >> 16); - aprint_normal("si_identify: chan%d id - 0x%08X\n", chan, ch->ch_id); - return 0; } @@ -327,7 +324,7 @@ si_open(void *cookie, void (*intr)(void *, void *, u_int), void *arg) (void)RD4(sc, SICINBUFL(ch->ch_index)); /* Init controller */ - WR4(sc, SICOUTBUF(ch->ch_index), SIINIT); + WR4(sc, SICOUTBUF(ch->ch_index), SI_INIT); /* Enable polling */ WR4(sc, SIPOLL, RD4(sc, SIPOLL) | SIPOLL_EN(ch->ch_index)); diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 84bbf881fef1f..4e397e18ce564 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -34,8 +34,11 @@ #define SI_NUM_CHAN 4 #define SICOUTBUF(n) ((n) * 0xc + 0x00) -#define SIIDENTIFY 0x00000000 -#define SIINIT 0x00400300 +#define SI_INIT 0x00400300 +#define SI_IDENTIFY 0x00000000 +#define SI_RESET 0xFF000000 +#define SI_GBARD 0x14 +#define SI_GBAWR 0x15 #define SICINBUFH(n) ((n) * 0xc + 0x04) #define SICINBUFL(n) ((n) * 0xc + 0x08) #define SIPOLL 0x30 From 22b526da9577690c116435c0162ee53d338d8942 Mon Sep 17 00:00:00 2001 From: zac brown Date: Tue, 19 May 2026 18:35:56 +0000 Subject: [PATCH 11/35] refactor the send routines and multiboot protocol --- sys/arch/evbppc/nintendo/dev/gba_multiboot.h | 109 +++++++++---------- sys/arch/evbppc/nintendo/dev/gba_si.c | 2 +- sys/arch/evbppc/nintendo/dev/joybus.h | 82 +++++++++++--- sys/arch/evbppc/nintendo/dev/si.c | 38 ++++--- sys/arch/evbppc/nintendo/dev/si.h | 49 ++------- 5 files changed, 145 insertions(+), 135 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gba_multiboot.h b/sys/arch/evbppc/nintendo/dev/gba_multiboot.h index 7a394385a3f2a..ab60b1f94edd3 100644 --- a/sys/arch/evbppc/nintendo/dev/gba_multiboot.h +++ b/sys/arch/evbppc/nintendo/dev/gba_multiboot.h @@ -1,9 +1,36 @@ +/* $NetBSD: gba_multiboot.h,v 1.0 2026/05/18 22:54:30 gummybuns Exp $ */ + +/*- + * Copyright (c) 2026 ZacBrown + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + #ifndef _GBA_MULTIBOOT_H_ #define _GBA_MULTIBOOT_H_ #include "si.h" - -#define SI_TRANS_DELAY 1236 +#include "joybus.h" static uint32_t status; @@ -14,42 +41,6 @@ struct gba_multiboot_p { struct si_softc *sc; }; -static inline uint32_t -gba_reset(struct si_softc *sc, unsigned chan) -{ - struct siio_send data; - uint32_t out[1]; - uint32_t in[1]; - out[0] = SI_RESET; - data.chan = chan; - data.outsize = 1; - data.insize = 3; - data.in = in; - data.out = out; - - delay(SI_TRANS_DELAY); - __si_send(sc, &data); - return in[0]; -} - -static inline uint32_t -gba_identify(struct si_softc *sc, unsigned chan) -{ - struct siio_send data; - uint32_t out[1]; - uint32_t in[1]; - out[0] = SI_IDENTIFY; - data.chan = chan; - data.outsize = 1; - data.insize = 3; - data.in = in; - data.out = out; - - delay(SI_TRANS_DELAY); - __si_send(sc, &data); - return in[0]; -} - static inline uint32_t gba_read32(struct si_softc *sc, unsigned chan) { @@ -57,14 +48,14 @@ gba_read32(struct si_softc *sc, unsigned chan) uint8_t out[1]; uint8_t in[5]; - out[0] = SI_GBARD; + out[0] = JB_GBA_READ; data.chan = chan; data.outsize = 1; data.insize = 5; data.in = in; data.out = out; - delay(SI_TRANS_DELAY); + delay(JB_DELAY); __si_send(sc, &data); status = data.status; /* first four bytes are the data. 5th is status */ @@ -78,7 +69,7 @@ gba_send32(struct si_softc *sc, unsigned chan, uint32_t msg) uint8_t out[5]; uint8_t in[1]; - out[0] = SI_GBAWR; + out[0] = JB_GBA_WRITE; out[1] = (msg>>0)&0xFF; out[2] = (msg>>8)&0xFF; out[3] = (msg>>16)&0xFF; @@ -90,7 +81,7 @@ gba_send32(struct si_softc *sc, unsigned chan, uint32_t msg) data.in = in; data.out = out; - delay(SI_TRANS_DELAY); + delay(JB_DELAY); __si_send(sc, &data); status = data.status; return (uint32_t)in[0]; @@ -149,8 +140,9 @@ docrc(uint32_t crc, uint32_t val) static unsigned int __gba_multiboot(struct gba_multiboot_p *gbm) { - uint32_t res; + uint32_t enc, sessionkeyraw, sessionkey, res; int count, i; + unsigned int fcrc, ourkey, sendsize; unsigned chan = gbm->chan; unsigned char *rom = gbm->rom; long size = gbm->size; @@ -158,37 +150,36 @@ __gba_multiboot(struct gba_multiboot_p *gbm) count = 0; for (;;) { - if (count == 500) { - aprint_normal("GIVING UP\n"); - return -1; // TODO better return val + if (count >= 1000) { + aprint_normal("multiboot: ch %d initialize failure\n", + chan); + return EAGAIN; } - gba_reset(sc, chan); - res = gba_identify(sc, chan); - aprint_normal("res is 0x%08X\n", res); + jb_reset(sc, chan, JB_DELAY); + res = jb_identify(sc, chan, JB_DELAY); if (res & 0x00001000) { - aprint_normal("WE FOUND OUR MATCH!\n"); break; } count++; } - unsigned int sendsize = ((size+7)&~7); - unsigned int ourkey = calckey(sendsize); + sendsize = ((size+7)&~7); + ourkey = calckey(sendsize); - uint32_t sessionkeyraw = gba_read32(sc, chan); - uint32_t sessionkey = bswap32(sessionkeyraw^0x7365646F); // No idea this magic number + sessionkeyraw = gba_read32(sc, chan); + sessionkey = bswap32(sessionkeyraw^0x7365646F); gba_send32(sc, chan, bswap32(ourkey)); - unsigned int fcrc = 0x15A0; // i have no idea this one either.. - aprint_normal("SENDING HEADER\n"); - /* send header */ + fcrc = 0x15A0; + + aprint_normal("multiboot: ch %d sending header\n", chan); for (i = 0; i < 0xC0; i += 4) { gba_send32(sc, chan, bswap32(*(uint32_t*)(rom+i))); } - aprint_normal("SENDING ROM\n"); + aprint_normal("multiboot: ch %d sending rom\n", chan); for (i = 0xC0; i < sendsize; i += 4) { - uint32_t enc = ((rom[i+3]<<24)|(rom[i+2]<<16)|(rom[i+1]<<8)|(rom[i])); + enc = ((rom[i+3]<<24)|(rom[i+2]<<16)|(rom[i+1]<<8)|(rom[i])); fcrc = docrc(fcrc, enc); sessionkey = (sessionkey*0x6177614B)+1; enc^=sessionkey; diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.c b/sys/arch/evbppc/nintendo/dev/gba_si.c index c26a543cdf042..c5c4cbf0f1175 100644 --- a/sys/arch/evbppc/nintendo/dev/gba_si.c +++ b/sys/arch/evbppc/nintendo/dev/gba_si.c @@ -108,7 +108,7 @@ gba_si_match(device_t parent, cfdata_t cf, void *aux) chan = saa->saa_index; ch = &sc->sc_chan[chan]; aprint_normal("gba: checking 0x%08X...\n", ch->ch_id); - if (IS_GBA(ch->ch_id)) { + if (ch->ch_id == JB_GBA) { aprint_normal("gba: identified ch%d as a gba device\n", chan); return 1; } diff --git a/sys/arch/evbppc/nintendo/dev/joybus.h b/sys/arch/evbppc/nintendo/dev/joybus.h index cfba56e1fbc35..7ac43bae9a006 100644 --- a/sys/arch/evbppc/nintendo/dev/joybus.h +++ b/sys/arch/evbppc/nintendo/dev/joybus.h @@ -26,10 +26,11 @@ * SUCH DAMAGE. */ -#include -__KERNEL_RCSID(0, "$NetBSD: joybus.h,v 1.0 2026/05/18 22:54:30 gummybuns Exp $"); +#ifndef _JOYBUS_H_ +#define _JOYBUS_H_ #include +#include "si.h" #define JB_WIRELESS __BIT(15) #define JB_WIRELESS_RECV __BIT(14) @@ -43,20 +44,69 @@ __KERNEL_RCSID(0, "$NetBSD: joybus.h,v 1.0 2026/05/18 22:54:30 gummybuns Exp $") #define JB_WIRELESS_NONCTRL __BIT(3) #define JB_WIRELESS_LITE __BIT(2) -#define SI_NONE 0x0000 -#define SI_N64 0x0500 -#define SI_N64MIC 0x0001 -#define SI_N64KB 0x0002 -#define SI_N64MS 0x0200 -#define SI_GBA 0x0004 -#define SI_GBABIOS 0x0800 -#define SI_GC 0x0900 -#define SI_WAVEBRD_RECV 0xe960 -#define SI_WAVEBRD JB_WIRELESS & JB_RUMBLE & JB_CONTROLLER -#define SI_GCKB 0x0802 -#define SI_GCSTEER 0x0800 /* risk: steering wheel + gbabios identical. */ +#define JB_IDENTIFY 0x00000000 +#define JB_RESET 0xFF000000 +#define JB_GBA_READ 0x14 +#define JB_GBA_WRITE 0x15 + +#define JB_NONE 0x0000 +#define JB_N64 0x0500 +#define JB_N64MIC 0x0001 +#define JB_N64KB 0x0002 +#define JB_N64MS 0x0200 +#define JB_GBA 0x0004 +#define JB_GC 0x0900 +#define JB_WAVEBRD_RECV 0xe960 +#define JB_WAVEBRD JB_WIRELESS & JB_RUMBLE & JB_CONTROLLER +#define JB_GCKB 0x0802 +#define JB_GCSTEER 0x0800 +#define JB_GBABIOS 0x08 /* GBA BIOS actually sends a 1byte response and + * sets SISR to NOREP. The second byte will be + * whatever was in SIIOBUF before send */ #define IS_DOLPHIN(n) ISSET(n, JB_CONTROLLER) #define IS_N64(n) !ISSET(n, JB_CONTROLLER) -#define IS_GCPAD(n) (((n) & (JB_CONTROLLER | JB_DOLPHIN)) == SI_GC) || ISSET(n, JB_WIRELESS) -#define IS_GBA(n) (n == SI_GBA || n == SI_GBABIOS) +#define IS_GCPAD(n) (((n) & (JB_CONTROLLER | JB_DOLPHIN)) == JB_GC) || \ + ISSET(n, JB_WIRELESS) + +#define JB_DELAY 50 /* lowest delay with results for multiboot */ + +static inline uint32_t +jb_reset(struct si_softc *sc, unsigned chan, long us) +{ + struct siio_send data; + uint32_t out[1]; + uint32_t in[1]; + out[0] = JB_RESET; + + data.chan = chan; + data.outsize = 1; + data.insize = 3; + data.in = in; + data.out = out; + + delay(us); + __si_send(sc, &data); + return in[0]; +} + +static inline uint32_t +jb_identify(struct si_softc *sc, unsigned chan, long us) +{ + struct siio_send data; + uint32_t out[1]; + uint32_t in[1]; + out[0] = JB_IDENTIFY; + + data.chan = chan; + data.outsize = 1; + data.insize = 3; + data.in = in; + data.out = out; + + delay(us); + __si_send(sc, &data); + return in[0]; +} + +#endif diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index 2b0e0575a7d9c..183fd59cf576f 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -188,24 +188,28 @@ si_identify(device_t self, unsigned chan) { struct si_softc * const sc = device_private(self); struct si_channel *ch; - struct siio_send data; - uint32_t out[1]; - uint32_t in[1]; - int res; - - out[0] = SI_IDENTIFY; - data.chan = chan; - data.out = out; - data.in = in; - data.outsize = 1; - data.insize = 3; - - if ((res = __si_send(sc, &data)) != 0) { - aprint_normal("si_identify: chan%d sisr - 0x%08X\n", chan, res); - } + uint32_t id; + uint32_t sisr; + uint8_t msb; + int cnt; ch = &sc->sc_chan[chan]; - ch->ch_id = (uint16_t)(in[0] >> 16); + cnt = 0; + + /* + * Identify call is normaly 2bytes, GBA BIOS however sends a 1byte resp + * and sets SISR as NOREP. We need to try to reset the device and see + * if it can be put into the proper state + */ + do { + jb_reset(sc, chan, 1000); + id = jb_identify(sc, chan, 1000); + msb = (uint8_t)(id >> 24); + ch->ch_id = (uint16_t)(id >> 16); + sisr = RD4(sc, SISR); + cnt++; + } while (cnt < 1000 && msb == JB_GBABIOS && (sisr & SISR_NOREP(chan))); + return 0; } @@ -324,7 +328,7 @@ si_open(void *cookie, void (*intr)(void *, void *, u_int), void *arg) (void)RD4(sc, SICINBUFL(ch->ch_index)); /* Init controller */ - WR4(sc, SICOUTBUF(ch->ch_index), SI_INIT); + WR4(sc, SICOUTBUF(ch->ch_index), 0x00400300); /* Enable polling */ WR4(sc, SIPOLL, RD4(sc, SIPOLL) | SIPOLL_EN(ch->ch_index)); diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 4e397e18ce564..d89b71808d9fb 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -34,11 +34,6 @@ #define SI_NUM_CHAN 4 #define SICOUTBUF(n) ((n) * 0xc + 0x00) -#define SI_INIT 0x00400300 -#define SI_IDENTIFY 0x00000000 -#define SI_RESET 0xFF000000 -#define SI_GBARD 0x14 -#define SI_GBAWR 0x15 #define SICINBUFH(n) ((n) * 0xc + 0x04) #define SICINBUFL(n) ((n) * 0xc + 0x08) #define SIPOLL 0x30 @@ -153,37 +148,20 @@ struct siio_send { static inline int __si_send(struct si_softc *sc, struct siio_send *data) { - uint32_t comcsr, sisr, shift_amt, cnt; //, i, val; + uint32_t cnt, comcsr, sisr, shift_amt, status; unsigned chan; chan = data->chan; - //aprint_normal("\n"); - //aprint_normal("__si_send: chan %d siiobuf before clear is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); - //aprint_normal("SIPOLL state: 0x%08X\n", RD4(sc, SIPOLL)); SIIOBUF_CLEAR(sc); - //aprint_normal("__si_send: chan %d siiobuf after clear is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); + data->status = 0; /* siiobuf must to be written in increments of 4 bytes */ cnt = ((data->outsize+3)/4); - //aprint_normal("__si_send: chan %d out buf (outsize %d / cnt %d)\n", chan, data->outsize, cnt); SIIOBUF_WR(sc, data->out, cnt); - /* - for (uint32_t i = 0; i < cnt; i++) { - uint32_t val = 0; - size_t sz = MIN(4, data->outsize - (i * 4)); - memcpy(&val, ((uint8_t *)data->out) + (i * 4), sz); - aprint_normal("__si_send: chan %d is copying %d bytes: 0x%X\n", chan,sz, val); - WR4(sc, SIIOBUF + i, val); - } - */ - //aprint_normal("__si_send: chan %d siiobuf after write is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); WR4(sc, SISR, SISR_ERROR_MASK(chan)); sisr = RD4(sc, SISR); - if ((sisr & SISR_ERROR_MASK(chan)) != 0) { - //aprint_normal("tried to clear sisr but it is currently %08x\n", sisr); - } AWAIT_SICOMCSR(sc); WR4(sc, SICOMCSR, @@ -192,35 +170,22 @@ __si_send(struct si_softc *sc, struct siio_send *data) __SHIFTIN(0, SICOMCSR_TCINTMSK) | __SHIFTIN(data->outsize, SICOMCSR_OUTLNGTH) | __SHIFTIN(data->insize, SICOMCSR_INLNGTH) | - __SHIFTIN(chan, SICOMCSR_CHANNEL) + __SHIFTIN(chan, SICOMCSR_CHANNEL) | + SICOMCSR_TSTART ); - comcsr = RD4(sc, SICOMCSR); - //aprint_normal("__side_send: chan %d sicomcsr is 0x%08X\n", chan, comcsr); - WR4(sc, SICOMCSR, comcsr | SICOMCSR_TSTART); AWAIT_SICOMCSR(sc); comcsr = RD4(sc, SICOMCSR); WR4(sc, SICOMCSR, comcsr | SICOMCSR_TCINT); - - //aprint_normal("__si_send: chan %d siiobuf after command is set to 0x%08X\n", chan, RD4(sc, SIIOBUF)); - SIIOBUF_RD(sc, data->in, data->insize); - - comcsr = RD4(sc, SICOMCSR); if (ISSET(comcsr, SICOMCSR_COMERR)) { sisr = RD4(sc, SISR); - //aprint_normal("__si_send: chan %d sisr is set to 0x%08X\n", chan, sisr); shift_amt = 8 * (SI_NUM_CHAN - 1 - chan); - data->status = ((sisr & SISR_ERROR_MASK(chan)) >> shift_amt) & 0x3F; - if (data->status == 0xC) { - aprint_normal("!!!!!!!!!!!!!\n"); - } + status = ((sisr & SISR_ERROR_MASK(chan)) >> shift_amt) & 0x3F; + data->status = status; } - //aprint_normal("Running delay(36450)\n"); - //delay(36450); - + SIIOBUF_RD(sc, data->in, data->insize); return 0; } - #endif /* _WII_DEV_SI_H_ */ From a4fbc68e2683deae4d0ab20711df6182959e2b82 Mon Sep 17 00:00:00 2001 From: zac Date: Thu, 28 May 2026 11:14:58 -0400 Subject: [PATCH 12/35] the great cleanup has begun - move multiboot to userland - go back to only a single send ioctl - the rest will also live in userland - cleanup joybus since we dont need shared code there either now --- sys/arch/evbppc/nintendo/dev/gba_multiboot.h | 203 ------------------- sys/arch/evbppc/nintendo/dev/gba_si.c | 103 ++++------ sys/arch/evbppc/nintendo/dev/joybus.h | 49 +---- sys/arch/evbppc/nintendo/dev/si.c | 24 ++- sys/arch/evbppc/nintendo/dev/si.h | 7 + 5 files changed, 78 insertions(+), 308 deletions(-) delete mode 100644 sys/arch/evbppc/nintendo/dev/gba_multiboot.h diff --git a/sys/arch/evbppc/nintendo/dev/gba_multiboot.h b/sys/arch/evbppc/nintendo/dev/gba_multiboot.h deleted file mode 100644 index ab60b1f94edd3..0000000000000 --- a/sys/arch/evbppc/nintendo/dev/gba_multiboot.h +++ /dev/null @@ -1,203 +0,0 @@ -/* $NetBSD: gba_multiboot.h,v 1.0 2026/05/18 22:54:30 gummybuns Exp $ */ - -/*- - * Copyright (c) 2026 ZacBrown - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, - * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, - * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED - * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, - * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef _GBA_MULTIBOOT_H_ -#define _GBA_MULTIBOOT_H_ - -#include "si.h" -#include "joybus.h" - -static uint32_t status; - -struct gba_multiboot_p { - long size; - unsigned chan; - unsigned char *rom; - struct si_softc *sc; -}; - -static inline uint32_t -gba_read32(struct si_softc *sc, unsigned chan) -{ - struct siio_send data; - uint8_t out[1]; - uint8_t in[5]; - - out[0] = JB_GBA_READ; - data.chan = chan; - data.outsize = 1; - data.insize = 5; - data.in = in; - data.out = out; - - delay(JB_DELAY); - __si_send(sc, &data); - status = data.status; - /* first four bytes are the data. 5th is status */ - return *(uint32_t *)in; -} - -static inline uint32_t -gba_send32(struct si_softc *sc, unsigned chan, uint32_t msg) -{ - struct siio_send data; - uint8_t out[5]; - uint8_t in[1]; - - out[0] = JB_GBA_WRITE; - out[1] = (msg>>0)&0xFF; - out[2] = (msg>>8)&0xFF; - out[3] = (msg>>16)&0xFF; - out[4] = (msg>>24)&0xFF; - - data.chan = chan; - data.outsize = 5; - data.insize = 1; - data.in = in; - data.out = out; - - delay(JB_DELAY); - __si_send(sc, &data); - status = data.status; - return (uint32_t)in[0]; -} - -static unsigned int -calckey(unsigned int size) -{ - unsigned int ret = 0; - size=(size-0x200) >> 3; - int res1 = (size&0x3F80) << 1; - res1 |= (size&0x4000) << 2; - res1 |= (size&0x7F); - res1 |= 0x380000; - int res2 = res1; - res1 = res2 >> 0x10; - int res3 = res2 >> 8; - res3 += res1; - res3 += res2; - res3 <<= 24; - res3 |= res2; - res3 |= 0x80808080; - - if((res3&0x200) == 0) { - ret |= (((res3)&0xFF)^0x4B)<<24; - ret |= (((res3>>8)&0xFF)^0x61)<<16; - ret |= (((res3>>16)&0xFF)^0x77)<<8; - ret |= (((res3>>24)&0xFF)^0x61); - } else { - ret |= (((res3)&0xFF)^0x73)<<24; - ret |= (((res3>>8)&0xFF)^0x65)<<16; - ret |= (((res3>>16)&0xFF)^0x64)<<8; - ret |= (((res3>>24)&0xFF)^0x6F); - } - return ret; -} - -static unsigned int -docrc(uint32_t crc, uint32_t val) -{ - int i; - for(i = 0; i < 0x20; i++) - { - if((crc^val)&1) - { - crc>>=1; - crc^=0xa1c1; - } - else - crc>>=1; - val>>=1; - } - return crc; -} - -static unsigned int -__gba_multiboot(struct gba_multiboot_p *gbm) -{ - uint32_t enc, sessionkeyraw, sessionkey, res; - int count, i; - unsigned int fcrc, ourkey, sendsize; - unsigned chan = gbm->chan; - unsigned char *rom = gbm->rom; - long size = gbm->size; - struct si_softc *sc = gbm->sc; - - count = 0; - for (;;) { - if (count >= 1000) { - aprint_normal("multiboot: ch %d initialize failure\n", - chan); - return EAGAIN; - } - - jb_reset(sc, chan, JB_DELAY); - res = jb_identify(sc, chan, JB_DELAY); - if (res & 0x00001000) { - break; - } - count++; - } - - sendsize = ((size+7)&~7); - ourkey = calckey(sendsize); - - sessionkeyraw = gba_read32(sc, chan); - sessionkey = bswap32(sessionkeyraw^0x7365646F); - gba_send32(sc, chan, bswap32(ourkey)); - fcrc = 0x15A0; - - aprint_normal("multiboot: ch %d sending header\n", chan); - for (i = 0; i < 0xC0; i += 4) { - gba_send32(sc, chan, bswap32(*(uint32_t*)(rom+i))); - } - - aprint_normal("multiboot: ch %d sending rom\n", chan); - for (i = 0xC0; i < sendsize; i += 4) { - enc = ((rom[i+3]<<24)|(rom[i+2]<<16)|(rom[i+1]<<8)|(rom[i])); - fcrc = docrc(fcrc, enc); - sessionkey = (sessionkey*0x6177614B)+1; - enc^=sessionkey; - enc^=((~(i+(0x20<<20)))+1); - enc^=0x20796220; - gba_send32(sc, chan, enc); - } - - fcrc |= (sendsize<<16); - sessionkey = (sessionkey*0x6177614B)+1; - fcrc^=sessionkey; - fcrc^=((~(i+(0x20<<20)))+1); - fcrc^=0x20796220; - - gba_send32(sc, chan, fcrc); - gba_read32(sc, chan); - - return 0; -} - -#endif diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.c b/sys/arch/evbppc/nintendo/dev/gba_si.c index c5c4cbf0f1175..731963b94465f 100644 --- a/sys/arch/evbppc/nintendo/dev/gba_si.c +++ b/sys/arch/evbppc/nintendo/dev/gba_si.c @@ -45,19 +45,14 @@ __KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/05/18 22:53:30 gummybuns Exp $") #include "si.h" #include "joybus.h" -#include "gba_multiboot.h" struct gba_send { - uint32_t status; /* sisr status for this channel */ uint32_t insize; /* bytes to receive. max 128 */ uint32_t outsize; /* bytes to send. max 128 */ + uint32_t *status; /* sisr status for this channel */ void *in; /* buffer to store response */ void *out; /* buffer to send out to gba */ -}; - -struct gba_multiboot { - long size; - void *rom; + long delay; /* delay the transaction (microsec) */ }; extern struct cfdriver gba_cd; @@ -70,10 +65,10 @@ struct gba_softc { #define GBA_SEND _IOWR(0, 1, struct gba_send) -#define GBA_MULTIBOOT _IOWR(0, 2, struct gba_multiboot) static int gba_si_match(device_t, cfdata_t, void *); static void gba_si_attach(device_t, device_t, void *); +static int gbaioctl_send(struct si_channel *ch, struct gba_send *gbs); dev_type_open(gba_open); dev_type_close(gba_close); @@ -128,8 +123,6 @@ gba_si_attach(device_t parent, device_t self, void *aux) sc->ch = ch; sc->sc_bst = psc->sc_bst; sc->sc_bsh = psc->sc_bsh; - // TODO - i dont know if i need to disable polling or not - //WR4(psc, SIPOLL, 0); } int @@ -188,58 +181,11 @@ gba_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) struct gba_softc * const gbasc = device_lookup_private(&gba_cd, minor(dev)); struct si_channel *ch = gbasc->ch; - struct si_softc * const sc = ch->ch_sc; int err; switch(cmd) { - case GBA_MULTIBOOT: - err = 0; - struct gba_multiboot *gbm = (struct gba_multiboot *)data; - struct gba_multiboot_p gbmp; - void *rom = kmem_alloc(gbm->size, KM_SLEEP); - if ((err = copyin(gbm->rom, rom, gbm->size)) != 0) { - goto multiboot_cleanup; - } - - gbmp.sc = sc; - gbmp.chan = ch->ch_index; - gbmp.rom = (unsigned char *)rom; - gbmp.size = gbm->size; - - err = __gba_multiboot(&gbmp); -multiboot_cleanup: - kmem_free(rom, gbm->size); - break; case GBA_SEND: - err = 0; - struct siio_send sd; - struct gba_send *gbs = (struct gba_send *)data; - if (gbs->outsize > SIIOBUF_SIZE || gbs->insize > SIIOBUF_SIZE) { - return EINVAL; - } - - sd.chan = ch->ch_index; - sd.outsize = gbs->outsize; - sd.insize = gbs->insize; - sd.out = kmem_alloc(gbs->outsize, KM_SLEEP); - sd.in = kmem_alloc(gbs->insize, KM_SLEEP); - - if ((err = copyin(gbs->out, sd.out, sd.outsize)) != 0) { - goto si_send_cleanup; - } - - if ((err = __si_send(sc, &sd)) != 0) { - goto si_send_cleanup; - } - - if ((err = copyout(sd.in, gbs->in, sd.insize)) != 0) { - goto si_send_cleanup; - } - - gbs->status = sd.status; -si_send_cleanup: - kmem_free(sd.out, sd.outsize); - kmem_free(sd.in, sd.insize); + err = gbaioctl_send(ch, (struct gba_send *)data); break; default: err = EINVAL; @@ -248,3 +194,44 @@ gba_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) return err; } + +static int +gbaioctl_send(struct si_channel *ch, struct gba_send *gbs) +{ + int err; + struct si_softc *sc; + struct siio_send sd; + + err = 0; + sc = ch->ch_sc; + if (gbs->outsize > SIIOBUF_SIZE || gbs->insize > SIIOBUF_SIZE) { + return EINVAL; + } + + sd.chan = ch->ch_index; + sd.outsize = gbs->outsize; + sd.insize = gbs->insize; + sd.out = kmem_alloc(gbs->outsize, KM_SLEEP); + sd.in = kmem_alloc(gbs->insize, KM_SLEEP); + sd.delay = gbs->delay; + + if ((err = copyin(gbs->out, sd.out, sd.outsize)) != 0) { + goto si_send_cleanup; + } + + if ((err = __si_send(sc, &sd)) != 0) { + goto si_send_cleanup; + } + + if ((err = copyout(sd.in, gbs->in, sd.insize)) != 0) { + goto si_send_cleanup; + } + + if ((err = copyout(&sd.status, gbs->status, sizeof(uint32_t))) != 0) { + goto si_send_cleanup; + } +si_send_cleanup: + kmem_free(sd.out, sd.outsize); + kmem_free(sd.in, sd.insize); + return err; +} diff --git a/sys/arch/evbppc/nintendo/dev/joybus.h b/sys/arch/evbppc/nintendo/dev/joybus.h index 7ac43bae9a006..cf268a5caa9ee 100644 --- a/sys/arch/evbppc/nintendo/dev/joybus.h +++ b/sys/arch/evbppc/nintendo/dev/joybus.h @@ -44,10 +44,10 @@ #define JB_WIRELESS_NONCTRL __BIT(3) #define JB_WIRELESS_LITE __BIT(2) -#define JB_IDENTIFY 0x00000000 -#define JB_RESET 0xFF000000 -#define JB_GBA_READ 0x14 -#define JB_GBA_WRITE 0x15 +#define CMD_IDENTIFY 0x00000000 /* pad with zeros to clear siiobuf */ +#define CMD_RESET 0xFF000000 /* pad with zeros to clear siiobuf */ +#define CMD_GBA_READ 0x14 +#define CMD_GBA_WRITE 0x15 #define JB_NONE 0x0000 #define JB_N64 0x0500 @@ -68,45 +68,4 @@ #define IS_N64(n) !ISSET(n, JB_CONTROLLER) #define IS_GCPAD(n) (((n) & (JB_CONTROLLER | JB_DOLPHIN)) == JB_GC) || \ ISSET(n, JB_WIRELESS) - -#define JB_DELAY 50 /* lowest delay with results for multiboot */ - -static inline uint32_t -jb_reset(struct si_softc *sc, unsigned chan, long us) -{ - struct siio_send data; - uint32_t out[1]; - uint32_t in[1]; - out[0] = JB_RESET; - - data.chan = chan; - data.outsize = 1; - data.insize = 3; - data.in = in; - data.out = out; - - delay(us); - __si_send(sc, &data); - return in[0]; -} - -static inline uint32_t -jb_identify(struct si_softc *sc, unsigned chan, long us) -{ - struct siio_send data; - uint32_t out[1]; - uint32_t in[1]; - out[0] = JB_IDENTIFY; - - data.chan = chan; - data.outsize = 1; - data.insize = 3; - data.in = in; - data.out = out; - - delay(us); - __si_send(sc, &data); - return in[0]; -} - #endif diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index 183fd59cf576f..0f996356ec493 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -58,6 +58,7 @@ static void si_softintr(void *); static int si_rescan(device_t, const char *, const int *); static int si_print(void *, const char *); +static uint32_t send_cmd(struct si_softc *, uint32_t, unsigned, long); static int si_identify(device_t, unsigned); static void si_get_report_desc(void *, void **, int *); @@ -183,6 +184,25 @@ si_print(void *aux, const char *pnp) } +static uint32_t +send_cmd(struct si_softc *sc, uint32_t cmd, unsigned chan, long us) +{ + struct siio_send data; + uint32_t out[1]; + uint32_t in[1]; + out[0] = cmd; + + data.chan = chan; + data.outsize = 1; + data.insize = 3; + data.in = in; + data.out = out; + data.delay = us; + + __si_send(sc, &data); + return in[0]; +} + static int si_identify(device_t self, unsigned chan) { @@ -202,8 +222,8 @@ si_identify(device_t self, unsigned chan) * if it can be put into the proper state */ do { - jb_reset(sc, chan, 1000); - id = jb_identify(sc, chan, 1000); + send_cmd(sc, CMD_RESET, chan, 1000); + id = send_cmd(sc, CMD_IDENTIFY, chan, 1000); msb = (uint8_t)(id >> 24); ch->ch_id = (uint16_t)(id >> 16); sisr = RD4(sc, SISR); diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index d89b71808d9fb..c2dc8cc5b9e87 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -143,6 +143,7 @@ struct siio_send { uint32_t outsize; /* number of bytes for out buffer */ void *in; /* buffer to store response */ void *out; /* buffer to send out to ext device */ + long delay; /* delay the transaction (microsec) */ }; static inline int @@ -163,6 +164,12 @@ __si_send(struct si_softc *sc, struct siio_send *data) WR4(sc, SISR, SISR_ERROR_MASK(chan)); sisr = RD4(sc, SISR); + + /* + * libogc uses interrupts for non-blocking. i think this is ok for now + */ + delay(data->delay); + AWAIT_SICOMCSR(sc); WR4(sc, SICOMCSR, SICOMCSR_CH_EN | From afa5416c53c515b62d80bbe18895d63b1139cca6 Mon Sep 17 00:00:00 2001 From: zac Date: Thu, 28 May 2026 12:08:52 -0400 Subject: [PATCH 13/35] move to a generic gcport char device gcport is the gamecube port that has a device attached. it will match everything besides the gamecube controller, which currently uses the existing logic to attach as a uhid keeping things generic removed references to gba --- sys/arch/evbppc/conf/NINTENDO | 2 +- sys/arch/evbppc/conf/majors.evbppc | 2 +- sys/arch/evbppc/nintendo/dev/files.dev | 6 +- .../nintendo/dev/{gba_si.c => gcport_si.c} | 75 ++++++++++--------- sys/arch/evbppc/nintendo/dev/si.c | 20 +---- 5 files changed, 46 insertions(+), 59 deletions(-) rename sys/arch/evbppc/nintendo/dev/{gba_si.c => gcport_si.c} (71%) diff --git a/sys/arch/evbppc/conf/NINTENDO b/sys/arch/evbppc/conf/NINTENDO index ce7521a30ea30..efee8e23b10ba 100644 --- a/sys/arch/evbppc/conf/NINTENDO +++ b/sys/arch/evbppc/conf/NINTENDO @@ -133,7 +133,7 @@ options WSDISPLAY_MULTICONS ahb0 at mainbus0 irq 14 si0 at mainbus0 addr 0x0d006400 irq 3 # Serial interface uhid* at si0 -gba* at si0 +gcport* at si0 exi0 at mainbus0 addr 0x0d006800 irq 4 # External interface rtcsram0 at exi0 # RTC/SRAM chip gecko0 at exi0 # USB Gecko diff --git a/sys/arch/evbppc/conf/majors.evbppc b/sys/arch/evbppc/conf/majors.evbppc index 2814d96aecc60..20dce4457788a 100644 --- a/sys/arch/evbppc/conf/majors.evbppc +++ b/sys/arch/evbppc/conf/majors.evbppc @@ -83,7 +83,7 @@ device-major twe char 76 twe #device-major obsolete char 98 obsolete (nsmb) device-major xlcom char 99 xlcom -device-major gba char 100 +device-major gcport char 100 # Majors up to 143 are reserved for machine-dependent drivers. # New machine-independent driver majors are assigned in diff --git a/sys/arch/evbppc/nintendo/dev/files.dev b/sys/arch/evbppc/nintendo/dev/files.dev index 65e7e28c87075..ad70a9ff3b5ab 100644 --- a/sys/arch/evbppc/nintendo/dev/files.dev +++ b/sys/arch/evbppc/nintendo/dev/files.dev @@ -37,9 +37,9 @@ file arch/evbppc/nintendo/dev/si.c si attach uhid at si with uhid_si file arch/evbppc/nintendo/dev/uhid_si.c uhid_si -device gba -attach gba at si with gba_si -file arch/evbppc/nintendo/dev/gba_si.c gba_si +device gcport +attach gcport at si with gcport_si +file arch/evbppc/nintendo/dev/gcport_si.c gcport_si define ahb { [addr=-1], [irq=-1] } device ahb: ahb diff --git a/sys/arch/evbppc/nintendo/dev/gba_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c similarity index 71% rename from sys/arch/evbppc/nintendo/dev/gba_si.c rename to sys/arch/evbppc/nintendo/dev/gcport_si.c index 731963b94465f..431f439693368 100644 --- a/sys/arch/evbppc/nintendo/dev/gba_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -1,4 +1,4 @@ -/* $NetBSD: gba_si.c,v 1.0 2026/05/18 22:54:30 gummybuns Exp $ */ +/* $NetBSD: gcport_si.c,v 1.0 2026/05/18 22:54:30 gummybuns Exp $ */ /*- * Copyright (c) 2026 ZacBrown @@ -27,7 +27,7 @@ */ #include -__KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/05/18 22:53:30 gummybuns Exp $"); +__KERNEL_RCSID(0, "$NetBSD: gcport_si.c,v 1.0 2026/05/18 22:53:30 gummybuns Exp $"); #include #include @@ -46,17 +46,17 @@ __KERNEL_RCSID(0, "$NetBSD: gba_si.c,v 1.0 2026/05/18 22:53:30 gummybuns Exp $") #include "si.h" #include "joybus.h" -struct gba_send { +struct si_payload { uint32_t insize; /* bytes to receive. max 128 */ uint32_t outsize; /* bytes to send. max 128 */ uint32_t *status; /* sisr status for this channel */ void *in; /* buffer to store response */ - void *out; /* buffer to send out to gba */ + void *out; /* buffer to send out to device */ long delay; /* delay the transaction (microsec) */ }; -extern struct cfdriver gba_cd; -struct gba_softc { +extern struct cfdriver gcport_cd; +struct gcport_softc { device_t sc_dev; struct si_channel *ch; bus_space_tag_t sc_bst; @@ -64,20 +64,20 @@ struct gba_softc { }; -#define GBA_SEND _IOWR(0, 1, struct gba_send) +#define SI_SEND _IOWR(0, 1, struct si_payload) -static int gba_si_match(device_t, cfdata_t, void *); -static void gba_si_attach(device_t, device_t, void *); -static int gbaioctl_send(struct si_channel *ch, struct gba_send *gbs); +static int gcport_si_match(device_t, cfdata_t, void *); +static void gcport_si_attach(device_t, device_t, void *); +static int siioctl_send(struct si_channel *ch, struct si_payload *sp); -dev_type_open(gba_open); -dev_type_close(gba_close); -dev_type_ioctl(gba_ioctl); +dev_type_open(gcport_open); +dev_type_close(gcport_close); +dev_type_ioctl(gcport_ioctl); -const struct cdevsw gba_cdevsw = { - .d_open = gba_open, - .d_close = gba_close, - .d_ioctl = gba_ioctl, +const struct cdevsw gcport_cdevsw = { + .d_open = gcport_open, + .d_close = gcport_close, + .d_ioctl = gcport_ioctl, .d_read = noread, .d_write = nowrite, .d_stop = nostop, @@ -89,11 +89,11 @@ const struct cdevsw gba_cdevsw = { .d_flag = D_OTHER }; -CFATTACH_DECL_NEW(gba_si, sizeof(struct gba_softc), - gba_si_match, gba_si_attach, NULL, NULL); +CFATTACH_DECL_NEW(gcport_si, sizeof(struct gcport_softc), + gcport_si_match, gcport_si_attach, NULL, NULL); static int -gba_si_match(device_t parent, cfdata_t cf, void *aux) +gcport_si_match(device_t parent, cfdata_t cf, void *aux) { struct si_softc * const sc = device_private(parent); struct si_attach_args * const saa = aux; @@ -102,9 +102,12 @@ gba_si_match(device_t parent, cfdata_t cf, void *aux) chan = saa->saa_index; ch = &sc->sc_chan[chan]; - aprint_normal("gba: checking 0x%08X...\n", ch->ch_id); - if (ch->ch_id == JB_GBA) { - aprint_normal("gba: identified ch%d as a gba device\n", chan); + aprint_normal("gcport: checking 0x%08X...\n", ch->ch_id); + /* NOTE - existing functionality uses uhid for gc_pad. This will + * match any other device + */ + if (ch->ch_id != 0 && !(IS_GCPAD(ch->ch_id))) { + aprint_normal("gcport: identified ch%d as a device 0x%08X\n", chan, ch->ch_id); return 1; } @@ -112,11 +115,11 @@ gba_si_match(device_t parent, cfdata_t cf, void *aux) } static void -gba_si_attach(device_t parent, device_t self, void *aux) +gcport_si_attach(device_t parent, device_t self, void *aux) { struct si_softc * const psc = device_private(parent); struct si_attach_args * const saa = aux; - struct gba_softc * const sc = device_private(self); + struct gcport_softc * const sc = device_private(self); struct si_channel *ch = &psc->sc_chan[saa->saa_index]; sc->sc_dev = self; @@ -126,9 +129,9 @@ gba_si_attach(device_t parent, device_t self, void *aux) } int -gba_open(dev_t dev, int flags, int mode, struct lwp *l) +gcport_open(dev_t dev, int flags, int mode, struct lwp *l) { - struct gba_softc * const sc = device_lookup_private(&gba_cd, minor(dev)); + struct gcport_softc *sc = device_lookup_private(&gcport_cd, minor(dev)); struct si_channel *ch = sc->ch; int error; @@ -147,10 +150,9 @@ gba_open(dev_t dev, int flags, int mode, struct lwp *l) } int -gba_close(dev_t dev, int flags, int mode, struct lwp *l) +gcport_close(dev_t dev, int flags, int mode, struct lwp *l) { - struct gba_softc * const sc = device_lookup_private(&gba_cd, - minor(dev)); + struct gcport_softc *sc = device_lookup_private(&gcport_cd, minor(dev)); struct si_channel *ch = sc->ch; mutex_enter(&ch->ch_lock); @@ -176,16 +178,15 @@ gba_close(dev_t dev, int flags, int mode, struct lwp *l) * no one is using but me. so i can define my own mutex for that purpose. */ int -gba_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) +gcport_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { - struct gba_softc * const gbasc = device_lookup_private(&gba_cd, - minor(dev)); - struct si_channel *ch = gbasc->ch; + struct gcport_softc *sc = device_lookup_private(&gcport_cd, minor(dev)); + struct si_channel *ch = sc->ch; int err; switch(cmd) { - case GBA_SEND: - err = gbaioctl_send(ch, (struct gba_send *)data); + case SI_SEND: + err = siioctl_send(ch, (struct si_payload *)data); break; default: err = EINVAL; @@ -196,7 +197,7 @@ gba_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) } static int -gbaioctl_send(struct si_channel *ch, struct gba_send *gbs) +siioctl_send(struct si_channel *ch, struct si_payload *gbs) { int err; struct si_softc *sc; diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index 0f996356ec493..160bd9a9ef33a 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -209,26 +209,12 @@ si_identify(device_t self, unsigned chan) struct si_softc * const sc = device_private(self); struct si_channel *ch; uint32_t id; - uint32_t sisr; - uint8_t msb; - int cnt; ch = &sc->sc_chan[chan]; - cnt = 0; - /* - * Identify call is normaly 2bytes, GBA BIOS however sends a 1byte resp - * and sets SISR as NOREP. We need to try to reset the device and see - * if it can be put into the proper state - */ - do { - send_cmd(sc, CMD_RESET, chan, 1000); - id = send_cmd(sc, CMD_IDENTIFY, chan, 1000); - msb = (uint8_t)(id >> 24); - ch->ch_id = (uint16_t)(id >> 16); - sisr = RD4(sc, SISR); - cnt++; - } while (cnt < 1000 && msb == JB_GBABIOS && (sisr & SISR_NOREP(chan))); + send_cmd(sc, CMD_RESET, chan, 1000); + id = send_cmd(sc, CMD_IDENTIFY, chan, 1000); + ch->ch_id = (uint16_t)(id >> 16); return 0; } From 5d0b8e4664e933067743bb2ef9ef4c76a8874741 Mon Sep 17 00:00:00 2001 From: zac Date: Fri, 29 May 2026 13:18:56 -0400 Subject: [PATCH 14/35] add a mutex and some todos --- etc/etc.evbppc/MAKEDEV.conf | 2 ++ sys/arch/evbppc/nintendo/dev/gcport_si.c | 17 ++++++++++++++--- sys/arch/evbppc/nintendo/dev/si.h | 7 +++++++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/etc/etc.evbppc/MAKEDEV.conf b/etc/etc.evbppc/MAKEDEV.conf index e866d6ad088fd..d8577b7240068 100644 --- a/etc/etc.evbppc/MAKEDEV.conf +++ b/etc/etc.evbppc/MAKEDEV.conf @@ -26,6 +26,8 @@ all_md) makedev virtio ;; +# TODO - i think i can add something here to create my device files +# instead of manually calling mknod i just dont know yet.. # ramdisk definition is found at distrib/evbppc/ramdisk/Makefile xlcom[0-9]*) diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index 431f439693368..32a1128d77b33 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -107,7 +107,8 @@ gcport_si_match(device_t parent, cfdata_t cf, void *aux) * match any other device */ if (ch->ch_id != 0 && !(IS_GCPAD(ch->ch_id))) { - aprint_normal("gcport: identified ch%d as a device 0x%08X\n", chan, ch->ch_id); + aprint_normal("gcport: identified ch%d as a device 0x%08X\n", + chan, ch->ch_id); return 1; } @@ -131,10 +132,20 @@ gcport_si_attach(device_t parent, device_t self, void *aux) int gcport_open(dev_t dev, int flags, int mode, struct lwp *l) { - struct gcport_softc *sc = device_lookup_private(&gcport_cd, minor(dev)); - struct si_channel *ch = sc->ch; + struct gcport_softc *sc; + struct si_channel *ch; int error; + /* TODO maybe there is a way to have the minor number reflect the + * actual port instead of an auto increment thing + */ + sc = device_lookup_private(&gcport_cd, minor(dev)); + + if (sc == NULL) { + return ENXIO; + } + + ch = sc->ch; mutex_enter(&ch->ch_lock); if (ISSET(ch->ch_state, SI_STATE_OPEN)) { diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index c2dc8cc5b9e87..44b18f30be9a9 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -152,6 +152,11 @@ __si_send(struct si_softc *sc, struct siio_send *data) uint32_t cnt, comcsr, sisr, shift_amt, status; unsigned chan; + /* TODO - is the mutex necessary? The docs say you should absolutely + * not change OUTLNGTH / INLNGTH mid transaction, but we are awaiting + * the TSTART before/after already.. + */ + mutex_enter(&sicomcsr_lock); chan = data->chan; SIIOBUF_CLEAR(sc); @@ -192,6 +197,8 @@ __si_send(struct si_softc *sc, struct siio_send *data) } SIIOBUF_RD(sc, data->in, data->insize); + + mutex_exit(&sicomcsr_lock); return 0; } From 7f72f91065833dfc6108d02a9e10b67026cf1647 Mon Sep 17 00:00:00 2001 From: zac Date: Fri, 29 May 2026 14:30:59 -0400 Subject: [PATCH 15/35] remove a todo --- sys/arch/evbppc/nintendo/dev/gcport_si.c | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index 32a1128d77b33..c708a0babebb3 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -176,18 +176,6 @@ gcport_close(dev_t dev, int flags, int mode, struct lwp *l) return 0; } -/** - * TODO: - * - * i dont really want to touch the other guys code at all if i dont have to. - * i dont think that i do. according to the docs you should never set - * TSTART if you are in the middle of a transaction. i can add the AWAIT to - * one or two of his lines np. - * - * then it says you should never change OUTLENGTH / INLENGTH / CHANNEL in the - * middle of a transaction. these are only things used for the siiobuf, which - * no one is using but me. so i can define my own mutex for that purpose. - */ int gcport_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { From 34a1839b8e74cd415e02fa410d9ce24c74d73226 Mon Sep 17 00:00:00 2001 From: zac Date: Fri, 29 May 2026 15:11:08 -0400 Subject: [PATCH 16/35] remove a todo --- sys/arch/evbppc/nintendo/dev/si.h | 4 ---- 1 file changed, 4 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 44b18f30be9a9..64fd71c194aff 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -152,10 +152,6 @@ __si_send(struct si_softc *sc, struct siio_send *data) uint32_t cnt, comcsr, sisr, shift_amt, status; unsigned chan; - /* TODO - is the mutex necessary? The docs say you should absolutely - * not change OUTLNGTH / INLNGTH mid transaction, but we are awaiting - * the TSTART before/after already.. - */ mutex_enter(&sicomcsr_lock); chan = data->chan; From b95949c3a0cf8bea13d438e3387562a9a641be1b Mon Sep 17 00:00:00 2001 From: zac Date: Sun, 31 May 2026 13:52:20 -0400 Subject: [PATCH 17/35] device minor number reflects physical port - define the four physical ports in the conf - update the match to compare the channel to the unit number --- sys/arch/evbppc/conf/NINTENDO | 5 ++++- sys/arch/evbppc/nintendo/dev/gcport_si.c | 12 ++++-------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/sys/arch/evbppc/conf/NINTENDO b/sys/arch/evbppc/conf/NINTENDO index efee8e23b10ba..d76edbc78daea 100644 --- a/sys/arch/evbppc/conf/NINTENDO +++ b/sys/arch/evbppc/conf/NINTENDO @@ -133,7 +133,10 @@ options WSDISPLAY_MULTICONS ahb0 at mainbus0 irq 14 si0 at mainbus0 addr 0x0d006400 irq 3 # Serial interface uhid* at si0 -gcport* at si0 +gcport0 at si0 +gcport1 at si0 +gcport2 at si0 +gcport3 at si0 exi0 at mainbus0 addr 0x0d006800 irq 4 # External interface rtcsram0 at exi0 # RTC/SRAM chip gecko0 at exi0 # USB Gecko diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index c708a0babebb3..01f003fc03013 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -98,15 +98,14 @@ gcport_si_match(device_t parent, cfdata_t cf, void *aux) struct si_softc * const sc = device_private(parent); struct si_attach_args * const saa = aux; struct si_channel *ch; + int unit; unsigned chan; chan = saa->saa_index; ch = &sc->sc_chan[chan]; - aprint_normal("gcport: checking 0x%08X...\n", ch->ch_id); - /* NOTE - existing functionality uses uhid for gc_pad. This will - * match any other device - */ - if (ch->ch_id != 0 && !(IS_GCPAD(ch->ch_id))) { + unit = cf->cf_unit; + + if (chan == unit && ch->ch_id != 0 && !(IS_GCPAD(ch->ch_id))) { aprint_normal("gcport: identified ch%d as a device 0x%08X\n", chan, ch->ch_id); return 1; @@ -136,9 +135,6 @@ gcport_open(dev_t dev, int flags, int mode, struct lwp *l) struct si_channel *ch; int error; - /* TODO maybe there is a way to have the minor number reflect the - * actual port instead of an auto increment thing - */ sc = device_lookup_private(&gcport_cd, minor(dev)); if (sc == NULL) { From 6db34e62eed4d763c3ecd344fd2d335f3811f970 Mon Sep 17 00:00:00 2001 From: zac Date: Sun, 31 May 2026 14:47:11 -0400 Subject: [PATCH 18/35] rename a variable and try to get makedev to work --- etc/etc.evbppc/MAKEDEV.conf | 7 +++++-- sys/arch/evbppc/nintendo/dev/gcport_si.c | 20 ++++++++++---------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/etc/etc.evbppc/MAKEDEV.conf b/etc/etc.evbppc/MAKEDEV.conf index d8577b7240068..4c7816b6f0de1 100644 --- a/etc/etc.evbppc/MAKEDEV.conf +++ b/etc/etc.evbppc/MAKEDEV.conf @@ -26,11 +26,14 @@ all_md) makedev virtio ;; -# TODO - i think i can add something here to create my device files -# instead of manually calling mknod i just dont know yet.. # ramdisk definition is found at distrib/evbppc/ramdisk/Makefile xlcom[0-9]*) unit=${i#xlcom} mkdev xlcom$unit c 99 $unit "" "" $u_uucp ;; + +gcport[0-3]*) + unit=${i#gcport} + mkdev gcport$unit c 100 $unit "" "" $u_uucp + ;; diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index 01f003fc03013..1813f2d350f1d 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -192,7 +192,7 @@ gcport_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) } static int -siioctl_send(struct si_channel *ch, struct si_payload *gbs) +siioctl_send(struct si_channel *ch, struct si_payload *p) { int err; struct si_softc *sc; @@ -200,18 +200,18 @@ siioctl_send(struct si_channel *ch, struct si_payload *gbs) err = 0; sc = ch->ch_sc; - if (gbs->outsize > SIIOBUF_SIZE || gbs->insize > SIIOBUF_SIZE) { + if (p->outsize > SIIOBUF_SIZE || p->insize > SIIOBUF_SIZE) { return EINVAL; } sd.chan = ch->ch_index; - sd.outsize = gbs->outsize; - sd.insize = gbs->insize; - sd.out = kmem_alloc(gbs->outsize, KM_SLEEP); - sd.in = kmem_alloc(gbs->insize, KM_SLEEP); - sd.delay = gbs->delay; + sd.outsize = p->outsize; + sd.insize = p->insize; + sd.out = kmem_alloc(p->outsize, KM_SLEEP); + sd.in = kmem_alloc(p->insize, KM_SLEEP); + sd.delay = p->delay; - if ((err = copyin(gbs->out, sd.out, sd.outsize)) != 0) { + if ((err = copyin(p->out, sd.out, sd.outsize)) != 0) { goto si_send_cleanup; } @@ -219,11 +219,11 @@ siioctl_send(struct si_channel *ch, struct si_payload *gbs) goto si_send_cleanup; } - if ((err = copyout(sd.in, gbs->in, sd.insize)) != 0) { + if ((err = copyout(sd.in, p->in, sd.insize)) != 0) { goto si_send_cleanup; } - if ((err = copyout(&sd.status, gbs->status, sizeof(uint32_t))) != 0) { + if ((err = copyout(&sd.status, p->status, sizeof(uint32_t))) != 0) { goto si_send_cleanup; } si_send_cleanup: From b38e97020d3de50fe4b86f0786c210e5eaf38519 Mon Sep 17 00:00:00 2001 From: zac Date: Sun, 31 May 2026 15:06:00 -0400 Subject: [PATCH 19/35] i think i need to include the actual calls in all --- etc/etc.evbppc/MAKEDEV.conf | 1 + 1 file changed, 1 insertion(+) diff --git a/etc/etc.evbppc/MAKEDEV.conf b/etc/etc.evbppc/MAKEDEV.conf index 4c7816b6f0de1..1e868ab810a0b 100644 --- a/etc/etc.evbppc/MAKEDEV.conf +++ b/etc/etc.evbppc/MAKEDEV.conf @@ -22,6 +22,7 @@ all_md) makedev radio makedev kttcp makedev xlcom0 + makedev gcport0 gcport1 gcport2 gcport3 makedev cfs makedev virtio ;; From b72303a19c2946d2768c2d4c1017d188ea4f9c3b Mon Sep 17 00:00:00 2001 From: Zac Brown Date: Mon, 1 Jun 2026 20:53:01 -0400 Subject: [PATCH 20/35] Update sys/arch/evbppc/nintendo/dev/si.c Co-authored-by: Jared McNeill --- sys/arch/evbppc/nintendo/dev/si.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index 160bd9a9ef33a..afa14cb1487eb 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -69,7 +69,7 @@ static usbd_status si_set_report(void *, int, void *, int); static usbd_status si_get_report(void *, int, void *, int); static usbd_status si_write(void *, void *, int); -kmutex_t sicomcsr_lock; +static kmutex_t sicomcsr_lock; CFATTACH_DECL_NEW(si, sizeof(struct si_softc), si_match, si_attach, NULL, NULL); From 48ec656338da89fde718670eec97c1bf9e71c487 Mon Sep 17 00:00:00 2001 From: gummybuns Date: Wed, 3 Jun 2026 14:40:26 -0400 Subject: [PATCH 21/35] update hierarchy si0 -> gcport -> uhid --- sys/arch/evbppc/conf/NINTENDO | 7 +--- sys/arch/evbppc/nintendo/dev/files.dev | 11 +++--- sys/arch/evbppc/nintendo/dev/gcport_si.c | 47 ++++++++++++------------ sys/arch/evbppc/nintendo/dev/si.c | 8 +--- sys/arch/evbppc/nintendo/dev/si.h | 7 ++++ sys/arch/evbppc/nintendo/dev/uhid_si.c | 6 +-- 6 files changed, 42 insertions(+), 44 deletions(-) diff --git a/sys/arch/evbppc/conf/NINTENDO b/sys/arch/evbppc/conf/NINTENDO index d76edbc78daea..b9e865c922b8e 100644 --- a/sys/arch/evbppc/conf/NINTENDO +++ b/sys/arch/evbppc/conf/NINTENDO @@ -132,11 +132,8 @@ options WSDISPLAY_MULTICONS ahb0 at mainbus0 irq 14 si0 at mainbus0 addr 0x0d006400 irq 3 # Serial interface -uhid* at si0 -gcport0 at si0 -gcport1 at si0 -gcport2 at si0 -gcport3 at si0 +gcport* at si0 +uhid* at gcport? exi0 at mainbus0 addr 0x0d006800 irq 4 # External interface rtcsram0 at exi0 # RTC/SRAM chip gecko0 at exi0 # USB Gecko diff --git a/sys/arch/evbppc/nintendo/dev/files.dev b/sys/arch/evbppc/nintendo/dev/files.dev index ad70a9ff3b5ab..6da129f30704b 100644 --- a/sys/arch/evbppc/nintendo/dev/files.dev +++ b/sys/arch/evbppc/nintendo/dev/files.dev @@ -30,17 +30,18 @@ attach gecko at exi file arch/evbppc/nintendo/dev/gecko.c gecko needs-flag define si { } -device si: si, hid +device si: si attach si at mainbus file arch/evbppc/nintendo/dev/si.c si -attach uhid at si with uhid_si -file arch/evbppc/nintendo/dev/uhid_si.c uhid_si - -device gcport +define gcport { } +device gcport: gcport, hid attach gcport at si with gcport_si file arch/evbppc/nintendo/dev/gcport_si.c gcport_si +attach uhid at gcport with uhid_si +file arch/evbppc/nintendo/dev/uhid_si.c uhid_si + define ahb { [addr=-1], [irq=-1] } device ahb: ahb attach ahb at mainbus diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index 1813f2d350f1d..74af7668866d2 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -56,18 +56,12 @@ struct si_payload { }; extern struct cfdriver gcport_cd; -struct gcport_softc { - device_t sc_dev; - struct si_channel *ch; - bus_space_tag_t sc_bst; - bus_space_handle_t sc_bsh; -}; - #define SI_SEND _IOWR(0, 1, struct si_payload) static int gcport_si_match(device_t, cfdata_t, void *); static void gcport_si_attach(device_t, device_t, void *); +static int gcport_si_print(void *, const char *); static int siioctl_send(struct si_channel *ch, struct si_payload *sp); dev_type_open(gcport_open); @@ -95,23 +89,7 @@ CFATTACH_DECL_NEW(gcport_si, sizeof(struct gcport_softc), static int gcport_si_match(device_t parent, cfdata_t cf, void *aux) { - struct si_softc * const sc = device_private(parent); - struct si_attach_args * const saa = aux; - struct si_channel *ch; - int unit; - unsigned chan; - - chan = saa->saa_index; - ch = &sc->sc_chan[chan]; - unit = cf->cf_unit; - - if (chan == unit && ch->ch_id != 0 && !(IS_GCPAD(ch->ch_id))) { - aprint_normal("gcport: identified ch%d as a device 0x%08X\n", - chan, ch->ch_id); - return 1; - } - - return 0; + return 1; } static void @@ -126,6 +104,27 @@ gcport_si_attach(device_t parent, device_t self, void *aux) sc->ch = ch; sc->sc_bst = psc->sc_bst; sc->sc_bsh = psc->sc_bsh; + + config_found(self, saa, gcport_si_print, CFARGS( + .submatch = config_stdsubmatch, .locators = NULL)); +} + +static int +gcport_si_print(void *aux, const char *pnp) +{ + struct si_attach_args *saa = aux; + + if (pnp != NULL) { + aprint_normal("uhid at %s", pnp); + } + + /* + * The Wii Operations Manual for RVL-001 refers to the controller + * ports as "Nintendo GameCube Controller Sockets". + */ + aprint_normal(" socket %d", saa->saa_index + 1); + + return UNCONF; } int diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index afa14cb1487eb..85b1d6b89ff41 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -69,7 +69,7 @@ static usbd_status si_set_report(void *, int, void *, int); static usbd_status si_get_report(void *, int, void *, int); static usbd_status si_write(void *, void *, int); -static kmutex_t sicomcsr_lock; +kmutex_t sicomcsr_lock; CFATTACH_DECL_NEW(si, sizeof(struct si_softc), si_match, si_attach, NULL, NULL); @@ -170,15 +170,11 @@ si_print(void *aux, const char *pnp) { struct si_attach_args *saa = aux; - if (pnp != NULL) { - aprint_normal("uhid at %s", pnp); - } - /* * The Wii Operations Manual for RVL-001 refers to the controller * ports as "Nintendo GameCube Controller Sockets". */ - aprint_normal(" socket %d", saa->saa_index + 1); + aprint_normal(" socket %d\n", saa->saa_index + 1); return UNCONF; } diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 64fd71c194aff..268ec9988c270 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -136,6 +136,13 @@ struct si_attach_args { int saa_index; }; +struct gcport_softc { + device_t sc_dev; + struct si_channel *ch; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; +}; + struct siio_send { unsigned chan; /* which controller port */ uint32_t status; /* the sisr result for this channel */ diff --git a/sys/arch/evbppc/nintendo/dev/uhid_si.c b/sys/arch/evbppc/nintendo/dev/uhid_si.c index d0191b0f332e1..795d1f8524fe3 100644 --- a/sys/arch/evbppc/nintendo/dev/uhid_si.c +++ b/sys/arch/evbppc/nintendo/dev/uhid_si.c @@ -56,11 +56,9 @@ CFATTACH_DECL_NEW(uhid_si, sizeof(struct uhid_softc), static int uhid_si_match(device_t parent, cfdata_t cf, void *aux) { - struct si_softc * const sc = device_private(parent); - struct si_attach_args * const saa = aux; - struct si_channel *ch; + struct gcport_softc * const sc = device_private(parent); + struct si_channel *ch = sc->ch; - ch = &sc->sc_chan[saa->saa_index]; if (IS_GCPAD(ch->ch_id)) { return 1; } From d38b8e14d95e41f7c04180bddfc342eab63a083b Mon Sep 17 00:00:00 2001 From: gummybuns Date: Thu, 4 Jun 2026 14:00:17 -0400 Subject: [PATCH 22/35] got interrupt controller identification to work - changed args to si_identify - removed the interrupt setup from si_open and put into si_attach - tweaked how polling is initialized - for now removed the uhid stuff in favor of print statements - confirmed it works on all 4 controllers --- sys/arch/evbppc/nintendo/dev/si.c | 66 +++++++++++++++++++------------ sys/arch/evbppc/nintendo/dev/si.h | 13 ++++-- 2 files changed, 50 insertions(+), 29 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index 85b1d6b89ff41..333bc1f0500a0 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -59,7 +59,7 @@ static void si_softintr(void *); static int si_rescan(device_t, const char *, const int *); static int si_print(void *, const char *); static uint32_t send_cmd(struct si_softc *, uint32_t, unsigned, long); -static int si_identify(device_t, unsigned); +static int si_identify(struct si_softc *, unsigned); static void si_get_report_desc(void *, void **, int *); static int si_open(void *, void (*)(void *, void *, unsigned), void *); @@ -117,7 +117,7 @@ si_attach(device_t parent, device_t self, void *aux) si_softintr, ch); KASSERT(ch->ch_si != NULL); - si_identify(self, chan); + si_identify(sc, chan); t = &ch->ch_hidev; t->_cookie = &sc->sc_chan[chan]; @@ -128,16 +128,31 @@ si_attach(device_t parent, device_t self, void *aux) t->_set_report = si_set_report; t->_get_report = si_get_report; t->_write = si_write; + + /* Init controller */ + WR4(sc, SICOUTBUF(ch->ch_index), 0x00400300); } + ih = intr_establish_xname(maa->maa_irq, IST_LEVEL, IPL_VM, si_intr, sc, + device_xname(self)); + KASSERT(ih != NULL); + + /* write to all SICOUTBUF double buffers */ + WR4(sc, SISR, SISR_SICNOUTBUF); + WR4(sc, SIPOLL, + SIPOLL_EN(0) | + SIPOLL_EN(1) | + SIPOLL_EN(2) | + SIPOLL_EN(3) | __SHIFTIN(7, SIPOLL_X) | __SHIFTIN(1, SIPOLL_Y)); - WR4(sc, SICOMCSR, SICOMCSR_RDSTINT | SICOMCSR_RDSTINTMSK); - ih = intr_establish_xname(maa->maa_irq, IST_LEVEL, IPL_VM, si_intr, sc, - device_xname(self)); - KASSERT(ih != NULL); + WR4(sc, SICOMCSR, + RD4(sc, SICOMCSR) | + SICOMCSR_RDSTINT | + SICOMCSR_RDSTINTMSK | + SICOMCSR_TSTART); si_rescan(self, NULL, NULL); } @@ -200,9 +215,8 @@ send_cmd(struct si_softc *sc, uint32_t cmd, unsigned chan, long us) } static int -si_identify(device_t self, unsigned chan) +si_identify(struct si_softc *sc, unsigned chan) { - struct si_softc * const sc = device_private(self); struct si_channel *ch; uint32_t id; @@ -270,6 +284,7 @@ si_intr(void *priv) struct si_softc *sc = priv; unsigned chan; uint32_t comcsr, sr; + int ret = 0; comcsr = RD4(sc, SICOMCSR); @@ -284,11 +299,23 @@ si_intr(void *priv) struct si_channel *ch = &sc->sc_chan[chan]; if (ISSET(sr, SISR_RDST(chan))) { - /* Reading INBUF[HL] de-asserts RDSTINT. */ - si_make_report(sc, chan, ch->ch_buf, false); - - if (ISSET(ch->ch_state, SI_STATE_OPEN)) { - softint_schedule(ch->ch_si); + /* clears the sisr by reading inbuf */ + (void)RD4(sc, SICINBUFH(ch->ch_index)); + (void)RD4(sc, SICINBUFL(ch->ch_index)); + + if (((sr & SISR_ERROR_MASK(chan)) == 0) && !(IS_GCPAD(ch->ch_id))) { + si_identify(sc, ch->ch_index); + if (IS_GCPAD(ch->ch_id)) { + aprint_normal("CONTROLLER DETECTED!!!\n"); + // TODO - add this stuff back + //si_make_report(sc, chan, ch->ch_buf, false); + //if (ISSET(ch->ch_state, SI_STATE_OPEN)) { + // softint_schedule(ch->ch_si); + //} + } + } else if (((sr & SISR_ERROR_MASK(chan)) != 0) && (IS_GCPAD(ch->ch_id))) { + aprint_normal("CONTROLLER DISCONNECTED\n"); + ch->ch_id = 0; } } @@ -312,7 +339,6 @@ static int si_open(void *cookie, void (*intr)(void *, void *, u_int), void *arg) { struct si_channel *ch = cookie; - struct si_softc *sc = ch->ch_sc; int error; mutex_enter(&ch->ch_lock); @@ -326,18 +352,6 @@ si_open(void *cookie, void (*intr)(void *, void *, u_int), void *arg) ch->ch_intrarg = arg; ch->ch_state |= SI_STATE_OPEN; - (void)RD4(sc, SICINBUFH(ch->ch_index)); - (void)RD4(sc, SICINBUFL(ch->ch_index)); - - /* Init controller */ - WR4(sc, SICOUTBUF(ch->ch_index), 0x00400300); - - /* Enable polling */ - WR4(sc, SIPOLL, RD4(sc, SIPOLL) | SIPOLL_EN(ch->ch_index)); - - WR4(sc, SISR, SISR_WR(ch->ch_index)); - WR4(sc, SICOMCSR, RD4(sc, SICOMCSR) | SICOMCSR_TSTART); - error = 0; unlock: diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 268ec9988c270..83d1a3b17bef4 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -53,6 +53,7 @@ #define SICOMCSR_CHANNEL __BITS(2, 1) #define SICOMCSR_TSTART __BIT(0) #define SISR 0x38 +#define SISR_SICNOUTBUF __BIT(31) #define SISR_OFF(n) ((3 - (n)) * 8) #define SISR_WR(n) __BIT(SISR_OFF(n) + 7) #define SISR_RDST(n) __BIT(SISR_OFF(n) + 5) @@ -156,12 +157,13 @@ struct siio_send { static inline int __si_send(struct si_softc *sc, struct siio_send *data) { - uint32_t cnt, comcsr, sisr, shift_amt, status; + uint32_t cnt, comcsr, comcsr_prev, sisr, shift_amt, status; unsigned chan; mutex_enter(&sicomcsr_lock); chan = data->chan; + comcsr_prev = RD4(sc, SICOMCSR); SIIOBUF_CLEAR(sc); data->status = 0; @@ -172,7 +174,6 @@ __si_send(struct si_softc *sc, struct siio_send *data) WR4(sc, SISR, SISR_ERROR_MASK(chan)); sisr = RD4(sc, SISR); - /* * libogc uses interrupts for non-blocking. i think this is ok for now */ @@ -191,7 +192,13 @@ __si_send(struct si_softc *sc, struct siio_send *data) AWAIT_SICOMCSR(sc); comcsr = RD4(sc, SICOMCSR); - WR4(sc, SICOMCSR, comcsr | SICOMCSR_TCINT); + + /* clear TCINT and preserve previous masks otherwise we lose polling */ + WR4(sc, SICOMCSR, comcsr | + SICOMCSR_TCINT | + (comcsr_prev & SICOMCSR_TCINTMSK) | + (comcsr_prev & SICOMCSR_RDSTINTMSK)); + if (ISSET(comcsr, SICOMCSR_COMERR)) { sisr = RD4(sc, SISR); shift_amt = 8 * (SI_NUM_CHAN - 1 - chan); From 618f85c57a88f08fe7db22e27fd6d117459d3d11 Mon Sep 17 00:00:00 2001 From: gummybuns Date: Sat, 6 Jun 2026 13:11:56 -0400 Subject: [PATCH 23/35] it is not working but worth comitting - i tried to use software interrupts to rescan for new devices - but i get kernel panics because you cant have sleep operations in these. and i think that the uhid / config_found therefore are not safe. - need to refactor to use something different --- sys/arch/evbppc/nintendo/dev/gcport_si.c | 53 +++++++++++++- sys/arch/evbppc/nintendo/dev/joybus.h | 1 - sys/arch/evbppc/nintendo/dev/si.c | 91 ++++++++---------------- sys/arch/evbppc/nintendo/dev/si.h | 32 ++++++++- sys/arch/evbppc/nintendo/dev/uhid_si.c | 16 ++++- 5 files changed, 124 insertions(+), 69 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index 74af7668866d2..32f33af679f62 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -62,6 +62,8 @@ extern struct cfdriver gcport_cd; static int gcport_si_match(device_t, cfdata_t, void *); static void gcport_si_attach(device_t, device_t, void *); static int gcport_si_print(void *, const char *); +static void gcport_si_softintr(void *); +static int gcport_si_rescan(device_t, const char *, const int *); static int siioctl_send(struct si_channel *ch, struct si_payload *sp); dev_type_open(gcport_open); @@ -104,9 +106,11 @@ gcport_si_attach(device_t parent, device_t self, void *aux) sc->ch = ch; sc->sc_bst = psc->sc_bst; sc->sc_bsh = psc->sc_bsh; + ch->ch_gcport_dev = self; + ch->ch_gcport_si = softint_establish(SOFTINT_SERIAL, + gcport_si_softintr, ch); - config_found(self, saa, gcport_si_print, CFARGS( - .submatch = config_stdsubmatch, .locators = NULL)); + gcport_si_rescan(self, NULL, NULL); } static int @@ -171,6 +175,49 @@ gcport_close(dev_t dev, int flags, int mode, struct lwp *l) return 0; } +static int +gcport_si_rescan(device_t self, const char *ifattr, const int *locs) +{ + struct si_attach_args saa; + unsigned is_gcpad; + int res; + device_t uhid_dev; + struct gcport_softc * const gsc = device_private(self); + struct si_channel *ch = gsc->ch; + struct si_softc *sc = ch->ch_sc; + + ch->ch_id = si_identify(sc, ch->ch_index); + is_gcpad = IS_GCPAD(ch->ch_id); + + aprint_normal("GCPORT_SI_RESCAN: NEW ID 0x%08X\n", ch->ch_id); + + if (is_gcpad && ch->ch_uhid_dev == NULL) { + aprint_normal("GCPORT_SI_RESCAN: WE HAVE CONFIG FOUND EVENT\n"); + saa.saa_hidev = &ch->ch_hidev; + saa.saa_index = ch->ch_index; + aprint_normal("GCPORT_SI_RESCAN: SET SAA\n"); + uhid_dev = config_found(self, &saa, gcport_si_print, CFARGS_NONE); + aprint_normal("GCPORT_SI_RESCAN: FINISHED CONFIG_FOUND\n"); + ch->ch_uhid_dev = uhid_dev; + } else if (!is_gcpad && ch->ch_uhid_dev != NULL) { + aprint_normal("GCPORT_SI_RESCAN: WE HAVE A DETACH EVENT\n"); + res = config_detach_children(ch->ch_gcport_dev, 0); + if (res == 0) { + ch->ch_uhid_dev = NULL; + } + } + + return 0; + +} + +void +gcport_si_softintr(void *priv) +{ + struct si_channel *ch = priv; + gcport_si_rescan(ch->ch_gcport_dev, NULL, NULL); +} + int gcport_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { @@ -214,7 +261,7 @@ siioctl_send(struct si_channel *ch, struct si_payload *p) goto si_send_cleanup; } - if ((err = __si_send(sc, &sd)) != 0) { + if ((err = si_send(sc, &sd)) != 0) { goto si_send_cleanup; } diff --git a/sys/arch/evbppc/nintendo/dev/joybus.h b/sys/arch/evbppc/nintendo/dev/joybus.h index cf268a5caa9ee..eaab425bf721e 100644 --- a/sys/arch/evbppc/nintendo/dev/joybus.h +++ b/sys/arch/evbppc/nintendo/dev/joybus.h @@ -30,7 +30,6 @@ #define _JOYBUS_H_ #include -#include "si.h" #define JB_WIRELESS __BIT(15) #define JB_WIRELESS_RECV __BIT(14) diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index 333bc1f0500a0..bc222ecfd9ef5 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -58,8 +58,6 @@ static void si_softintr(void *); static int si_rescan(device_t, const char *, const int *); static int si_print(void *, const char *); -static uint32_t send_cmd(struct si_softc *, uint32_t, unsigned, long); -static int si_identify(struct si_softc *, unsigned); static void si_get_report_desc(void *, void **, int *); static int si_open(void *, void (*)(void *, void *, unsigned), void *); @@ -111,13 +109,15 @@ si_attach(device_t parent, device_t self, void *aux) ch = &sc->sc_chan[chan]; ch->ch_sc = sc; ch->ch_index = chan; + ch->ch_gcport_dev = NULL; + ch->ch_uhid_dev = NULL; mutex_init(&ch->ch_lock, MUTEX_DEFAULT, IPL_VM); cv_init(&ch->ch_cv, "sich"); ch->ch_si = softint_establish(SOFTINT_SERIAL, si_softintr, ch); KASSERT(ch->ch_si != NULL); - si_identify(sc, chan); + ch->ch_id = si_identify(sc, chan); t = &ch->ch_hidev; t->_cookie = &sc->sc_chan[chan]; @@ -194,41 +194,6 @@ si_print(void *aux, const char *pnp) return UNCONF; } - -static uint32_t -send_cmd(struct si_softc *sc, uint32_t cmd, unsigned chan, long us) -{ - struct siio_send data; - uint32_t out[1]; - uint32_t in[1]; - out[0] = cmd; - - data.chan = chan; - data.outsize = 1; - data.insize = 3; - data.in = in; - data.out = out; - data.delay = us; - - __si_send(sc, &data); - return in[0]; -} - -static int -si_identify(struct si_softc *sc, unsigned chan) -{ - struct si_channel *ch; - uint32_t id; - - ch = &sc->sc_chan[chan]; - - send_cmd(sc, CMD_RESET, chan, 1000); - id = send_cmd(sc, CMD_IDENTIFY, chan, 1000); - ch->ch_id = (uint16_t)(id >> 16); - - return 0; -} - static void si_make_report(struct si_softc *sc, unsigned chan, void *report, bool with_rid) { @@ -284,6 +249,8 @@ si_intr(void *priv) struct si_softc *sc = priv; unsigned chan; uint32_t comcsr, sr; + uint32_t inbuf[2]; + unsigned is_gcpad, has_err; int ret = 0; @@ -294,37 +261,37 @@ si_intr(void *priv) WR4(sc, SICOMCSR, comcsr | SICOMCSR_TCINT); } - if (ISSET(comcsr, SICOMCSR_RDSTINT)) { - for (chan = 0; chan < SI_NUM_CHAN; chan++) { - struct si_channel *ch = &sc->sc_chan[chan]; - - if (ISSET(sr, SISR_RDST(chan))) { - /* clears the sisr by reading inbuf */ - (void)RD4(sc, SICINBUFH(ch->ch_index)); - (void)RD4(sc, SICINBUFL(ch->ch_index)); - - if (((sr & SISR_ERROR_MASK(chan)) == 0) && !(IS_GCPAD(ch->ch_id))) { - si_identify(sc, ch->ch_index); - if (IS_GCPAD(ch->ch_id)) { - aprint_normal("CONTROLLER DETECTED!!!\n"); - // TODO - add this stuff back - //si_make_report(sc, chan, ch->ch_buf, false); - //if (ISSET(ch->ch_state, SI_STATE_OPEN)) { - // softint_schedule(ch->ch_si); - //} - } - } else if (((sr & SISR_ERROR_MASK(chan)) != 0) && (IS_GCPAD(ch->ch_id))) { - aprint_normal("CONTROLLER DISCONNECTED\n"); - ch->ch_id = 0; + if (!ISSET(comcsr, SICOMCSR_RDSTINT)) { + goto si_intr_done; + } + + for (chan = 0; chan < SI_NUM_CHAN; chan++) { + struct si_channel *ch = &sc->sc_chan[chan]; + + if (ISSET(sr, SISR_RDST(chan))) { + is_gcpad = IS_GCPAD(ch->ch_id) != 0; + + /* clears the sisr by reading inbuf */ + inbuf[0] = RD4(sc, SICINBUFH(chan)); + inbuf[1] = RD4(sc, SICINBUFL(chan)); + has_err = GCPAD_ERR(inbuf); + + if (is_gcpad) { + si_make_report(sc, chan, ch->ch_buf, false); + if (ISSET(ch->ch_state, SI_STATE_OPEN)) { + softint_schedule(ch->ch_si); } } - ret = 1; + if (!(has_err ^ is_gcpad) && ch->ch_gcport_si != NULL) { + softint_schedule(ch->ch_gcport_si); + } } + ret = 1; } +si_intr_done: WR4(sc, SISR, sr & SISR_ERROR_ACK_ALL); - return ret; } diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 83d1a3b17bef4..0a1fdbe1901ab 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -31,6 +31,8 @@ #include +#include "joybus.h" + #define SI_NUM_CHAN 4 #define SICOUTBUF(n) ((n) * 0xc + 0x00) @@ -71,6 +73,9 @@ #define SIIOBUF_SIZE 128 #define GCPAD_REPORT_SIZE 9 +#define GCPAD_ERRSTAT(_buf) ISSET((_buf)[0], __BIT(31)) +#define GCPAD_ERRLATCH(_buf) ISSET((_buf)[0], __BIT(30)) +#define GCPAD_ERR(_buf) (GCPAD_ERRSTAT(_buf)) || (GCPAD_ERRLATCH(_buf)) #define GCPAD_START(_buf) ISSET((_buf)[0], 0x10) #define GCPAD_Y(_buf) ISSET((_buf)[0], 0x08) #define GCPAD_X(_buf) ISSET((_buf)[0], 0x04) @@ -107,6 +112,8 @@ extern kmutex_t sicomcsr_lock; struct si_channel { struct si_softc *ch_sc; device_t ch_dev; + device_t ch_gcport_dev; + device_t ch_uhid_dev; unsigned ch_index; struct hidev_tag ch_hidev; kmutex_t ch_lock; @@ -122,6 +129,7 @@ struct si_channel { void *ch_desc; int ch_descsize; void *ch_si; + void *ch_gcport_si; }; struct si_softc { @@ -139,9 +147,10 @@ struct si_attach_args { struct gcport_softc { device_t sc_dev; - struct si_channel *ch; bus_space_tag_t sc_bst; bus_space_handle_t sc_bsh; + + struct si_channel *ch; }; struct siio_send { @@ -155,7 +164,7 @@ struct siio_send { }; static inline int -__si_send(struct si_softc *sc, struct siio_send *data) +si_send(struct si_softc *sc, struct siio_send *data) { uint32_t cnt, comcsr, comcsr_prev, sisr, shift_amt, status; unsigned chan; @@ -212,4 +221,23 @@ __si_send(struct si_softc *sc, struct siio_send *data) return 0; } +static inline int +si_identify(struct si_softc *sc, unsigned chan) { + struct siio_send data; + uint32_t out[1]; + uint32_t in[1]; + + out[0] = CMD_IDENTIFY; + + data.chan = chan; + data.outsize = 1; + data.insize = 3; + data.in = in; + data.out = out; + data.delay = 0; + + si_send(sc, &data); + return (uint16_t)(in[0] >> 16); +} + #endif /* _WII_DEV_SI_H_ */ diff --git a/sys/arch/evbppc/nintendo/dev/uhid_si.c b/sys/arch/evbppc/nintendo/dev/uhid_si.c index 795d1f8524fe3..6ceb167aaee5f 100644 --- a/sys/arch/evbppc/nintendo/dev/uhid_si.c +++ b/sys/arch/evbppc/nintendo/dev/uhid_si.c @@ -46,12 +46,13 @@ __KERNEL_RCSID(0, "$NetBSD: uhid_si.c,v 1.1 2026/01/09 22:54:30 jmcneill Exp $") static int uhid_si_match(device_t, cfdata_t, void *); static void uhid_si_attach(device_t, device_t, void *); +static int uhid_si_detach(device_t, int flags); static int uhid_si_ioctl(struct uhid_softc *, u_long, void *, int, struct lwp *); CFATTACH_DECL_NEW(uhid_si, sizeof(struct uhid_softc), - uhid_si_match, uhid_si_attach, NULL, NULL); + uhid_si_match, uhid_si_attach, uhid_si_detach, NULL); static int uhid_si_match(device_t parent, cfdata_t cf, void *aux) @@ -72,12 +73,25 @@ uhid_si_attach(device_t parent, device_t self, void *aux) struct uhid_softc * const sc = device_private(self); struct si_attach_args * const saa = aux; + aprint_normal("INSIDE UHID_SI_ATTACH\n"); sc->sc_dev = self; sc->sc_report_id = saa->saa_index + 1; sc->sc_ioctl = uhid_si_ioctl; sc->sc_hidev = saa->saa_hidev; + aprint_normal("CALLING UHID_ATTACH_COMMON\n"); uhid_attach_common(sc); + aprint_normal("FINISHED UHID_SI_ATTACH\n"); +} + +static int +uhid_si_detach(device_t self, int flags) +{ + aprint_normal("INSIDE UHID_SI_DETACH\n"); + struct uhid_softc * const sc = device_private(self); + int res = uhid_detach_common(sc); + aprint_normal("FINISHED UHID_SI_DETACH\n"); + return res; } static int From a8e0c574160adc88b81f7aeb8179593752de963a Mon Sep 17 00:00:00 2001 From: gummybuns Date: Sat, 6 Jun 2026 14:03:29 -0400 Subject: [PATCH 24/35] got workqueue to work --- sys/arch/evbppc/nintendo/dev/gcport_si.c | 20 ++++++++++++++------ sys/arch/evbppc/nintendo/dev/si.h | 3 +++ sys/arch/evbppc/nintendo/dev/uhid_si.c | 5 ----- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index 32f33af679f62..27cdc547a1390 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -65,6 +65,7 @@ static int gcport_si_print(void *, const char *); static void gcport_si_softintr(void *); static int gcport_si_rescan(device_t, const char *, const int *); static int siioctl_send(struct si_channel *ch, struct si_payload *sp); +static void gcport_si_work(struct work *, void *); dev_type_open(gcport_open); dev_type_close(gcport_close); @@ -101,6 +102,7 @@ gcport_si_attach(device_t parent, device_t self, void *aux) struct si_attach_args * const saa = aux; struct gcport_softc * const sc = device_private(self); struct si_channel *ch = &psc->sc_chan[saa->saa_index]; + int err; sc->sc_dev = self; sc->ch = ch; @@ -110,6 +112,12 @@ gcport_si_attach(device_t parent, device_t self, void *aux) ch->ch_gcport_si = softint_establish(SOFTINT_SERIAL, gcport_si_softintr, ch); + /* TODO - figure out the prio / ipl / flags */ + err = workqueue_create(&ch->ch_wqp, "todo", gcport_si_work, ch, 0, 0, 0); + if (err != 0) { + /* TODO how do i actually handle this type of situation */ + aprint_normal("ch%d failed to create workqueue\n", ch->ch_index); + } gcport_si_rescan(self, NULL, NULL); } @@ -189,18 +197,12 @@ gcport_si_rescan(device_t self, const char *ifattr, const int *locs) ch->ch_id = si_identify(sc, ch->ch_index); is_gcpad = IS_GCPAD(ch->ch_id); - aprint_normal("GCPORT_SI_RESCAN: NEW ID 0x%08X\n", ch->ch_id); - if (is_gcpad && ch->ch_uhid_dev == NULL) { - aprint_normal("GCPORT_SI_RESCAN: WE HAVE CONFIG FOUND EVENT\n"); saa.saa_hidev = &ch->ch_hidev; saa.saa_index = ch->ch_index; - aprint_normal("GCPORT_SI_RESCAN: SET SAA\n"); uhid_dev = config_found(self, &saa, gcport_si_print, CFARGS_NONE); - aprint_normal("GCPORT_SI_RESCAN: FINISHED CONFIG_FOUND\n"); ch->ch_uhid_dev = uhid_dev; } else if (!is_gcpad && ch->ch_uhid_dev != NULL) { - aprint_normal("GCPORT_SI_RESCAN: WE HAVE A DETACH EVENT\n"); res = config_detach_children(ch->ch_gcport_dev, 0); if (res == 0) { ch->ch_uhid_dev = NULL; @@ -215,6 +217,12 @@ void gcport_si_softintr(void *priv) { struct si_channel *ch = priv; + workqueue_enqueue(ch->ch_wqp, &ch->ch_work, NULL); +} + +void gcport_si_work(struct work *wk, void *arg) +{ + struct si_channel *ch = arg; gcport_si_rescan(ch->ch_gcport_dev, NULL, NULL); } diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 0a1fdbe1901ab..805f14a2d4118 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -30,6 +30,7 @@ #define _WII_DEV_SI_H_ #include +#include #include "joybus.h" @@ -130,6 +131,8 @@ struct si_channel { int ch_descsize; void *ch_si; void *ch_gcport_si; + struct workqueue *ch_wqp; + struct work ch_work; }; struct si_softc { diff --git a/sys/arch/evbppc/nintendo/dev/uhid_si.c b/sys/arch/evbppc/nintendo/dev/uhid_si.c index 6ceb167aaee5f..4d0fe4fa03e0f 100644 --- a/sys/arch/evbppc/nintendo/dev/uhid_si.c +++ b/sys/arch/evbppc/nintendo/dev/uhid_si.c @@ -73,24 +73,19 @@ uhid_si_attach(device_t parent, device_t self, void *aux) struct uhid_softc * const sc = device_private(self); struct si_attach_args * const saa = aux; - aprint_normal("INSIDE UHID_SI_ATTACH\n"); sc->sc_dev = self; sc->sc_report_id = saa->saa_index + 1; sc->sc_ioctl = uhid_si_ioctl; sc->sc_hidev = saa->saa_hidev; - aprint_normal("CALLING UHID_ATTACH_COMMON\n"); uhid_attach_common(sc); - aprint_normal("FINISHED UHID_SI_ATTACH\n"); } static int uhid_si_detach(device_t self, int flags) { - aprint_normal("INSIDE UHID_SI_DETACH\n"); struct uhid_softc * const sc = device_private(self); int res = uhid_detach_common(sc); - aprint_normal("FINISHED UHID_SI_DETACH\n"); return res; } From 34a4b1c0530247ceb4f2900bab9452978789603b Mon Sep 17 00:00:00 2001 From: gummybuns Date: Sat, 6 Jun 2026 14:13:28 -0400 Subject: [PATCH 25/35] removed delay from the si_send --- sys/arch/evbppc/nintendo/dev/gcport_si.c | 2 -- sys/arch/evbppc/nintendo/dev/si.c | 5 +++++ sys/arch/evbppc/nintendo/dev/si.h | 7 ------- 3 files changed, 5 insertions(+), 9 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index 27cdc547a1390..f1565c10d2346 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -52,7 +52,6 @@ struct si_payload { uint32_t *status; /* sisr status for this channel */ void *in; /* buffer to store response */ void *out; /* buffer to send out to device */ - long delay; /* delay the transaction (microsec) */ }; extern struct cfdriver gcport_cd; @@ -263,7 +262,6 @@ siioctl_send(struct si_channel *ch, struct si_payload *p) sd.insize = p->insize; sd.out = kmem_alloc(p->outsize, KM_SLEEP); sd.in = kmem_alloc(p->insize, KM_SLEEP); - sd.delay = p->delay; if ((err = copyin(p->out, sd.out, sd.outsize)) != 0) { goto si_send_cleanup; diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index bc222ecfd9ef5..c179546908f84 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -283,6 +283,11 @@ si_intr(void *priv) } } + + /* + * attach event: non-gcpad has no errors + * detach event: gcpad has errors + */ if (!(has_err ^ is_gcpad) && ch->ch_gcport_si != NULL) { softint_schedule(ch->ch_gcport_si); } diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 805f14a2d4118..e0d161d03a741 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -163,7 +163,6 @@ struct siio_send { uint32_t outsize; /* number of bytes for out buffer */ void *in; /* buffer to store response */ void *out; /* buffer to send out to ext device */ - long delay; /* delay the transaction (microsec) */ }; static inline int @@ -186,11 +185,6 @@ si_send(struct si_softc *sc, struct siio_send *data) WR4(sc, SISR, SISR_ERROR_MASK(chan)); sisr = RD4(sc, SISR); - /* - * libogc uses interrupts for non-blocking. i think this is ok for now - */ - delay(data->delay); - AWAIT_SICOMCSR(sc); WR4(sc, SICOMCSR, SICOMCSR_CH_EN | @@ -237,7 +231,6 @@ si_identify(struct si_softc *sc, unsigned chan) { data.insize = 3; data.in = in; data.out = out; - data.delay = 0; si_send(sc, &data); return (uint16_t)(in[0] >> 16); From ecc4b90015b36a4b94e4a9996a49c20ae56ecb8d Mon Sep 17 00:00:00 2001 From: gummybuns Date: Sat, 6 Jun 2026 20:34:56 -0400 Subject: [PATCH 26/35] tried to handle todo --- sys/arch/evbppc/nintendo/dev/gcport_si.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index f1565c10d2346..1f52b150c6aa6 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -111,11 +111,12 @@ gcport_si_attach(device_t parent, device_t self, void *aux) ch->ch_gcport_si = softint_establish(SOFTINT_SERIAL, gcport_si_softintr, ch); - /* TODO - figure out the prio / ipl / flags */ - err = workqueue_create(&ch->ch_wqp, "todo", gcport_si_work, ch, 0, 0, 0); + err = workqueue_create(&ch->ch_wqp, "gcport", gcport_si_work, ch, + PRI_NONE, IPL_NONE, 0); if (err != 0) { - /* TODO how do i actually handle this type of situation */ - aprint_normal("ch%d failed to create workqueue\n", ch->ch_index); + aprint_normal("gcport_si: ch%d failed to create workqueue\n", + ch->ch_index); + ch->ch_wqp = NULL; } gcport_si_rescan(self, NULL, NULL); } @@ -216,7 +217,9 @@ void gcport_si_softintr(void *priv) { struct si_channel *ch = priv; - workqueue_enqueue(ch->ch_wqp, &ch->ch_work, NULL); + if (ch->ch_wqp != NULL) { + workqueue_enqueue(ch->ch_wqp, &ch->ch_work, NULL); + } } void gcport_si_work(struct work *wk, void *arg) From 376f8797f178b6cbf92f0a18b83da799d38b072d Mon Sep 17 00:00:00 2001 From: Zac Brown Date: Sun, 7 Jun 2026 09:44:59 -0400 Subject: [PATCH 27/35] Update sys/arch/evbppc/conf/NINTENDO Co-authored-by: Jared McNeill --- sys/arch/evbppc/conf/NINTENDO | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/sys/arch/evbppc/conf/NINTENDO b/sys/arch/evbppc/conf/NINTENDO index b9e865c922b8e..dd2d6ed8e1436 100644 --- a/sys/arch/evbppc/conf/NINTENDO +++ b/sys/arch/evbppc/conf/NINTENDO @@ -133,7 +133,10 @@ options WSDISPLAY_MULTICONS ahb0 at mainbus0 irq 14 si0 at mainbus0 addr 0x0d006400 irq 3 # Serial interface gcport* at si0 -uhid* at gcport? +uhid0 at gcport0 +uhid1 at gcport1 +uhid2 at gcport2 +uhid3 at gcport3 exi0 at mainbus0 addr 0x0d006800 irq 4 # External interface rtcsram0 at exi0 # RTC/SRAM chip gecko0 at exi0 # USB Gecko From 4ca6ca6b96a7129f292d24e0973aaaa37d575bde Mon Sep 17 00:00:00 2001 From: Zac Brown Date: Sun, 7 Jun 2026 09:56:47 -0400 Subject: [PATCH 28/35] Update sys/arch/evbppc/nintendo/dev/uhid_si.c Co-authored-by: Jared McNeill --- sys/arch/evbppc/nintendo/dev/uhid_si.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/uhid_si.c b/sys/arch/evbppc/nintendo/dev/uhid_si.c index 4d0fe4fa03e0f..0ceecbaffea78 100644 --- a/sys/arch/evbppc/nintendo/dev/uhid_si.c +++ b/sys/arch/evbppc/nintendo/dev/uhid_si.c @@ -60,11 +60,7 @@ uhid_si_match(device_t parent, cfdata_t cf, void *aux) struct gcport_softc * const sc = device_private(parent); struct si_channel *ch = sc->ch; - if (IS_GCPAD(ch->ch_id)) { - return 1; - } - - return 0; + return IS_GCPAD(ch->ch_id); } static void From c5a9209c55477a6e9bc106138c20981cc67ceced Mon Sep 17 00:00:00 2001 From: Zac Brown Date: Sun, 7 Jun 2026 09:57:01 -0400 Subject: [PATCH 29/35] Update sys/arch/evbppc/nintendo/dev/uhid_si.c Co-authored-by: Jared McNeill --- sys/arch/evbppc/nintendo/dev/uhid_si.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/uhid_si.c b/sys/arch/evbppc/nintendo/dev/uhid_si.c index 0ceecbaffea78..b81b75a332a1b 100644 --- a/sys/arch/evbppc/nintendo/dev/uhid_si.c +++ b/sys/arch/evbppc/nintendo/dev/uhid_si.c @@ -81,8 +81,8 @@ static int uhid_si_detach(device_t self, int flags) { struct uhid_softc * const sc = device_private(self); - int res = uhid_detach_common(sc); - return res; + + return uhid_detach_common(sc); } static int From b568099a6463ff96ec9bde5c89d5400519aa6a53 Mon Sep 17 00:00:00 2001 From: gummybuns Date: Sun, 7 Jun 2026 14:43:44 -0400 Subject: [PATCH 30/35] update workqueue_create to use proper args --- sys/arch/evbppc/nintendo/dev/gcport_si.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index 1f52b150c6aa6..340a3e139fa4c 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -112,7 +112,7 @@ gcport_si_attach(device_t parent, device_t self, void *aux) gcport_si_softintr, ch); err = workqueue_create(&ch->ch_wqp, "gcport", gcport_si_work, ch, - PRI_NONE, IPL_NONE, 0); + PRI_NONE, IPL_VM, 0); if (err != 0) { aprint_normal("gcport_si: ch%d failed to create workqueue\n", ch->ch_index); From 1327b6ae4eb9c508e2f19f973bd4f2ca201c8c51 Mon Sep 17 00:00:00 2001 From: gummybuns Date: Sun, 7 Jun 2026 14:46:56 -0400 Subject: [PATCH 31/35] remove the gcport_si softintr --- sys/arch/evbppc/nintendo/dev/gcport_si.c | 12 ------------ sys/arch/evbppc/nintendo/dev/si.c | 5 +++-- sys/arch/evbppc/nintendo/dev/si.h | 1 - 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index 340a3e139fa4c..51694b3cabc59 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -61,7 +61,6 @@ extern struct cfdriver gcport_cd; static int gcport_si_match(device_t, cfdata_t, void *); static void gcport_si_attach(device_t, device_t, void *); static int gcport_si_print(void *, const char *); -static void gcport_si_softintr(void *); static int gcport_si_rescan(device_t, const char *, const int *); static int siioctl_send(struct si_channel *ch, struct si_payload *sp); static void gcport_si_work(struct work *, void *); @@ -108,8 +107,6 @@ gcport_si_attach(device_t parent, device_t self, void *aux) sc->sc_bst = psc->sc_bst; sc->sc_bsh = psc->sc_bsh; ch->ch_gcport_dev = self; - ch->ch_gcport_si = softint_establish(SOFTINT_SERIAL, - gcport_si_softintr, ch); err = workqueue_create(&ch->ch_wqp, "gcport", gcport_si_work, ch, PRI_NONE, IPL_VM, 0); @@ -213,15 +210,6 @@ gcport_si_rescan(device_t self, const char *ifattr, const int *locs) } -void -gcport_si_softintr(void *priv) -{ - struct si_channel *ch = priv; - if (ch->ch_wqp != NULL) { - workqueue_enqueue(ch->ch_wqp, &ch->ch_work, NULL); - } -} - void gcport_si_work(struct work *wk, void *arg) { struct si_channel *ch = arg; diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index c179546908f84..1914993efb545 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -288,8 +288,9 @@ si_intr(void *priv) * attach event: non-gcpad has no errors * detach event: gcpad has errors */ - if (!(has_err ^ is_gcpad) && ch->ch_gcport_si != NULL) { - softint_schedule(ch->ch_gcport_si); + if (!(has_err ^ is_gcpad) && ch->ch_wqp != NULL) { + workqueue_enqueue(ch->ch_wqp, &ch->ch_work, + NULL); } } ret = 1; diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index e0d161d03a741..7de1c0bd1b9f0 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -130,7 +130,6 @@ struct si_channel { void *ch_desc; int ch_descsize; void *ch_si; - void *ch_gcport_si; struct workqueue *ch_wqp; struct work ch_work; }; From d3fd1a6379b7b12baa73d6ad2dd6a5339ef50c9f Mon Sep 17 00:00:00 2001 From: gummybuns Date: Sun, 7 Jun 2026 14:52:34 -0400 Subject: [PATCH 32/35] move send logic to si.c - make the mutex static - add function headers to si.h - move the implementation to si.c --- sys/arch/evbppc/nintendo/dev/si.c | 73 ++++++++++++++++++++++++++++++- sys/arch/evbppc/nintendo/dev/si.h | 73 +------------------------------ 2 files changed, 74 insertions(+), 72 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index 1914993efb545..01affc4397eb3 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -67,7 +67,7 @@ static usbd_status si_set_report(void *, int, void *, int); static usbd_status si_get_report(void *, int, void *, int); static usbd_status si_write(void *, void *, int); -kmutex_t sicomcsr_lock; +static kmutex_t sicomcsr_lock; CFATTACH_DECL_NEW(si, sizeof(struct si_softc), si_match, si_attach, NULL, NULL); @@ -394,3 +394,74 @@ si_write(void *cookie, void *data, int len) { return USBD_INVAL; } + +int +si_send(struct si_softc *sc, struct siio_send *data) +{ + uint32_t cnt, comcsr, comcsr_prev, sisr, shift_amt, status; + unsigned chan; + + mutex_enter(&sicomcsr_lock); + chan = data->chan; + + comcsr_prev = RD4(sc, SICOMCSR); + SIIOBUF_CLEAR(sc); + data->status = 0; + + /* siiobuf must to be written in increments of 4 bytes */ + cnt = ((data->outsize+3)/4); + SIIOBUF_WR(sc, data->out, cnt); + + WR4(sc, SISR, SISR_ERROR_MASK(chan)); + sisr = RD4(sc, SISR); + + AWAIT_SICOMCSR(sc); + WR4(sc, SICOMCSR, + SICOMCSR_CH_EN | + SICOMCSR_CMD_EN | + __SHIFTIN(0, SICOMCSR_TCINTMSK) | + __SHIFTIN(data->outsize, SICOMCSR_OUTLNGTH) | + __SHIFTIN(data->insize, SICOMCSR_INLNGTH) | + __SHIFTIN(chan, SICOMCSR_CHANNEL) | + SICOMCSR_TSTART + ); + AWAIT_SICOMCSR(sc); + + comcsr = RD4(sc, SICOMCSR); + + /* clear TCINT and preserve previous masks otherwise we lose polling */ + WR4(sc, SICOMCSR, comcsr | + SICOMCSR_TCINT | + (comcsr_prev & SICOMCSR_TCINTMSK) | + (comcsr_prev & SICOMCSR_RDSTINTMSK)); + + if (ISSET(comcsr, SICOMCSR_COMERR)) { + sisr = RD4(sc, SISR); + shift_amt = 8 * (SI_NUM_CHAN - 1 - chan); + status = ((sisr & SISR_ERROR_MASK(chan)) >> shift_amt) & 0x3F; + data->status = status; + } + + SIIOBUF_RD(sc, data->in, data->insize); + + mutex_exit(&sicomcsr_lock); + return 0; +} + +int +si_identify(struct si_softc *sc, unsigned chan) { + struct siio_send data; + uint32_t out[1]; + uint32_t in[1]; + + out[0] = CMD_IDENTIFY; + + data.chan = chan; + data.outsize = 1; + data.insize = 3; + data.in = in; + data.out = out; + + si_send(sc, &data); + return (uint16_t)(in[0] >> 16); +} diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 7de1c0bd1b9f0..2fce3b8fab623 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -108,7 +108,6 @@ do { while (RD4(sc, SICOMCSR) & SICOMCSR_TSTART); } while (0) struct si_softc; -extern kmutex_t sicomcsr_lock; struct si_channel { struct si_softc *ch_sc; @@ -164,75 +163,7 @@ struct siio_send { void *out; /* buffer to send out to ext device */ }; -static inline int -si_send(struct si_softc *sc, struct siio_send *data) -{ - uint32_t cnt, comcsr, comcsr_prev, sisr, shift_amt, status; - unsigned chan; - - mutex_enter(&sicomcsr_lock); - chan = data->chan; - - comcsr_prev = RD4(sc, SICOMCSR); - SIIOBUF_CLEAR(sc); - data->status = 0; - - /* siiobuf must to be written in increments of 4 bytes */ - cnt = ((data->outsize+3)/4); - SIIOBUF_WR(sc, data->out, cnt); - - WR4(sc, SISR, SISR_ERROR_MASK(chan)); - sisr = RD4(sc, SISR); - - AWAIT_SICOMCSR(sc); - WR4(sc, SICOMCSR, - SICOMCSR_CH_EN | - SICOMCSR_CMD_EN | - __SHIFTIN(0, SICOMCSR_TCINTMSK) | - __SHIFTIN(data->outsize, SICOMCSR_OUTLNGTH) | - __SHIFTIN(data->insize, SICOMCSR_INLNGTH) | - __SHIFTIN(chan, SICOMCSR_CHANNEL) | - SICOMCSR_TSTART - ); - AWAIT_SICOMCSR(sc); - - comcsr = RD4(sc, SICOMCSR); - - /* clear TCINT and preserve previous masks otherwise we lose polling */ - WR4(sc, SICOMCSR, comcsr | - SICOMCSR_TCINT | - (comcsr_prev & SICOMCSR_TCINTMSK) | - (comcsr_prev & SICOMCSR_RDSTINTMSK)); - - if (ISSET(comcsr, SICOMCSR_COMERR)) { - sisr = RD4(sc, SISR); - shift_amt = 8 * (SI_NUM_CHAN - 1 - chan); - status = ((sisr & SISR_ERROR_MASK(chan)) >> shift_amt) & 0x3F; - data->status = status; - } - - SIIOBUF_RD(sc, data->in, data->insize); - - mutex_exit(&sicomcsr_lock); - return 0; -} - -static inline int -si_identify(struct si_softc *sc, unsigned chan) { - struct siio_send data; - uint32_t out[1]; - uint32_t in[1]; - - out[0] = CMD_IDENTIFY; - - data.chan = chan; - data.outsize = 1; - data.insize = 3; - data.in = in; - data.out = out; - - si_send(sc, &data); - return (uint16_t)(in[0] >> 16); -} +int si_send(struct si_softc *sc, struct siio_send *); +int si_identify(struct si_softc *, unsigned); #endif /* _WII_DEV_SI_H_ */ From d0114a546f3b2e23066048718df76591ec57f81c Mon Sep 17 00:00:00 2001 From: gummybuns Date: Sun, 7 Jun 2026 21:08:57 -0400 Subject: [PATCH 33/35] improve si_send / ioctl - in siioctl_send round up to the nearest 4byte word - use kmem_zalloc so extra data is all zeros - update siio_send to use uint32_t * out/in - fix a bug in SIIOBUF_CLEAR - move validations to si_send --- sys/arch/evbppc/nintendo/dev/gcport_si.c | 17 +++++++++-------- sys/arch/evbppc/nintendo/dev/si.c | 16 ++++++++++++++-- sys/arch/evbppc/nintendo/dev/si.h | 8 ++++---- 3 files changed, 27 insertions(+), 14 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index 51694b3cabc59..ab0cd8ab069a5 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -238,21 +238,22 @@ gcport_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) static int siioctl_send(struct si_channel *ch, struct si_payload *p) { - int err; + int err, outsize_r, insize_r; struct si_softc *sc; struct siio_send sd; err = 0; sc = ch->ch_sc; - if (p->outsize > SIIOBUF_SIZE || p->insize > SIIOBUF_SIZE) { - return EINVAL; - } + /* siiobuf must to be written in increments of 4 bytes */ + outsize_r = roundup(p->outsize, 4); + insize_r = roundup(p->insize, 4); + + sd.out = kmem_zalloc(outsize_r, KM_SLEEP); + sd.in = kmem_zalloc(insize_r, KM_SLEEP); sd.chan = ch->ch_index; sd.outsize = p->outsize; sd.insize = p->insize; - sd.out = kmem_alloc(p->outsize, KM_SLEEP); - sd.in = kmem_alloc(p->insize, KM_SLEEP); if ((err = copyin(p->out, sd.out, sd.outsize)) != 0) { goto si_send_cleanup; @@ -270,7 +271,7 @@ siioctl_send(struct si_channel *ch, struct si_payload *p) goto si_send_cleanup; } si_send_cleanup: - kmem_free(sd.out, sd.outsize); - kmem_free(sd.in, sd.insize); + kmem_free(sd.out, outsize_r); + kmem_free(sd.in, insize_r); return err; } diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index 01affc4397eb3..062d7e3fe3db3 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -401,6 +401,18 @@ si_send(struct si_softc *sc, struct siio_send *data) uint32_t cnt, comcsr, comcsr_prev, sisr, shift_amt, status; unsigned chan; + if (data->chan > 3) { + return EINVAL; + } + + if (data->outsize > SIIOBUF_SIZE || data->insize > SIIOBUF_SIZE) { + return EINVAL; + } + + if (data->out == NULL || data->in == NULL) { + return EINVAL; + } + mutex_enter(&sicomcsr_lock); chan = data->chan; @@ -408,7 +420,7 @@ si_send(struct si_softc *sc, struct siio_send *data) SIIOBUF_CLEAR(sc); data->status = 0; - /* siiobuf must to be written in increments of 4 bytes */ + /* outsize is number of bytes. we need number of words */ cnt = ((data->outsize+3)/4); SIIOBUF_WR(sc, data->out, cnt); @@ -442,7 +454,7 @@ si_send(struct si_softc *sc, struct siio_send *data) data->status = status; } - SIIOBUF_RD(sc, data->in, data->insize); + SIIOBUF_RD(sc, (void *)data->in, data->insize); mutex_exit(&sicomcsr_lock); return 0; diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 2fce3b8fab623..133d97845d84b 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -95,8 +95,8 @@ #define WR4(sc, reg, val) \ bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) #define SIIOBUF_CLEAR(sc) \ - bus_space_set_region_1((sc)->sc_bst, (sc)->sc_bsh, SIIOBUF, 0, \ - SIIOBUF_SIZE) + bus_space_set_region_4((sc)->sc_bst, (sc)->sc_bsh, SIIOBUF, 0, \ + (SIIOBUF_SIZE / 4)) #define SIIOBUF_WR(sc, buf, cnt) \ bus_space_write_region_4((sc)->sc_bst, (sc)->sc_bsh, SIIOBUF, buf, cnt) #define SIIOBUF_RD(sc, buf, cnt) \ @@ -159,8 +159,8 @@ struct siio_send { uint32_t status; /* the sisr result for this channel */ uint32_t insize; /* number of bytes for in buffer */ uint32_t outsize; /* number of bytes for out buffer */ - void *in; /* buffer to store response */ - void *out; /* buffer to send out to ext device */ + uint32_t *in; /* buffer to store response */ + uint32_t *out; /* buffer to send out to ext device */ }; int si_send(struct si_softc *sc, struct siio_send *); From ef00c2e1168768a506d79aafbd24766a9c0774d0 Mon Sep 17 00:00:00 2001 From: gummybuns Date: Sun, 7 Jun 2026 21:18:30 -0400 Subject: [PATCH 34/35] fix si_print --- sys/arch/evbppc/nintendo/dev/si.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index 062d7e3fe3db3..4cf8e5871563e 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -185,11 +185,15 @@ si_print(void *aux, const char *pnp) { struct si_attach_args *saa = aux; + if (pnp != NULL) { + aprint_normal("gcport at %s", pnp); + } + /* * The Wii Operations Manual for RVL-001 refers to the controller * ports as "Nintendo GameCube Controller Sockets". */ - aprint_normal(" socket %d\n", saa->saa_index + 1); + aprint_normal(" socket %d", saa->saa_index + 1); return UNCONF; } From 58d9eaffbaae0a41f862dec1fcac40ae0c366933 Mon Sep 17 00:00:00 2001 From: gummybuns Date: Thu, 11 Jun 2026 22:50:52 -0400 Subject: [PATCH 35/35] did the whole thing again pretty much this time i am trying to do everything async to avoid spinning on TSTART. - ioctl changed to instead manage si_control struct - write begins a transaction - si_send only allows one transaction at a time. marks others as pending. - si_intr handles tcint with a separate workqueue - si_send_complete finishes transaction and runs the next pending - read can read back the response of the transaction still have to implement poll. the other awkward thing is if you ctrl-c out of a program it doesnt clean up the state of the si_control. like if you write but dont do the read. then you cant do the next write.. the reason for that is the read() actually frees up the memory. there is prolly a better way to do things --- sys/arch/evbppc/nintendo/dev/gcport_si.c | 211 ++++++++++++++--------- sys/arch/evbppc/nintendo/dev/si.c | 154 +++++++++++------ sys/arch/evbppc/nintendo/dev/si.h | 44 +++-- sys/arch/evbppc/nintendo/dev/uhid_si.c | 5 +- 4 files changed, 266 insertions(+), 148 deletions(-) diff --git a/sys/arch/evbppc/nintendo/dev/gcport_si.c b/sys/arch/evbppc/nintendo/dev/gcport_si.c index ab0cd8ab069a5..f4391a71072f7 100644 --- a/sys/arch/evbppc/nintendo/dev/gcport_si.c +++ b/sys/arch/evbppc/nintendo/dev/gcport_si.c @@ -46,24 +46,26 @@ __KERNEL_RCSID(0, "$NetBSD: gcport_si.c,v 1.0 2026/05/18 22:53:30 gummybuns Exp #include "si.h" #include "joybus.h" -struct si_payload { - uint32_t insize; /* bytes to receive. max 128 */ - uint32_t outsize; /* bytes to send. max 128 */ - uint32_t *status; /* sisr status for this channel */ - void *in; /* buffer to store response */ - void *out; /* buffer to send out to device */ +struct si_control_payload { + uint32_t insize; + uint32_t outsize; }; extern struct cfdriver gcport_cd; -#define SI_SEND _IOWR(0, 1, struct si_payload) +#define SI_CTRL_GET _IOWR(0, 1, struct si_control) +#define SI_CTRL_SET _IOWR(0, 2, struct si_control_payload) -static int gcport_si_match(device_t, cfdata_t, void *); static void gcport_si_attach(device_t, device_t, void *); +static int gcport_si_match(device_t, cfdata_t, void *); +static int gcport_si_read(dev_t, struct uio *, int); +static int gcport_si_write(dev_t, struct uio *, int); static int gcport_si_print(void *, const char *); -static int gcport_si_rescan(device_t, const char *, const int *); -static int siioctl_send(struct si_channel *ch, struct si_payload *sp); -static void gcport_si_work(struct work *, void *); + +static void gcport_work(struct work *, void *); + +static int siioctl_ctrl_get(struct gcport_softc *, struct si_control *); +static int siioctl_ctrl_set(struct gcport_softc *, struct si_control_payload *); dev_type_open(gcport_open); dev_type_close(gcport_close); @@ -73,8 +75,8 @@ const struct cdevsw gcport_cdevsw = { .d_open = gcport_open, .d_close = gcport_close, .d_ioctl = gcport_ioctl, - .d_read = noread, - .d_write = nowrite, + .d_read = gcport_si_read, + .d_write = gcport_si_write, .d_stop = nostop, .d_tty = notty, .d_poll = nopoll, @@ -100,6 +102,7 @@ gcport_si_attach(device_t parent, device_t self, void *aux) struct si_attach_args * const saa = aux; struct gcport_softc * const sc = device_private(self); struct si_channel *ch = &psc->sc_chan[saa->saa_index]; + struct si_control *ctrl = &sc->ctrl; int err; sc->sc_dev = self; @@ -107,15 +110,19 @@ gcport_si_attach(device_t parent, device_t self, void *aux) sc->sc_bst = psc->sc_bst; sc->sc_bsh = psc->sc_bsh; ch->ch_gcport_dev = self; + ch->ch_gcport_sc = sc; + + ctrl->insize = 0; + ctrl->outsize = 0; + ctrl->status = SI_AVAILABLE; - err = workqueue_create(&ch->ch_wqp, "gcport", gcport_si_work, ch, - PRI_NONE, IPL_VM, 0); + err = workqueue_create(&sc->wqp, "gcport_rdstint", + gcport_work, sc, PRI_NONE, IPL_VM, 0); if (err != 0) { aprint_normal("gcport_si: ch%d failed to create workqueue\n", ch->ch_index); - ch->ch_wqp = NULL; + sc->wqp = NULL; } - gcport_si_rescan(self, NULL, NULL); } static int @@ -180,52 +187,18 @@ gcport_close(dev_t dev, int flags, int mode, struct lwp *l) return 0; } -static int -gcport_si_rescan(device_t self, const char *ifattr, const int *locs) -{ - struct si_attach_args saa; - unsigned is_gcpad; - int res; - device_t uhid_dev; - struct gcport_softc * const gsc = device_private(self); - struct si_channel *ch = gsc->ch; - struct si_softc *sc = ch->ch_sc; - - ch->ch_id = si_identify(sc, ch->ch_index); - is_gcpad = IS_GCPAD(ch->ch_id); - - if (is_gcpad && ch->ch_uhid_dev == NULL) { - saa.saa_hidev = &ch->ch_hidev; - saa.saa_index = ch->ch_index; - uhid_dev = config_found(self, &saa, gcport_si_print, CFARGS_NONE); - ch->ch_uhid_dev = uhid_dev; - } else if (!is_gcpad && ch->ch_uhid_dev != NULL) { - res = config_detach_children(ch->ch_gcport_dev, 0); - if (res == 0) { - ch->ch_uhid_dev = NULL; - } - } - - return 0; - -} - -void gcport_si_work(struct work *wk, void *arg) -{ - struct si_channel *ch = arg; - gcport_si_rescan(ch->ch_gcport_dev, NULL, NULL); -} - int gcport_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) { struct gcport_softc *sc = device_lookup_private(&gcport_cd, minor(dev)); - struct si_channel *ch = sc->ch; int err; switch(cmd) { - case SI_SEND: - err = siioctl_send(ch, (struct si_payload *)data); + case SI_CTRL_GET: + err = siioctl_ctrl_get(sc, (struct si_control *)data); + break; + case SI_CTRL_SET: + err = siioctl_ctrl_set(sc, (struct si_control_payload *)data); break; default: err = EINVAL; @@ -236,42 +209,118 @@ gcport_ioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l) } static int -siioctl_send(struct si_channel *ch, struct si_payload *p) +gcport_si_read(dev_t dev, struct uio *uio, int ioflag) { + struct gcport_softc *sc = device_lookup_private(&gcport_cd, minor(dev)); + struct si_packet *pk = &sc->pk; + struct si_channel *ch = sc->ch; + struct si_control *ctrl = &sc->ctrl; + int err, insize_r, outsize_r; + + + if (ctrl->status != SI_COMPLETE) { + return EBUSY; + } + + outsize_r = roundup(ctrl->outsize, 4); + insize_r = roundup(ctrl->insize, 4); + + err = uiomove(pk->in, ctrl->insize, uio); + kmem_free(pk->out, outsize_r); + kmem_free(pk->in, insize_r); + + mutex_enter(&ch->ch_lock); + ctrl->status = SI_AVAILABLE; + mutex_exit(&ch->ch_lock); + + return err; +} + +static int +gcport_si_write(dev_t dev, struct uio *uio, int ioflag) +{ + struct gcport_softc *sc = device_lookup_private(&gcport_cd, minor(dev)); + struct si_packet *pk = &sc->pk; + struct si_control *ctrl = &sc->ctrl; + struct si_channel *ch = sc->ch; int err, outsize_r, insize_r; - struct si_softc *sc; - struct siio_send sd; - err = 0; - sc = ch->ch_sc; + if (ctrl->status != SI_AVAILABLE) { + return EBUSY; + } /* siiobuf must to be written in increments of 4 bytes */ - outsize_r = roundup(p->outsize, 4); - insize_r = roundup(p->insize, 4); - - sd.out = kmem_zalloc(outsize_r, KM_SLEEP); - sd.in = kmem_zalloc(insize_r, KM_SLEEP); - sd.chan = ch->ch_index; - sd.outsize = p->outsize; - sd.insize = p->insize; + outsize_r = roundup(ctrl->outsize, 4); + insize_r = roundup(ctrl->insize, 4); - if ((err = copyin(p->out, sd.out, sd.outsize)) != 0) { - goto si_send_cleanup; + if (outsize_r > SIIOBUF_SIZE || insize_r > SIIOBUF_SIZE) { + return EINVAL; } - if ((err = si_send(sc, &sd)) != 0) { - goto si_send_cleanup; + mutex_enter(&ch->ch_lock); + pk->out = kmem_zalloc(outsize_r, KM_SLEEP); + pk->in = kmem_zalloc(insize_r, KM_SLEEP); + pk->chan = ch->ch_index; + pk->outsize = ctrl->outsize; + pk->insize = ctrl->insize; + + err = uiomove(pk->out, pk->outsize, uio); + mutex_exit(&ch->ch_lock); + + if (err == 0) { + si_send(ch->ch_sc, pk); } - if ((err = copyout(sd.in, p->in, sd.insize)) != 0) { - goto si_send_cleanup; + return err; +} + +static void +gcport_work(struct work *wk, void *arg) +{ + struct si_attach_args saa; + struct gcport_softc *sc; + struct si_channel *ch; + int res; + + sc = arg; + ch = sc->ch; + + if (ch->ch_uhid_dev == NULL) { + saa.saa_hidev = &ch->ch_hidev; + saa.saa_index = ch->ch_index; + ch->ch_uhid_dev = config_found(sc->sc_dev, &saa, + gcport_si_print, CFARGS_NONE); + } else { + res = config_detach_children(ch->ch_gcport_dev, 0); + if (res == 0) { + ch->ch_uhid_dev = NULL; + } } +} + +static int +siioctl_ctrl_get(struct gcport_softc *sc, struct si_control *ctrl_out) +{ + struct si_control *ctrl = &sc->ctrl; + + ctrl_out->insize = ctrl->insize; + ctrl_out->outsize = ctrl->outsize; + ctrl_out->status = ctrl->status; - if ((err = copyout(&sd.status, p->status, sizeof(uint32_t))) != 0) { - goto si_send_cleanup; + return 0; +} + +static int +siioctl_ctrl_set(struct gcport_softc *sc, struct si_control_payload *p) +{ + struct si_control *ctrl = &sc->ctrl; + + if (ctrl->status != SI_AVAILABLE) { + return EBUSY; } -si_send_cleanup: - kmem_free(sd.out, outsize_r); - kmem_free(sd.in, insize_r); - return err; + + ctrl->insize = p->insize; + ctrl->outsize = p->outsize; + + return 0; } diff --git a/sys/arch/evbppc/nintendo/dev/si.c b/sys/arch/evbppc/nintendo/dev/si.c index 4cf8e5871563e..4fd114bf9d1a6 100644 --- a/sys/arch/evbppc/nintendo/dev/si.c +++ b/sys/arch/evbppc/nintendo/dev/si.c @@ -58,6 +58,7 @@ static void si_softintr(void *); static int si_rescan(device_t, const char *, const int *); static int si_print(void *, const char *); +static void si_send_complete(struct work *, void *); static void si_get_report_desc(void *, void **, int *); static int si_open(void *, void (*)(void *, void *, unsigned), void *); @@ -68,6 +69,7 @@ static usbd_status si_get_report(void *, int, void *, int); static usbd_status si_write(void *, void *, int); static kmutex_t sicomcsr_lock; +static int cur_chan = -1; CFATTACH_DECL_NEW(si, sizeof(struct si_softc), si_match, si_attach, NULL, NULL); @@ -86,6 +88,7 @@ si_attach(device_t parent, device_t self, void *aux) struct mainbus_attach_args * const maa = aux; struct si_softc * const sc = device_private(self); unsigned chan; + int err; void *ih; KASSERT(device_unit(self) == 0); @@ -100,7 +103,15 @@ si_attach(device_t parent, device_t self, void *aux) aprint_error_dev(self, "couldn't map registers\n"); return; } + + mutex_init(&sicomcsr_lock, MUTEX_DEFAULT, IPL_VM); + err = workqueue_create(&sc->wqp, "si_tcint", si_send_complete, + sc, PRI_NONE, IPL_VM, 0); + if (err != 0) { + aprint_normal("si: failed to create workqueue\n"); + sc->wqp = NULL; + } for (chan = 0; chan < SI_NUM_CHAN; chan++) { struct si_channel *ch; @@ -117,8 +128,6 @@ si_attach(device_t parent, device_t self, void *aux) si_softintr, ch); KASSERT(ch->ch_si != NULL); - ch->ch_id = si_identify(sc, chan); - t = &ch->ch_hidev; t->_cookie = &sc->sc_chan[chan]; t->_get_report_desc = si_get_report_desc; @@ -251,10 +260,12 @@ static int si_intr(void *priv) { struct si_softc *sc = priv; + struct gcport_softc *gsc; + struct si_channel *ch; unsigned chan; uint32_t comcsr, sr; uint32_t inbuf[2]; - unsigned is_gcpad, has_err; + unsigned err, uhid; int ret = 0; @@ -262,7 +273,9 @@ si_intr(void *priv) sr = RD4(sc, SISR); if (ISSET(comcsr, SICOMCSR_TCINT)) { - WR4(sc, SICOMCSR, comcsr | SICOMCSR_TCINT); + WR4(sc, SICOMCSR, (comcsr | SICOMCSR_TCINT) & ~SICOMCSR_TSTART); + workqueue_enqueue(sc->wqp, &sc->work, NULL); + ret = 1; } if (!ISSET(comcsr, SICOMCSR_RDSTINT)) { @@ -270,17 +283,18 @@ si_intr(void *priv) } for (chan = 0; chan < SI_NUM_CHAN; chan++) { - struct si_channel *ch = &sc->sc_chan[chan]; + ch = &sc->sc_chan[chan]; + gsc = ch->ch_gcport_sc; + uhid = ch->ch_uhid_dev != NULL; if (ISSET(sr, SISR_RDST(chan))) { - is_gcpad = IS_GCPAD(ch->ch_id) != 0; - /* clears the sisr by reading inbuf */ inbuf[0] = RD4(sc, SICINBUFH(chan)); inbuf[1] = RD4(sc, SICINBUFL(chan)); - has_err = GCPAD_ERR(inbuf); + err = GCPAD_ERR(inbuf); - if (is_gcpad) { + if (uhid) { + aprint_normal("I AM IN RDST UHID!!!!!!\n"); si_make_report(sc, chan, ch->ch_buf, false); if (ISSET(ch->ch_state, SI_STATE_OPEN)) { softint_schedule(ch->ch_si); @@ -289,12 +303,11 @@ si_intr(void *priv) /* - * attach event: non-gcpad has no errors - * detach event: gcpad has errors + * attach event: non-uhid has no errors + * detach event: uhid has errors */ - if (!(has_err ^ is_gcpad) && ch->ch_wqp != NULL) { - workqueue_enqueue(ch->ch_wqp, &ch->ch_work, - NULL); + if ((uhid == err) && gsc->wqp != NULL) { + workqueue_enqueue(gsc->wqp, &gsc->work, NULL); } } ret = 1; @@ -400,9 +413,11 @@ si_write(void *cookie, void *data, int len) } int -si_send(struct si_softc *sc, struct siio_send *data) +si_send(struct si_softc *sc, struct si_packet *data) { - uint32_t cnt, comcsr, comcsr_prev, sisr, shift_amt, status; + struct gcport_softc *gsc; + struct si_channel *ch; + uint32_t cnt; unsigned chan; if (data->chan > 3) { @@ -420,7 +435,26 @@ si_send(struct si_softc *sc, struct siio_send *data) mutex_enter(&sicomcsr_lock); chan = data->chan; - comcsr_prev = RD4(sc, SICOMCSR); + if (cur_chan != -1) { + aprint_normal("SI_SEND: ALREADY A TRANSACTION IN FLIGHT\n"); + ch = &sc->sc_chan[chan]; + mutex_enter(&ch->ch_lock); + gsc = ch->ch_gcport_sc; + (&gsc->ctrl)->status = SI_PENDING; + mutex_exit(&ch->ch_lock); + mutex_exit(&sicomcsr_lock); + return EBUSY; + } + + cur_chan = chan; + ch = &sc->sc_chan[cur_chan]; + + mutex_enter(&ch->ch_lock); + + gsc = ch->ch_gcport_sc; + (&gsc->ctrl)->status = SI_ACTIVE; + mutex_exit(&ch->ch_lock); + SIIOBUF_CLEAR(sc); data->status = 0; @@ -429,55 +463,73 @@ si_send(struct si_softc *sc, struct siio_send *data) SIIOBUF_WR(sc, data->out, cnt); WR4(sc, SISR, SISR_ERROR_MASK(chan)); - sisr = RD4(sc, SISR); - AWAIT_SICOMCSR(sc); WR4(sc, SICOMCSR, SICOMCSR_CH_EN | SICOMCSR_CMD_EN | - __SHIFTIN(0, SICOMCSR_TCINTMSK) | + SICOMCSR_TCINTMSK | + SICOMCSR_RDSTINTMSK | __SHIFTIN(data->outsize, SICOMCSR_OUTLNGTH) | __SHIFTIN(data->insize, SICOMCSR_INLNGTH) | __SHIFTIN(chan, SICOMCSR_CHANNEL) | SICOMCSR_TSTART ); - AWAIT_SICOMCSR(sc); - - comcsr = RD4(sc, SICOMCSR); - - /* clear TCINT and preserve previous masks otherwise we lose polling */ - WR4(sc, SICOMCSR, comcsr | - SICOMCSR_TCINT | - (comcsr_prev & SICOMCSR_TCINTMSK) | - (comcsr_prev & SICOMCSR_RDSTINTMSK)); - - if (ISSET(comcsr, SICOMCSR_COMERR)) { - sisr = RD4(sc, SISR); - shift_amt = 8 * (SI_NUM_CHAN - 1 - chan); - status = ((sisr & SISR_ERROR_MASK(chan)) >> shift_amt) & 0x3F; - data->status = status; - } - - SIIOBUF_RD(sc, (void *)data->in, data->insize); mutex_exit(&sicomcsr_lock); return 0; } -int -si_identify(struct si_softc *sc, unsigned chan) { - struct siio_send data; - uint32_t out[1]; - uint32_t in[1]; +static void +si_send_complete(struct work *, void *arg) +{ + struct si_softc *sc; + struct si_channel *ch; + struct gcport_softc *gsc; + struct si_packet *pk; + struct si_control *ctrl; + int i, prev_chan, status; + + sc = arg; + + mutex_enter(&sicomcsr_lock); + prev_chan = cur_chan; - out[0] = CMD_IDENTIFY; + if (prev_chan < 0) { + aprint_normal("CUR_CHAN IS ALREADY -1. EXIT\n"); + mutex_exit(&sicomcsr_lock); + return; + } - data.chan = chan; - data.outsize = 1; - data.insize = 3; - data.in = in; - data.out = out; + ch = &sc->sc_chan[prev_chan]; + + /* complete the transaction */ + mutex_enter(&ch->ch_lock); + gsc = ch->ch_gcport_sc; + pk = &gsc->pk; + ctrl = &gsc->ctrl; + SIIOBUF_RD(sc, (void *)pk->in, pk->insize); + ctrl->status = SI_COMPLETE; + cur_chan = -1; + mutex_exit(&ch->ch_lock); + mutex_exit(&sicomcsr_lock); + + /* find the next pending command */ + i = prev_chan % 5; + do { + ch = &sc->sc_chan[i]; + gsc = ch->ch_gcport_sc; + + mutex_enter(&ch->ch_lock); + ctrl = &gsc->ctrl; + pk = &gsc->pk; + status = ctrl->status; + mutex_exit(&ch->ch_lock); + + if (status == SI_READY) { + si_send(sc, pk); + return; + } - si_send(sc, &data); - return (uint16_t)(in[0] >> 16); + i = (i + 1) % 5; + } while (i != prev_chan); } diff --git a/sys/arch/evbppc/nintendo/dev/si.h b/sys/arch/evbppc/nintendo/dev/si.h index 133d97845d84b..dbffb09da30da 100644 --- a/sys/arch/evbppc/nintendo/dev/si.h +++ b/sys/arch/evbppc/nintendo/dev/si.h @@ -107,10 +107,19 @@ #define AWAIT_SICOMCSR(sc) \ do { while (RD4(sc, SICOMCSR) & SICOMCSR_TSTART); } while (0) + +#define SI_AVAILABLE 0 /* can perform a transaction */ +#define SI_READY 1 /* transaction is ready to be sent */ +#define SI_PENDING 2 /* another transaction in progress. wait */ +#define SI_ACTIVE 3 /* transaction is in flight */ +#define SI_COMPLETE 4 /* transaction compelted */ + struct si_softc; +struct si_packet; struct si_channel { struct si_softc *ch_sc; + struct gcport_softc *ch_gcport_sc; device_t ch_dev; device_t ch_gcport_dev; device_t ch_uhid_dev; @@ -129,8 +138,6 @@ struct si_channel { void *ch_desc; int ch_descsize; void *ch_si; - struct workqueue *ch_wqp; - struct work ch_work; }; struct si_softc { @@ -139,6 +146,8 @@ struct si_softc { bus_space_handle_t sc_bsh; struct si_channel sc_chan[SI_NUM_CHAN]; + struct workqueue *wqp; + struct work work; }; struct si_attach_args { @@ -146,16 +155,14 @@ struct si_attach_args { int saa_index; }; -struct gcport_softc { - device_t sc_dev; - bus_space_tag_t sc_bst; - bus_space_handle_t sc_bsh; - - struct si_channel *ch; +struct si_control { + uint32_t insize; + uint32_t outsize; + unsigned status; }; -struct siio_send { - unsigned chan; /* which controller port */ +struct si_packet { + unsigned chan; /* the channel to send on */ uint32_t status; /* the sisr result for this channel */ uint32_t insize; /* number of bytes for in buffer */ uint32_t outsize; /* number of bytes for out buffer */ @@ -163,7 +170,20 @@ struct siio_send { uint32_t *out; /* buffer to send out to ext device */ }; -int si_send(struct si_softc *sc, struct siio_send *); -int si_identify(struct si_softc *, unsigned); +struct gcport_softc { + device_t sc_dev; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + + struct workqueue *wqp; + struct work work; + + struct si_packet pk; + struct si_control ctrl; + struct si_channel *ch; +}; + + +int si_send(struct si_softc *sc, struct si_packet *); #endif /* _WII_DEV_SI_H_ */ diff --git a/sys/arch/evbppc/nintendo/dev/uhid_si.c b/sys/arch/evbppc/nintendo/dev/uhid_si.c index b81b75a332a1b..9fe3128e0b708 100644 --- a/sys/arch/evbppc/nintendo/dev/uhid_si.c +++ b/sys/arch/evbppc/nintendo/dev/uhid_si.c @@ -57,10 +57,7 @@ CFATTACH_DECL_NEW(uhid_si, sizeof(struct uhid_softc), static int uhid_si_match(device_t parent, cfdata_t cf, void *aux) { - struct gcport_softc * const sc = device_private(parent); - struct si_channel *ch = sc->ch; - - return IS_GCPAD(ch->ch_id); + return 1; } static void