[PATCH 2/4] usbutils: Support USB 3.0 hub descriptor output.

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



USB 3.0 hubs have a different hub descriptor than USB 2.0 hubs, with a
different bDescriptorType.  USB 3.0 hubs don't have transaction
translators (TTs) since they only handle SuperSpeed devices.  The USB 3.0
hubs also have a different port status and change format.

Sample output from a USB 3.0 hub prototype:

Hub Descriptor:
  bLength              12
  bDescriptorType      42
  nNbrPorts             4
  wHubCharacteristic 0x0009
    Per-port power switching
    Per-port overcurrent protection
  bPwrOn2PwrGood        0 * 2 milli seconds
  bHubContrCurrent      8 milli Ampere
  bHubDecLat          0.0 micro seconds
  wHubDelay             0 nano seconds
  DeviceRemovable    0x00
 Hub Port Status:
   Port 1: 0000.02a0 5Gbps power Rx.Detect
   Port 2: 0000.02a0 5Gbps power Rx.Detect
   Port 3: 0000.02a0 5Gbps power Rx.Detect
   Port 4: 0000.02a0 5Gbps power Rx.Detect

Signed-off-by: Sarah Sharp <sarah.a.sharp@xxxxxxxxxxxxxxx>
---
 lsusb.c |  130 ++++++++++++++++++++++++++++++++++++++++++++++++---------------
 1 files changed, 99 insertions(+), 31 deletions(-)

diff --git a/lsusb.c b/lsusb.c
index 97590b5..a25ad69 100644
--- a/lsusb.c
+++ b/lsusb.c
@@ -121,7 +121,7 @@ static char *dump_comm_descriptor(struct usb_dev_handle *dev, unsigned char *buf
 static void dump_hid_device(struct usb_dev_handle *dev, struct usb_interface_descriptor *interface, unsigned char *buf);
 static void dump_audiostreaming_endpoint(unsigned char *buf, int protocol);
 static void dump_midistreaming_endpoint(unsigned char *buf);
-static void dump_hub(char *prefix, unsigned char *p, int has_tt);
+static void dump_hub(char *prefix, unsigned char *p, int tt_type);
 static void dump_ccid_device(unsigned char *buf);
 
 /* ---------------------------------------------------------------------- */
@@ -2499,9 +2499,10 @@ static void dump_dfu_interface(unsigned char *buf)
 			buf[8], buf[7]);
 }
 
-static void dump_hub(char *prefix, unsigned char *p, int has_tt)
+static void dump_hub(char *prefix, unsigned char *p, int tt_type)
 {
 	unsigned int l, i, j;
+	unsigned int offset;
 	unsigned int wHubChar = (p[4] << 8) | p[3];
 
 	printf("%sHub Descriptor:\n", prefix);
@@ -2533,23 +2534,46 @@ static void dump_hub(char *prefix, unsigned char *p, int has_tt)
 		printf("%s    No overcurrent protection\n", prefix);
 		break;
 	}
-	if (has_tt) {
+	/* USB 3.0 hubs don't have TTs. */
+	if (tt_type >= 1 && tt_type < 3) {
 		l = (wHubChar >> 5) & 0x03;
 		printf("%s    TT think time %d FS bits\n", prefix, (l + 1) * 8);
 	}
-	if (wHubChar & (1<<7))
+	/* USB 3.0 hubs don't have port indicators.  Sad face. */
+	if (tt_type != 3 && 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]);
+
+	/* USB 3.0 hubs report current in units of aCurrentUnit, or 4 mA */
+	if (tt_type == 3)
+		printf("%s  bHubContrCurrent   %4u milli Ampere\n",
+				prefix, p[6]*4);
+	else
+		printf("%s  bHubContrCurrent    %3u milli Ampere\n",
+				prefix, p[6]);
+
+	if (tt_type == 3) {
+		printf("%s  bHubDecLat          0.%1u micro seconds\n",
+				prefix, p[7]);
+		printf("%s  wHubDelay          %4u nano seconds\n",
+				prefix, (p[8] << 4) +(p[7]));
+		offset = 10;
+	} else {
+		offset = 7;
+	}
+
 	l = (p[2] >> 3) + 1; /* this determines the variable number of bytes following */
 	if (l > HUB_STATUS_BYTELEN)
 		l = HUB_STATUS_BYTELEN;
 	printf("%s  DeviceRemovable   ", prefix);
 	for (i = 0; i < l; i++)
-		printf(" 0x%02x", p[7+i]);
-	printf("\n%s  PortPwrCtrlMask   ", prefix);
-	for (j = 0; j < l; j++)
-		printf(" 0x%02x", p[7+i+j]);
+		printf(" 0x%02x", p[offset+i]);
+
+	if (tt_type != 3) {
+		printf("\n%s  PortPwrCtrlMask   ", prefix);
+		for (j = 0; j < l; j++)
+			printf(" 0x%02x", p[offset+i+j]);
+	}
 	printf("\n");
 }
 
@@ -3104,16 +3128,37 @@ bad:
 
 /* ---------------------------------------------------------------------- */
 
-static void do_hub(struct usb_dev_handle *fd, unsigned has_tt)
+static void do_hub(struct usb_dev_handle *fd, unsigned tt_type, unsigned speed)
 {
 	unsigned char buf[7 /* base descriptor */
 			+ 2 /* bitmasks */ * HUB_STATUS_BYTELEN];
-	int i, ret;
+	int i, ret, value;
+	unsigned int link_state;
+	unsigned char *link_state_descriptions[] = {
+		" U0",
+		" U1",
+		" U2",
+		" suspend",
+		" SS.disabled",
+		" Rx.Detect",
+		" SS.Inactive",
+		" Polling",
+		" Recovery",
+		" Hot Reset",
+		" Compliance",
+		" Loopback",
+	};
+
+	/* USB 3.0 hubs have a slightly different descriptor */
+	if (speed == 0x0300)
+		value = 0x2A;
+	else
+		value = 0x29;
 
 	ret = usb_control_msg(fd,
 			USB_ENDPOINT_IN | USB_TYPE_CLASS | USB_RECIP_DEVICE,
 			USB_REQ_GET_DESCRIPTOR,
-			0x29 << 8, 0,
+			value << 8, 0,
 			buf, sizeof buf, CTRL_TIMEOUT);
 	if (ret < 9 /* at least one port's bitmasks */) {
 		if (ret >= 0)
@@ -3125,7 +3170,7 @@ static void do_hub(struct usb_dev_handle *fd, unsigned has_tt)
 			perror("can't get hub descriptor");
 		return;
 	}
-	dump_hub("", buf, has_tt);
+	dump_hub("", buf, tt_type);
 
 	printf(" Hub Port Status:\n");
 	for (i = 0; i < buf[2]; i++) {
@@ -3149,23 +3194,46 @@ static void do_hub(struct usb_dev_handle *fd, unsigned has_tt)
 			status[3], status[2],
 			status[1], status[0]);
 		/* CAPS are used to highlight "transient" states */
-		printf("%s%s%s%s%s",
-			(status[2] & 0x10) ? " C_RESET" : "",
-			(status[2] & 0x08) ? " C_OC" : "",
-			(status[2] & 0x04) ? " C_SUSPEND" : "",
-			(status[2] & 0x02) ? " C_ENABLE" : "",
-			(status[2] & 0x01) ? " C_CONNECT" : "");
-		printf("%s%s%s%s%s%s%s%s%s%s\n",
-			(status[1] & 0x10) ? " indicator" : "",
-			(status[1] & 0x08) ? " test" : "",
-			(status[1] & 0x04) ? " highspeed" : "",
-			(status[1] & 0x02) ? " lowspeed" : "",
-			(status[1] & 0x01) ? " power" : "",
-			(status[0] & 0x10) ? " RESET" : "",
-			(status[0] & 0x08) ? " oc" : "",
-			(status[0] & 0x04) ? " suspend" : "",
-			(status[0] & 0x02) ? " enable" : "",
-			(status[0] & 0x01) ? " connect" : "");
+		if (speed != 0x0300) {
+			printf("%s%s%s%s%s",
+					(status[2] & 0x10) ? " C_RESET" : "",
+					(status[2] & 0x08) ? " C_OC" : "",
+					(status[2] & 0x04) ? " C_SUSPEND" : "",
+					(status[2] & 0x02) ? " C_ENABLE" : "",
+					(status[2] & 0x01) ? " C_CONNECT" : "");
+			printf("%s%s%s%s%s%s%s%s%s%s\n",
+					(status[1] & 0x10) ? " indicator" : "",
+					(status[1] & 0x08) ? " test" : "",
+					(status[1] & 0x04) ? " highspeed" : "",
+					(status[1] & 0x02) ? " lowspeed" : "",
+					(status[1] & 0x01) ? " power" : "",
+					(status[0] & 0x10) ? " RESET" : "",
+					(status[0] & 0x08) ? " oc" : "",
+					(status[0] & 0x04) ? " suspend" : "",
+					(status[0] & 0x02) ? " enable" : "",
+					(status[0] & 0x01) ? " connect" : "");
+		} else {
+			link_state = ((status[0] & 0xe0) >> 5) +
+				((status[1] & 0x1) << 4);
+			printf("%s%s%s%s%s",
+					(status[2] & 0x80) ? " C_CONFIG_ERROR" : "",
+					(status[2] & 0x40) ? " C_LINK_STATE" : "",
+					(status[2] & 0x20) ? " C_BH_RESET" : "",
+					(status[2] & 0x10) ? " C_RESET" : "",
+					(status[2] & 0x08) ? " C_OC" : "",
+					(status[2] & 0x01) ? " C_CONNECT" : "");
+			printf("%s%s",
+					((status[1] & 0x1C) == 0) ? " 5Gbps" : " Unknown Speed",
+					(status[1] & 0x02) ? " power" : "");
+			/* Link state is bits 8:5 */
+			if (link_state < 0xC0)
+				printf("%s", link_state_descriptions[link_state]);
+			printf("%s%s%s%s\n",
+					(status[0] & 0x10) ? " RESET" : "",
+					(status[0] & 0x08) ? " oc" : "",
+					(status[0] & 0x02) ? " enable" : "",
+					(status[0] & 0x01) ? " connect" : "");
+		}
 	}
 }
 
@@ -3463,7 +3531,7 @@ static void dumpdev(struct usb_device *dev)
 		return;
 
 	if (dev->descriptor.bDeviceClass == USB_CLASS_HUB)
-		do_hub(udev, dev->descriptor.bDeviceProtocol);
+		do_hub(udev, dev->descriptor.bDeviceProtocol, dev->descriptor.bcdUSB);
 	if (dev->descriptor.bcdUSB >= 0x0200) {
 		do_dualspeed(udev);
 		do_debug(udev);
-- 
1.6.3.3

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux