1
0
mirror of https://github.com/gdsports/USBHost_t36 synced 2024-11-27 19:42:15 -05:00

Fix adding to follup lists while also processing them

This commit is contained in:
PaulStoffregen 2017-02-08 06:35:56 -08:00
parent 38dea38146
commit 46324071f0
2 changed files with 131 additions and 26 deletions

3
host.h
View File

@ -92,11 +92,12 @@ struct Transfer_struct {
} qtd; } qtd;
// linked list of queued, not-yet-completed transfers // linked list of queued, not-yet-completed transfers
Transfer_t *next_followup; Transfer_t *next_followup;
Transfer_t *prev_followup;
// data to be used by callback function // data to be used by callback function
Pipe_t *pipe; Pipe_t *pipe;
void *buffer; void *buffer;
uint32_t length; uint32_t length;
uint32_t unused[4]; uint32_t unused[3];
}; };
void init_Device_Pipe_Transfer_memory(void); void init_Device_Pipe_Transfer_memory(void);

View File

@ -192,6 +192,7 @@ void pulse(int usec)
// PORT_STATE_RECOVERY 3 // PORT_STATE_RECOVERY 3
// PORT_STATE_ACTIVE 4 // PORT_STATE_ACTIVE 4
void usbhs_isr(void) void usbhs_isr(void)
{ {
uint32_t stat = USBHS_USBSTS; uint32_t stat = USBHS_USBSTS;
@ -222,27 +223,37 @@ void usbhs_isr(void)
if (stat & USBHS_USBSTS_UAI) { // completed qTD(s) from the async schedule if (stat & USBHS_USBSTS_UAI) { // completed qTD(s) from the async schedule
Serial.println("Async Followup"); Serial.println("Async Followup");
Transfer_t *prev=NULL; print(async_followup_first, async_followup_last);
Transfer_t *p = async_followup_first; Transfer_t *p = async_followup_first;
while (p) { while (p) {
Transfer_t *next = p->next_followup;
if (followup_Transfer(p)) { if (followup_Transfer(p)) {
// transfer completed // transfer completed
if (prev) { Transfer_t *next = p->next_followup;
prev->next_followup = next; remove_from_async_followup_list(p);
} else { free_Transfer(p);
async_followup_first = next; p = next;
}
} else { } else {
// transfer still pending // transfer still pending
prev = p; p = p->next_followup;
} }
p = next;
} }
async_followup_last = prev; print(async_followup_first, async_followup_last);
} }
if (stat & USBHS_USBSTS_UPI) { // completed qTD(s) from the periodic schedule if (stat & USBHS_USBSTS_UPI) { // completed qTD(s) from the periodic schedule
Serial.println("Periodic Followup");
Transfer_t *p = periodic_followup_first;
while (p) {
if (followup_Transfer(p)) {
// transfer completed
Transfer_t *next = p->next_followup;
remove_from_periodic_followup_list(p);
free_Transfer(p);
p = next;
} else {
// transfer still pending
p = p->next_followup;
}
}
} }
if (stat & USBHS_USBSTS_PCI) { // port change detected if (stat & USBHS_USBSTS_PCI) { // port change detected
@ -338,6 +349,7 @@ void enumeration(const Transfer_t *transfer)
break; break;
case 1: // request all 18 bytes of device descriptor case 1: // request all 18 bytes of device descriptor
Serial.println("TODO: request 18 byte device descriptor");
break; break;
@ -593,31 +605,25 @@ bool new_Transfer(Pipe_t *pipe, void *buffer, uint32_t len)
// last points to transfer (which becomes new halt) // last points to transfer (which becomes new halt)
last->qtd.next = (uint32_t)transfer; last->qtd.next = (uint32_t)transfer;
transfer->qtd.next = 1; transfer->qtd.next = 1;
// link all the new qTD by next_followup // link all the new qTD by next_followup & prev_followup
Transfer_t *prev = NULL;
Transfer_t *p = halt; Transfer_t *p = halt;
while (p->qtd.next != (uint32_t)transfer) { while (p->qtd.next != (uint32_t)transfer) {
Transfer_t *n = (Transfer_t *)p->qtd.next; Transfer_t *n = (Transfer_t *)p->qtd.next;
p->prev_followup = prev;
p->next_followup = n; p->next_followup = n;
prev = p;
p = n; p = n;
} }
p->next_followup = NULL; p->next_followup = NULL;
print(halt, p);
// add them to a followup list // add them to a followup list
if (pipe->type == 0 || pipe->type == 2) { if (pipe->type == 0 || pipe->type == 2) {
// control or bulk // control or bulk
if (async_followup_first == NULL) { add_to_async_followup_list(halt, p);
async_followup_first = halt;
} else {
async_followup_last->next_followup = halt;
}
async_followup_last = p;
} else { } else {
// interrupt // interrupt
if (periodic_followup_first == NULL) { add_to_periodic_followup_list(halt, p);
periodic_followup_first = halt;
} else {
periodic_followup_last->next_followup = halt;
}
periodic_followup_last = p;
} }
// old halt becomes new transfer, this commits all new qTDs to QH // old halt becomes new transfer, this commits all new qTDs to QH
halt->qtd.token = token; halt->qtd.token = token;
@ -640,12 +646,69 @@ bool followup_Transfer(Transfer_t *transfer)
} }
// do callback function... // do callback function...
Serial.println(" completed"); Serial.println(" completed");
free_Transfer(transfer);
return true; return true;
} }
return false; return false;
} }
static void add_to_async_followup_list(Transfer_t *first, Transfer_t *last)
{
last->next_followup = NULL; // always add to end of list
if (async_followup_last == NULL) {
first->prev_followup = NULL;
async_followup_first = first;
} else {
first->prev_followup = async_followup_last;
async_followup_last->next_followup = first;
}
async_followup_last = last;
}
static void remove_from_async_followup_list(Transfer_t *transfer)
{
Transfer_t *next = transfer->next_followup;
Transfer_t *prev = transfer->prev_followup;
if (prev) {
prev->next_followup = next;
} else {
async_followup_first = next;
}
if (next) {
next->prev_followup = prev;
} else {
async_followup_last = prev;
}
}
static void add_to_periodic_followup_list(Transfer_t *first, Transfer_t *last)
{
last->next_followup = NULL; // always add to end of list
if (periodic_followup_last == NULL) {
first->prev_followup = NULL;
periodic_followup_first = first;
} else {
first->prev_followup = periodic_followup_last;
periodic_followup_last->next_followup = first;
}
periodic_followup_last = last;
}
static void remove_from_periodic_followup_list(Transfer_t *transfer)
{
Transfer_t *next = transfer->next_followup;
Transfer_t *prev = transfer->prev_followup;
if (prev) {
prev->next_followup = next;
} else {
periodic_followup_first = next;
}
if (next) {
next->prev_followup = prev;
} else {
periodic_followup_last = prev;
}
}
void print(const Transfer_t *transfer) void print(const Transfer_t *transfer)
{ {
if (!((uint32_t)transfer & 0xFFFFFFE0)) return; if (!((uint32_t)transfer & 0xFFFFFFE0)) return;
@ -665,6 +728,47 @@ void print(const Transfer_t *transfer)
Serial.println(); Serial.println();
} }
void print(const Transfer_t *first, const Transfer_t *last)
{
Serial.print("Transfer Followup List ");
Serial.print((uint32_t)first, HEX);
Serial.print(" to ");
Serial.println((uint32_t)last, HEX);
Serial.println(" forward:");
while (first) {
Serial.print(" ");
Serial.print((uint32_t)first, HEX);
print_token(first->qtd.token);
first = first->next_followup;
}
Serial.println(" backward:");
while (last) {
Serial.print(" ");
Serial.print((uint32_t)last, HEX);
print_token(last->qtd.token);
last = last->prev_followup;
}
}
void print_token(uint32_t token)
{
switch ((token >> 8) & 3) {
case 0:
Serial.print(" OUT ");
Serial.println((token >> 16) & 0x7FFF);
break;
case 1:
Serial.print(" IN ");
Serial.println((token >> 16) & 0x7FFF);
break;
case 2:
Serial.println(" SETUP");
break;
default:
Serial.println(" unknown");
}
}
void print(const Pipe_t *pipe) void print(const Pipe_t *pipe)
{ {
if (!((uint32_t)pipe & 0xFFFFFFE0)) return; if (!((uint32_t)pipe & 0xFFFFFFE0)) return;