538 lines
16 KiB
Diff
538 lines
16 KiB
Diff
|
--- usbutils-0.11/lsusb.c 2002-08-05 23:35:21.000000000 -0700
|
||
|
+++ usbutils/lsusb.c 2004-02-14 13:00:41.531597608 -0800
|
||
|
@@ -58,8 +58,8 @@
|
||
|
#define _GNU_SOURCE
|
||
|
#include <getopt.h>
|
||
|
|
||
|
-#define CTRL_RETRIES 50
|
||
|
-#define CTRL_TIMEOUT 100 /* milliseconds */
|
||
|
+#define CTRL_RETRIES 2
|
||
|
+#define CTRL_TIMEOUT (5*1000) /* milliseconds */
|
||
|
|
||
|
#define USB_DT_CS_DEVICE 0x21
|
||
|
#define USB_DT_CS_CONFIG 0x22
|
||
|
@@ -106,7 +106,6 @@ static int usb_control_msg(int fd, u_int
|
||
|
ctrl.value = value;
|
||
|
ctrl.index = index;
|
||
|
ctrl.length = size;
|
||
|
- ctrl.timeout = 1000;
|
||
|
ctrl.data = data;
|
||
|
ctrl.timeout = CTRL_TIMEOUT;
|
||
|
try = 0;
|
||
|
@@ -119,10 +118,11 @@ static int usb_control_msg(int fd, u_int
|
||
|
|
||
|
/* ---------------------------------------------------------------------- */
|
||
|
|
||
|
+static int dev_has_strings;
|
||
|
+
|
||
|
static int get_string(int fd, char *buf, size_t size, u_int8_t id, u_int16_t lang)
|
||
|
{
|
||
|
unsigned char b[256];
|
||
|
- wchar_t w[128];
|
||
|
unsigned int i;
|
||
|
int ret;
|
||
|
|
||
|
@@ -133,17 +133,38 @@ static int get_string(int fd, char *buf,
|
||
|
if (!id || fd == -1)
|
||
|
return 0;
|
||
|
|
||
|
- b[0] = b[1] = 0xbf;
|
||
|
- ret = usb_control_msg(fd, USB_DIR_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | id, 0, sizeof(b), b);
|
||
|
+ b[0] = b[1] = 0;
|
||
|
+
|
||
|
+ /* try reading all at once ... some devices misbehave here */
|
||
|
+ ret = usb_control_msg(fd, USB_DIR_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | id, lang, sizeof(b), b);
|
||
|
+ if (ret > 0)
|
||
|
+ goto got_all;
|
||
|
+
|
||
|
+ /* read string length first ... most devices handle this ok */
|
||
|
+ ret = usb_control_msg(fd, USB_DIR_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | id, lang, 2, b);
|
||
|
+ if (ret < 0) {
|
||
|
+ if (open_mode == O_RDWR)
|
||
|
+ fprintf(stderr, "cannot peek string descriptor %d, error = %s(%d)\n", id, strerror(errno), errno);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ if (ret < 2 || b[0] < 2 || b[1] != USB_DT_STRING) {
|
||
|
+ fprintf(stderr, "string descriptor %d invalid (%02x %02x; len=%d)\n", id, b[0], b[1], ret);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = usb_control_msg(fd, USB_DIR_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_STRING << 8) | id, lang, b[0], b);
|
||
|
if (ret < 0) {
|
||
|
if (open_mode == O_RDWR)
|
||
|
fprintf(stderr, "cannot get string descriptor %d, error = %s(%d)\n", id, strerror(errno), errno);
|
||
|
return 0;
|
||
|
}
|
||
|
+
|
||
|
+got_all:
|
||
|
if (ret < 2 || b[0] < 2 || b[1] != USB_DT_STRING) {
|
||
|
fprintf(stderr, "string descriptor %d invalid (%02x %02x; len=%d)\n", id, b[0], b[1], ret);
|
||
|
return 0;
|
||
|
}
|
||
|
+ dev_has_strings = 1;
|
||
|
#if 0
|
||
|
for (i = 0; i < ((b[0] - 2) / 2); i++)
|
||
|
w[i] = b[2+2*i] | (b[3+2*i] << 8);
|
||
|
@@ -151,7 +172,9 @@ static int get_string(int fd, char *buf,
|
||
|
return wcstombs(buf, w, size);
|
||
|
#else
|
||
|
for (i = 0; i < ((b[0] - 2) / 2); i++)
|
||
|
- buf[i] = b[2+2*i];
|
||
|
+ buf[i] = b[3+2*i]
|
||
|
+ ? '?' /* character's not available in iso-8859/1 */
|
||
|
+ : b[2+2*i];
|
||
|
buf[i] = 0;
|
||
|
return i;
|
||
|
#endif
|
||
|
@@ -297,21 +320,25 @@ static void dump_device(int fd, unsigned
|
||
|
dump_junk(buf, " ", 18);
|
||
|
}
|
||
|
|
||
|
-static void dump_config(int fd, unsigned char *buf)
|
||
|
+static void dump_config(int fd, unsigned char *buf, u_int16_t lang)
|
||
|
{
|
||
|
+ char str[128];
|
||
|
+
|
||
|
if (buf[1] != USB_DT_CONFIG)
|
||
|
printf(" Warning: Invalid descriptor\n");
|
||
|
else if (buf[0] < 9)
|
||
|
printf(" Warning: Descriptor too short\n");
|
||
|
+ get_string(fd, str, sizeof(str), buf[6], lang);
|
||
|
printf(" Configuration Descriptor:\n"
|
||
|
" bLength %5u\n"
|
||
|
" bDescriptorType %5u\n"
|
||
|
" wTotalLength %5u\n"
|
||
|
" bNumInterfaces %5u\n"
|
||
|
" bConfigurationValue %5u\n"
|
||
|
- " iConfiguration %5u\n"
|
||
|
+ " iConfiguration %5u %s\n"
|
||
|
" bmAttributes 0x%02x\n",
|
||
|
- buf[0], buf[1], buf[2] | (buf[3] << 8), buf[4], buf[5], buf[6], buf[7]);
|
||
|
+ buf[0], buf[1], buf[2] | (buf[3] << 8), buf[4], buf[5],
|
||
|
+ buf[6], str, buf[7]);
|
||
|
if (buf[7] & 0x40)
|
||
|
printf(" Self Powered\n");
|
||
|
if (buf[7] & 0x20)
|
||
|
@@ -352,6 +379,9 @@ static void dump_endpoint(int fd, unsign
|
||
|
{
|
||
|
static const char *typeattr[] = { "Control", "Isochronous", "Bulk", "Interrupt" };
|
||
|
static const char *syncattr[] = { "none", "Asynchronous", "Adaptive", "Synchronous" };
|
||
|
+ static const char *usage[] = { "Data", "Feedback", "Implicit feedback Data", "(reserved)" };
|
||
|
+ static const char *hb[] = { "once", "twice", "three times", "(?)" };
|
||
|
+ unsigned wMaxPacket = buf[4] | (buf[5] << 8);
|
||
|
|
||
|
if (buf[1] != USB_DT_ENDPOINT)
|
||
|
printf(" Warning: Invalid descriptor\n");
|
||
|
@@ -364,15 +394,19 @@ static void dump_endpoint(int fd, unsign
|
||
|
" bmAttributes %5u\n"
|
||
|
" Transfer Type %s\n"
|
||
|
" Synch Type %s\n"
|
||
|
- " wMaxPacketSize %5u\n"
|
||
|
+ " Usage Type %s\n"
|
||
|
+ " wMaxPacketSize 0x%04x bytes %d %s\n"
|
||
|
" bInterval %5u\n",
|
||
|
buf[0], buf[1], buf[2], buf[2] & 15, (buf[2] & 0x80) ? "IN" : "OUT",
|
||
|
buf[3], typeattr[buf[3] & 3], syncattr[(buf[3] >> 2) & 3],
|
||
|
- buf[4] | (buf[5] << 8), buf[6]);
|
||
|
+ usage[(buf[3] >> 4) & 3],
|
||
|
+ wMaxPacket, wMaxPacket & 0x3ff, hb [(wMaxPacket >> 11) & 3],
|
||
|
+ buf[6]);
|
||
|
if (buf[0] < 9) {
|
||
|
dump_junk(buf, " ", 7);
|
||
|
return;
|
||
|
}
|
||
|
+ /* only for audio endpoints */
|
||
|
printf(" bRefresh %5u\n"
|
||
|
" bSynchAddress %5u\n",
|
||
|
buf[7], buf[8]);
|
||
|
@@ -1017,23 +1051,53 @@ static void dump_midistreaming_endpoint(
|
||
|
dump_junk(buf, " ", 4+buf[3]);
|
||
|
}
|
||
|
|
||
|
-
|
||
|
-static void dump_hub(char *p)
|
||
|
+static void dump_hub(char *prefix, unsigned char *p, int has_tt)
|
||
|
{
|
||
|
unsigned int l, i, j;
|
||
|
+ unsigned wHubChar = (p[4] << 8) | p[3];
|
||
|
|
||
|
- printf(" Hub Descriptor:\n");
|
||
|
- printf(" bLength %3u\n",p[0]);
|
||
|
- printf(" bDesriptorType %3u\n",p[1]);
|
||
|
- printf(" nNbrPorts %3u\n",p[2]);
|
||
|
- printf(" wHubCharacteristic 0x%02x 0x%02x\n", p[3],p[4]);
|
||
|
- printf(" bPwrOn2PwrGood %3u * 2 milli seconds\n",p[5]);
|
||
|
- printf(" bHubContrCurrent %3u milli Ampere\n",p[6]);
|
||
|
+ printf("%sHub Descriptor:\n", prefix);
|
||
|
+ printf("%s bLength %3u\n", prefix, p[0]);
|
||
|
+ printf("%s bDescriptorType %3u\n", prefix, p[1]);
|
||
|
+ printf("%s nNbrPorts %3u\n", prefix, p[2]);
|
||
|
+ printf("%s wHubCharacteristic 0x%04x\n", prefix, wHubChar);
|
||
|
+ switch (wHubChar & 0x03) {
|
||
|
+ case 0:
|
||
|
+ printf("%s Ganged power switching\n", prefix);
|
||
|
+ break;
|
||
|
+ case 1:
|
||
|
+ printf("%s Per-port power switching\n", prefix);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ printf("%s No power switching (usb 1.0)\n", prefix);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (wHubChar & 0x04)
|
||
|
+ printf("%s Compound device\n", prefix);
|
||
|
+ switch ((wHubChar >> 3) & 0x03) {
|
||
|
+ case 0:
|
||
|
+ printf("%s Ganged overcurrent protection\n", prefix);
|
||
|
+ break;
|
||
|
+ case 1:
|
||
|
+ printf("%s Per-port overcurrent protection\n", prefix);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ printf("%s No overcurrent protection\n", prefix);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ if (has_tt) {
|
||
|
+ l = (wHubChar >> 5) & 0x03;
|
||
|
+ printf("%s TT think time %d FS bits\n", prefix, (l + 1) * 8);
|
||
|
+ }
|
||
|
+ if (wHubChar & (1<<7))
|
||
|
+ printf("%s Port indicators\n", prefix);
|
||
|
+ printf("%s bPwrOn2PwrGood %3u * 2 milli seconds\n", prefix, p[5]);
|
||
|
+ printf("%s bHubContrCurrent %3u milli Ampere\n", prefix, p[6]);
|
||
|
l= (p[2] >> 3) + 1; /* this determines the variable number of bytes following */
|
||
|
- printf(" DeviceRemovable ");
|
||
|
+ printf("%s DeviceRemovable ", prefix);
|
||
|
for(i = 0; i < l; i++)
|
||
|
printf(" 0x%02x", p[7+i]);
|
||
|
- printf("\n PortPwrCtrlMask ");
|
||
|
+ printf("\n%s PortPwrCtrlMask ", prefix);
|
||
|
for(j = 0; j < l; j++)
|
||
|
printf(" 0x%02x ", p[7+i+j]);
|
||
|
printf("\n");
|
||
|
@@ -1047,7 +1111,7 @@ static void dump_hub(char *p)
|
||
|
|
||
|
static void dump_report_desc(unsigned char *b, int l)
|
||
|
{
|
||
|
- unsigned int t, j, bsize, btag, btype, data, hut;
|
||
|
+ unsigned int t, j, bsize, btag, btype, data = 1000, hut = 1000;
|
||
|
int i;
|
||
|
char *types[4] = { "Main", "Global", "Local", "reserved" };
|
||
|
char indent[] = " ";
|
||
|
@@ -1168,21 +1232,131 @@ static void dump_hid_device(int fd, unsi
|
||
|
}
|
||
|
}
|
||
|
|
||
|
+static char *
|
||
|
+dump_comm_descriptor(int fd, unsigned char *buf, char *indent, u_int16_t lang)
|
||
|
+{
|
||
|
+ int tmp;
|
||
|
+ char str [128];
|
||
|
+
|
||
|
+ switch (buf[2]) {
|
||
|
+ case 0:
|
||
|
+ if (buf[0] != 5)
|
||
|
+ goto bad;
|
||
|
+ printf( "%sCDC Header:\n"
|
||
|
+ "%s bcdCDC %x.%02x\n",
|
||
|
+ indent,
|
||
|
+ indent, buf[4], buf[3]);
|
||
|
+ break;
|
||
|
+ case 0x01: /* call management functional desc */
|
||
|
+ if (buf [0] != 5)
|
||
|
+ goto bad;
|
||
|
+ printf( "%sCDC Call Management:\n"
|
||
|
+ "%s bmCapabilities 0x%02x\n",
|
||
|
+ indent,
|
||
|
+ indent, buf[3]);
|
||
|
+ if (buf[3] & 0x01)
|
||
|
+ printf( "%s call management\n", indent);
|
||
|
+ if (buf[3] & 0x02)
|
||
|
+ printf( "%s use DataInterface\n", indent);
|
||
|
+ printf("%s bDataInterface %d\n", indent, buf[4]);
|
||
|
+ break;
|
||
|
+ case 0x02: /* acm functional desc */
|
||
|
+ if (buf [0] != 4)
|
||
|
+ goto bad;
|
||
|
+ printf( "%sCDC ACM:\n"
|
||
|
+ "%s bmCapabilities %02x\n",
|
||
|
+ indent,
|
||
|
+ indent, buf[3]);
|
||
|
+ if (buf[3] & 0x08)
|
||
|
+ printf( "%s connection notifications\n", indent);
|
||
|
+ if (buf[3] & 0x04)
|
||
|
+ printf( "%s sends break\n", indent);
|
||
|
+ if (buf[3] & 0x02)
|
||
|
+ printf( "%s line coding and serial state\n", indent);
|
||
|
+ if (buf[3] & 0x01)
|
||
|
+ printf( "%s get/set/clear comm features\n", indent);
|
||
|
+ break;
|
||
|
+ case 0x06: /* union desc */
|
||
|
+ if (buf [0] < 5)
|
||
|
+ goto bad;
|
||
|
+ printf( "%sCDC Union:\n"
|
||
|
+ "%s bMasterInterface %d\n"
|
||
|
+ "%s bSlaveInterface ",
|
||
|
+ indent,
|
||
|
+ indent, buf [3],
|
||
|
+ indent);
|
||
|
+ for (tmp = 4; tmp < buf [0]; tmp++)
|
||
|
+ printf("%d ", buf [tmp]);
|
||
|
+ printf("\n");
|
||
|
+ break;
|
||
|
+ case 0x0f: /* ethernet functional desc */
|
||
|
+ if (buf [0] != 13)
|
||
|
+ goto bad;
|
||
|
+ get_string(fd, str, sizeof str, buf[3], lang);
|
||
|
+ tmp = buf [7] << 8;
|
||
|
+ tmp |= buf [6]; tmp <<= 8;
|
||
|
+ tmp |= buf [5]; tmp <<= 8;
|
||
|
+ tmp |= buf [4];
|
||
|
+ printf( "%sCDC Ethernet:\n"
|
||
|
+ "%s iMacAddress %d %s\n"
|
||
|
+ "%s bmEthernetStatistics 0x%08x\n",
|
||
|
+ indent,
|
||
|
+ indent, buf[3], (buf[3] && *str) ? str : "(?)",
|
||
|
+ indent, tmp);
|
||
|
+ /* FIXME dissect ALL 28 bits */
|
||
|
+ printf( "%s wMaxSegmentSize %d\n"
|
||
|
+ "%s wNumberMCFilters 0x%04x\n"
|
||
|
+ "%s bNumberPowerFilters %d\n",
|
||
|
+ indent, (buf[9]<<8)|buf[8],
|
||
|
+ indent, (buf[11]<<8)|buf[10],
|
||
|
+ indent, buf[12]);
|
||
|
+ break;
|
||
|
+ /* FIXME there are about a dozen more descriptor types */
|
||
|
+ default:
|
||
|
+ return "unsupported comm descriptor";
|
||
|
+ }
|
||
|
+ return 0;
|
||
|
+
|
||
|
+bad:
|
||
|
+ return "corrupt comm descriptor";
|
||
|
+}
|
||
|
+
|
||
|
/* ---------------------------------------------------------------------- */
|
||
|
|
||
|
+static void do_hub(int fd, int has_tt)
|
||
|
+{
|
||
|
+ unsigned char buf [7];
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ ret = usb_control_msg(fd, USB_DIR_IN | USB_TYPE_CLASS,
|
||
|
+ USB_REQ_GET_DESCRIPTOR, 0x29 << 8, 0,
|
||
|
+ sizeof buf, buf);
|
||
|
+ if (ret != sizeof buf) {
|
||
|
+ perror ("can't get hub descriptor");
|
||
|
+ return;
|
||
|
+ }
|
||
|
+ dump_hub("", buf, has_tt);
|
||
|
+}
|
||
|
+
|
||
|
static void do_config(int fd, unsigned int nr, u_int16_t lang)
|
||
|
{
|
||
|
- unsigned char buf[1024],*p;
|
||
|
- unsigned int sz,curinterface;
|
||
|
- int l;
|
||
|
+ unsigned char buf[1024],*p, *err;
|
||
|
+ unsigned int sz,curinterface = 1000;
|
||
|
u_int8_t curclass = 0xff, cursubclass = 0xff;
|
||
|
+ unsigned retries = 0;
|
||
|
|
||
|
+ for (;;) {
|
||
|
if (usb_control_msg(fd, USB_DIR_IN, USB_REQ_GET_DESCRIPTOR, (USB_DT_CONFIG << 8) | nr,
|
||
|
0, USB_DT_CONFIG_SIZE, buf) < 0) {
|
||
|
+ if (retries++ >= 5) {
|
||
|
if (open_mode == O_RDWR)
|
||
|
fprintf(stdout, "cannot get config descriptor %d, %s (%d)\n", nr, strerror(errno), errno);
|
||
|
return;
|
||
|
+ }
|
||
|
+ continue;
|
||
|
+ } else break;
|
||
|
}
|
||
|
+
|
||
|
if (buf[0] < USB_DT_CONFIG_SIZE || buf[1] != USB_DT_CONFIG)
|
||
|
fprintf(stderr, "Warning: invalid config descriptor\n");
|
||
|
sz = buf[2] | buf[3] << 8;
|
||
|
@@ -1208,13 +1382,14 @@ static void do_config(int fd, unsigned i
|
||
|
}
|
||
|
switch (p[1]) {
|
||
|
case USB_DT_DEVICE:
|
||
|
+ /* NOTE: should NOT be found here! */
|
||
|
dump_device(fd, p, lang);
|
||
|
curclass = p[4];
|
||
|
cursubclass = p[5];
|
||
|
break;
|
||
|
|
||
|
case USB_DT_CONFIG:
|
||
|
- dump_config(fd, p);
|
||
|
+ dump_config(fd, p, lang);
|
||
|
break;
|
||
|
|
||
|
case USB_DT_INTERFACE:
|
||
|
@@ -1229,39 +1404,39 @@ static void do_config(int fd, unsigned i
|
||
|
break;
|
||
|
|
||
|
case USB_DT_CS_DEVICE:
|
||
|
- if (curclass == 3) {
|
||
|
+ if (curclass == USB_CLASS_HID) {
|
||
|
dump_hid_device(fd, p, curinterface);
|
||
|
break;
|
||
|
}
|
||
|
- printf(" unknown descriptor type:");
|
||
|
- dump_junk2(p, p[0]);
|
||
|
- break;
|
||
|
-
|
||
|
- case USB_DT_CS_CONFIG:
|
||
|
- printf(" unknown descriptor type:");
|
||
|
- dump_junk2(p, p[0]);
|
||
|
- break;
|
||
|
-
|
||
|
- case USB_DT_CS_STRING:
|
||
|
- printf(" unknown descriptor type:");
|
||
|
- dump_junk2(p, p[0]);
|
||
|
- break;
|
||
|
+ err = "unknown device class descriptor";
|
||
|
+ goto junk;
|
||
|
|
||
|
case USB_DT_CS_INTERFACE:
|
||
|
- if (curclass == 1 && cursubclass == 1) {
|
||
|
- dump_audiocontrol_interface(fd, p, lang);
|
||
|
+ err = "unknown interface class descriptor";
|
||
|
+ switch (curclass) {
|
||
|
+ case USB_CLASS_AUDIO:
|
||
|
+ switch (cursubclass) {
|
||
|
+ case 1:
|
||
|
+ dump_audiocontrol_interface(fd, p, lang);
|
||
|
+ break;
|
||
|
+ case 2:
|
||
|
+ dump_audiostreaming_interface(fd, p);
|
||
|
+ break;
|
||
|
+ case 3:
|
||
|
+ dump_midistreaming_interface(fd, p, lang);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ goto junk;
|
||
|
+ }
|
||
|
break;
|
||
|
- }
|
||
|
- if (curclass == 1 && cursubclass == 2) {
|
||
|
- dump_audiostreaming_interface(fd, p);
|
||
|
- break;
|
||
|
- }
|
||
|
- if (curclass == 1 && cursubclass == 3) {
|
||
|
- dump_midistreaming_interface(fd, p, lang);
|
||
|
+ case USB_CLASS_COMM:
|
||
|
+ err = dump_comm_descriptor (fd, p, " ", lang);
|
||
|
+ if (err)
|
||
|
+ goto junk;
|
||
|
break;
|
||
|
+ default:
|
||
|
+ goto junk;
|
||
|
}
|
||
|
- printf(" unknown descriptor type:");
|
||
|
- dump_junk2(p, p[0]);
|
||
|
break;
|
||
|
|
||
|
case USB_DT_CS_ENDPOINT:
|
||
|
@@ -1273,16 +1448,20 @@ static void do_config(int fd, unsigned i
|
||
|
dump_midistreaming_endpoint(fd, p);
|
||
|
break;
|
||
|
}
|
||
|
- printf(" unknown descriptor type:");
|
||
|
- dump_junk2(p, p[0]);
|
||
|
- break;
|
||
|
+ err = "unknown endpoint class descriptor";
|
||
|
+ goto junk;
|
||
|
|
||
|
case USB_DT_HUB:
|
||
|
- dump_hub(p);
|
||
|
+ /* NOTE only rather ancient hubs will include
|
||
|
+ * this with the config descriptor.
|
||
|
+ */
|
||
|
+ dump_hub(" ", p, 0);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
- printf(" unknown descriptor type:");
|
||
|
+ err = "unknown descriptor type";
|
||
|
+junk:
|
||
|
+ printf(" %s:", err);
|
||
|
dump_junk2(p, p[0]);
|
||
|
}
|
||
|
sz -= p[0];
|
||
|
@@ -1303,21 +1482,41 @@ static u_int16_t dump_langids(int fd, in
|
||
|
int i, l;
|
||
|
u_int16_t lang;
|
||
|
|
||
|
- b[0] = b[1] = 0xbf;
|
||
|
- l = usb_control_msg(fd, USB_DIR_IN, USB_REQ_GET_DESCRIPTOR, USB_DT_STRING << 8, 0, sizeof(b), b);
|
||
|
+ /* read string length first, like recent linuxes -- else some devices misbehave */
|
||
|
+ b[0] = b[1] = 0;
|
||
|
+ l = usb_control_msg(fd, USB_DIR_IN, USB_REQ_GET_DESCRIPTOR, USB_DT_STRING << 8, 0, 4, b);
|
||
|
|
||
|
+ if (l < 0 && errno == EPIPE)
|
||
|
+ l = 0;
|
||
|
if (l < 0) {
|
||
|
- if (open_mode == O_RDWR)
|
||
|
+ if (open_mode == O_RDWR && !quiet)
|
||
|
printf(" Language IDs: none (cannot get min. string descriptor; got len=%d, error=%d:%s)\n",
|
||
|
l, errno, strerror(errno));
|
||
|
return 0;
|
||
|
}
|
||
|
- if (l < 4 || b[0] != l) {
|
||
|
+ if (l == 0) {
|
||
|
+ if (!quiet)
|
||
|
+ printf(" Language IDs: none\n");
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ if (l < 4) {
|
||
|
+ if (!quiet)
|
||
|
printf(" Language IDs: none (invalid length string descriptor %02x; len=%d)\n", b[0], l);
|
||
|
return 0;
|
||
|
}
|
||
|
/* save first language ID for further get_string_descriptors */
|
||
|
lang = b[2] | (b[3] << 8);
|
||
|
+
|
||
|
+ /* maybe there's more than one */
|
||
|
+ if (b[0] > 4) {
|
||
|
+ l = usb_control_msg(fd, USB_DIR_IN, USB_REQ_GET_DESCRIPTOR, USB_DT_STRING << 8, 0, b[0], b);
|
||
|
+ if (l < 4 || b[0] != l) {
|
||
|
+ fprintf(stderr, "string 0 broken re-read, l = %d, b[0] = %d \n", l, b[0]);
|
||
|
+ b[0] = 4;
|
||
|
+ b[2] = lang;
|
||
|
+ b[3] = lang >> 8;
|
||
|
+ }
|
||
|
+ }
|
||
|
#if 0
|
||
|
printf ("dump_langids: ret=%d:%d, lang=0x%x, length=%d\n", l, errno, lang, b[0]);
|
||
|
dump_junk2 (b, 32);
|
||
|
@@ -1342,11 +1541,17 @@ static void dumpdev(unsigned char *devde
|
||
|
maxcfg = devdesc[17];
|
||
|
if (devdesc[0] < 18 || devdesc[1] != USB_DT_DEVICE)
|
||
|
maxcfg = 1;
|
||
|
+ dev_has_strings = 0;
|
||
|
lang = dump_langids(fd, 1);
|
||
|
dump_device(fd, devdesc, lang);
|
||
|
for (i = 0; i < maxcfg; i++)
|
||
|
do_config(fd, i, lang);
|
||
|
- lang = dump_langids(fd, 0);
|
||
|
+ if (devdesc[4] == USB_CLASS_HUB)
|
||
|
+ do_hub(fd, devdesc [6]);
|
||
|
+ /* FIXME if it's usb 2.0 and there's a device qualifier,
|
||
|
+ * optionally dump it and the other-speed config data
|
||
|
+ */
|
||
|
+ lang = dump_langids(fd, !dev_has_strings);
|
||
|
}
|
||
|
|
||
|
/* ---------------------------------------------------------------------- */
|
||
|
@@ -1560,7 +1765,7 @@ int main(int argc, char *argv[])
|
||
|
exit(1);
|
||
|
}
|
||
|
if ((err = names_init("./usb.ids")) != 0)
|
||
|
- if(err = names_init(USBIDS_FILE)) {
|
||
|
+ if((err = names_init(USBIDS_FILE)) != 0) {
|
||
|
printf("Error, cannot open USBIDS File \"%s\", %s\n", USBIDS_FILE, strerror(err));
|
||
|
exit(1);
|
||
|
}
|