From 1494a02918da165d417388f9b1541817de2e2026 Mon Sep 17 00:00:00 2001 From: PaulStoffregen Date: Fri, 25 May 2018 05:12:36 -0700 Subject: [PATCH] Print USB descriptors in debug output --- USBHost_t36.h | 6 ++ enumeration.cpp | 8 ++- print.cpp | 144 ++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 156 insertions(+), 2 deletions(-) diff --git a/USBHost_t36.h b/USBHost_t36.h index 4ae2669..68d5b10 100644 --- a/USBHost_t36.h +++ b/USBHost_t36.h @@ -309,6 +309,9 @@ protected: static void print_(const Pipe_t *pipe); static void print_driverlist(const char *name, const USBDriver *driver); 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_(const char *s) { Serial.print(s); } static void print_(int n) { Serial.print(n); } @@ -347,6 +350,9 @@ protected: static void print_(const Pipe_t *pipe) {} static void print_driverlist(const char *name, const USBDriver *driver) {} 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_(const char *s) {} static void print_(int n) {} diff --git a/enumeration.cpp b/enumeration.cpp index 0b49bf2..851bef9 100644 --- a/enumeration.cpp +++ b/enumeration.cpp @@ -183,6 +183,7 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 2; return; case 2: // parse 18 device desc bytes + print_device_descriptor(enumbuf); dev->bDeviceClass = enumbuf[4]; dev->bDeviceSubClass = enumbuf[5]; dev->bDeviceProtocol = enumbuf[6]; @@ -221,6 +222,7 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 6; return; case 6: // parse Manufacturer string + print_string_descriptor("Manufacturer: ", enumbuf + 4); convertStringDescriptorToASCIIString(0, dev, transfer); // TODO: receive the string... if (enumbuf[1]) dev->enum_state = 7; @@ -234,6 +236,7 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 8; return; case 8: // parse Product string + print_string_descriptor("Product: ", enumbuf + 4); convertStringDescriptorToASCIIString(1, dev, transfer); if (enumbuf[2]) dev->enum_state = 9; else dev->enum_state = 11; @@ -245,6 +248,7 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 10; return; case 10: // parse Serial Number string + print_string_descriptor("Serial Number: ", enumbuf + 4); convertStringDescriptorToASCIIString(2, dev, transfer); dev->enum_state = 11; break; @@ -257,6 +261,7 @@ void USBHost::enumeration(const Transfer_t *transfer) enumlen = enumbuf[2] | (enumbuf[3] << 8); println("Config data length = ", enumlen); if (enumlen > sizeof(enumbuf)) { + enumlen = sizeof(enumbuf); // TODO: how to handle device with too much config data } mk_setup(enumsetup, 0x80, 6, 0x0200, 0, enumlen); // 6=GET_DESCRIPTOR @@ -264,8 +269,7 @@ void USBHost::enumeration(const Transfer_t *transfer) dev->enum_state = 13; return; 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->bMaxPower = enumbuf[8]; // TODO: actually do something with interface descriptor? diff --git a/print.cpp b/print.cpp index bf4d6ae..1d7ae01 100644 --- a/print.cpp +++ b/print.cpp @@ -172,6 +172,150 @@ void USBHost::print_qh_list(const Pipe_t *list) 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) { if (ptr == NULL || len == 0) return;