mirror of
https://github.com/gdsports/USBHost_t36
synced 2025-02-16 06:50:14 -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,
|
static bool allocate_interrupt_pipe_bandwidth(Pipe_t *pipe,
|
||||||
uint32_t maxlen, uint32_t interval);
|
uint32_t maxlen, uint32_t interval);
|
||||||
static void add_qh_to_periodic_schedule(Pipe_t *pipe);
|
static void add_qh_to_periodic_schedule(Pipe_t *pipe);
|
||||||
|
static bool followup_Transfer(Transfer_t *transfer);
|
||||||
|
static void followup_Error(void);
|
||||||
protected:
|
protected:
|
||||||
#ifdef USBHOST_PRINT_DEBUG
|
#ifdef USBHOST_PRINT_DEBUG
|
||||||
static void print(const Transfer_t *transfer);
|
static void print(const Transfer_t *transfer);
|
||||||
@ -259,21 +261,21 @@ protected:
|
|||||||
static void println() { Serial.println(); }
|
static void println() { Serial.println(); }
|
||||||
static void print(uint32_t n, uint8_t b) { Serial.print(n, b); }
|
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(uint32_t n, uint8_t b) { Serial.println(n, b); }
|
||||||
static void println(const char *s, int n) {
|
static void print(const char *s, int n, uint8_t b = DEC) {
|
||||||
Serial.print(s); Serial.println(n); }
|
Serial.print(s); Serial.print(n, b); }
|
||||||
static void println(const char *s, unsigned int n) {
|
static void print(const char *s, unsigned int n, uint8_t b = DEC) {
|
||||||
Serial.print(s); Serial.println(n); }
|
Serial.print(s); Serial.print(n, b); }
|
||||||
static void println(const char *s, long n) {
|
static void print(const char *s, long n, uint8_t b = DEC) {
|
||||||
Serial.print(s); Serial.println(n); }
|
Serial.print(s); Serial.print(n, b); }
|
||||||
static void println(const char *s, unsigned long n) {
|
static void print(const char *s, unsigned long n, uint8_t b = DEC) {
|
||||||
Serial.print(s); Serial.println(n); }
|
Serial.print(s); Serial.print(n, b); }
|
||||||
static void println(const char *s, int n, uint8_t b) {
|
static void println(const char *s, int n, uint8_t b = DEC) {
|
||||||
Serial.print(s); Serial.println(n, b); }
|
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); }
|
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); }
|
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); }
|
Serial.print(s); Serial.println(n, b); }
|
||||||
#else
|
#else
|
||||||
static void print(const Transfer_t *transfer) {}
|
static void print(const Transfer_t *transfer) {}
|
||||||
@ -296,14 +298,14 @@ protected:
|
|||||||
static void println() {}
|
static void println() {}
|
||||||
static void print(uint32_t n, uint8_t b) {}
|
static void print(uint32_t n, uint8_t b) {}
|
||||||
static void println(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 print(const char *s, int n, uint8_t b = DEC) {}
|
||||||
static void println(const char *s, unsigned int n) {}
|
static void print(const char *s, unsigned int n, uint8_t b = DEC) {}
|
||||||
static void println(const char *s, long n) {}
|
static void print(const char *s, long n, uint8_t b = DEC) {}
|
||||||
static void println(const char *s, unsigned long n) {}
|
static void print(const char *s, unsigned long n, uint8_t b = DEC) {}
|
||||||
static void println(const char *s, int n, uint8_t b) {}
|
static void println(const char *s, int n, uint8_t b = DEC) {}
|
||||||
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) {}
|
||||||
static void println(const char *s, long n, uint8_t b) {}
|
static void println(const char *s, long n, uint8_t b = DEC) {}
|
||||||
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) {}
|
||||||
#endif
|
#endif
|
||||||
static void mk_setup(setup_t &s, uint32_t bmRequestType, uint32_t bRequest,
|
static void mk_setup(setup_t &s, uint32_t bmRequestType, uint32_t bRequest,
|
||||||
uint32_t wValue, uint32_t wIndex, uint32_t wLength) {
|
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,
|
static void init_qTD(volatile Transfer_t *t, void *buf, uint32_t len,
|
||||||
uint32_t pid, uint32_t data01, bool irq);
|
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 add_to_async_followup_list(Transfer_t *first, Transfer_t *last);
|
||||||
static void remove_from_async_followup_list(Transfer_t *transfer);
|
static void remove_from_async_followup_list(Transfer_t *transfer);
|
||||||
static void add_to_periodic_followup_list(Transfer_t *first, Transfer_t *last);
|
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
|
if (stat & USBHS_USBSTS_PCI) { // port change detected
|
||||||
const uint32_t portstat = USBHS_PORTSC1;
|
const uint32_t portstat = USBHS_PORTSC1;
|
||||||
@ -753,9 +755,10 @@ bool USBHost::queue_Transfer(Pipe_t *pipe, Transfer_t *transfer)
|
|||||||
return true;
|
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)) {
|
if (!(transfer->qtd.token & 0x80)) {
|
||||||
// TODO: check error status
|
// TODO: check error status
|
||||||
@ -773,6 +776,91 @@ static bool followup_Transfer(Transfer_t *transfer)
|
|||||||
return false;
|
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)
|
static void add_to_async_followup_list(Transfer_t *first, Transfer_t *last)
|
||||||
{
|
{
|
||||||
last->next_followup = NULL; // always add to end of list
|
last->next_followup = NULL; // always add to end of list
|
||||||
|
Loading…
Reference in New Issue
Block a user