Skip to content

Commit 2de7def

Browse files
committed
Improve USB3 support
* Fixed `uhubctl -l <hub>` displaying unrelated devices for USB 3. * Some USB3 hubs use USB_SS_PORT_LS_SS_DISABLED when port is off, but some keep USB_SS_PORT_LS_RX_DETECT. To handle this, check USB_SS_PORT_STAT_POWER bit to detect if port is off.
1 parent f2d016a commit 2de7def

File tree

1 file changed

+57
-42
lines changed

1 file changed

+57
-42
lines changed

uhubctl.c

+57-42
Original file line numberDiff line numberDiff line change
@@ -505,7 +505,7 @@ static int print_port_status(struct hub_info * hub, int portmask)
505505
if (port_status & USB_PORT_STAT_SUSPEND) printf(" suspend");
506506
}
507507
} else {
508-
if (port_status == USB_SS_PORT_LS_SS_DISABLED) {
508+
if (!(port_status & USB_SS_PORT_STAT_POWER)) {
509509
printf(" off");
510510
} else {
511511
int link_state = port_status & USB_PORT_STAT_LINK_STATE;
@@ -591,54 +591,69 @@ static int usb_find_hubs()
591591
}
592592
}
593593
}
594+
if (!opt_exact) {
595+
/* Handle USB2/3 duality: */
596+
for (i=0; i<hub_count; i++) {
597+
/* Check only actionable hubs: */
598+
if (hubs[i].actionable != 1)
599+
continue;
600+
int match = -1;
601+
for (j=0; j<hub_count; j++) {
602+
if (i==j)
603+
continue;
604+
605+
/* Find hub which is USB2/3 dual to the hub above.
606+
* This is quite reliable and predictable on Linux
607+
* but not on Mac, where we may match wrong hub :(
608+
* It will work reliably on Mac if there is
609+
* only one compatible USB3 hub is connected.
610+
* Unfortunately, libusb does not provide any way
611+
* to detect USB2/3 dual hubs.
612+
* TODO: discover better way to find dual hub.
613+
*/
614+
615+
/* Hub and its dual must be different types: one USB2, another USB3: */
616+
if ((hubs[i].bcd_usb < USB_SS_BCD) ==
617+
(hubs[j].bcd_usb < USB_SS_BCD))
618+
continue;
619+
620+
/* But they must have the same vendor: */
621+
if (strncasecmp(hubs[i].vendor, hubs[j].vendor, 4))
622+
continue;
623+
624+
/* And the same number of ports: */
625+
if (hubs[i].nports != hubs[j].nports)
626+
continue;
627+
628+
/* Provisionally we choose this one as dual: */
629+
if (match < 0 && !hubs[j].actionable)
630+
match = j;
631+
632+
/* But if there is exact port path match,
633+
* we prefer it (true for Linux but not Mac):
634+
*/
635+
char *p1 = strchr(hubs[i].location, '-');
636+
char *p2 = strchr(hubs[j].location, '-');
637+
if (p1 && p2 && strcasecmp(p1, p2)==0) {
638+
match = j;
639+
break;
640+
}
641+
}
642+
if (match >= 0) {
643+
if (!hubs[match].actionable) {
644+
/* Use 2 to signify that this is derived dual device */
645+
hubs[match].actionable = 2;
646+
}
647+
}
648+
}
649+
}
594650
hub_phys_count = 0;
595651
for (i=0; i<hub_count; i++) {
596-
/* Check only actionable USB3 hubs: */
597652
if (!hubs[i].actionable)
598653
continue;
599654
if (hubs[i].bcd_usb < USB_SS_BCD || opt_exact) {
600655
hub_phys_count++;
601656
}
602-
if (opt_exact)
603-
continue;
604-
int match = -1;
605-
for (j=0; j<hub_count; j++) {
606-
if (i==j)
607-
continue;
608-
609-
/* Find hub which is USB2/3 dual to the hub above.
610-
* This is quite reliable and predictable on Linux
611-
* but not on Mac, where we may match wrong hub :(
612-
* It will work reliably on Mac if there is
613-
* only one compatible USB3 hub is connected.
614-
* TODO: discover better way to find dual hub.
615-
*/
616-
617-
/* Hub and its dual must be different types: one USB2, another USB3: */
618-
if ((hubs[i].bcd_usb < USB_SS_BCD) ==
619-
(hubs[j].bcd_usb < USB_SS_BCD))
620-
continue;
621-
622-
/* But they must have the same vendor: */
623-
if (strncasecmp(hubs[i].vendor, hubs[j].vendor, 4))
624-
continue;
625-
626-
/* Provisionally we choose this one as dual: */
627-
if (match < 0 && !hubs[j].actionable)
628-
match = j;
629-
630-
/* But if there is exact port path match,
631-
* we prefer it (true for Linux but not Mac):
632-
*/
633-
char *p1 = strchr(hubs[i].location, '-');
634-
char *p2 = strchr(hubs[j].location, '-');
635-
if (p1 && p2 && strcasecmp(p1, p2)==0) {
636-
match = j;
637-
break;
638-
}
639-
}
640-
if (match >= 0)
641-
hubs[match].actionable = 1;
642657
}
643658
if (perm_ok == 0 && hub_phys_count == 0) {
644659
return LIBUSB_ERROR_ACCESS;

0 commit comments

Comments
 (0)