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