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_qh_list(const Pipe_t *list); | ||||
static void print_device_descriptor(const uint8_t *p); | |||||
static void print_config_descriptor(const uint8_t *p, uint32_t maxlen); | |||||
static void print_string_descriptor(const char *name, const uint8_t *p); | |||||
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); } | ||||
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_qh_list(const Pipe_t *list) {} | ||||
static void print_device_descriptor(const uint8_t *p) {} | |||||
static void print_config_descriptor(const uint8_t *p, uint32_t maxlen) {} | |||||
static void print_string_descriptor(const char *name, const uint8_t *p) {} | |||||
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) {} | static void print_(const char *s) {} | ||||
static void print_(int n) {} | static void print_(int n) {} |
dev->enum_state = 2; | dev->enum_state = 2; | ||||
return; | return; | ||||
case 2: // parse 18 device desc bytes | case 2: // parse 18 device desc bytes | ||||
print_device_descriptor(enumbuf); | |||||
dev->bDeviceClass = enumbuf[4]; | dev->bDeviceClass = enumbuf[4]; | ||||
dev->bDeviceSubClass = enumbuf[5]; | dev->bDeviceSubClass = enumbuf[5]; | ||||
dev->bDeviceProtocol = enumbuf[6]; | dev->bDeviceProtocol = enumbuf[6]; | ||||
dev->enum_state = 6; | dev->enum_state = 6; | ||||
return; | return; | ||||
case 6: // parse Manufacturer string | case 6: // parse Manufacturer string | ||||
print_string_descriptor("Manufacturer: ", enumbuf + 4); | |||||
convertStringDescriptorToASCIIString(0, dev, transfer); | convertStringDescriptorToASCIIString(0, dev, transfer); | ||||
// TODO: receive the string... | // TODO: receive the string... | ||||
if (enumbuf[1]) dev->enum_state = 7; | if (enumbuf[1]) dev->enum_state = 7; | ||||
dev->enum_state = 8; | dev->enum_state = 8; | ||||
return; | return; | ||||
case 8: // parse Product string | case 8: // parse Product string | ||||
print_string_descriptor("Product: ", enumbuf + 4); | |||||
convertStringDescriptorToASCIIString(1, dev, transfer); | convertStringDescriptorToASCIIString(1, dev, transfer); | ||||
if (enumbuf[2]) dev->enum_state = 9; | if (enumbuf[2]) dev->enum_state = 9; | ||||
else dev->enum_state = 11; | else dev->enum_state = 11; | ||||
dev->enum_state = 10; | dev->enum_state = 10; | ||||
return; | return; | ||||
case 10: // parse Serial Number string | case 10: // parse Serial Number string | ||||
print_string_descriptor("Serial Number: ", enumbuf + 4); | |||||
convertStringDescriptorToASCIIString(2, dev, transfer); | convertStringDescriptorToASCIIString(2, dev, transfer); | ||||
dev->enum_state = 11; | dev->enum_state = 11; | ||||
break; | break; | ||||
enumlen = enumbuf[2] | (enumbuf[3] << 8); | enumlen = enumbuf[2] | (enumbuf[3] << 8); | ||||
println("Config data length = ", enumlen); | println("Config data length = ", enumlen); | ||||
if (enumlen > sizeof(enumbuf)) { | if (enumlen > sizeof(enumbuf)) { | ||||
enumlen = sizeof(enumbuf); | |||||
// TODO: how to handle device with too much config data | // TODO: how to handle device with too much config data | ||||
} | } | ||||
mk_setup(enumsetup, 0x80, 6, 0x0200, 0, enumlen); // 6=GET_DESCRIPTOR | mk_setup(enumsetup, 0x80, 6, 0x0200, 0, enumlen); // 6=GET_DESCRIPTOR | ||||
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 | ||||
println("bNumInterfaces = ", enumbuf[4]); | |||||
println("bConfigurationValue = ", enumbuf[5]); | |||||
print_config_descriptor(enumbuf, sizeof(enumbuf)); | |||||
dev->bmAttributes = enumbuf[7]; | dev->bmAttributes = enumbuf[7]; | ||||
dev->bMaxPower = enumbuf[8]; | dev->bMaxPower = enumbuf[8]; | ||||
// TODO: actually do something with interface descriptor? | // TODO: actually do something with interface descriptor? |
Serial.println(); | Serial.println(); | ||||
} | } | ||||
static void print_class_subclass_protocol(uint8_t c, uint8_t s, uint8_t p) | |||||
{ | |||||
Serial.print(c); | |||||
if (c == 3) Serial.print("(HID)"); | |||||
if (c == 8) Serial.print("(Mass Storage)"); | |||||
if (c == 9) Serial.print("(Hub)"); | |||||
Serial.print(" / "); | |||||
Serial.print(s); | |||||
if (c == 3 && s == 1) Serial.print("(Boot)"); | |||||
if (c == 8 && s == 6) Serial.print("(SCSI)"); | |||||
Serial.print(" / "); | |||||
Serial.print(p); | |||||
if (c == 3 && s == 1 && p == 1) Serial.print("(Keyboard)"); | |||||
if (c == 3 && s == 1 && p == 2) Serial.print("(Mouse)"); | |||||
if (c == 8 && s == 6 && p == 0x50) Serial.print("(Bulk Only)"); | |||||
if (c == 8 && s == 6 && p == 0x62) Serial.print("(UAS)"); | |||||
if (c == 9 && s == 0 && p == 1) Serial.print("(Single-TT)"); | |||||
if (c == 9 && s == 0 && p == 2) Serial.print("(Multi-TT)"); | |||||
Serial.println(); | |||||
} | |||||
void USBHost::print_device_descriptor(const uint8_t *p) | |||||
{ | |||||
Serial.println("Device Descriptor:"); | |||||
Serial.print(" "); | |||||
print_hexbytes(p, p[0]); | |||||
if (p[0] != 18) { | |||||
Serial.println("error: device must be 18 bytes"); | |||||
return; | |||||
} | |||||
if (p[1] != 1) { | |||||
Serial.println("error: device must type 1"); | |||||
return; | |||||
} | |||||
Serial.printf(" VendorID = %04X, ProductID = %04X, Version = %04X", | |||||
p[8] | (p[9] << 8), p[10] | (p[11] << 8), p[12] | (p[13] << 8)); | |||||
Serial.println(); | |||||
Serial.print(" Class/Subclass/Protocol = "); | |||||
print_class_subclass_protocol(p[4], p[5], p[6]); | |||||
Serial.print(" Number of Configurations = "); | |||||
Serial.println(p[17]); | |||||
} | |||||
void USBHost::print_config_descriptor(const uint8_t *p, uint32_t maxlen) | |||||
{ | |||||
// Descriptor Types: (USB 2.0, page 251) | |||||
Serial.println("Configuration Descriptor:"); | |||||
Serial.print(" "); | |||||
print_hexbytes(p, p[0]); | |||||
if (p[0] != 9) { | |||||
Serial.println("error: config must be 9 bytes"); | |||||
return; | |||||
} | |||||
if (p[1] != 2) { | |||||
Serial.println("error: config must type 2"); | |||||
return; | |||||
} | |||||
Serial.print(" NumInterfaces = "); | |||||
Serial.println(p[4]); | |||||
Serial.print(" ConfigurationValue = "); | |||||
Serial.println(p[5]); | |||||
uint32_t len = p[2] | (p[3] << 8); | |||||
if (len > maxlen) len = maxlen; | |||||
len -= p[0]; | |||||
p += 9; | |||||
while (len > 0) { | |||||
if (p[0] > len) { | |||||
Serial.print(" "); | |||||
print_hexbytes(p, len); | |||||
Serial.println(" error: length beyond total data size"); | |||||
break; | |||||
} | |||||
Serial.print(" "); | |||||
print_hexbytes(p, p[0]); | |||||
if (p[0] == 9 && p[1] == 4) { // Interface Descriptor | |||||
Serial.print(" Interface = "); | |||||
Serial.println(p[2]); | |||||
Serial.print(" Number of endpoints = "); | |||||
Serial.println(p[4]); | |||||
Serial.print(" Class/Subclass/Protocol = "); | |||||
print_class_subclass_protocol(p[5], p[6], p[7]); | |||||
} else if (p[0] >= 7 && p[0] <= 9 && p[1] == 5) { // Endpoint Descriptor | |||||
Serial.print(" Endpoint = "); | |||||
Serial.print(p[2] & 15); | |||||
Serial.println((p[2] & 128) ? " IN" : " OUT"); | |||||
Serial.print(" Type = "); | |||||
switch (p[3] & 3) { | |||||
case 0: Serial.println("Control"); break; | |||||
case 1: Serial.println("Isochronous"); break; | |||||
case 2: Serial.println("Bulk"); break; | |||||
case 3: Serial.println("Interrupt"); break; | |||||
} | |||||
Serial.print(" Max Size = "); | |||||
Serial.println(p[4] | (p[5] << 8)); | |||||
Serial.print(" Polling Interval = "); | |||||
Serial.println(p[6]); | |||||
} else if (p[0] == 8 && p[1] == 11) { // IAD | |||||
Serial.print(" Interface Association = "); | |||||
Serial.print(p[2]); | |||||
Serial.print(" through "); | |||||
Serial.println(p[2] + p[3] - 1); | |||||
Serial.print(" Class / Subclass / Protocol = "); | |||||
print_class_subclass_protocol(p[4], p[5], p[7]); | |||||
} else if (p[0] >= 9 && p[1] == 0x21) { // HID | |||||
Serial.print(" HID, "); | |||||
Serial.print(p[5]); | |||||
Serial.print(" report descriptor"); | |||||
if (p[5] != 1) Serial.print('s'); | |||||
Serial.println(); | |||||
} | |||||
len -= p[0]; | |||||
p += p[0]; | |||||
} | |||||
} | |||||
void USBHost::print_string_descriptor(const char *name, const uint8_t *p) | |||||
{ | |||||
uint32_t len = p[0]; | |||||
if (len < 4) return; | |||||
Serial.print(name); | |||||
len -= 2; | |||||
p += 2; | |||||
while (len >= 2) { | |||||
uint32_t c = p[0] | (p[1] << 8); | |||||
if (c < 0x80) { | |||||
Serial.write(c); | |||||
} else if (c < 0x800) { | |||||
Serial.write((c >> 6) | 0xC0); | |||||
Serial.write((c & 0x3F) | 0x80); | |||||
} else { | |||||
Serial.write((c >> 12) | 0xE0); | |||||
Serial.write(((c >> 6) & 0x3F) | 0x80); | |||||
Serial.write((c & 0x3F) | 0x80); | |||||
} | |||||
len -= 2; | |||||
p += 2; | |||||
} | |||||
Serial.println(); | |||||
//print_hexbytes(p, p[0]); | |||||
} | |||||
void USBHost::print_hexbytes(const void *ptr, uint32_t len) | void USBHost::print_hexbytes(const void *ptr, uint32_t len) | ||||
{ | { | ||||
if (ptr == NULL || len == 0) return; | if (ptr == NULL || len == 0) return; |