diff --git a/src/add-ons/kernel/bus_managers/usb/Device.cpp b/src/add-ons/kernel/bus_managers/usb/Device.cpp index f15b52216d..83e8adb509 100644 --- a/src/add-ons/kernel/bus_managers/usb/Device.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Device.cpp @@ -254,6 +254,22 @@ Device::Device(Object* parent, int8 hubAddress, uint8 hubPort, break; } + case USB_DESCRIPTOR_ENDPOINT_COMPANION: { + usb_endpoint_descriptor* desc = currentInterface + ->endpoint[currentInterface->endpoint_count - 1].descr; + if ((uint8*)desc != (&configData[descriptorStart + - desc->length])) { + TRACE_ERROR("found endpoint companion descriptor not immediately " + "following endpoint descriptor, ignoring!\n"); + break; + } + // TODO: It'd be nicer if we could store the endpoint companion + // descriptor along with the endpoint descriptor, but as the + // interface struct is public API, that would be an ABI break. + + // fall through + } + default: TRACE("got generic descriptor\n"); usb_generic_descriptor* genericDescriptor @@ -472,6 +488,29 @@ Device::InitEndpoints(int32 interfaceIndex) usb_endpoint_info* endpoint = &interfaceInfo->endpoint[i]; Pipe* pipe = NULL; + usb_endpoint_companion_descriptor* comp_descr = NULL; + if (fSpeed == USB_SPEED_SUPER) { + // We should have a companion descriptor for this device. + // Let's find it: it'll be the "i"th one. + size_t k = 0; + for (size_t j = 0; j < interfaceInfo->generic_count; j++) { + usb_descriptor* desc = interfaceInfo->generic[j]; + if (desc->endpoint.descriptor_type + != USB_DESCRIPTOR_ENDPOINT_COMPANION) { + continue; + } + if (k == i) { + comp_descr = (usb_endpoint_companion_descriptor*)desc; + break; + } + k++; + } + if (comp_descr == NULL) { + TRACE_ERROR("SuperSpeed device without an endpoint companion " + "descriptor!"); + } + } + Pipe::pipeDirection direction = Pipe::Out; if ((endpoint->descr->endpoint_address & 0x80) != 0) direction = Pipe::In; @@ -505,6 +544,10 @@ Device::InitEndpoints(int32 interfaceIndex) endpoint->descr->endpoint_address & 0x0f, fSpeed, direction, endpoint->descr->max_packet_size, endpoint->descr->interval, fHubAddress, fHubPort); + if (comp_descr != NULL) { + pipe->InitSuperSpeed(comp_descr->max_burst, + comp_descr->bytes_per_interval); + } endpoint->handle = pipe->USBID(); } } diff --git a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp index 96525ac359..6d976639c8 100644 --- a/src/add-ons/kernel/bus_managers/usb/Pipe.cpp +++ b/src/add-ons/kernel/bus_managers/usb/Pipe.cpp @@ -40,10 +40,21 @@ Pipe::InitCommon(int8 deviceAddress, uint8 endpointAddress, usb_speed speed, fHubAddress = hubAddress; fHubPort = hubPort; + fMaxBurst = 0; + fBytesPerInterval = 0; + GetBusManager()->NotifyPipeChange(this, USB_CHANGE_CREATED); } +void +Pipe::InitSuperSpeed(uint8 maxBurst, uint16 bytesPerInterval) +{ + fMaxBurst = maxBurst; + fBytesPerInterval = bytesPerInterval; +} + + void Pipe::SetHubInfo(int8 address, uint8 port) { diff --git a/src/add-ons/kernel/bus_managers/usb/usb_private.h b/src/add-ons/kernel/bus_managers/usb/usb_private.h index 93279c0865..2862f2c7c9 100644 --- a/src/add-ons/kernel/bus_managers/usb/usb_private.h +++ b/src/add-ons/kernel/bus_managers/usb/usb_private.h @@ -297,6 +297,8 @@ virtual void InitCommon(int8 deviceAddress, size_t maxPacketSize, uint8 interval, int8 hubAddress, uint8 hubPort); +virtual void InitSuperSpeed(uint8 maxBurst, + uint16 bytesPerInterval); virtual uint32 Type() const { return USB_OBJECT_PIPE; } virtual const char * TypeName() const { return "pipe"; } @@ -311,6 +313,12 @@ virtual const char * TypeName() const { return "pipe"; } { return fMaxPacketSize; } uint8 Interval() const { return fInterval; } + // SuperSpeed-only parameters + uint8 MaxBurst() const + { return fMaxBurst; } + uint16 BytesPerInterval() const + { return fBytesPerInterval; } + // Hub port being the one-based logical port number on the hub void SetHubInfo(int8 address, uint8 port); int8 HubAddress() const @@ -342,6 +350,8 @@ private: usb_speed fSpeed; size_t fMaxPacketSize; uint8 fInterval; + uint8 fMaxBurst; + uint16 fBytesPerInterval; int8 fHubAddress; uint8 fHubPort; bool fDataToggle; diff --git a/src/add-ons/kernel/bus_managers/usb/usbspec_private.h b/src/add-ons/kernel/bus_managers/usb/usbspec_private.h index dc8d068419..0a2899a5ae 100644 --- a/src/add-ons/kernel/bus_managers/usb/usbspec_private.h +++ b/src/add-ons/kernel/bus_managers/usb/usbspec_private.h @@ -71,6 +71,17 @@ struct usb_hub_descriptor { #define USB_DESCRIPTOR_HUB 0x29 +struct usb_endpoint_companion_descriptor { + uint8 length; + uint8 descriptor_type; + uint8 max_burst; + uint8 attributes; + uint16 bytes_per_interval; +} _PACKED; + +#define USB_DESCRIPTOR_ENDPOINT_COMPANION 0x30 + + // USB Spec 1.1 page 273 struct usb_port_status { diff --git a/src/add-ons/kernel/busses/usb/xhci.cpp b/src/add-ons/kernel/busses/usb/xhci.cpp index 89d075f501..7508fca44a 100644 --- a/src/add-ons/kernel/busses/usb/xhci.cpp +++ b/src/add-ons/kernel/busses/usb/xhci.cpp @@ -1395,7 +1395,7 @@ XHCI::AllocateDevice(Hub *parent, int8 hubAddress, uint8 hubPort, // configure the Control endpoint 0 if (ConfigureEndpoint(slot, 0, USB_OBJECT_CONTROL_PIPE, false, - device->trb_addr, 0, maxPacketSize, speed) != B_OK) { + device->trb_addr, 0, maxPacketSize, speed, 0, 0) != B_OK) { TRACE_ERROR("unable to configure default control endpoint\n"); delete_area(device->input_ctx_area); delete_area(device->device_ctx_area); @@ -1645,7 +1645,8 @@ XHCI::_InsertEndpointForPipe(Pipe *pipe) status_t status = ConfigureEndpoint(device->slot, id, pipe->Type(), pipe->Direction() == Pipe::In, device->endpoints[id].trb_addr, - pipe->Interval(), pipe->MaxPacketSize(), usbDevice->Speed()); + pipe->Interval(), pipe->MaxPacketSize(), usbDevice->Speed(), + pipe->MaxBurst(), pipe->BytesPerInterval()); if (status != B_OK) { TRACE_ERROR("unable to configure endpoint\n"); return status; @@ -1844,7 +1845,8 @@ XHCI::_UnlinkDescriptorForPipe(xhci_td *descriptor, xhci_endpoint *endpoint) status_t XHCI::ConfigureEndpoint(uint8 slot, uint8 number, uint8 type, bool directionIn, - uint64 ringAddr, uint16 interval, uint16 maxPacketSize, usb_speed speed) + uint64 ringAddr, uint16 interval, uint16 maxPacketSize, usb_speed speed, + uint8 maxBurst, uint16 bytesPerInterval) { struct xhci_device* device = &fDevices[slot]; @@ -1903,21 +1905,18 @@ XHCI::ConfigureEndpoint(uint8 slot, uint8 number, uint8 type, bool directionIn, // For non-isochronous endpoints, we want the controller to retry failed // transfers, if possible. (XHCI 1.1 § 4.10.2.3 p189.) - if (!(type & USB_OBJECT_ISO_PIPE)) + if ((type & USB_OBJECT_ISO_PIPE) == 0) dwendpoint1 |= ENDPOINT_1_CERR(3); - // Assign maximum burst size. - // TODO: While computing the maximum burst this way is correct for USB2 - // devices, it is merely acceptable for USB3 devices, which have a more - // correct value stored in the Companion Descriptor. (Further, this value - // in the USB3 Companion Descriptor is to be used for *all* endpoints, not - // just Interrupt and Isoch ones.) - uint8 maxBurst = (maxPacketSize & 0x1800) >> 11; - if (speed >= USB_SPEED_HIGHSPEED - && (((type & USB_OBJECT_INTERRUPT_PIPE) != 0) - || (type & USB_OBJECT_ISO_PIPE) != 0)) { - dwendpoint1 |= ENDPOINT_1_MAXBURST(maxBurst); + // Assign maximum burst size. For USB3 devices this is passed in; for + // all other devices we compute it. (XHCI 1.1 § 4.8.2 p154.) + if (speed == USB_SPEED_HIGHSPEED && (type & (USB_OBJECT_INTERRUPT_PIPE + | USB_OBJECT_ISO_PIPE)) != 0) { + maxBurst = (maxPacketSize & 0x1800) >> 11; + } else if (speed != USB_SPEED_SUPER) { + maxBurst = 0; } + dwendpoint1 |= ENDPOINT_1_MAXBURST(maxBurst); // Assign maximum packet size, set the ring address, and set the // "Dequeue Cycle State" bit. (XHCI 1.1 § 6.2.3 Table 6-10 p430.) @@ -1934,10 +1933,15 @@ XHCI::ConfigureEndpoint(uint8 slot, uint8 number, uint8 type, bool directionIn, } // Assign maximum ESIT payload. (XHCI 1.1 § 4.14.2 p250.) - // TODO: This computation is *only* correct for USB2 devices. - if (((type & USB_OBJECT_INTERRUPT_PIPE) != 0) - || ((type & USB_OBJECT_ISO_PIPE) != 0)) { - dwendpoint4 |= ENDPOINT_4_MAXESITPAYLOAD((maxBurst + 1) * maxPacketSize); + if ((type & (USB_OBJECT_INTERRUPT_PIPE | USB_OBJECT_ISO_PIPE)) != 0) { + // TODO: For SuperSpeedPlus endpoints, there is yet another descriptor + // for isochronous endpoints that specifies the maximum ESIT payload. + // We don't fetch this yet, so just fall back to the USB2 computation + // method if bytesPerInterval is 0. + if (speed == USB_SPEED_SUPER && bytesPerInterval != 0) + dwendpoint4 |= ENDPOINT_4_MAXESITPAYLOAD(bytesPerInterval); + else if (speed >= USB_SPEED_HIGHSPEED) + dwendpoint4 |= ENDPOINT_4_MAXESITPAYLOAD((maxBurst + 1) * maxPacketSize); } _WriteContext(&device->input_ctx->endpoints[number].dwendpoint0, diff --git a/src/add-ons/kernel/busses/usb/xhci.h b/src/add-ons/kernel/busses/usb/xhci.h index 674c421a3d..f5d5a07b9a 100644 --- a/src/add-ons/kernel/busses/usb/xhci.h +++ b/src/add-ons/kernel/busses/usb/xhci.h @@ -137,7 +137,8 @@ private: status_t ConfigureEndpoint(uint8 slot, uint8 number, uint8 type, bool directionIn, uint64 ringAddr, uint16 interval, uint16 maxPacketSize, - usb_speed speed); + usb_speed speed, uint8 maxBurst, + uint16 bytesPerInterval); status_t _InsertEndpointForPipe(Pipe *pipe); status_t _RemoveEndpointForPipe(Pipe *pipe); diff --git a/src/add-ons/kernel/busses/usb/xhci_rh.cpp b/src/add-ons/kernel/busses/usb/xhci_rh.cpp index 5556c8c08c..e313b136ed 100644 --- a/src/add-ons/kernel/busses/usb/xhci_rh.cpp +++ b/src/add-ons/kernel/busses/usb/xhci_rh.cpp @@ -31,20 +31,11 @@ static usb_device_descriptor sXHCIRootHubDevice = }; -struct usb_endpoint_ss_comp_descriptor { - uint8 length; - uint8 descriptor_type; - uint16 burst; - uint8 attributes; - uint16 internal; -} _PACKED; - - struct xhci_root_hub_configuration_s { usb_configuration_descriptor configuration; usb_interface_descriptor interface; usb_endpoint_descriptor endpoint; - usb_endpoint_ss_comp_descriptor endpc; + usb_endpoint_companion_descriptor endpc; usb_hub_descriptor hub; } _PACKED; @@ -86,7 +77,7 @@ static xhci_root_hub_configuration_s sXHCIRootHubConfig = { // endpoint companion descriptor 7, - 0x30, + USB_DESCRIPTOR_ENDPOINT_COMPANION, 0, 0, 0