Print USB descriptors in debug output

This commit is contained in:
PaulStoffregen 2018-05-25 05:12:36 -07:00
parent fd4842d94b
commit 1494a02918
3 changed files with 156 additions and 2 deletions

View File

@ -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) {}

View File

@ -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?

144
print.cpp
View File

@ -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;