1
0
mirror of https://github.com/gdsports/USBHost_t36 synced 2024-11-22 00:52:19 -05:00

Add to periodic sched using interval+offset & binary tree

This commit is contained in:
PaulStoffregen 2017-02-26 09:40:49 -08:00
parent 1c5d403aba
commit 80225dfe22
5 changed files with 79 additions and 20 deletions

View File

@ -95,12 +95,12 @@ struct Pipe_struct {
Device_t *device; Device_t *device;
uint8_t type; // 0=control, 1=isochronous, 2=bulk, 3=interrupt 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 direction; // 0=out, 1=in (changes for control, others fixed)
uint8_t start_mask; uint8_t start_mask; // TODO: is this redundant?
uint8_t complete_mask; uint8_t complete_mask; // TODO: is this redundant?
Pipe_t *next; Pipe_t *next;
void (*callback_function)(const Transfer_t *); void (*callback_function)(const Transfer_t *);
uint16_t periodic_interval; uint16_t periodic_interval;
uint16_t periodic_offset; uint16_t periodic_offset; // TODO: is this redundant?
uint32_t unused1; uint32_t unused1;
uint32_t unused2; uint32_t unused2;
uint32_t unused3; uint32_t unused3;
@ -174,12 +174,14 @@ private:
static void free_Transfer(Transfer_t *q); static void free_Transfer(Transfer_t *q);
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);
protected: protected:
static void print(const Transfer_t *transfer); static void print(const Transfer_t *transfer);
static void print(const Transfer_t *first, const Transfer_t *last); static void print(const Transfer_t *first, const Transfer_t *last);
static void print_token(uint32_t token); static void print_token(uint32_t token);
static void print(const Pipe_t *pipe); static void print(const Pipe_t *pipe);
static void print_driverlist(const char *name, const USBDriver *driver); 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_hexbytes(const void *ptr, uint32_t len);
static void print(const char *s) { Serial.print(s); } static void print(const char *s) { Serial.print(s); }
static void print(int n) { Serial.print(n); } static void print(int n) { Serial.print(n); }

View File

@ -24,6 +24,10 @@
#include <Arduino.h> #include <Arduino.h>
#include "USBHost.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 #define PERIODIC_LIST_SIZE 32
static uint32_t periodictable[PERIODIC_LIST_SIZE] __attribute__ ((aligned(4096), used)); 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) { } else if (type == 3) {
// interrupt: add to periodic schedule // interrupt: add to periodic schedule
// TODO: link it into the periodic table add_qh_to_periodic_schedule(pipe);
//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);
} }
return pipe; return pipe;
} }
@ -867,6 +857,53 @@ bool USBHost::allocate_interrupt_pipe_bandwidth(Pipe_t *pipe, uint32_t maxlen, u
return true; 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) void USBHost::delete_Pipe(Pipe_t *pipe)
{ {

View File

@ -138,7 +138,8 @@ void USBHub::control(const Transfer_t *transfer)
} else if (state == numports) { } else if (state == numports) {
println("power turned on to all ports"); println("power turned on to all ports");
println("device addr = ", device->address); 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); println("pipe cap1 = ", changepipe->qh.capabilities[0], HEX);
changepipe->callback_function = callback; changepipe->callback_function = callback;
queue_Data_Transfer(changepipe, &changebits, 1, this); queue_Data_Transfer(changepipe, &changebits, 1, this);

View File

@ -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 if (size != 8) return false; // must be 8 bytes for Keyboard Boot Protocol
uint32_t interval = descriptors[24]; uint32_t interval = descriptors[24];
println("polling interval = ", interval); 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; datapipe->callback_function = callback;
queue_Data_Transfer(datapipe, report, 8, this); queue_Data_Transfer(datapipe, report, 8, this);
return true; return true;

View File

@ -146,6 +146,25 @@ void USBHost::print_driverlist(const char *name, const USBDriver *driver)
Serial.println(); 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) void USBHost::print_hexbytes(const void *ptr, uint32_t len)
{ {