1d6e4f54fSJérôme Duval /* 2d6e4f54fSJérôme Duval * Copyright 2011, Haiku Inc. All rights reserved. 3d6e4f54fSJérôme Duval * Distributed under the terms of the MIT License. 4d6e4f54fSJérôme Duval * 5d6e4f54fSJérôme Duval * Authors: 6d6e4f54fSJérôme Duval * Michael Lotz <mmlr@mlotz.ch> 7d6e4f54fSJérôme Duval * Jian Chiang <j.jian.chiang@gmail.com> 8d6e4f54fSJérôme Duval */ 9d6e4f54fSJérôme Duval 10d6e4f54fSJérôme Duval 11d6e4f54fSJérôme Duval #include "xhci.h" 12d6e4f54fSJérôme Duval 13d6e4f54fSJérôme Duval #define USB_MODULE_NAME "xhci roothub" 14d6e4f54fSJérôme Duval 15d6e4f54fSJérôme Duval static usb_device_descriptor sXHCIRootHubDevice = 16d6e4f54fSJérôme Duval { 17d6e4f54fSJérôme Duval 18, // Descriptor length 18d6e4f54fSJérôme Duval USB_DESCRIPTOR_DEVICE, // Descriptor type 19d6e4f54fSJérôme Duval 0x300, // USB 3.0 20d6e4f54fSJérôme Duval 0x09, // Class (9 = Hub) 21d6e4f54fSJérôme Duval 0, // Subclass 22d6e4f54fSJérôme Duval 3, // Protocol 23d6e4f54fSJérôme Duval 9, // Max packet size on endpoint 0 24d6e4f54fSJérôme Duval 0, // Vendor ID 25d6e4f54fSJérôme Duval 0, // Product ID 26*2b31b4a8SJérôme Duval 0x300, // Version 27d6e4f54fSJérôme Duval 1, // Index of manufacturer string 28d6e4f54fSJérôme Duval 2, // Index of product string 29d6e4f54fSJérôme Duval 0, // Index of serial number string 30d6e4f54fSJérôme Duval 1 // Number of configurations 31d6e4f54fSJérôme Duval }; 32d6e4f54fSJérôme Duval 33d6e4f54fSJérôme Duval 34d6e4f54fSJérôme Duval struct usb_endpoint_ss_comp_descriptor { 35d6e4f54fSJérôme Duval uint8 length; 36d6e4f54fSJérôme Duval uint8 descriptor_type; 37d6e4f54fSJérôme Duval uint16 burst; 38d6e4f54fSJérôme Duval uint8 attributes; 39d6e4f54fSJérôme Duval uint16 internal; 40d6e4f54fSJérôme Duval } _PACKED; 41d6e4f54fSJérôme Duval 42d6e4f54fSJérôme Duval 43d6e4f54fSJérôme Duval struct xhci_root_hub_configuration_s { 44d6e4f54fSJérôme Duval usb_configuration_descriptor configuration; 45d6e4f54fSJérôme Duval usb_interface_descriptor interface; 46d6e4f54fSJérôme Duval usb_endpoint_descriptor endpoint; 47d6e4f54fSJérôme Duval usb_endpoint_ss_comp_descriptor endpc; 48d6e4f54fSJérôme Duval usb_hub_descriptor hub; 49d6e4f54fSJérôme Duval } _PACKED; 50d6e4f54fSJérôme Duval 51d6e4f54fSJérôme Duval 52d6e4f54fSJérôme Duval static xhci_root_hub_configuration_s sXHCIRootHubConfig = 53d6e4f54fSJérôme Duval { 54d6e4f54fSJérôme Duval { // configuration descriptor 55d6e4f54fSJérôme Duval 9, // Descriptor length 56d6e4f54fSJérôme Duval USB_DESCRIPTOR_CONFIGURATION, // Descriptor type 57d6e4f54fSJérôme Duval sizeof(sXHCIRootHubConfig), // Total length of configuration (including 58d6e4f54fSJérôme Duval // interface, endpoint and hub descriptors) 59d6e4f54fSJérôme Duval 1, // Number of interfaces 60d6e4f54fSJérôme Duval 1, // Value of this configuration 61d6e4f54fSJérôme Duval 0, // Index of configuration string 62d6e4f54fSJérôme Duval 0x40, // Attributes (0x40 = self powered) 63d6e4f54fSJérôme Duval 0 // Max power (0, since self powered) 64d6e4f54fSJérôme Duval }, 65d6e4f54fSJérôme Duval 66d6e4f54fSJérôme Duval { // interface descriptor 67d6e4f54fSJérôme Duval 9, // Descriptor length 68d6e4f54fSJérôme Duval USB_DESCRIPTOR_INTERFACE, // Descriptor type 69d6e4f54fSJérôme Duval 0, // Interface number 70d6e4f54fSJérôme Duval 0, // Alternate setting 71d6e4f54fSJérôme Duval 1, // Number of endpoints 72d6e4f54fSJérôme Duval 0x09, // Interface class (9 = Hub) 73d6e4f54fSJérôme Duval 0, // Interface subclass 74d6e4f54fSJérôme Duval 0, // Interface protocol 75d6e4f54fSJérôme Duval 0 // Index of interface string 76d6e4f54fSJérôme Duval }, 77d6e4f54fSJérôme Duval 78d6e4f54fSJérôme Duval { // endpoint descriptor 79d6e4f54fSJérôme Duval 7, // Descriptor length 80d6e4f54fSJérôme Duval USB_DESCRIPTOR_ENDPOINT, // Descriptor type 81d6e4f54fSJérôme Duval USB_REQTYPE_DEVICE_IN | 1, // Endpoint address (first in IN endpoint) 82d6e4f54fSJérôme Duval 0x03, // Attributes (0x03 = interrupt endpoint) 83d6e4f54fSJérôme Duval 2, // Max packet size 84d6e4f54fSJérôme Duval 0xff // Interval 85d6e4f54fSJérôme Duval }, 86d6e4f54fSJérôme Duval 87d6e4f54fSJérôme Duval { // endpoint companion descriptor 88d6e4f54fSJérôme Duval 7, 89d6e4f54fSJérôme Duval 0x30, 90d6e4f54fSJérôme Duval 0, 91d6e4f54fSJérôme Duval 0, 92d6e4f54fSJérôme Duval 0 93d6e4f54fSJérôme Duval }, 94d6e4f54fSJérôme Duval 95d6e4f54fSJérôme Duval { // hub descriptor 96d6e4f54fSJérôme Duval 9, // Descriptor length (including 97d6e4f54fSJérôme Duval // deprecated power control mask) 98d6e4f54fSJérôme Duval USB_DESCRIPTOR_HUB, // Descriptor type 99d6e4f54fSJérôme Duval 0x0f, // Number of ports 100d6e4f54fSJérôme Duval 0x0000, // Hub characteristics 101d6e4f54fSJérôme Duval 10, // Power on to power good (in 2ms units) 102d6e4f54fSJérôme Duval 0, // Maximum current (in mA) 103d6e4f54fSJérôme Duval 0x00, // All ports are removable 104d6e4f54fSJérôme Duval 0xff // Deprecated power control mask 105d6e4f54fSJérôme Duval } 106d6e4f54fSJérôme Duval }; 107d6e4f54fSJérôme Duval 108d6e4f54fSJérôme Duval 109d6e4f54fSJérôme Duval struct xhci_root_hub_string_s { 110d6e4f54fSJérôme Duval uint8 length; 111d6e4f54fSJérôme Duval uint8 descriptor_type; 112d6e4f54fSJérôme Duval uint16 unicode_string[12]; 113d6e4f54fSJérôme Duval } _PACKED; 114d6e4f54fSJérôme Duval 115d6e4f54fSJérôme Duval 116d6e4f54fSJérôme Duval static xhci_root_hub_string_s sXHCIRootHubStrings[3] = { 117d6e4f54fSJérôme Duval { 118d6e4f54fSJérôme Duval 4, // Descriptor length 119d6e4f54fSJérôme Duval USB_DESCRIPTOR_STRING, // Descriptor type 120d6e4f54fSJérôme Duval { 121d6e4f54fSJérôme Duval 0x0409 // Supported language IDs (English US) 122d6e4f54fSJérôme Duval } 123d6e4f54fSJérôme Duval }, 124d6e4f54fSJérôme Duval 125d6e4f54fSJérôme Duval { 126d6e4f54fSJérôme Duval 22, // Descriptor length 127d6e4f54fSJérôme Duval USB_DESCRIPTOR_STRING, // Descriptor type 128d6e4f54fSJérôme Duval { 129d6e4f54fSJérôme Duval 'H', 'A', 'I', 'K', 'U', // Characters 130d6e4f54fSJérôme Duval ' ', 'I', 'n', 'c', '.' 131d6e4f54fSJérôme Duval } 132d6e4f54fSJérôme Duval }, 133d6e4f54fSJérôme Duval 134d6e4f54fSJérôme Duval { 135d6e4f54fSJérôme Duval 26, // Descriptor length 136d6e4f54fSJérôme Duval USB_DESCRIPTOR_STRING, // Descriptor type 137d6e4f54fSJérôme Duval { 138d6e4f54fSJérôme Duval 'X', 'H', 'C', 'I', ' ', // Characters 139d6e4f54fSJérôme Duval 'R', 'o', 'o', 't', 'H', 140d6e4f54fSJérôme Duval 'u', 'b' 141d6e4f54fSJérôme Duval } 142d6e4f54fSJérôme Duval } 143d6e4f54fSJérôme Duval }; 144d6e4f54fSJérôme Duval 145d6e4f54fSJérôme Duval 146d6e4f54fSJérôme Duval XHCIRootHub::XHCIRootHub(Object *rootObject, int8 deviceAddress) 147d6e4f54fSJérôme Duval : Hub(rootObject, 0, rootObject->GetStack()->IndexOfBusManager(rootObject->GetBusManager()), 148d6e4f54fSJérôme Duval sXHCIRootHubDevice, deviceAddress, USB_SPEED_SUPER, true) 149d6e4f54fSJérôme Duval { 150d6e4f54fSJérôme Duval } 151d6e4f54fSJérôme Duval 152d6e4f54fSJérôme Duval 153d6e4f54fSJérôme Duval status_t 154d6e4f54fSJérôme Duval XHCIRootHub::ProcessTransfer(XHCI *xhci, Transfer *transfer) 155d6e4f54fSJérôme Duval { 156d6e4f54fSJérôme Duval if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) == 0) 157d6e4f54fSJérôme Duval return B_ERROR; 158d6e4f54fSJérôme Duval 159d6e4f54fSJérôme Duval usb_request_data *request = transfer->RequestData(); 160d6e4f54fSJérôme Duval TRACE_MODULE("request: %d\n", request->Request); 161d6e4f54fSJérôme Duval 162d6e4f54fSJérôme Duval status_t status = B_TIMED_OUT; 163d6e4f54fSJérôme Duval size_t actualLength = 0; 164d6e4f54fSJérôme Duval switch (request->Request) { 165d6e4f54fSJérôme Duval case USB_REQUEST_GET_STATUS: { 166d6e4f54fSJérôme Duval if (request->Index == 0) { 167d6e4f54fSJérôme Duval // get hub status 168d6e4f54fSJérôme Duval actualLength = MIN(sizeof(usb_port_status), 169d6e4f54fSJérôme Duval transfer->DataLength()); 170d6e4f54fSJérôme Duval // the hub reports whether the local power failed (bit 0) 171d6e4f54fSJérôme Duval // and if there is a over-current condition (bit 1). 172d6e4f54fSJérôme Duval // everything as 0 means all is ok. 173d6e4f54fSJérôme Duval memset(transfer->Data(), 0, actualLength); 174d6e4f54fSJérôme Duval status = B_OK; 175d6e4f54fSJérôme Duval break; 176d6e4f54fSJérôme Duval } 177d6e4f54fSJérôme Duval 178d6e4f54fSJérôme Duval usb_port_status portStatus; 179d6e4f54fSJérôme Duval if (xhci->GetPortStatus(request->Index - 1, &portStatus) >= B_OK) { 180d6e4f54fSJérôme Duval actualLength = MIN(sizeof(usb_port_status), transfer->DataLength()); 181d6e4f54fSJérôme Duval memcpy(transfer->Data(), (void *)&portStatus, actualLength); 182d6e4f54fSJérôme Duval status = B_OK; 183d6e4f54fSJérôme Duval } 184d6e4f54fSJérôme Duval 185d6e4f54fSJérôme Duval break; 186d6e4f54fSJérôme Duval } 187d6e4f54fSJérôme Duval 188d6e4f54fSJérôme Duval case USB_REQUEST_SET_ADDRESS: 189d6e4f54fSJérôme Duval if (request->Value >= 128) { 190d6e4f54fSJérôme Duval status = B_TIMED_OUT; 191d6e4f54fSJérôme Duval break; 192d6e4f54fSJérôme Duval } 193d6e4f54fSJérôme Duval 194d6e4f54fSJérôme Duval TRACE_MODULE("set address: %d\n", request->Value); 195d6e4f54fSJérôme Duval status = B_OK; 196d6e4f54fSJérôme Duval break; 197d6e4f54fSJérôme Duval 198d6e4f54fSJérôme Duval case USB_REQUEST_GET_DESCRIPTOR: 199d6e4f54fSJérôme Duval TRACE_MODULE("get descriptor: %d\n", request->Value >> 8); 200d6e4f54fSJérôme Duval 201d6e4f54fSJérôme Duval switch (request->Value >> 8) { 202d6e4f54fSJérôme Duval case USB_DESCRIPTOR_DEVICE: { 203d6e4f54fSJérôme Duval actualLength = MIN(sizeof(usb_device_descriptor), 204d6e4f54fSJérôme Duval transfer->DataLength()); 205d6e4f54fSJérôme Duval memcpy(transfer->Data(), (void *)&sXHCIRootHubDevice, 206d6e4f54fSJérôme Duval actualLength); 207d6e4f54fSJérôme Duval status = B_OK; 208d6e4f54fSJérôme Duval break; 209d6e4f54fSJérôme Duval } 210d6e4f54fSJérôme Duval 211d6e4f54fSJérôme Duval case USB_DESCRIPTOR_CONFIGURATION: { 212d6e4f54fSJérôme Duval actualLength = MIN(sizeof(xhci_root_hub_configuration_s), 213d6e4f54fSJérôme Duval transfer->DataLength()); 214d6e4f54fSJérôme Duval sXHCIRootHubConfig.hub.num_ports = xhci->PortCount(); 215d6e4f54fSJérôme Duval memcpy(transfer->Data(), (void *)&sXHCIRootHubConfig, 216d6e4f54fSJérôme Duval actualLength); 217d6e4f54fSJérôme Duval status = B_OK; 218d6e4f54fSJérôme Duval break; 219d6e4f54fSJérôme Duval } 220d6e4f54fSJérôme Duval 221d6e4f54fSJérôme Duval case USB_DESCRIPTOR_STRING: { 222d6e4f54fSJérôme Duval uint8 index = request->Value & 0x00ff; 223d6e4f54fSJérôme Duval if (index > 2) 224d6e4f54fSJérôme Duval break; 225d6e4f54fSJérôme Duval 226d6e4f54fSJérôme Duval actualLength = MIN(sXHCIRootHubStrings[index].length, 227d6e4f54fSJérôme Duval transfer->DataLength()); 228d6e4f54fSJérôme Duval memcpy(transfer->Data(), (void *)&sXHCIRootHubStrings[index], 229d6e4f54fSJérôme Duval actualLength); 230d6e4f54fSJérôme Duval status = B_OK; 231d6e4f54fSJérôme Duval break; 232d6e4f54fSJérôme Duval } 233d6e4f54fSJérôme Duval 234d6e4f54fSJérôme Duval case USB_DESCRIPTOR_HUB: { 235d6e4f54fSJérôme Duval actualLength = MIN(sizeof(usb_hub_descriptor), 236d6e4f54fSJérôme Duval transfer->DataLength()); 237d6e4f54fSJérôme Duval sXHCIRootHubConfig.hub.num_ports = xhci->PortCount(); 238d6e4f54fSJérôme Duval memcpy(transfer->Data(), (void *)&sXHCIRootHubConfig.hub, 239d6e4f54fSJérôme Duval actualLength); 240d6e4f54fSJérôme Duval status = B_OK; 241d6e4f54fSJérôme Duval break; 242d6e4f54fSJérôme Duval } 243d6e4f54fSJérôme Duval } 244d6e4f54fSJérôme Duval break; 245d6e4f54fSJérôme Duval 246d6e4f54fSJérôme Duval case USB_REQUEST_SET_CONFIGURATION: 247d6e4f54fSJérôme Duval status = B_OK; 248d6e4f54fSJérôme Duval break; 249d6e4f54fSJérôme Duval 250d6e4f54fSJérôme Duval case USB_REQUEST_CLEAR_FEATURE: { 251d6e4f54fSJérôme Duval if (request->Index == 0) { 252d6e4f54fSJérôme Duval // we don't support any hub changes 253d6e4f54fSJérôme Duval TRACE_MODULE_ERROR("clear feature: no hub changes\n"); 254d6e4f54fSJérôme Duval break; 255d6e4f54fSJérôme Duval } 256d6e4f54fSJérôme Duval 257d6e4f54fSJérôme Duval TRACE_MODULE("clear feature: %d\n", request->Value); 258d6e4f54fSJérôme Duval if (xhci->ClearPortFeature(request->Index - 1, request->Value) >= B_OK) 259d6e4f54fSJérôme Duval status = B_OK; 260d6e4f54fSJérôme Duval break; 261d6e4f54fSJérôme Duval } 262d6e4f54fSJérôme Duval 263d6e4f54fSJérôme Duval case USB_REQUEST_SET_FEATURE: { 264d6e4f54fSJérôme Duval if (request->Index == 0) { 265d6e4f54fSJérôme Duval // we don't support any hub changes 266d6e4f54fSJérôme Duval TRACE_MODULE_ERROR("set feature: no hub changes\n"); 267d6e4f54fSJérôme Duval break; 268d6e4f54fSJérôme Duval } 269d6e4f54fSJérôme Duval 270d6e4f54fSJérôme Duval TRACE_MODULE("set feature: %d\n", request->Value); 271d6e4f54fSJérôme Duval if (xhci->SetPortFeature(request->Index - 1, request->Value) >= B_OK) 272d6e4f54fSJérôme Duval status = B_OK; 273d6e4f54fSJérôme Duval break; 274d6e4f54fSJérôme Duval } 275d6e4f54fSJérôme Duval } 276d6e4f54fSJérôme Duval 277d6e4f54fSJérôme Duval transfer->Finished(status, actualLength); 278d6e4f54fSJérôme Duval delete transfer; 279d6e4f54fSJérôme Duval return B_OK; 280d6e4f54fSJérôme Duval } 281