diff --git a/USBHost_t36.h b/USBHost_t36.h index 0b4bae6..38169a0 100644 --- a/USBHost_t36.h +++ b/USBHost_t36.h @@ -237,6 +237,8 @@ private: static bool allocate_interrupt_pipe_bandwidth(Pipe_t *pipe, uint32_t maxlen, uint32_t interval); static void add_qh_to_periodic_schedule(Pipe_t *pipe); + static bool followup_Transfer(Transfer_t *transfer); + static void followup_Error(void); protected: #ifdef USBHOST_PRINT_DEBUG static void print(const Transfer_t *transfer); @@ -259,21 +261,21 @@ protected: static void println() { Serial.println(); } static void print(uint32_t n, uint8_t b) { Serial.print(n, b); } static void println(uint32_t n, uint8_t b) { Serial.println(n, b); } - static void println(const char *s, int n) { - Serial.print(s); Serial.println(n); } - static void println(const char *s, unsigned int n) { - Serial.print(s); Serial.println(n); } - static void println(const char *s, long n) { - Serial.print(s); Serial.println(n); } - static void println(const char *s, unsigned long n) { - Serial.print(s); Serial.println(n); } - static void println(const char *s, int n, uint8_t b) { + static void print(const char *s, int n, uint8_t b = DEC) { + Serial.print(s); Serial.print(n, b); } + static void print(const char *s, unsigned int n, uint8_t b = DEC) { + Serial.print(s); Serial.print(n, b); } + static void print(const char *s, long n, uint8_t b = DEC) { + Serial.print(s); Serial.print(n, b); } + static void print(const char *s, unsigned long n, uint8_t b = DEC) { + Serial.print(s); Serial.print(n, b); } + static void println(const char *s, int n, uint8_t b = DEC) { Serial.print(s); Serial.println(n, b); } - static void println(const char *s, unsigned int n, uint8_t b) { + static void println(const char *s, unsigned int n, uint8_t b = DEC) { Serial.print(s); Serial.println(n, b); } - static void println(const char *s, long n, uint8_t b) { + static void println(const char *s, long n, uint8_t b = DEC) { Serial.print(s); Serial.println(n, b); } - static void println(const char *s, unsigned long n, uint8_t b) { + static void println(const char *s, unsigned long n, uint8_t b = DEC) { Serial.print(s); Serial.println(n, b); } #else static void print(const Transfer_t *transfer) {} @@ -296,14 +298,14 @@ protected: static void println() {} static void print(uint32_t n, uint8_t b) {} static void println(uint32_t n, uint8_t b) {} - static void println(const char *s, int n) {} - static void println(const char *s, unsigned int n) {} - static void println(const char *s, long n) {} - static void println(const char *s, unsigned long n) {} - static void println(const char *s, int n, uint8_t b) {} - static void println(const char *s, unsigned int n, uint8_t b) {} - static void println(const char *s, long n, uint8_t b) {} - static void println(const char *s, unsigned long n, uint8_t b) {} + static void print(const char *s, int n, uint8_t b = DEC) {} + static void print(const char *s, unsigned int n, uint8_t b = DEC) {} + static void print(const char *s, long n, uint8_t b = DEC) {} + static void print(const char *s, unsigned long n, uint8_t b = DEC) {} + static void println(const char *s, int n, uint8_t b = DEC) {} + static void println(const char *s, unsigned int n, uint8_t b = DEC) {} + static void println(const char *s, long n, uint8_t b = DEC) {} + static void println(const char *s, unsigned long n, uint8_t b = DEC) {} #endif static void mk_setup(setup_t &s, uint32_t bmRequestType, uint32_t bRequest, uint32_t wValue, uint32_t wIndex, uint32_t wLength) { diff --git a/ehci.cpp b/ehci.cpp index 7e04639..2e69bae 100644 --- a/ehci.cpp +++ b/ehci.cpp @@ -92,7 +92,6 @@ static USBDriverTimer *active_timers=NULL; static void init_qTD(volatile Transfer_t *t, void *buf, uint32_t len, uint32_t pid, uint32_t data01, bool irq); -static bool followup_Transfer(Transfer_t *transfer); static void add_to_async_followup_list(Transfer_t *first, Transfer_t *last); static void remove_from_async_followup_list(Transfer_t *transfer); static void add_to_periodic_followup_list(Transfer_t *first, Transfer_t *last); @@ -305,6 +304,9 @@ void USBHost::isr() } } } + if (stat & USBHS_USBSTS_UEI) { + followup_Error(); + } if (stat & USBHS_USBSTS_PCI) { // port change detected const uint32_t portstat = USBHS_PORTSC1; @@ -753,9 +755,10 @@ bool USBHost::queue_Transfer(Pipe_t *pipe, Transfer_t *transfer) return true; } -static bool followup_Transfer(Transfer_t *transfer) +bool USBHost::followup_Transfer(Transfer_t *transfer) { - //println(" Followup ", (uint32_t)transfer, HEX); + print(" Followup ", (uint32_t)transfer, HEX); + println(" token=", transfer->qtd.token, HEX); if (!(transfer->qtd.token & 0x80)) { // TODO: check error status @@ -773,6 +776,91 @@ static bool followup_Transfer(Transfer_t *transfer) return false; } +void USBHost::followup_Error(void) +{ + println("ERROR Followup"); + Transfer_t *p = async_followup_first; + while (p) { + if (followup_Transfer(p)) { + // transfer completed + Transfer_t *next = p->next_followup; + remove_from_async_followup_list(p); + println(" remove from followup list"); + if (p->qtd.token & 0x40) { + Pipe_t *haltedpipe = p->pipe; + free_Transfer(p); + // traverse the rest of the list for unfinished work + // from this halted pipe. Remove from the followup + // list and put onto our own temporary list + Transfer_t *first = NULL; + Transfer_t *last = NULL; + p = next; + while (p) { + Transfer_t *next2 = p->next_followup; + if (p->pipe == haltedpipe) { + println(" stray halted ", (uint32_t)p, HEX); + remove_from_async_followup_list(p); + if (first == NULL) { + first = p; + last = p; + } else { + last->next_followup = p; + } + p->next_followup = NULL; + if (next == p) next = next2; + } + p = next2; + } + // halted pipe (probably) still has unfinished transfers + // find the halted pipe's dummy halt transfer + p = (Transfer_t *)(haltedpipe->qh.next & ~0x1F); + while (p && ((p->qtd.token & 0x40) == 0)) { + print(" qtd: ", (uint32_t)p, HEX); + print(", token=", (uint32_t)p->qtd.token, HEX); + println(", next=", (uint32_t)p->qtd.next, HEX); + p = (Transfer_t *)(p->qtd.next & ~0x1F); + } + if (p) { + // unhalt the pipe, "forget" unfinished transfers + // hopefully they're all on the list we made! + println(" dummy halt: ", (uint32_t)p, HEX); + haltedpipe->qh.next = (uint32_t)p; + haltedpipe->qh.current = 0; + haltedpipe->qh.token = 0; + } else { + println(" no dummy halt found, yikes!"); + // TODO: this should never happen, but what if it does? + } + + // Do any driver callbacks belonging to the unfinished + // transfers. This is done last, after retoring the + // pipe to a working state (if possible) so the driver + // callback can use the pipe. + p = first; + while (p) { + uint32_t token = p->qtd.token; + if (token & 0x8000 && haltedpipe->callback_function) { + // driver expects a callback + p->qtd.token = token | 0x40; + (*(p->pipe->callback_function))(p); + } + Transfer_t *next2 = p->next_followup; + free_Transfer(p); + p = next2; + } + } else { + free_Transfer(p); + } + p = next; + } else { + // transfer still pending + println(" remain on followup list"); + p = p->next_followup; + } + } + // TODO: handle errors from periodic schedule! +} + static void add_to_async_followup_list(Transfer_t *first, Transfer_t *last) { last->next_followup = NULL; // always add to end of list