summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md12
-rw-r--r--uhubctl.c71
2 files changed, 51 insertions, 32 deletions
diff --git a/README.md b/README.md
index 4850159..f91cf8d 100644
--- a/README.md
+++ b/README.md
@@ -57,8 +57,9 @@ This is list of known compatible USB hubs:
| Plugable | USB3-HUB7BC | 7 | 3.0 |`2109:0813`| 2015 | |
| Plugable | USB3-HUB7C | 7 | 3.0 |`2109:0813`| 2015 | |
| Plugable | USB3-HUB7-81X | 7 | 3.0 |`2109:0813`| 2012 | |
-| Raspberry Pi | Model B+, 2 B, 3 B (port 2 only) | 4 | 2.0 | | 2011 | |
-| Raspberry Pi | Model 3 B+ | 6 | 2.0 |`0424:2514`| 2018 | |
+| Raspberry Pi | B+, 2B, 3B (port 2 only) | 4 | 2.0 | | 2011 | |
+| Raspberry Pi | 3B+ | 6 | 2.0 |`0424:2514`| 2018 | |
+| Raspberry Pi | 4B (ganged, must use `-p all` to cut off VBUS) | 4 | 3.0 |`2109:3431`| 2019 | |
| Renesas | uPD720202 PCIe USB 3.0 host controller | 2 | 3.0 | | 2013 | |
| Rosewill | RHUB-210 | 4 | 2.0 |`0409:005A`| 2011 | 2014 |
| Sanwa Supply | USB-HUB14GPH | 4 | 1.1 | | 2001 | 2003 |
@@ -267,11 +268,10 @@ For reference, Raspberry Pi models have following internal USB topology:
Second hub `1-1.1` (daisy-chained to main): 3 independently controlled ports, `1` is used for Ethernet+wifi,
and ports `2,3` are available with proper per-port power switching.
In other words, 2 out of total 4 ports wired outside do support independent power switching on 3B+.
-* 4B: Hardware supports power switching, but current firmware is reporting broken USB descriptors.
- For more details see Raspberry Pi issue https://github.com/raspberrypi/linux/issues/3079.
- USB3 hub `2`, 4 ports, per-port power switching. BOS `ContainerID` not reported (required for USB3).
+* 4B: Hardware only supports ganged power switching, firmware is reporting inconsistent USB descriptors.
+ USB3 hub `2`, 4 ports, incorrectly reports per-port power switching. BOS `ContainerID` not reported (required for USB3).
USB2 hub `1`, 1 port, no usable ports, connects hub `1-1` below.
- USB2 hub `1-1`, 4 ports, dual to USB3 hub above. Hub descriptor incorrectly reports ganged power switching.
+ USB2 hub `1-1`, 4 ports, dual to USB3 hub above. Hub descriptor reports ganged power switching.
USB2 hub `3`, 1 port, OTG controller, incorrectly reports ganged power switching.
As a workaround, you can buy any external USB hub from supported list,
diff --git a/uhubctl.c b/uhubctl.c
index adbfa04..544d7e6 100644
--- a/uhubctl.c
+++ b/uhubctl.c
@@ -408,9 +408,54 @@ static int get_hub_info(struct libusb_device *dev, struct hub_info *info)
strcat(info->location, s);
}
+ /* Get container_id: */
+ bzero(info->container_id, sizeof(info->container_id));
+ struct libusb_bos_descriptor *bos;
+ rc = libusb_get_bos_descriptor(devh, &bos);
+ if (rc == 0) {
+ int cap;
+#ifdef __FreeBSD__
+ for (cap=0; cap < bos->bNumDeviceCapabilities; cap++) {
+#else
+ for (cap=0; cap < bos->bNumDeviceCaps; cap++) {
+#endif
+ if (bos->dev_capability[cap]->bDevCapabilityType == LIBUSB_BT_CONTAINER_ID) {
+ struct libusb_container_id_descriptor *container_id;
+ rc = libusb_get_container_id_descriptor(NULL, bos->dev_capability[cap], &container_id);
+ if (rc == 0) {
+ int i;
+ for (i=0; i<16; i++) {
+ sprintf(info->container_id+i*2, "%02x", container_id->ContainerID[i]);
+ }
+ info->container_id[i*2] = 0;
+ libusb_free_container_id_descriptor(container_id);
+ }
+ }
+ }
+ libusb_free_bos_descriptor(bos);
+
+ /* Raspberry Pi 4 hack for USB3 root hub: */
+ if (strlen(info->container_id)==0 &&
+ strcasecmp(info->vendor, "1d6b:0003")==0 &&
+ info->level==1 &&
+ info->nports==4 &&
+ bcd_usb==USB_SS_BCD)
+ {
+ strcpy(info->container_id, "5cf3ee30d5074925b001802d79434c30");
+ }
+ }
+
info->ppps = 0;
/* Logical Power Switching Mode */
int lpsm = uhd->wHubCharacteristics[0] & HUB_CHAR_LPSM;
+ if (lpsm == HUB_CHAR_COMMON_LPSM && info->nports == 1) {
+ /* For 1 port hubs, ganged power switching is the same as per-port: */
+ lpsm = HUB_CHAR_INDV_PORT_LPSM;
+ }
+ /* Raspberry Pi 4 reports inconsistent descriptors, override: */
+ if (lpsm == HUB_CHAR_COMMON_LPSM && strcasecmp(info->vendor, "2109:3431")==0) {
+ lpsm = HUB_CHAR_INDV_PORT_LPSM;
+ }
/* Over-Current Protection Mode */
int ocpm = uhd->wHubCharacteristics[0] & HUB_CHAR_OCPM;
/* LPSM must be supported per-port, and OCPM per port or ganged */
@@ -423,32 +468,6 @@ static int get_hub_info(struct libusb_device *dev, struct hub_info *info)
} else {
rc = len;
}
- /* Get container_id: */
- bzero(info->container_id, sizeof(info->container_id));
- struct libusb_bos_descriptor *bos;
- rc = libusb_get_bos_descriptor(devh, &bos);
- if (rc == 0) {
- int cap;
-#ifdef __FreeBSD__
- for (cap=0; cap < bos->bNumDeviceCapabilities; cap++) {
-#else
- for (cap=0; cap < bos->bNumDeviceCaps; cap++) {
-#endif
- if (bos->dev_capability[cap]->bDevCapabilityType == LIBUSB_BT_CONTAINER_ID) {
- struct libusb_container_id_descriptor *container_id;
- rc = libusb_get_container_id_descriptor(NULL, bos->dev_capability[cap], &container_id);
- if (rc == 0) {
- int i;
- for (i=0; i<16; i++) {
- sprintf(info->container_id+i*2, "%02x", container_id->ContainerID[i]);
- }
- info->container_id[i*2] = 0;
- libusb_free_container_id_descriptor(container_id);
- }
- }
- }
- libusb_free_bos_descriptor(bos);
- }
libusb_close(devh);
}
return rc;