|
|
|
|
|
|
|
|
s.word2 = wIndex | (wLength << 16); |
|
|
s.word2 = wIndex | (wLength << 16); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
static uint8_t enumbuf[255]; |
|
|
|
|
|
|
|
|
static uint8_t enumbuf[256] __attribute__ ((aligned(16))); |
|
|
|
|
|
|
|
|
void enumeration(const Transfer_t *transfer) |
|
|
void enumeration(const Transfer_t *transfer) |
|
|
{ |
|
|
{ |
|
|
|
|
|
|
|
|
//print(transfer); |
|
|
//print(transfer); |
|
|
Device_t *dev = transfer->pipe->device; |
|
|
Device_t *dev = transfer->pipe->device; |
|
|
|
|
|
|
|
|
switch (dev->enum_state) { |
|
|
|
|
|
case 0: // read 8 bytes of device desc, set max packet, and send set address |
|
|
|
|
|
pipe_set_maxlen(dev->control_pipe, enumbuf[7]); |
|
|
|
|
|
mk_setup(dev->setup, 0, 5, assign_addr(), 0, 0); // 5=SET_ADDRESS |
|
|
|
|
|
new_Transfer(dev->control_pipe, NULL, 0); |
|
|
|
|
|
dev->enum_state = 1; |
|
|
|
|
|
break; |
|
|
|
|
|
case 1: // request all 18 bytes of device descriptor |
|
|
|
|
|
pipe_set_addr(dev->control_pipe, dev->setup.wValue); |
|
|
|
|
|
mk_setup(dev->setup, 0x80, 6, 0x0100, 0, 18); // 6=GET_DESCRIPTOR |
|
|
|
|
|
new_Transfer(dev->control_pipe, enumbuf, 18); |
|
|
|
|
|
dev->enum_state = 2; |
|
|
|
|
|
break; |
|
|
|
|
|
case 2: // read 18 device desc bytes, request first 9 bytes of config desc |
|
|
|
|
|
// TODO: actually do something with device descriptor? |
|
|
|
|
|
mk_setup(dev->setup, 0x80, 6, 0x0200, 0, 9); // 6=GET_DESCRIPTOR |
|
|
|
|
|
new_Transfer(dev->control_pipe, enumbuf, 9); |
|
|
|
|
|
dev->enum_state = 3; |
|
|
|
|
|
break; |
|
|
|
|
|
case 3: // read 9 bytes, request all of config desc |
|
|
|
|
|
len = enumbuf[2] | (enumbuf[3] << 8); |
|
|
|
|
|
Serial.print("Config data length = "); |
|
|
|
|
|
Serial.println(len); |
|
|
|
|
|
if (len > sizeof(enumbuf)) { |
|
|
|
|
|
// TODO: how to handle device with too much config data |
|
|
|
|
|
|
|
|
while (1) { |
|
|
|
|
|
// Within this large switch/case, "break" means we've done |
|
|
|
|
|
// some work, but more remains to be done in a different |
|
|
|
|
|
// state. Generally break is used after parsing received |
|
|
|
|
|
// data, but what happens next could be different states. |
|
|
|
|
|
// When completed, return is used. Generally, return happens |
|
|
|
|
|
// only after a new control transfer is queued, or when |
|
|
|
|
|
// enumeration is complete and no more communication is needed. |
|
|
|
|
|
switch (dev->enum_state) { |
|
|
|
|
|
case 0: // read 8 bytes of device desc, set max packet, and send set address |
|
|
|
|
|
pipe_set_maxlen(dev->control_pipe, enumbuf[7]); |
|
|
|
|
|
mk_setup(dev->setup, 0, 5, assign_addr(), 0, 0); // 5=SET_ADDRESS |
|
|
|
|
|
new_Transfer(dev->control_pipe, NULL, 0); |
|
|
|
|
|
dev->enum_state = 1; |
|
|
|
|
|
return; |
|
|
|
|
|
case 1: // request all 18 bytes of device descriptor |
|
|
|
|
|
pipe_set_addr(dev->control_pipe, dev->setup.wValue); |
|
|
|
|
|
mk_setup(dev->setup, 0x80, 6, 0x0100, 0, 18); // 6=GET_DESCRIPTOR |
|
|
|
|
|
new_Transfer(dev->control_pipe, enumbuf, 18); |
|
|
|
|
|
dev->enum_state = 2; |
|
|
|
|
|
return; |
|
|
|
|
|
case 2: // parse 18 device desc bytes |
|
|
|
|
|
dev->bDeviceClass = enumbuf[4]; |
|
|
|
|
|
dev->bDeviceSubClass = enumbuf[5]; |
|
|
|
|
|
dev->bDeviceProtocol = enumbuf[6]; |
|
|
|
|
|
dev->idVendor = enumbuf[8] | (enumbuf[9] << 8); |
|
|
|
|
|
dev->idProduct = enumbuf[10] | (enumbuf[11] << 8); |
|
|
|
|
|
enumbuf[0] = enumbuf[14]; |
|
|
|
|
|
enumbuf[1] = enumbuf[15]; |
|
|
|
|
|
enumbuf[2] = enumbuf[16]; |
|
|
|
|
|
if ((enumbuf[0] | enumbuf[1] | enumbuf[2]) > 0) { |
|
|
|
|
|
dev->enum_state = 3; |
|
|
|
|
|
} else { |
|
|
|
|
|
dev->enum_state = 11; |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
case 3: // request Language ID |
|
|
|
|
|
len = sizeof(enumbuf) - 4; |
|
|
|
|
|
mk_setup(dev->setup, 0x80, 6, 0x0300, 0, len); // 6=GET_DESCRIPTOR |
|
|
|
|
|
new_Transfer(dev->control_pipe, enumbuf + 4, len); |
|
|
|
|
|
dev->enum_state = 4; |
|
|
|
|
|
return; |
|
|
|
|
|
case 4: // parse Language ID |
|
|
|
|
|
if (enumbuf[4] < 4 || enumbuf[5] != 3) { |
|
|
|
|
|
dev->enum_state = 11; |
|
|
|
|
|
} else { |
|
|
|
|
|
dev->LanguageID = enumbuf[6] | (enumbuf[7] << 8); |
|
|
|
|
|
if (enumbuf[0]) dev->enum_state = 5; |
|
|
|
|
|
else if (enumbuf[1]) dev->enum_state = 7; |
|
|
|
|
|
else if (enumbuf[2]) dev->enum_state = 9; |
|
|
|
|
|
else dev->enum_state = 11; |
|
|
|
|
|
} |
|
|
|
|
|
break; |
|
|
|
|
|
case 5: // request Manufacturer string |
|
|
|
|
|
len = sizeof(enumbuf) - 4; |
|
|
|
|
|
mk_setup(dev->setup, 0x80, 6, 0x0300 | enumbuf[0], dev->LanguageID, len); |
|
|
|
|
|
new_Transfer(dev->control_pipe, enumbuf + 4, len); |
|
|
|
|
|
dev->enum_state = 6; |
|
|
|
|
|
return; |
|
|
|
|
|
case 6: // parse Manufacturer string |
|
|
|
|
|
// TODO: receive the string... |
|
|
|
|
|
if (enumbuf[1]) dev->enum_state = 7; |
|
|
|
|
|
else if (enumbuf[2]) dev->enum_state = 9; |
|
|
|
|
|
else dev->enum_state = 11; |
|
|
|
|
|
break; |
|
|
|
|
|
case 7: // request Product string |
|
|
|
|
|
len = sizeof(enumbuf) - 4; |
|
|
|
|
|
mk_setup(dev->setup, 0x80, 6, 0x0300 | enumbuf[1], dev->LanguageID, len); |
|
|
|
|
|
new_Transfer(dev->control_pipe, enumbuf + 4, len); |
|
|
|
|
|
dev->enum_state = 8; |
|
|
|
|
|
return; |
|
|
|
|
|
case 8: // parse Product string |
|
|
|
|
|
// TODO: receive the string... |
|
|
|
|
|
if (enumbuf[2]) dev->enum_state = 9; |
|
|
|
|
|
else dev->enum_state = 11; |
|
|
|
|
|
break; |
|
|
|
|
|
case 9: // request Serial Number string |
|
|
|
|
|
len = sizeof(enumbuf) - 4; |
|
|
|
|
|
mk_setup(dev->setup, 0x80, 6, 0x0300 | enumbuf[2], dev->LanguageID, len); |
|
|
|
|
|
new_Transfer(dev->control_pipe, enumbuf + 4, len); |
|
|
|
|
|
dev->enum_state = 10; |
|
|
|
|
|
return; |
|
|
|
|
|
case 10: // parse Serial Number string |
|
|
|
|
|
// TODO: receive the string... |
|
|
|
|
|
dev->enum_state = 11; |
|
|
|
|
|
break; |
|
|
|
|
|
case 11: // request first 9 bytes of config desc |
|
|
|
|
|
mk_setup(dev->setup, 0x80, 6, 0x0200, 0, 9); // 6=GET_DESCRIPTOR |
|
|
|
|
|
new_Transfer(dev->control_pipe, enumbuf, 9); |
|
|
|
|
|
dev->enum_state = 12; |
|
|
|
|
|
return; |
|
|
|
|
|
case 12: // read 9 bytes, request all of config desc |
|
|
|
|
|
len = enumbuf[2] | (enumbuf[3] << 8); |
|
|
|
|
|
Serial.print("Config data length = "); |
|
|
|
|
|
Serial.println(len); |
|
|
|
|
|
if (len > sizeof(enumbuf)) { |
|
|
|
|
|
// TODO: how to handle device with too much config data |
|
|
|
|
|
} |
|
|
|
|
|
mk_setup(dev->setup, 0x80, 6, 0x0200, 0, len); // 6=GET_DESCRIPTOR |
|
|
|
|
|
new_Transfer(dev->control_pipe, enumbuf, len); |
|
|
|
|
|
dev->enum_state = 13; |
|
|
|
|
|
return; |
|
|
|
|
|
case 13: // read all config desc, send set config |
|
|
|
|
|
Serial.print("bNumInterfaces = "); |
|
|
|
|
|
Serial.println(enumbuf[4]); |
|
|
|
|
|
Serial.print("bConfigurationValue = "); |
|
|
|
|
|
Serial.println(enumbuf[5]); |
|
|
|
|
|
// TODO: actually do something with interface descriptor? |
|
|
|
|
|
mk_setup(dev->setup, 0, 9, enumbuf[5], 0, 0); // 9=SET_CONFIGURATION |
|
|
|
|
|
new_Transfer(dev->control_pipe, NULL, 0); |
|
|
|
|
|
dev->enum_state = 14; |
|
|
|
|
|
return; |
|
|
|
|
|
case 14: // device is now configured |
|
|
|
|
|
// TODO: initialize drivers?? |
|
|
|
|
|
dev->enum_state = 15; |
|
|
|
|
|
return; |
|
|
|
|
|
case 15: // control transfers for other stuff?? |
|
|
|
|
|
default: |
|
|
|
|
|
return; |
|
|
} |
|
|
} |
|
|
mk_setup(dev->setup, 0x80, 6, 0x0200, 0, len); // 6=GET_DESCRIPTOR |
|
|
|
|
|
new_Transfer(dev->control_pipe, enumbuf, len); |
|
|
|
|
|
dev->enum_state = 4; |
|
|
|
|
|
break; |
|
|
|
|
|
case 4: // read all config desc, send set config |
|
|
|
|
|
Serial.print("bNumInterfaces = "); |
|
|
|
|
|
Serial.println(enumbuf[4]); |
|
|
|
|
|
Serial.print("bConfigurationValue = "); |
|
|
|
|
|
Serial.println(enumbuf[5]); |
|
|
|
|
|
// TODO: actually do something with interface descriptor? |
|
|
|
|
|
mk_setup(dev->setup, 0, 9, enumbuf[5], 0, 0); // 9=SET_CONFIGURATION |
|
|
|
|
|
new_Transfer(dev->control_pipe, NULL, 0); |
|
|
|
|
|
dev->enum_state = 5; |
|
|
|
|
|
break; |
|
|
|
|
|
case 5: // device is now configured |
|
|
|
|
|
// TODO: initialize drivers?? |
|
|
|
|
|
dev->enum_state = 6; |
|
|
|
|
|
break; |
|
|
|
|
|
case 6: // control transfers for other stuff?? |
|
|
|
|
|
default: |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
uint32_t assign_addr(void) |
|
|
uint32_t assign_addr(void) |