@@ -95,12 +95,12 @@ struct Pipe_struct { | |||
Device_t *device; | |||
uint8_t type; // 0=control, 1=isochronous, 2=bulk, 3=interrupt | |||
uint8_t direction; // 0=out, 1=in (changes for control, others fixed) | |||
uint8_t start_mask; | |||
uint8_t complete_mask; | |||
uint8_t start_mask; // TODO: is this redundant? | |||
uint8_t complete_mask; // TODO: is this redundant? | |||
Pipe_t *next; | |||
void (*callback_function)(const Transfer_t *); | |||
uint16_t periodic_interval; | |||
uint16_t periodic_offset; | |||
uint16_t periodic_offset; // TODO: is this redundant? | |||
uint32_t unused1; | |||
uint32_t unused2; | |||
uint32_t unused3; | |||
@@ -174,12 +174,14 @@ private: | |||
static void free_Transfer(Transfer_t *q); | |||
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); | |||
protected: | |||
static void print(const Transfer_t *transfer); | |||
static void print(const Transfer_t *first, const Transfer_t *last); | |||
static void print_token(uint32_t token); | |||
static void print(const Pipe_t *pipe); | |||
static void print_driverlist(const char *name, const USBDriver *driver); | |||
static void print_qh_list(const Pipe_t *list); | |||
static void print_hexbytes(const void *ptr, uint32_t len); | |||
static void print(const char *s) { Serial.print(s); } | |||
static void print(int n) { Serial.print(n); } |
@@ -24,6 +24,10 @@ | |||
#include <Arduino.h> | |||
#include "USBHost.h" | |||
// Size of the periodic list, in milliseconds. This determines the | |||
// slowest rate we can poll interrupt endpoints. Each entry uses | |||
// 12 bytes (4 for a pointer, 8 for bandwidth management). | |||
// may be 8, 16, 32, 64, 128, 256, 512, 1024 | |||
#define PERIODIC_LIST_SIZE 32 | |||
static uint32_t periodictable[PERIODIC_LIST_SIZE] __attribute__ ((aligned(4096), used)); | |||
@@ -422,21 +426,7 @@ Pipe_t * USBHost::new_Pipe(Device_t *dev, uint32_t type, uint32_t endpoint, | |||
} | |||
} else if (type == 3) { | |||
// interrupt: add to periodic schedule | |||
// TODO: link it into the periodic table | |||
//add_qh_to_periodic_schedule(pipe); | |||
// TODO: built tree... | |||
//uint32_t finterval = interval >> 3; | |||
//for (uint32_t i=offset; i < PERIODIC_LIST_SIZE; i += finterval) { | |||
// uint32_t list = periodictable[i]; | |||
//} | |||
// quick hack for testing, just put it into the first table entry | |||
pipe->qh.horizontal_link = periodictable[0]; | |||
periodictable[0] = (uint32_t)&(pipe->qh) | 2; // 2=QH | |||
println("init periodictable with ", periodictable[0], HEX); | |||
add_qh_to_periodic_schedule(pipe); | |||
} | |||
return pipe; | |||
} | |||
@@ -867,6 +857,53 @@ bool USBHost::allocate_interrupt_pipe_bandwidth(Pipe_t *pipe, uint32_t maxlen, u | |||
return true; | |||
} | |||
// put a new pipe into the periodic schedule tree | |||
// according to periodic_interval and periodic_offset | |||
// | |||
void USBHost::add_qh_to_periodic_schedule(Pipe_t *pipe) | |||
{ | |||
// quick hack for testing, just put it into the first table entry | |||
println("add_qh_to_periodic_schedule:"); | |||
#if 0 | |||
pipe->qh.horizontal_link = periodictable[0]; | |||
periodictable[0] = (uint32_t)&(pipe->qh) | 2; // 2=QH | |||
println("init periodictable with ", periodictable[0], HEX); | |||
#else | |||
uint32_t interval = pipe->periodic_interval; | |||
uint32_t offset = pipe->periodic_offset; | |||
println(" interval = ", interval); | |||
println(" offset = ", offset); | |||
// TODO: does this really make an inverted tree like EHCI figure 4-18, page 93 | |||
for (uint32_t i=offset; i < PERIODIC_LIST_SIZE; i += interval) { | |||
uint32_t num = periodictable[i]; | |||
Pipe_t *node = (Pipe_t *)(num & 0xFFFFFFE0); | |||
if ((num & 1) || ((num & 6) == 2 && node->periodic_interval < interval)) { | |||
println(" add to slot ", i); | |||
pipe->qh.horizontal_link = num; | |||
periodictable[i] = (uint32_t)&(pipe->qh) | 2; // 2=QH | |||
} else { | |||
println(" traverse list ", i); | |||
// TODO: skip past iTD, siTD when/if we support isochronous | |||
while (node->periodic_interval >= interval) { | |||
if (node->qh.horizontal_link & 1) break; | |||
num = node->qh.horizontal_link; | |||
node = (Pipe_t *)(num & 0xFFFFFFE0); | |||
} | |||
pipe->qh.horizontal_link = num; | |||
node->qh.horizontal_link = (uint32_t)pipe | 2; // 2=QH | |||
} | |||
} | |||
#endif | |||
println("Periodic Schedule:"); | |||
for (uint32_t i=0; i < PERIODIC_LIST_SIZE; i++) { | |||
if (i < 10) print(" "); | |||
print(i); | |||
print(": "); | |||
print_qh_list((Pipe_t *)(periodictable[i] & 0xFFFFFFE0)); | |||
} | |||
} | |||
void USBHost::delete_Pipe(Pipe_t *pipe) | |||
{ |
@@ -138,7 +138,8 @@ void USBHub::control(const Transfer_t *transfer) | |||
} else if (state == numports) { | |||
println("power turned on to all ports"); | |||
println("device addr = ", device->address); | |||
changepipe = new_Pipe(device, 3, endpoint, 1, 1, 512); | |||
// TODO: use hub's interrupt endpoint interval | |||
changepipe = new_Pipe(device, 3, endpoint, 1, 1, 64); | |||
println("pipe cap1 = ", changepipe->qh.capabilities[0], HEX); | |||
changepipe->callback_function = callback; | |||
queue_Data_Transfer(changepipe, &changebits, 1, this); |
@@ -59,7 +59,7 @@ bool KeyboardController::claim(Device_t *dev, int type, const uint8_t *descripto | |||
if (size != 8) return false; // must be 8 bytes for Keyboard Boot Protocol | |||
uint32_t interval = descriptors[24]; | |||
println("polling interval = ", interval); | |||
datapipe = new_Pipe(dev, 3, endpoint, 1, 8, 64); | |||
datapipe = new_Pipe(dev, 3, endpoint, 1, 8, interval); | |||
datapipe->callback_function = callback; | |||
queue_Data_Transfer(datapipe, report, 8, this); | |||
return true; |
@@ -146,6 +146,25 @@ void USBHost::print_driverlist(const char *name, const USBDriver *driver) | |||
Serial.println(); | |||
} | |||
void USBHost::print_qh_list(const Pipe_t *list) | |||
{ | |||
if (!list) { | |||
Serial.println("(empty)"); | |||
return; | |||
} | |||
const Pipe_t *node = list; | |||
while (1) { | |||
Serial.print((uint32_t)node, HEX); | |||
node = (const Pipe_t *)(node->qh.horizontal_link & 0xFFFFFFE0); | |||
if (!node) break; | |||
if (node == list) { | |||
Serial.print(" (loops)"); | |||
break; | |||
} | |||
Serial.print(" -> "); | |||
} | |||
Serial.println(); | |||
} | |||
void USBHost::print_hexbytes(const void *ptr, uint32_t len) | |||
{ |