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