protected: | protected: | ||||
static Pipe_t * new_Pipe(Device_t *dev, uint32_t type, uint32_t endpoint, | static Pipe_t * new_Pipe(Device_t *dev, uint32_t type, uint32_t endpoint, | ||||
uint32_t direction, uint32_t max_packet_len); | uint32_t direction, uint32_t max_packet_len); | ||||
static bool new_Transfer(Pipe_t *pipe, void *buffer, uint32_t len); | |||||
static bool new_Control_Transfer(Device_t *dev, setup_t *setup, | |||||
void *buf, USBDriver *driver=NULL); | |||||
static bool new_Data_Transfer(Pipe_t *pipe, void *buffer, | |||||
uint32_t len, USBDriver *driver); | |||||
static Device_t * new_Device(uint32_t speed, uint32_t hub_addr, uint32_t hub_port); | static Device_t * new_Device(uint32_t speed, uint32_t hub_addr, uint32_t hub_port); | ||||
static void enumeration(const Transfer_t *transfer); | static void enumeration(const Transfer_t *transfer); | ||||
static void driver_ready_for_device(USBDriver *driver); | static void driver_ready_for_device(USBDriver *driver); | ||||
private: | private: | ||||
static void isr(); | static void isr(); | ||||
static void claim_drivers(Device_t *dev); | static void claim_drivers(Device_t *dev); | ||||
static bool queue_Transfer(Pipe_t *pipe, Transfer_t *transfer); | |||||
static void init_Device_Pipe_Transfer_memory(void); | static void init_Device_Pipe_Transfer_memory(void); | ||||
static Device_t * allocate_Device(void); | static Device_t * allocate_Device(void); | ||||
static void free_Device(Device_t *q); | static void free_Device(Device_t *q); |
} | } | ||||
// Create a Transfer and queue it | |||||
// Create a Control Transfer and queue it | |||||
// | // | ||||
bool USBHost::new_Transfer(Pipe_t *pipe, void *buffer, uint32_t len) | |||||
bool USBHost::new_Control_Transfer(Device_t *dev, setup_t *setup, void *buf, USBDriver *driver) | |||||
{ | { | ||||
Serial.println("new_Transfer"); | |||||
Transfer_t *transfer = allocate_Transfer(); | |||||
Transfer_t *transfer, *data, *status; | |||||
uint32_t status_direction; | |||||
Serial.println("new_Control_Transfer"); | |||||
if (setup->wLength > 16384) return false; // max 16K data for control | |||||
transfer = allocate_Transfer(); | |||||
if (!transfer) return false; | if (!transfer) return false; | ||||
if (pipe->type == 0) { | |||||
// control transfer | |||||
Transfer_t *data, *status; | |||||
uint32_t status_direction; | |||||
if (len > 16384) { | |||||
// hopefully we never need more | |||||
// than 16K in a control transfer | |||||
free_Transfer(transfer); | |||||
return false; | |||||
} | |||||
status = allocate_Transfer(); | |||||
if (!status) { | |||||
status = allocate_Transfer(); | |||||
if (!status) { | |||||
free_Transfer(transfer); | |||||
return false; | |||||
} | |||||
if (setup->wLength > 0) { | |||||
data = allocate_Transfer(); | |||||
if (!data) { | |||||
free_Transfer(transfer); | free_Transfer(transfer); | ||||
free_Transfer(status); | |||||
return false; | return false; | ||||
} | } | ||||
if (len > 0) { | |||||
data = allocate_Transfer(); | |||||
if (!data) { | |||||
free_Transfer(transfer); | |||||
free_Transfer(status); | |||||
return false; | |||||
} | |||||
init_qTD(data, buffer, len, pipe->direction, 1, false); | |||||
transfer->qtd.next = (uint32_t)data; | |||||
data->qtd.next = (uint32_t)status; | |||||
status_direction = pipe->direction ^ 1; | |||||
} else { | |||||
transfer->qtd.next = (uint32_t)status; | |||||
status_direction = 1; // always IN, USB 2.0 page 226 | |||||
} | |||||
Serial.print("setup address "); | |||||
Serial.println((uint32_t)&pipe->device->setup, HEX); | |||||
init_qTD(transfer, &pipe->device->setup, 8, 2, 0, false); | |||||
init_qTD(status, NULL, 0, status_direction, 1, true); | |||||
status->pipe = pipe; | |||||
status->buffer = buffer; | |||||
status->length = len; | |||||
status->qtd.next = 1; | |||||
uint32_t pid = (setup->bmRequestType & 0x80) ? 1 : 0; | |||||
init_qTD(data, buf, setup->wLength, pid, 1, false); | |||||
transfer->qtd.next = (uint32_t)data; | |||||
data->qtd.next = (uint32_t)status; | |||||
status_direction = pid ^ 1; | |||||
} else { | } else { | ||||
// bulk, interrupt or isochronous transfer | |||||
free_Transfer(transfer); | |||||
return false; | |||||
transfer->qtd.next = (uint32_t)status; | |||||
status_direction = 1; // always IN, USB 2.0 page 226 | |||||
} | } | ||||
Serial.print("setup address "); | |||||
Serial.println((uint32_t)setup, HEX); | |||||
init_qTD(transfer, setup, 8, 2, 0, false); | |||||
init_qTD(status, NULL, 0, status_direction, 1, true); | |||||
status->pipe = dev->control_pipe; | |||||
status->buffer = buf; | |||||
status->length = setup->wLength; | |||||
status->qtd.next = 1; | |||||
return queue_Transfer(dev->control_pipe, transfer); | |||||
} | |||||
// Create a Bulk or Interrupt Transfer and queue it | |||||
// | |||||
bool USBHost::new_Data_Transfer(Pipe_t *pipe, void *buffer, uint32_t len, USBDriver *driver) | |||||
{ | |||||
Serial.println("new_Data_Transfer"); | |||||
//Transfer_t *transfer = allocate_Transfer(); | |||||
//if (!transfer) return false; | |||||
return false; | |||||
//return queue_Transfer(pipe, transfer); | |||||
} | |||||
bool USBHost::queue_Transfer(Pipe_t *pipe, Transfer_t *transfer) | |||||
{ | |||||
// find halt qTD | // find halt qTD | ||||
Transfer_t *halt = (Transfer_t *)(pipe->qh.next); | Transfer_t *halt = (Transfer_t *)(pipe->qh.next); | ||||
while (!(halt->qtd.token & 0x40)) halt = (Transfer_t *)(halt->qtd.next); | while (!(halt->qtd.token & 0x40)) halt = (Transfer_t *)(halt->qtd.next); |
// any new devices detected while enumerating would | // any new devices detected while enumerating would | ||||
// go onto a waiting list | // go onto a waiting list | ||||
mk_setup(dev->setup, 0x80, 6, 0x0100, 0, 8); // 6=GET_DESCRIPTOR | mk_setup(dev->setup, 0x80, 6, 0x0100, 0, 8); // 6=GET_DESCRIPTOR | ||||
new_Transfer(dev->control_pipe, enumbuf, 8); | |||||
new_Control_Transfer(dev, &dev->setup, enumbuf); | |||||
return dev; | return dev; | ||||
} | } | ||||
case 0: // read 8 bytes of device desc, set max packet, and send set address | case 0: // read 8 bytes of device desc, set max packet, and send set address | ||||
pipe_set_maxlen(dev->control_pipe, enumbuf[7]); | pipe_set_maxlen(dev->control_pipe, enumbuf[7]); | ||||
mk_setup(dev->setup, 0, 5, assign_addr(), 0, 0); // 5=SET_ADDRESS | mk_setup(dev->setup, 0, 5, assign_addr(), 0, 0); // 5=SET_ADDRESS | ||||
new_Transfer(dev->control_pipe, NULL, 0); | |||||
new_Control_Transfer(dev, &dev->setup, NULL); | |||||
dev->enum_state = 1; | dev->enum_state = 1; | ||||
return; | return; | ||||
case 1: // request all 18 bytes of device descriptor | case 1: // request all 18 bytes of device descriptor | ||||
pipe_set_addr(dev->control_pipe, dev->setup.wValue); | pipe_set_addr(dev->control_pipe, dev->setup.wValue); | ||||
mk_setup(dev->setup, 0x80, 6, 0x0100, 0, 18); // 6=GET_DESCRIPTOR | mk_setup(dev->setup, 0x80, 6, 0x0100, 0, 18); // 6=GET_DESCRIPTOR | ||||
new_Transfer(dev->control_pipe, enumbuf, 18); | |||||
new_Control_Transfer(dev, &dev->setup, enumbuf); | |||||
dev->enum_state = 2; | dev->enum_state = 2; | ||||
return; | return; | ||||
case 2: // parse 18 device desc bytes | case 2: // parse 18 device desc bytes | ||||
case 3: // request Language ID | case 3: // request Language ID | ||||
len = sizeof(enumbuf) - 4; | len = sizeof(enumbuf) - 4; | ||||
mk_setup(dev->setup, 0x80, 6, 0x0300, 0, len); // 6=GET_DESCRIPTOR | mk_setup(dev->setup, 0x80, 6, 0x0300, 0, len); // 6=GET_DESCRIPTOR | ||||
new_Transfer(dev->control_pipe, enumbuf + 4, len); | |||||
new_Control_Transfer(dev, &dev->setup, enumbuf + 4); | |||||
dev->enum_state = 4; | dev->enum_state = 4; | ||||
return; | return; | ||||
case 4: // parse Language ID | case 4: // parse Language ID | ||||
case 5: // request Manufacturer string | case 5: // request Manufacturer string | ||||
len = sizeof(enumbuf) - 4; | len = sizeof(enumbuf) - 4; | ||||
mk_setup(dev->setup, 0x80, 6, 0x0300 | enumbuf[0], dev->LanguageID, len); | mk_setup(dev->setup, 0x80, 6, 0x0300 | enumbuf[0], dev->LanguageID, len); | ||||
new_Transfer(dev->control_pipe, enumbuf + 4, len); | |||||
new_Control_Transfer(dev, &dev->setup, enumbuf + 4); | |||||
dev->enum_state = 6; | dev->enum_state = 6; | ||||
return; | return; | ||||
case 6: // parse Manufacturer string | case 6: // parse Manufacturer string | ||||
case 7: // request Product string | case 7: // request Product string | ||||
len = sizeof(enumbuf) - 4; | len = sizeof(enumbuf) - 4; | ||||
mk_setup(dev->setup, 0x80, 6, 0x0300 | enumbuf[1], dev->LanguageID, len); | mk_setup(dev->setup, 0x80, 6, 0x0300 | enumbuf[1], dev->LanguageID, len); | ||||
new_Transfer(dev->control_pipe, enumbuf + 4, len); | |||||
new_Control_Transfer(dev, &dev->setup, enumbuf + 4); | |||||
dev->enum_state = 8; | dev->enum_state = 8; | ||||
return; | return; | ||||
case 8: // parse Product string | case 8: // parse Product string | ||||
case 9: // request Serial Number string | case 9: // request Serial Number string | ||||
len = sizeof(enumbuf) - 4; | len = sizeof(enumbuf) - 4; | ||||
mk_setup(dev->setup, 0x80, 6, 0x0300 | enumbuf[2], dev->LanguageID, len); | mk_setup(dev->setup, 0x80, 6, 0x0300 | enumbuf[2], dev->LanguageID, len); | ||||
new_Transfer(dev->control_pipe, enumbuf + 4, len); | |||||
new_Control_Transfer(dev, &dev->setup, enumbuf + 4); | |||||
dev->enum_state = 10; | dev->enum_state = 10; | ||||
return; | return; | ||||
case 10: // parse Serial Number string | case 10: // parse Serial Number string | ||||
break; | break; | ||||
case 11: // request first 9 bytes of config desc | case 11: // request first 9 bytes of config desc | ||||
mk_setup(dev->setup, 0x80, 6, 0x0200, 0, 9); // 6=GET_DESCRIPTOR | mk_setup(dev->setup, 0x80, 6, 0x0200, 0, 9); // 6=GET_DESCRIPTOR | ||||
new_Transfer(dev->control_pipe, enumbuf, 9); | |||||
new_Control_Transfer(dev, &dev->setup, enumbuf); | |||||
dev->enum_state = 12; | dev->enum_state = 12; | ||||
return; | return; | ||||
case 12: // read 9 bytes, request all of config desc | case 12: // read 9 bytes, request all of config desc | ||||
// TODO: how to handle device with too much config data | // TODO: how to handle device with too much config data | ||||
} | } | ||||
mk_setup(dev->setup, 0x80, 6, 0x0200, 0, len); // 6=GET_DESCRIPTOR | mk_setup(dev->setup, 0x80, 6, 0x0200, 0, len); // 6=GET_DESCRIPTOR | ||||
new_Transfer(dev->control_pipe, enumbuf, len); | |||||
new_Control_Transfer(dev, &dev->setup, enumbuf); | |||||
dev->enum_state = 13; | dev->enum_state = 13; | ||||
return; | return; | ||||
case 13: // read all config desc, send set config | case 13: // read all config desc, send set config | ||||
dev->bMaxPower = enumbuf[8]; | dev->bMaxPower = enumbuf[8]; | ||||
// TODO: actually do something with interface descriptor? | // TODO: actually do something with interface descriptor? | ||||
mk_setup(dev->setup, 0, 9, enumbuf[5], 0, 0); // 9=SET_CONFIGURATION | mk_setup(dev->setup, 0, 9, enumbuf[5], 0, 0); // 9=SET_CONFIGURATION | ||||
new_Transfer(dev->control_pipe, NULL, 0); | |||||
new_Control_Transfer(dev, &dev->setup, NULL); | |||||
dev->enum_state = 14; | dev->enum_state = 14; | ||||
return; | return; | ||||
case 14: // device is now configured | case 14: // device is now configured |
// TODO: need a way to do control transfers with our own setup data. | // TODO: need a way to do control transfers with our own setup data. | ||||
mk_setup(dev->setup, 0xA0, 6, 0x2900, 0, sizeof(hub_desc)); | mk_setup(dev->setup, 0xA0, 6, 0x2900, 0, sizeof(hub_desc)); | ||||
new_Transfer(dev->control_pipe, hub_desc, sizeof(hub_desc)); | |||||
new_Control_Transfer(dev, &dev->setup, hub_desc); | |||||
return true; | return true; | ||||
} | } | ||||
{ | { | ||||
// TODO: need a way to do control transfers with our own setup data. | // TODO: need a way to do control transfers with our own setup data. | ||||
mk_setup(device->setup, 0x23, 3, 8, port, 0); | mk_setup(device->setup, 0x23, 3, 8, port, 0); | ||||
new_Transfer(device->control_pipe, NULL, 0); | |||||
new_Control_Transfer(device, &device->setup, NULL); | |||||
} | } | ||||
bool USBHub::control(const Transfer_t *transfer) | bool USBHub::control(const Transfer_t *transfer) |