|
|
|
|
|
|
|
|
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(" "); |