mirror of
https://github.com/gdsports/USBHost_t36
synced 2024-11-21 16:45:04 -05:00
Add error recovery for async schedule errors & halted pipes
This commit is contained in:
parent
50016717b3
commit
e345c0360d
@ -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) {
|
||||
|
94
ehci.cpp
94
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
|
||||
|
Loading…
Reference in New Issue
Block a user