| uint32_t stat = USBHS_USBSTS; | uint32_t stat = USBHS_USBSTS; | ||||
| USBHS_USBSTS = stat; // clear pending interrupts | USBHS_USBSTS = stat; // clear pending interrupts | ||||
| //stat &= USBHS_USBINTR; // mask away unwanted interrupts | //stat &= USBHS_USBINTR; // mask away unwanted interrupts | ||||
| #if 1 | |||||
| #if 0 | |||||
| println(); | println(); | ||||
| println("ISR: ", stat, HEX); | println("ISR: ", stat, HEX); | ||||
| //if (stat & USBHS_USBSTS_UI) println(" USB Interrupt"); | //if (stat & USBHS_USBSTS_UI) println(" USB Interrupt"); | ||||
| #endif | #endif | ||||
| if (stat & USBHS_USBSTS_UAI) { // completed qTD(s) from the async schedule | if (stat & USBHS_USBSTS_UAI) { // completed qTD(s) from the async schedule | ||||
| println("Async Followup"); | |||||
| //println("Async Followup"); | |||||
| //print(async_followup_first, async_followup_last); | //print(async_followup_first, async_followup_last); | ||||
| Transfer_t *p = async_followup_first; | Transfer_t *p = async_followup_first; | ||||
| while (p) { | while (p) { | ||||
| //print(async_followup_first, async_followup_last); | //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 | ||||
| println("Periodic Followup"); | |||||
| //println("Periodic Followup"); | |||||
| Transfer_t *p = periodic_followup_first; | Transfer_t *p = periodic_followup_first; | ||||
| while (p) { | while (p) { | ||||
| if (followup_Transfer(p)) { | if (followup_Transfer(p)) { | ||||
| Transfer_t *transfer, *data, *status; | Transfer_t *transfer, *data, *status; | ||||
| uint32_t status_direction; | uint32_t status_direction; | ||||
| println("new_Control_Transfer"); | |||||
| //println("new_Control_Transfer"); | |||||
| if (setup->wLength > 16384) return false; // max 16K data for control | if (setup->wLength > 16384) return false; // max 16K data for control | ||||
| transfer = allocate_Transfer(); | transfer = allocate_Transfer(); | ||||
| if (!transfer) { | if (!transfer) { | ||||
| // TODO: option for zero length packet? Maybe in Pipe_t fields? | // TODO: option for zero length packet? Maybe in Pipe_t fields? | ||||
| println("new_Data_Transfer"); | |||||
| //println("new_Data_Transfer"); | |||||
| // allocate qTDs | // allocate qTDs | ||||
| transfer = allocate_Transfer(); | transfer = allocate_Transfer(); | ||||
| if (!transfer) return false; | if (!transfer) return false; | ||||
| bool USBHost::followup_Transfer(Transfer_t *transfer) | bool USBHost::followup_Transfer(Transfer_t *transfer) | ||||
| { | { | ||||
| print(" Followup ", (uint32_t)transfer, HEX); | |||||
| println(" token=", transfer->qtd.token, 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 | ||||
| best_offset = offset; | best_offset = offset; | ||||
| } | } | ||||
| } | } | ||||
| print(" best_bandwidth = "); | |||||
| print(best_bandwidth); | |||||
| print(", at offset = "); | |||||
| println(best_offset); | |||||
| print(" best_bandwidth = ", best_bandwidth); | |||||
| //print(best_bandwidth); | |||||
| println(", at offset = ", best_offset); | |||||
| //println(best_offset); | |||||
| // a 125 us micro frame can fit 7500 bytes, or 234 of our 32-byte units | // a 125 us micro frame can fit 7500 bytes, or 234 of our 32-byte units | ||||
| // fail if the best found needs more than 80% (234 * 0.8) in any uframe | // fail if the best found needs more than 80% (234 * 0.8) in any uframe | ||||
| if (best_bandwidth > 187) return false; | if (best_bandwidth > 187) return false; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| print(" best_bandwidth = "); | |||||
| println(best_bandwidth); | |||||
| print(", at offset = "); | |||||
| print(best_offset); | |||||
| print(", shift= "); | |||||
| println(best_shift); | |||||
| print(" best_bandwidth = ", best_bandwidth); | |||||
| //println(best_bandwidth); | |||||
| print(", at offset = ", best_offset); | |||||
| //print(best_offset); | |||||
| println(", shift= ", best_shift); | |||||
| //println(best_shift); | |||||
| // a 125 us micro frame can fit 7500 bytes, or 234 of our 32-byte units | // a 125 us micro frame can fit 7500 bytes, or 234 of our 32-byte units | ||||
| // fail if the best found needs more than 80% (234 * 0.8) in any uframe | // fail if the best found needs more than 80% (234 * 0.8) in any uframe | ||||
| if (best_bandwidth > 187) return false; | if (best_bandwidth > 187) return false; | ||||
| void USBHost::add_qh_to_periodic_schedule(Pipe_t *pipe) | void USBHost::add_qh_to_periodic_schedule(Pipe_t *pipe) | ||||
| { | { | ||||
| // quick hack for testing, just put it into the first table entry | // quick hack for testing, just put it into the first table entry | ||||
| println("add_qh_to_periodic_schedule: ", (uint32_t)pipe, HEX); | |||||
| //println("add_qh_to_periodic_schedule: ", (uint32_t)pipe, HEX); | |||||
| #if 0 | #if 0 | ||||
| pipe->qh.horizontal_link = periodictable[0]; | pipe->qh.horizontal_link = periodictable[0]; | ||||
| periodictable[0] = (uint32_t)&(pipe->qh) | 2; // 2=QH | periodictable[0] = (uint32_t)&(pipe->qh) | 2; // 2=QH | ||||
| #else | #else | ||||
| uint32_t interval = pipe->periodic_interval; | uint32_t interval = pipe->periodic_interval; | ||||
| uint32_t offset = pipe->periodic_offset; | uint32_t offset = pipe->periodic_offset; | ||||
| println(" interval = ", interval); | |||||
| println(" offset = ", offset); | |||||
| //println(" interval = ", interval); | |||||
| //println(" offset = ", offset); | |||||
| // By an interative miracle, hopefully make an inverted tree of EHCI figure 4-18, page 93 | // By an interative miracle, hopefully make an inverted tree of EHCI figure 4-18, page 93 | ||||
| for (uint32_t i=offset; i < PERIODIC_LIST_SIZE; i += interval) { | for (uint32_t i=offset; i < PERIODIC_LIST_SIZE; i += interval) { | ||||
| print(" old slot ", i); | |||||
| print(": "); | |||||
| print_qh_list((Pipe_t *)(periodictable[i] & 0xFFFFFFE0)); | |||||
| //print(" old slot ", i); | |||||
| //print(": "); | |||||
| //print_qh_list((Pipe_t *)(periodictable[i] & 0xFFFFFFE0)); | |||||
| uint32_t num = periodictable[i]; | uint32_t num = periodictable[i]; | ||||
| Pipe_t *node = (Pipe_t *)(num & 0xFFFFFFE0); | Pipe_t *node = (Pipe_t *)(num & 0xFFFFFFE0); | ||||
| if ((num & 1) || ((num & 6) == 2 && node->periodic_interval < interval)) { | if ((num & 1) || ((num & 6) == 2 && node->periodic_interval < interval)) { | ||||
| println(" add to slot ", i); | |||||
| //println(" add to slot ", i); | |||||
| pipe->qh.horizontal_link = num; | pipe->qh.horizontal_link = num; | ||||
| periodictable[i] = (uint32_t)&(pipe->qh) | 2; // 2=QH | periodictable[i] = (uint32_t)&(pipe->qh) | 2; // 2=QH | ||||
| } else { | } else { | ||||
| println(" traverse list ", i); | |||||
| //println(" traverse list ", i); | |||||
| // TODO: skip past iTD, siTD when/if we support isochronous | // TODO: skip past iTD, siTD when/if we support isochronous | ||||
| while (node->periodic_interval >= interval) { | while (node->periodic_interval >= interval) { | ||||
| if (node == pipe) goto nextslot; | if (node == pipe) goto nextslot; | ||||
| print(" num ", num, HEX); | |||||
| print(" node ", (uint32_t)node, HEX); | |||||
| println("->", node->qh.horizontal_link, HEX); | |||||
| //print(" num ", num, HEX); | |||||
| //print(" node ", (uint32_t)node, HEX); | |||||
| //println("->", node->qh.horizontal_link, HEX); | |||||
| if (node->qh.horizontal_link & 1) break; | if (node->qh.horizontal_link & 1) break; | ||||
| num = node->qh.horizontal_link; | num = node->qh.horizontal_link; | ||||
| node = (Pipe_t *)(num & 0xFFFFFFE0); | node = (Pipe_t *)(num & 0xFFFFFFE0); | ||||
| if (n == pipe) goto nextslot; | if (n == pipe) goto nextslot; | ||||
| n = (Pipe_t *)(n->qh.horizontal_link & 0xFFFFFFE0); | n = (Pipe_t *)(n->qh.horizontal_link & 0xFFFFFFE0); | ||||
| } while (n != NULL); | } while (n != NULL); | ||||
| print(" adding at node ", (uint32_t)node, HEX); | |||||
| print(", num=", num, HEX); | |||||
| println(", node->qh.horizontal_link=", node->qh.horizontal_link, HEX); | |||||
| //print(" adding at node ", (uint32_t)node, HEX); | |||||
| //print(", num=", num, HEX); | |||||
| //println(", node->qh.horizontal_link=", node->qh.horizontal_link, HEX); | |||||
| pipe->qh.horizontal_link = node->qh.horizontal_link; | pipe->qh.horizontal_link = node->qh.horizontal_link; | ||||
| node->qh.horizontal_link = (uint32_t)pipe | 2; // 2=QH | node->qh.horizontal_link = (uint32_t)pipe | 2; // 2=QH | ||||
| // TODO: is it really necessary to keep doing the outer | // TODO: is it really necessary to keep doing the outer | ||||
| // we could avoid extra work by just returning here. | // we could avoid extra work by just returning here. | ||||
| } | } | ||||
| nextslot: | nextslot: | ||||
| print(" new slot ", i); | |||||
| print(": "); | |||||
| print_qh_list((Pipe_t *)(periodictable[i] & 0xFFFFFFE0)); | |||||
| //print(" new slot ", i); | |||||
| //print(": "); | |||||
| //print_qh_list((Pipe_t *)(periodictable[i] & 0xFFFFFFE0)); | |||||
| {} | |||||
| } | } | ||||
| #endif | #endif | ||||
| #if 1 | |||||
| #if 0 | |||||
| println("Periodic Schedule:"); | println("Periodic Schedule:"); | ||||
| for (uint32_t i=0; i < PERIODIC_LIST_SIZE; i++) { | for (uint32_t i=0; i < PERIODIC_LIST_SIZE; i++) { | ||||
| if (i < 10) print(" "); | if (i < 10) print(" "); |