diff --git a/include/gint/drivers/states.h b/include/gint/drivers/states.h index ff7d827..018c46a 100644 --- a/include/gint/drivers/states.h +++ b/include/gint/drivers/states.h @@ -13,6 +13,7 @@ extern "C" { #endif +#include #include #include @@ -88,13 +89,23 @@ typedef struct { typedef struct { /* Control and power-up. We don't save power-related registers from other modules nor UPONCR, because they must be changed to use the module */ - uint16_t SYSCFG, DVSTCTR, TESTMODE, REG_C2; - /* FIFO configuration */ - uint16_t CFIFOSEL, D0FIFOSEL, D1FIFOSEL; + uint16_t SYSCFG, BUSWAIT, DVSTCTR, SOFCFG, TESTMODE, REG_C2; /* Interrupt configuration */ - uint16_t INTENB0, BRDYENB, NRDYENB, BEMPENB, SOFCFG; - /* Default Control Pipe (maybe not needed) */ - uint16_t DCPCFG, DCPMAXP, DCPCTR; + uint16_t INTENB0, INTENB1, BRDYENB, NRDYENB, BEMPENB; + /* Default Control Pipe */ + uint16_t DCPMAXP; + +#ifdef GINT_USB_DEBUG + /* Registers tracked read-only for state analysis and debugging */ + uint16_t SYSSTS, FRMNUM, UFRMNUM; + uint16_t CFIFOSEL, D0FIFOSEL, D1FIFOSEL, CFIFOCTR, D0FIFOCTR, D1FIFOCTR; + uint16_t INTSTS0, INTSTS1, BRDYSTS, NRDYSTS, BEMPSTS; + uint16_t DCPCFG, DCPCTR; + uint16_t USBADDR, USBREQ, USBVAL, USBINDX, USBLENG; + uint16_t PIPESEL, PIPECFG[9], PIPEnCTR[9], PIPEBUF[9]; + /* Ignored: UPONCR, PIPEnMAXP, PIPEnPERI, PIPEnTRN, PIPEnTRE, DEVADDn */ +#endif + } usb_state_t; #ifdef __cplusplus diff --git a/src/usb/configure.c b/src/usb/configure.c index 38cf14f..deba0e0 100644 --- a/src/usb/configure.c +++ b/src/usb/configure.c @@ -208,15 +208,6 @@ void usb_configure(void) } } -void usb_configure_clear_pipes(void) -{ - for(int i = 0; i < 32; i++) - { - if(!conf_ep[i].intf) continue; - usb_pipe_clear(conf_ep[i].pipe); - } -} - usb_interface_t const * const *usb_configure_interfaces(void) { return conf_if; diff --git a/src/usb/pipes.c b/src/usb/pipes.c index 433acd7..02ab5cf 100644 --- a/src/usb/pipes.c +++ b/src/usb/pipes.c @@ -58,7 +58,15 @@ void usb_pipe_configure(int address, endpoint_t const *ep) void usb_pipe_clear(int pipe) { - if(pipe <= 0 || pipe > 9) return; + if(pipe < 0 || pipe > 9) return; + + if(pipe == 0) { + USB.DCPCTR.PID = PID_NAK; + usb_while(USB.DCPCTR.PBUSY); + + USB.DCPCTR.SQCLR = 1; + usb_while(USB.DCPCTR.SQMON != 0); + } /* Set PID=NAK then use ACLRM to clear the pipe */ USB.PIPECTR[pipe-1].PID = PID_NAK; @@ -74,6 +82,24 @@ void usb_pipe_clear(int pipe) usb_while(USB.PIPECTR[pipe-1].SQMON != 0); } +void usb_pipe_reset(int pipe) +{ + if(pipe < 0 || pipe > 9) return; + usb_pipe_clear(pipe); + + if(pipe == 0) { + USB.DCPCFG.word = 0x0000; + USB.DCPCTR.word = 0x0000; + USB.DCPMAXP.word = 0x0000; + return; + } + + USB.PIPESEL.PIPESEL = pipe; + USB.PIPECFG.word = 0x0000; + USB.PIPECTR[pipe-1].word = 0x0000; + USB.PIPEBUF.word = 0x0000; +} + //--- // Operation on FIFO controllers //--- @@ -161,6 +187,13 @@ static void fifo_unbind(fifo_t ct) } } +void usb_pipe_reset_fifos(void) +{ + fifo_unbind(CF); + fifo_unbind(D0F); + fifo_unbind(D1F); +} + //--- // Writing operations //--- diff --git a/src/usb/usb.c b/src/usb/usb.c index c0e7228..f2461bc 100644 --- a/src/usb/usb.c +++ b/src/usb/usb.c @@ -176,6 +176,11 @@ int usb_open(usb_interface_t const **interfaces, gint_call_t callback) USB.SYSCFG.USBE = 1; } + usb_pipe_reset_fifos(); + for(int i = 0; i <= 9; i++) + usb_pipe_reset(i); + usb_pipe_init_transfers(); + /* Prepare the default control pipe. */ USB.DCPCFG.DIR = 0; USB.DCPMAXP.DEVSEL = 0; @@ -187,18 +192,10 @@ int usb_open(usb_interface_t const **interfaces, gint_call_t callback) USB.CFIFOSEL.RCNT = 0; USB.CFIFOSEL.REW = 0; USB.CFIFOSEL.BIGEND = 1; - /* Clear D0FIFOSEL and D1FIFOSEL so that pipes can be configured */ - USB.D0FIFOSEL.word = 0x0000; - USB.D1FIFOSEL.word = 0x0000; - - /* Configure other pipes to use activated interfaces */ - usb_configure(); - usb_configure_clear_pipes(); - /* Initialize transfer tracker for multi-part transfers */ - usb_pipe_init_transfers(); /* VBSE=1 RSME=0 SOFE=0 DVSE=1 CTRE=1 BEMPE=1 NRDYE=0 BRDYE=0 */ USB.INTENB0.word = 0x9c00; + USB.INTENB1.word = 0x0000; USB.BRDYENB = 0x0000; USB.NRDYENB = 0x0000; USB.BEMPENB = 0x0000; @@ -271,7 +268,8 @@ static void usb_interrupt_handler(void) /* When configured, run the callback for usb_open() */ if(USB.INTSTS0.DVSQ == 3) { - usb_configure_clear_pipes(); + usb_configure(); + usb_open_status = true; gint_call(usb_open_callback); usb_open_callback = GINT_CALL_NULL; @@ -301,24 +299,61 @@ static void usb_interrupt_handler(void) void hsave(usb_state_t *s) { s->SYSCFG = USB.SYSCFG.word; + s->BUSWAIT = USB.BUSWAIT.word; + s->DVSTCTR = USB.DVSTCTR.word; + s->SOFCFG = USB.SOFCFG.word; s->TESTMODE = USB.TESTMODE.word; s->REG_C2 = USB.REG_C2; + s->INTENB0 = USB.INTENB0.word; + s->INTENB1 = USB.INTENB1.word; + s->BRDYENB = USB.BRDYENB; + s->NRDYENB = USB.NRDYENB; + s->BEMPENB = USB.BEMPENB; + + s->DCPMAXP = USB.DCPMAXP.word; + +#ifdef GINT_USB_DEBUG + /* Save some other state for inspection only. Since we need to write to + PIPESEL in order to read PIPECFG etc, enable writing. */ + hpoweron_write(); + + s->SYSSTS = USB.SYSSTS.word; + s->FRMNUM = USB.FRMNUM.word; + s->UFRMNUM = USB.UFRMNUM.word; + s->CFIFOSEL = USB.CFIFOSEL.word; s->D0FIFOSEL = USB.D0FIFOSEL.word; s->D1FIFOSEL = USB.D1FIFOSEL.word; + s->CFIFOCTR = USB.CFIFOCTR.word; + s->D0FIFOCTR = USB.D0FIFOCTR.word; + s->D1FIFOCTR = USB.D1FIFOCTR.word; - s->INTENB0 = USB.INTENB0.word; - s->BRDYENB = USB.BRDYENB; - s->NRDYENB = USB.NRDYENB; - s->BEMPENB = USB.BEMPENB; - s->SOFCFG = USB.SOFCFG.word; + s->INTSTS0 = USB.INTSTS0.word; + s->INTSTS1 = USB.INTSTS1.word; + s->BRDYSTS = USB.BRDYSTS; + s->NRDYSTS = USB.NRDYSTS; + s->BEMPSTS = USB.BEMPSTS; s->DCPCFG = USB.DCPCFG.word; - s->DCPMAXP = USB.DCPMAXP.word; s->DCPCTR = USB.DCPCTR.word; + s->USBADDR = USB.USBADDR.word; + s->USBREQ = USB.USBREQ.word; + s->USBVAL = USB.USBVAL.word; + s->USBINDX = USB.USBINDX.word; + s->USBLENG = USB.USBLENG.word; + + s->PIPESEL = USB.PIPESEL.word; + for(int i = 0; i < 9; i++) { + USB.PIPESEL.PIPESEL = i+1; + s->PIPECFG[i] = USB.PIPECFG.word; + s->PIPEnCTR[i] = USB.PIPECTR[i].word; + s->PIPEBUF[i] = USB.PIPEBUF.word; + } +#endif + /* Leave the module open for gint to use it, or for the next restore to proceed more quickly (if during a world switch) */ } @@ -331,30 +366,33 @@ static void hrestore(usb_state_t const *s) usb_open_status = false; USB.DVSTCTR.word = s->DVSTCTR; + USB.SOFCFG.word = s->SOFCFG; USB.TESTMODE.word = s->TESTMODE; + USB.FRMNUM.word = 0; USB.REG_C2 = s->REG_C2; - USB.CFIFOSEL.word = s->CFIFOSEL; - USB.D0FIFOSEL.word = s->D0FIFOSEL; - USB.D1FIFOSEL.word = s->D1FIFOSEL; - USB.INTENB0.word = s->INTENB0; + USB.INTENB1.word = s->INTENB1; USB.BRDYENB = s->BRDYENB; USB.NRDYENB = s->NRDYENB; USB.BEMPENB = s->BEMPENB; - USB.SOFCFG.word = s->SOFCFG; - USB.DCPCFG.word = s->DCPCFG; + usb_pipe_reset_fifos(); + for(int i = 0; i <= 9; i++) + usb_pipe_reset(i); + USB.DCPMAXP.word = s->DCPMAXP; - USB.DCPCTR.word = s->DCPCTR; + USB.PIPESEL.word = 0x0000; /* Clear remaining interrupts. Read-only bits will be ignored */ - USB.INTSTS0.word = 0; - USB.BRDYSTS = 0; - USB.NRDYSTS = 0; - USB.BEMPSTS = 0; + USB.INTSTS0.word = 0x0000; + USB.INTSTS1.word = 0x0000; + USB.BRDYSTS = 0x0000; + USB.NRDYSTS = 0x0000; + USB.BEMPSTS = 0x0000; /* Restore SYSCFG last as clearing SCKE disables writing */ + USB.BUSWAIT.word = s->BUSWAIT; USB.SYSCFG.word = s->SYSCFG; } diff --git a/src/usb/usb_private.h b/src/usb/usb_private.h index 592858b..02ed9fc 100644 --- a/src/usb/usb_private.h +++ b/src/usb/usb_private.h @@ -126,6 +126,12 @@ void usb_pipe_configure(int address, endpoint_t const *ep); /* usb_pipe_clear(): Clear all data in the pipe */ void usb_pipe_clear(int pipe); +/* usb_pipe_reset(): Clear all data in pipe and reset it to a blank state */ +void usb_pipe_reset(int pipe); + +/* usb_pipe_reset_fifos(): Unbind all FIFOs from pipes */ +void usb_pipe_reset_fifos(void); + /* usb_pipe_write_bemp(): Callback for the BEMP interrupt on a pipe */ void usb_pipe_write_bemp(int pipe);