From aefe4850cdd6870747acaaa1f77f8fe1e9940173 Mon Sep 17 00:00:00 2001 From: Augustin Cavalier Date: Sun, 14 Jul 2019 20:08:31 -0400 Subject: [PATCH] USB: Rework the device speed detection code. This is more in line with how OpenBSD and FreeBSD do this detection; and should provide at least some support for USB 3.0+ hubs. Potentially helps with #15001. Change-Id: I313400b790b52fbca490c9fc8b721bedb97a64f9 --- src/add-ons/kernel/bus_managers/usb/Hub.cpp | 34 +++++++++++++-------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/add-ons/kernel/bus_managers/usb/Hub.cpp b/src/add-ons/kernel/bus_managers/usb/Hub.cpp index 2998221ef6..5703b20055 100644 --- a/src/add-ons/kernel/bus_managers/usb/Hub.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Hub.cpp @@ -257,24 +257,34 @@ Hub::Explore(change_item **changeList) fChildren[i] = NULL; } - usb_speed speed = USB_SPEED_FULLSPEED; - // Hack - We currently do not support USB3.0 Hubs - // This is for XHCI, which anyway rechecks the port speed - // This will in no way work for non-root USB3.0 Hubs - if (fDeviceDescriptor.usb_version == 0x300) - speed = USB_SPEED_SUPERSPEED; - else if (fPortStatus[i].status & PORT_STATUS_LOW_SPEED) - speed = USB_SPEED_LOWSPEED; - else if (fPortStatus[i].status & PORT_STATUS_HIGH_SPEED) - speed = USB_SPEED_HIGHSPEED; + // Determine the device speed. + usb_speed speed; + + // PORT_STATUS_LOW_SPEED and PORT_STATUS_SS_POWER are the + // same, but PORT_STATUS_POWER will not be set for SS + // devices, hence this somewhat convoluted logic. + if ((fPortStatus[i].status & PORT_STATUS_POWER) != 0) { + if ((fPortStatus[i].status & PORT_STATUS_HIGH_SPEED) != 0) + speed = USB_SPEED_HIGHSPEED; + else if ((fPortStatus[i].status & PORT_STATUS_LOW_SPEED) != 0) + speed = USB_SPEED_LOWSPEED; + else + speed = USB_SPEED_FULLSPEED; + } else { + // This must be a SuperSpeed device, which will + // simply inherit our speed. + speed = Speed(); + } + if (speed > Speed()) + speed = Speed(); // either let the device inherit our addresses (if we are // already potentially using a transaction translator) or - // set ourselfs as the hub when we might become the + // set ourselves as the hub when we might become the // transaction translator for the device. int8 hubAddress = HubAddress(); uint8 hubPort = HubPort(); - if (Speed() == USB_SPEED_HIGHSPEED || fDeviceDescriptor.usb_version == 0x300) { + if (Speed() == USB_SPEED_HIGHSPEED || Speed() == USB_SPEED_SUPERSPEED) { hubAddress = DeviceAddress(); hubPort = i + 1; }