summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Hancock <hancockrwd@gmail.com>2021-11-24 23:37:32 -0600
committerRobert Hancock <hancockrwd@gmail.com>2022-04-17 23:58:13 -0600
commitfcb671851592d8c844c1a5e70b196953c4f58fde (patch)
treea69baec77077677dd3831097ee76235dd5695777
parent4bf4819a0dfddc53810a640e3be83dbbeeab0802 (diff)
downloadusbutils-fcb671851592d8c844c1a5e70b196953c4f58fde.tar.gz
lsusb: Improve status display for SuperSpeedPlus hubs
Add more status information for SuperSpeedPlus hubs by using the EXT_PORT_STATUS request to determine the actual link speed ID and number of lanes that the hub reports it is connected with. This is needed to be able to figure out the actual connection speed for SuperSpeedPlus devices. This requires parsing the BOS prior to the hub information, since we can only use EXT_PORT_STATUS if the device actually has a SuperSpeedPlus device capability. Also fix some issues with the SuperSpeedPlus device capability parsing - the speed attribute and speed ID counts were off by one, and the minimum functional speed information is now parsed out. Signed-off-by: Robert Hancock <hancockrwd@gmail.com>
-rw-r--r--lsusb.c42
1 files changed, 30 insertions, 12 deletions
diff --git a/lsusb.c b/lsusb.c
index 58102c2..2644c0f 100644
--- a/lsusb.c
+++ b/lsusb.c
@@ -2802,7 +2802,8 @@ bad:
/* ---------------------------------------------------------------------- */
-static void do_hub(libusb_device_handle *fd, unsigned tt_type, unsigned speed)
+static void do_hub(libusb_device_handle *fd, unsigned tt_type, unsigned speed,
+ bool has_ssp)
{
unsigned char buf[7 /* base descriptor */
+ 2 /* bitmasks */ * HUB_STATUS_BYTELEN];
@@ -2822,6 +2823,7 @@ static void do_hub(libusb_device_handle *fd, unsigned tt_type, unsigned speed)
"Compliance",
"Loopback",
};
+ bool is_ext_status = tt_type == 3 && speed >= 0x0310 && has_ssp;
/* USB 3.x hubs have a slightly different descriptor */
if (speed >= 0x0300)
@@ -2851,14 +2853,16 @@ static void do_hub(libusb_device_handle *fd, unsigned tt_type, unsigned speed)
printf(" Hub Port Status:\n");
for (i = 0; i < buf[2]; i++) {
- unsigned char status[4];
+ unsigned char status[8];
+ /* Request EXT_PORT_STATUS for USB 3.1 SuperSpeedPlus hubs,
+ PORT_STATUS otherwise */
ret = usb_control_msg(fd,
LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_CLASS
| LIBUSB_RECIPIENT_OTHER,
LIBUSB_REQUEST_GET_STATUS,
- 0, i + 1,
- status, sizeof status,
+ is_ext_status ? 2 : 0, i + 1,
+ status, is_ext_status ? 8 : 4,
CTRL_TIMEOUT);
if (ret < 0) {
fprintf(stderr,
@@ -2871,7 +2875,7 @@ static void do_hub(libusb_device_handle *fd, unsigned tt_type, unsigned speed)
status[3], status[2],
status[1], status[0]);
/* CAPS are used to highlight "transient" states */
- if (speed != 0x0300) {
+ if (speed < 0x0300) {
printf("%s%s%s%s%s",
(status[2] & 0x10) ? " C_RESET" : "",
(status[2] & 0x08) ? " C_OC" : "",
@@ -2913,6 +2917,16 @@ static void do_hub(libusb_device_handle *fd, unsigned tt_type, unsigned speed)
(status[0] & 0x02) ? " enable" : "",
(status[0] & 0x01) ? " connect" : "");
}
+
+ if (is_ext_status && (status[0] & 0x01)) {
+ printf(" Ext Status: %02x%02x.%02x%02x\n",
+ status[7], status[6],
+ status[5], status[4]);
+ printf(" RX Speed Attribute ID: %d Lanes: %d\n",
+ status[4] & 0x0f, (status[5] & 0x0f)+1);
+ printf(" TX Speed Attribute ID: %d Lanes: %d\n",
+ (status[4] >> 4) & 0x0f, ((status[5] >> 4) & 0x0f)+1);
+ }
}
}
@@ -3208,9 +3222,12 @@ static void dump_ssp_device_capability_desc(unsigned char *buf)
" bmAttributes 0x%08x\n",
buf[0], buf[1], buf[2], bm_attr);
- printf(" Sublink Speed Attribute count %u\n", buf[4] & 0x1f);
- printf(" Sublink Speed ID count %u\n", (bm_attr >> 5) & 0xf);
+ printf(" Sublink Speed Attribute count %u\n", (buf[4] & 0x1f)+1);
+ printf(" Sublink Speed ID count %u\n", ((bm_attr >> 5) & 0xf)+1);
printf(" wFunctionalitySupport 0x%02x%02x\n", buf[9], buf[8]);
+ printf(" Min functional Speed Attribute ID: %u\n", buf[8] & 0x0f);
+ printf(" Min functional RX lanes: %u\n", buf[9] & 0x0f);
+ printf(" Min functional TX lanes: %u\n", (buf[9] >> 4) & 0x0f);
for (i = 0; i <= (buf[4] & 0x1f); i++) {
ss_attr = convert_le_u32(buf + 12 + (i * 4));
@@ -3417,7 +3434,7 @@ static void dump_billboard_alt_mode_capability_desc(libusb_device_handle *dev, u
buf[4], buf[5], buf[6], buf[7]);
}
-static void dump_bos_descriptor(libusb_device_handle *fd)
+static void dump_bos_descriptor(libusb_device_handle *fd, bool* has_ssp)
{
/* Total length of BOS descriptors varies.
* Read first static 5 bytes which include the total length before
@@ -3491,6 +3508,7 @@ static void dump_bos_descriptor(libusb_device_handle *fd)
break;
case USB_DC_SUPERSPEEDPLUS:
dump_ssp_device_capability_desc(buf);
+ *has_ssp = true;
break;
case USB_DC_CONTAINER_ID:
dump_container_id_device_capability_desc(buf);
@@ -3527,6 +3545,7 @@ static void dumpdev(libusb_device *dev)
struct libusb_device_descriptor desc;
int i, ret;
int otg;
+ bool has_ssp = false;
otg = 0;
ret = libusb_open(dev, &udev);
@@ -3565,11 +3584,10 @@ static void dumpdev(libusb_device *dev)
if (!udev)
return;
+ if (desc.bcdUSB >= 0x0201)
+ dump_bos_descriptor(udev, &has_ssp);
if (desc.bDeviceClass == LIBUSB_CLASS_HUB)
- do_hub(udev, desc.bDeviceProtocol, desc.bcdUSB);
- if (desc.bcdUSB >= 0x0201) {
- dump_bos_descriptor(udev);
- }
+ do_hub(udev, desc.bDeviceProtocol, desc.bcdUSB, has_ssp);
if (desc.bcdUSB == 0x0200) {
do_dualspeed(udev);
}