1/** 2 * \brief this file contains the emulation code for the root hub 3 */ 4/* 5 * Copyright (c) 2007-2013 ETH Zurich. 6 * All rights reserved. 7 * 8 * This file is distributed under the terms in the attached LICENSE file. 9 * If you do not find this file, copies can be found by writing to: 10 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 11 */ 12 13#include <stdlib.h> 14#include <stdio.h> 15#include <string.h> 16#include <barrelfish/barrelfish.h> 17 18#include "ehci_device.h" 19 20#include <usb/usb.h> 21#include <usb/usb_descriptor.h> 22#include <usb/usb_error.h> 23#include <usb/usb_request.h> 24 25#include <usb_device.h> 26#include <usb_controller.h> 27#include <usb_hub.h> 28#include "usb_ehci.h" 29#include "usb_ehci_root_hub.h" 30 31 32/* 33 * -------------------------------------------------------------------------- 34 * local variables defining the descriptors of the root hub 35 */ 36static const struct usb_device_descriptor rh_dev_desc = { 37 .bLength = sizeof(struct usb_device_descriptor), 38 .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE, 39 .bcdUSB = 0x0200, 40 .bDeviceClass = USB_HUB_CLASS_CODE, 41 .bDeviceSubClass = USB_HUB_SUBCLASS_CODE, 42 .bDeviceProtocol = USB_HUB_PROTOCOL_HSHUBSTT, 43 .bMaxPacketSize0 = 64, 44 .idVendor = 0, 45 .idProduct = 0, 46 .bcdDevice = 0x0100, 47 .iManufacturer = 1, 48 .iProduct = 2, 49 .iSerialNumber = 0, 50 .bNumConfigurations = 1, 51}; 52 53static const struct usb_device_qualifier_descriptor rh_qual_desc = { 54 .bLength = sizeof(struct usb_device_qualifier_descriptor), 55 .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, 56 .bcdUSB = 0x0200, 57 .bDeviceClass = USB_HUB_CLASS_CODE, 58 .bDeviceSubClass = USB_HUB_SUBCLASS_CODE, 59 .bDeviceProtocol = USB_HUB_PROTOCOL_FSHUB, 60 .bMaxPacketSize0 = 0, 61 .bNumConfigurations = 0, 62 .bReserved = 0, 63}; 64 65static const struct usb_ehci_config_descriptor rh_cfg_desc = { 66 .config = { 67 .bLength = sizeof(struct usb_config_descriptor), 68 .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIG, 69 .wTotalLength = sizeof(rh_cfg_desc), 70 .bNumInterfaces = 1, 71 .bConfigurationValue = 1, 72 .iConfiguration = 0, 73 .bmAttributes = USB_CONFIG_SELF_POWERED, 74 .bMaxPower = 0, 75 }, 76 .iface = { 77 .bLength = sizeof(struct usb_interface_descriptor), 78 .bDescriptorType = USB_DESCRIPTOR_TYPE_INTERFACE, 79 .bNumEndpoints = 1, 80 .bInterfaceClass = USB_HUB_IFACE_CLASS_CODE, 81 .bInterfaceSubClass = USB_HUB_IFACE_SUBCLASS_CODE, 82 .bInterfaceProtocol = 0, 83 }, 84 .endpoint = { 85 .bLength = sizeof(struct usb_endpoint_descriptor), 86 .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, 87 .bEndpointAddress = { 88 USB_ENDPOINT_DIRECTION_IN, 89 0, 90 1 91 }, 92 .bmAttributes = { 93 0, 94 0, 95 0, 96 USB_ENDPOINT_TYPE_INTR 97 }, 98 .wMaxPacketSize = (8 << 8), 99 .bInterval = 255, 100 }, 101}; 102 103static const struct usb_hub_descriptor rh_desc = { 104 .bDescLength = 0, 105 .bDescriptorType = USB_DESCRIPTOR_TYPE_HUB, 106 .bNbrPorts = 0, 107 .wHubCharacteristics = { 108 0, 109 0, 110 0, 111 0, 112 0, 113 0 114 }, 115 .bPwrOn2PwrGood = 0, 116 .bHubContrCurrent = 0, 117 .bDeviceRemovable = { 118 0 119 } 120}; 121 122/* 123 * -------------------------------------------------------------------------- 124 * functions emulating the root hub requests 125 */ 126 127 128/** 129 * \brief this function is called when a port change detected interrupt is risen 130 * 131 * \param hc the host controller which got the interrupt 132 */ 133void usb_ehci_roothub_interrupt(usb_ehci_hc_t *hc) 134{ 135 USB_DEBUG_TR_ENTER; 136 137 for (uint16_t i = 0; i < hc->rh_num_ports; i++) { 138 ehci_portsc_t ps = ehci_portsc_rd(&hc->ehci_base, i); 139 /* clear out the change bits */ 140 if (ehci_portsc_occ_extract(ps) || ehci_portsc_pec_extract(ps) 141 || ehci_portsc_csc_extract(ps)) { 142 USB_DEBUG_HC("roothub_interrupt: port %i has changed\n", i+1); 143 } 144 } 145 /* defer the handing to the hub driver */ 146 usb_hub_root_interrupt(hc->controller); 147} 148 149#define C(req, recipent, dir) ((req) | ((recipent)<<8) | ((dir)<<16)) 150 151/** 152 * \brief emulates the execution of the requests on the root hub 153 * 154 * \param device the roothub device 155 * \param req the request to execute 156 * \param ret_data the data returned when a read request was executed 157 * \param ret_length the number of bytes in the returned data 158 */ 159usb_error_t usb_ehci_roothub_exec(struct usb_device *device, 160 struct usb_device_request *req, const void **ret_data, 161 uint16_t *ret_length) 162{ 163 USB_DEBUG_TR_ENTER; 164 usb_ehci_hc_t *hc = (usb_ehci_hc_t *) device->controller->hc_control; 165 const char *str; 166 const void *data = (const void *) &hc->rh_desc; 167 uint16_t data_length = 0; 168 169 170 switch (C(req->bRequest, req->bType.recipient, req->bType.direction)) { 171 /* clear feature requests */ 172 case C(USB_REQUEST_CLEAR_FEATURE, USB_REQUEST_RECIPIENT_DEVICE, USB_REQUEST_WRITE): 173 case C(USB_REQUEST_CLEAR_FEATURE, USB_REQUEST_RECIPIENT_INTERFACE, USB_REQUEST_WRITE): 174 case C(USB_REQUEST_CLEAR_FEATURE, USB_REQUEST_RECIPIENT_ENDPOINT, USB_REQUEST_WRITE): 175 /* no-op: don't handle write requests */ 176 break; 177 178 /* get configuration request */ 179 case C(USB_REQUEST_GET_CONFIG, USB_REQUEST_RECIPIENT_DEVICE, USB_REQUEST_READ): 180 data_length = 1; 181 hc->rh_desc.temp[0] = hc->rh_device_config; 182 break; 183 184 /* get descriptor request */ 185 case C(USB_REQUEST_GET_DESCRIPTOR, USB_REQUEST_RECIPIENT_DEVICE, USB_REQUEST_READ): 186 switch (req->wValue >> 8) { 187 /* 188 * the only the string type has an id.. the others 189 * result in an IO error if there is an id set. 190 */ 191 case USB_DESCRIPTOR_TYPE_DEVICE: 192 case USB_DESCRIPTOR_TYPE_HUB: 193 if ((req->wValue & 0xFF) != 0) { 194 return (USB_ERR_IOERROR); 195 } 196 if (req->bType.type != USB_REQUEST_TYPE_CLASS) { 197 data_length = sizeof(rh_dev_desc); 198 data = (const void *) &rh_dev_desc; 199 break; 200 } 201 /* handling class specific request */ 202 hc->rh_desc.hub_desc = rh_desc; 203 hc->rh_desc.hub_desc.bNbrPorts = hc 204 ->rh_num_ports; 205 hc->rh_desc.hub_desc.wHubCharacteristics 206 .port_indicator = ehci_hcsparams_p_indicator_rdf( 207 &hc->ehci_base); 208 hc->rh_desc.hub_desc.wHubCharacteristics 209 .power_mode = ehci_hcsparams_ppc_rdf(&hc->ehci_base); 210 hc->rh_desc.hub_desc.bPwrOn2PwrGood = 200; 211 hc->rh_desc.hub_desc.bDescLength = 8 212 + ((hc->rh_num_ports + 7) / 8); 213 data_length = hc->rh_desc.hub_desc.bDescLength; 214 break; 215 case USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER: 216 if ((req->wValue & 0xFF) != 0) { 217 return (USB_ERR_IOERROR); 218 } 219 data_length = sizeof(rh_qual_desc); 220 data = (const void *) &rh_qual_desc; 221 break; 222 223 case USB_DESCRIPTOR_TYPE_CONFIG: 224 if ((req->wValue & 0xFF) != 0) { 225 return (USB_ERR_IOERROR); 226 } 227 data_length = sizeof(rh_cfg_desc); 228 data = (const void *) &rh_cfg_desc; 229 break; 230 231 case USB_DESCRIPTOR_TYPE_STRING: 232 switch (req->wValue & 0xFF) { 233 case 0: 234 str = "\001"; 235 break; 236 case 1: 237 str = hc->rh_vendor; 238 break; 239 case 2: 240 str = "EHCI root hub"; 241 break; 242 default: 243 str = ""; 244 break; 245 } 246 /* 247 * TODO: MAKE STRING DESCRIPTOR 248 * len = ... 249 * store in hub_desc.tmp 250 */ 251 break; 252 default: 253 debug_printf("GET_DESC ->IOERR\n"); 254 return (USB_ERR_IOERROR); 255 break; 256 } 257 break; 258 259 /* get interface requests */ 260 case C(USB_REQUEST_GET_INTERFACE, USB_REQUEST_RECIPIENT_INTERFACE, USB_REQUEST_READ): 261 /* we don't have an alternative interface */ 262 data_length = 1; 263 hc->rh_desc.temp[0] = 0; 264 break; 265 266 /* get status request - device */ 267 case C(USB_REQUEST_GET_STATUS, USB_REQUEST_RECIPIENT_DEVICE, USB_REQUEST_READ): 268 if (req->bType.type != USB_REQUEST_TYPE_CLASS) { 269 data_length = 2; 270 hc->rh_desc.status.wStatus = USB_STATUS_SELF_POWERED; 271 break; 272 } 273 data_length = 16; 274 memset(hc->rh_desc.temp, 0, 16); 275 276 break; 277 278 /* get status request - interface or endpoint */ 279 case C(USB_REQUEST_GET_STATUS, USB_REQUEST_RECIPIENT_INTERFACE, USB_REQUEST_READ): 280 case C(USB_REQUEST_GET_STATUS, USB_REQUEST_RECIPIENT_ENDPOINT, USB_REQUEST_READ): 281 data_length = 2; 282 hc->rh_desc.status.wStatus = 0; 283 break; 284 285 /* set address request */ 286 case C(USB_REQUEST_SET_ADDRESS, USB_REQUEST_RECIPIENT_DEVICE, USB_REQUEST_WRITE): 287 if (req->wValue >= USB_EHCI_MAX_DEVICES) { 288 return (USB_ERR_IOERROR); 289 } 290 hc->rh_device_address = req->wValue; 291 break; 292 293 /* set configuration request */ 294 case C(USB_REQUEST_SET_CONFIG, USB_REQUEST_RECIPIENT_DEVICE, USB_REQUEST_WRITE): 295 if ((req->wValue != 0) && (req->wValue != 1)) { 296 return (USB_ERR_IOERROR); 297 } 298 hc->rh_device_config = req->wValue; 299 break; 300 301 /* set descriptor request */ 302 case C(USB_REQUEST_SET_DESCRIPTOR, USB_REQUEST_RECIPIENT_DEVICE, USB_REQUEST_WRITE): 303 /* do not allow to change the descriptor */ 304 break; 305 306 /* set feature request */ 307 case C(USB_REQUEST_SET_FEATURE, USB_REQUEST_RECIPIENT_DEVICE, USB_REQUEST_WRITE): 308 case C(USB_REQUEST_SET_FEATURE, USB_REQUEST_RECIPIENT_INTERFACE, USB_REQUEST_WRITE): 309 case C(USB_REQUEST_SET_FEATURE, USB_REQUEST_RECIPIENT_ENDPOINT, USB_REQUEST_WRITE): 310 /* setting a feature results in IO error */ 311 return (USB_ERR_IOERROR); 312 break; 313 314 /* set interface request */ 315 case C(USB_REQUEST_SET_INTERFACE, USB_REQUEST_RECIPIENT_INTERFACE, USB_REQUEST_WRITE): 316 break; 317 318 /* set synch frame request */ 319 case C(USB_REQUEST_SYNCH_FRAME, USB_REQUEST_RECIPIENT_ENDPOINT, USB_REQUEST_WRITE): 320 break; 321 322 /* 323 * handling hub class specific requests 324 */ 325 326 /* clear hub feature request */ 327 case C(USB_HUB_REQ_CLEAR_FEATURE, USB_REQUEST_RECIPIENT_OTHER, USB_REQUEST_WRITE): 328 if ((req->wIndex < 1) || (req->wLength > hc->rh_num_ports)) { 329 /* invalid port nuber */ 330 return (USB_ERR_IOERROR); 331 } 332 /* mackerel is zero based */ 333 req->wIndex--; 334 335 switch (req->wValue) { 336 case USB_HUB_FEATURE_PORT_ENABLE: 337 ehci_portsc_ped_wrf(&hc->ehci_base, req->wIndex, 0); 338 break; 339 case USB_HUB_FEATURE_PORT_SUSPEND: 340 if (ehci_portsc_sus_rdf(&hc->ehci_base, req->wIndex) 341 && (!ehci_portsc_fpr_rdf(&hc->ehci_base, req->wIndex))) { 342 ehci_portsc_fpr_wrf(&hc->ehci_base, req->wIndex, 1); 343 } 344 lib_usb_wait(20); 345 346 ehci_portsc_sus_wrf(&hc->ehci_base, req->wIndex, 0); 347 ehci_portsc_fpr_wrf(&hc->ehci_base, req->wIndex, 0); 348 ehci_portsc_ls_wrf(&hc->ehci_base, req->wIndex, 0x3); 349 lib_usb_wait(4); 350 break; 351 case USB_HUB_FEATURE_PORT_POWER: 352 ehci_portsc_pp_wrf(&hc->ehci_base, req->wIndex, 0); 353 break; 354 case USB_HUB_FEATURE_PORT_TEST: 355 /* clear port test */ 356 break; 357 358 case USB_HUB_FEATURE_PORT_INDICATOR: 359 ehci_portsc_pic_wrf(&hc->ehci_base, req->wIndex, 0); 360 break; 361 case USB_HUB_FEATURE_C_PORT_CONNECTION: 362 ehci_portsc_csc_wrf(&hc->ehci_base, req->wIndex, 1); 363 break; 364 365 case USB_HUB_FEATURE_C_PORT_ENABLE: 366 ehci_portsc_pec_wrf(&hc->ehci_base, req->wIndex, 1); 367 break; 368 case USB_HUB_FEATURE_C_PORT_SUSPEND: 369 ehci_portsc_sus_wrf(&hc->ehci_base, req->wIndex, 1); 370 break; 371 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: 372 ehci_portsc_occ_wrf(&hc->ehci_base, req->wIndex, 1); 373 break; 374 case USB_HUB_FEATURE_C_PORT_RESET: 375 hc->rh_reset = 0; 376 break; 377 default: 378 return (USB_ERR_IOERROR); 379 break; 380 } 381 break; 382 383 384 /* get hub status request */ 385 case C(USB_HUB_REQ_GET_STATUS, USB_REQUEST_RECIPIENT_OTHER, USB_REQUEST_READ): 386 if ((req->wIndex < 1) || (req->wIndex > hc->rh_num_ports)) { 387 /* invalid port number */ 388 debug_printf("ehci: root_hub_exec: invalid port number %i\n", 389 req->wIndex); 390 return (USB_ERR_IOERROR); 391 } 392 data_length = sizeof(hc->rh_desc.port_status); 393 struct usb_hub_port_status *ps = &(hc->rh_desc 394 .port_status); 395 memset(ps, 0, sizeof(*ps)); 396 /* subtract one, mackerel is zero based */ 397 ehci_portsc_t ehci_ps = ehci_portsc_rd(&hc->ehci_base, 398 req->wIndex - 1); 399 400 ps->wPortStatus.enabled = ehci_portsc_ped_extract(ehci_ps); 401 ps->wPortStatus.indicator = ehci_portsc_pic_extract(ehci_ps) > 0; 402 ps->wPortStatus.test_mode = ehci_portsc_ptc_extract(ehci_ps) > 0; 403 404 if (ehci_portsc_ls_extract(ehci_ps) == 0x1) { 405 /* low speed device */ 406 USB_DEBUG("port (%u) has low speed device\n", req->wIndex); 407 ps->wPortStatus.is_ls = 1; 408 ps->wPortStatus.is_hs = 0; 409 } else { 410 ps->wPortStatus.is_hs = 1; 411 ps->wPortStatus.is_ls = 0; 412 } 413 414 ps->wPortStatus.power_state = ehci_portsc_pp_extract(ehci_ps); 415 ps->wPortStatus.reset = ehci_portsc_pr_extract(ehci_ps); 416 ps->wPortStatus.over_current = ehci_portsc_oca_extract(ehci_ps); 417 if (ehci_portsc_sus_extract(ehci_ps) 418 && !(ehci_portsc_fpr_extract(ehci_ps))) { 419 ps->wPortStatus.suspend = 1; 420 } 421 ps->wPortStatus.connection = ehci_portsc_ccs_extract(ehci_ps); 422 423 ps->wPortChange.is_reset = hc->rh_reset; 424 ps->wPortChange.over_current = ehci_portsc_occ_extract(ehci_ps); 425 ps->wPortChange.resumed = ehci_portsc_fpr_extract(ehci_ps); 426 ps->wPortChange.disabled = ehci_portsc_pec_extract(ehci_ps); 427 ps->wPortChange.connect = ehci_portsc_csc_extract(ehci_ps); 428 429 break; 430 431 /* set hub feature request */ 432 case C(USB_HUB_REQ_SET_FEATURE, USB_REQUEST_RECIPIENT_OTHER, USB_REQUEST_WRITE): 433 if ((req->wIndex < 1) || (req->wIndex > hc->rh_num_ports)) { 434 /* invalid port number */ 435 return (USB_ERR_IOERROR); 436 } 437 /* mackerel is zero based */ 438 req->wIndex--; 439 switch (req->wValue) { 440 case USB_HUB_FEATURE_PORT_ENABLE: 441 ehci_portsc_ped_wrf(&hc->ehci_base, req->wIndex, 1); 442 break; 443 case USB_HUB_FEATURE_PORT_SUSPEND: 444 ehci_portsc_sus_wrf(&hc->ehci_base, req->wIndex, 1); 445 break; 446 case USB_HUB_FEATURE_PORT_RESET: 447 if (ehci_portsc_ls_rdf(&hc->ehci_base, req->wIndex) == 0x1) { 448 /* low speed device */ 449 usb_ehci_roothub_port_disown(hc, req->wIndex); 450 break; 451 } 452 /* initiate reset sequence */ 453 ehci_portsc_pr_wrf(&hc->ehci_base, req->wIndex, 1); 454 lib_usb_wait(200); 455 456 /* clear the reset */ 457 ehci_portsc_pr_wrf(&hc->ehci_base, req->wIndex, 0); 458 lib_usb_wait(200); 459 460 if (ehci_portsc_pr_rdf(&hc->ehci_base, req->wIndex)) { 461 debug_printf("exec: timeout while resetting port\n"); 462 return (USB_ERR_TIMEOUT); 463 } 464 465 if (!ehci_portsc_ped_rdf(&hc->ehci_base, req->wIndex)) { 466 /* 467 * TODO: DISOWNING PORTS... 468 * if (hc->flags.tt_present) { 469 usb_ehci_roothub_port_disown(hc, req->wIndex, 0); 470 }*/ 471 } 472 hc->rh_reset = 1; 473 474 break; 475 case USB_HUB_FEATURE_PORT_POWER: 476 ehci_portsc_pp_wrf(&hc->ehci_base, req->wIndex, 1); 477 break; 478 case USB_HUB_FEATURE_PORT_TEST: 479 break; 480 case USB_HUB_FEATURE_PORT_INDICATOR: 481 ehci_portsc_pic_wrf(&hc->ehci_base, req->wIndex, 1); 482 break; 483 default: 484 return (USB_ERR_IOERROR); 485 } 486 break; 487 488 /* transaction translator requests */ 489 case C(USB_HUB_REQ_CLEAR_TT_BUFFER, USB_REQUEST_RECIPIENT_OTHER, USB_REQUEST_WRITE): 490 case C(USB_HUB_REQ_RESET_TT, USB_REQUEST_RECIPIENT_OTHER, USB_REQUEST_WRITE): 491 case C(USB_HUB_REQ_STOP_TT, USB_REQUEST_RECIPIENT_OTHER, USB_REQUEST_WRITE): 492 /* root hub does not have a transaction translator */ 493 break; 494 default: 495 return (USB_ERR_IOERROR); 496 } 497 498 if (ret_length) { 499 *ret_length = data_length; 500 } 501 502 if (ret_data) { 503 504 *ret_data = data; 505 } 506 507 return (USB_ERR_OK); 508} 509 510 511/* 512 * \brief this function hands over the port to the companion controller 513 * 514 * \param hc the host controller of the root hub 515 * \param portno the port number to disown 516 */ 517void usb_ehci_roothub_port_disown(usb_ehci_hc_t *hc, uint16_t portno) 518{ 519 if (portno > ehci_hcsparams_n_ports_rdf(&hc->ehci_base)) { 520 debug_printf("ERROR: port does not exist! \n"); 521 return; 522 } 523 524 assert(portno > 0); 525 /* mackerel is zero based */ 526 portno--; 527 528 ehci_portsc_po_wrf(&hc->ehci_base, portno, 1); 529 530} 531 532