Request string descriptors during enumeration

This commit is contained in:
PaulStoffregen 2017-02-10 18:06:35 -08:00
parent 6122604f55
commit 03fb64e1ab
2 changed files with 147 additions and 48 deletions

27
host.h
View File

@ -60,6 +60,12 @@ struct Device_struct {
uint8_t hub_address;
uint8_t hub_port;
uint8_t enum_state;
uint8_t bDeviceClass;
uint8_t bDeviceSubClass;
uint8_t bDeviceProtocol;
uint16_t idVendor;
uint16_t idProduct;
uint16_t LanguageID;
};
struct Pipe_struct {
@ -108,4 +114,25 @@ void free_Pipe(Pipe_t *q);
Transfer_t * allocate_Transfer(void);
void free_Transfer(Transfer_t *q);
class USBHostDriver {
public:
virtual bool claim_device(Device_t *device) {
return false;
}
virtual bool claim_interface(Device_t *device) {
return false;
}
virtual void disconnect() {
}
};
class USBHub : public USBHostDriver {
};
#endif

View File

@ -330,7 +330,7 @@ void mk_setup(setup_t &s, uint32_t bmRequestType, uint32_t bRequest,
s.word2 = wIndex | (wLength << 16);
}
static uint8_t enumbuf[255];
static uint8_t enumbuf[256] __attribute__ ((aligned(16)));
void enumeration(const Transfer_t *transfer)
{
@ -341,55 +341,127 @@ void enumeration(const Transfer_t *transfer)
//print(transfer);
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)