@@ -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) { |
@@ -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 |