1219019Sgabor/* 2219019Sgabor * Copyright (c) 2007-2013 ETH Zurich. 3219019Sgabor * All rights reserved. 4219019Sgabor * 5219019Sgabor * This file is distributed under the terms in the attached LICENSE file. 6219019Sgabor * If you do not find this file, copies can be found by writing to: 7219019Sgabor * ETH Zurich D-INFK, Universitaetstrasse 6, CH-8092 Zurich. Attn: Systems Group. 8219019Sgabor */ 9219019Sgabor 10219019Sgabor#include <stdlib.h> 11219019Sgabor#include <stdio.h> 12219019Sgabor#include <string.h> 13219019Sgabor#include <barrelfish/barrelfish.h> 14219019Sgabor 15219019Sgabor#include "ohci_device.h" 16219019Sgabor 17219019Sgabor#include <usb/usb.h> 18219019Sgabor#include <usb/usb_descriptor.h> 19219019Sgabor#include <usb/usb_error.h> 20219019Sgabor#include <usb/usb_request.h> 21219019Sgabor#include <usb_device.h> 22219019Sgabor#include <usb_hub.h> 23219019Sgabor#include <usb_controller.h> 24219019Sgabor#include "usb_ohci.h" 25219019Sgabor#include "usb_ohci_root_hub.h" 26219019Sgabor 27219019Sgabor 28219019Sgaborstatic const struct usb_device_descriptor usb_ohci_root_hub_device_desc = { 29219019Sgabor .bLength = sizeof(struct usb_device_descriptor), 30219019Sgabor .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE, 31219019Sgabor .bcdUSB = 0x0100, 32219019Sgabor .bDeviceClass = USB_HUB_CLASS_CODE, 33219019Sgabor .bDeviceSubClass = USB_HUB_SUBCLASS_CODE, 34219019Sgabor .bDeviceProtocol = USB_HUB_PROTOCOL_FSHUB, 35219019Sgabor .bMaxPacketSize0 = 64, 36219019Sgabor .idVendor = 0, 37219019Sgabor .idProduct = 0, 38219019Sgabor .bcdDevice = 0x0100, 39219019Sgabor .iManufacturer = 1, 40219019Sgabor .iProduct = 2, 41219019Sgabor .iSerialNumber = 0, 42219019Sgabor .bNumConfigurations = 1, 43219019Sgabor}; 44219019Sgabor 45219019Sgaborstatic const struct usb_ohci_config_desc usb_ohci_root_hub_config_desc = { 46219019Sgabor.config_desc = { 47219019Sgabor .bLength = sizeof(struct usb_config_descriptor), 48219019Sgabor .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIG, 49219019Sgabor .wTotalLength = sizeof(usb_ohci_root_hub_config_desc), 50219019Sgabor .bNumInterfaces = 1, 51219019Sgabor .bConfigurationValue = 1, 52219019Sgabor .iConfiguration = 0, 53219019Sgabor .bmAttributes = USB_CONFIG_SELF_POWERED, 54219019Sgabor .bMaxPower = 0, 55219019Sgabor}, .iface_desc = { 56219019Sgabor.bLength = sizeof(struct usb_interface_descriptor), .bDescriptorType = 57219019Sgabor USB_DESCRIPTOR_TYPE_INTERFACE, .bNumEndpoints = 1, .bInterfaceClass = 58219019Sgabor USB_HUB_IFACE_CLASS_CODE, .bInterfaceSubClass = 59219019Sgabor USB_HUB_IFACE_SUBCLASS_CODE, .bInterfaceProtocol = 0, 60219019Sgabor}, .ep_desc = { 61219019Sgabor .bLength = sizeof(struct usb_endpoint_descriptor), 62219019Sgabor .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, 63219019Sgabor .bEndpointAddress = {USB_ENDPOINT_DIRECTION_IN,0,1}, 64219019Sgabor .bmAttributes = {0,0,0,USB_ENDPOINT_TYPE_INTR}, 65219019Sgabor .wMaxPacketSize = 32, 66219019Sgabor .bInterval = 255, 67219019Sgabor}, 68219019Sgabor}; 69219019Sgabor 70219019Sgaborstatic const struct usb_hub_descriptor usb_ohci_root_hub_desc = { 71219019Sgabor .bDescLength = 0, 72219019Sgabor .bDescriptorType = USB_DESCRIPTOR_TYPE_HUB, 73219019Sgabor .bNbrPorts = 0, 74219019Sgabor .wHubCharacteristics = {0, 0, 0, 0, 0, 0}, 75219019Sgabor .bPwrOn2PwrGood = 0, 76219019Sgabor .bHubContrCurrent = 0, 77219019Sgabor .bDeviceRemovable = {0} 78219019Sgabor}; 79219019Sgabor 80219019Sgabor/** 81219019Sgabor * \brief this function clears the old interrupt data and reads the 82219019Sgabor * status from the ports 83260003Sdim * 84219019Sgabor * \param hc the host controller 85219019Sgabor */ 86219019Sgaborvoid usb_ohci_root_hub_interrupt(usb_ohci_hc_t *hc) 87219019Sgabor{ 88219019Sgabor /* clear old interrupt data */ 89219019Sgabor memset(hc->root_hub_intr_data, 0, sizeof(hc->root_hub_intr_data)); 90219019Sgabor 91219019Sgabor /* get the root hub status */ 92219019Sgabor //ohci_rh_status_t hstatus = ohci_rh_status_rd(hc->ohci_base); 93219019Sgabor 94219019Sgabor 95219019Sgabor /* get the number of ports */ 96219019Sgabor uint16_t num_ports = hc->root_hub_num_ports + 1; 97219019Sgabor if (num_ports > (8 * sizeof(hc->root_hub_intr_data))) { 98219019Sgabor num_ports = (8 * sizeof(hc->root_hub_intr_data)); 99219019Sgabor } 100219019Sgabor 101260003Sdim //char buf[4048]; 102219019Sgabor // ohci_rh_portstat_pr(buf, 4047, hc->ohci_base); 103219019Sgabor // printf(buf); 104219019Sgabor ohci_rh_portstat_t ps; 105219019Sgabor /* set the bits in the interrupt data field */ 106219019Sgabor for (uint16_t i = 0; i < num_ports; i++) { 107219019Sgabor 108219019Sgabor ps = ohci_rh_portstat_rd(hc->ohci_base, i); 109219019Sgabor if (ps >> 16) { 110219019Sgabor /* port i has changed */ 111219019Sgabor USB_DEBUG("port %u, has changed..\n", i); 112219019Sgabor hc->root_hub_intr_data[i / 8] |= (1 << (i % 8)); 113219019Sgabor } 114219019Sgabor } 115219019Sgabor 116219019Sgabor /* TODO: Handle the hub interrupts */ 117219019Sgabor // assert(!"NYI: Root hub interrupt handling"); 118219019Sgabor //uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, sizeof(sc->sc_hub_idata)); 119219019Sgabor} 120219019Sgabor 121219019Sgabor/* 122219019Sgabor * \brief this function enables the status change interrupt 123219019Sgabor * of the root hub and updates the enabled_intrs field 124219019Sgabor * of the host controller. 125219019Sgabor * 126219019Sgabor * \param hc the host controller 127219019Sgabor */ 128219019Sgaborstatic void usb_ohci_root_hub_sc_intr_enable(usb_ohci_hc_t *hc) 129219019Sgabor{ 130219019Sgabor /* update the enabled interrupt field in our hc */ 131219019Sgabor ohci_interrupt_t ie = ohci_intenable_rd(hc->ohci_base); 132219019Sgabor ohci_interrupt_rhsc_insert(ie, 1); 133219019Sgabor hc->enabled_intrs = ie; 134219019Sgabor 135219019Sgabor /* enable the interrupt */ 136219019Sgabor ohci_intenable_rhsc_wrf(hc->ohci_base, 1); 137219019Sgabor 138219019Sgabor /* acknowledge any RHSC interrupts */ 139219019Sgabor ohci_intstatus_rhsc_wrf(hc->ohci_base, 1); 140219019Sgabor 141219019Sgabor usb_ohci_root_hub_interrupt(hc); 142219019Sgabor} 143219019Sgabor 144219019Sgabor/** 145219019Sgabor * \brief this function emulates the USB root hub device by software 146219019Sgabor * 147219019Sgabor * \param device the USB device we want to issue the request for 148281550Stijl * \param req the USB request to execute 149219019Sgabor * \param ret_data pointer to the returned data 150219019Sgabor * \param ret_length the returned length 151281550Stijl */ 152219019Sgaborusb_error_t usb_ohci_roothub_exec(struct usb_device *device, 153219019Sgabor struct usb_device_request *req, const void **ret_data, 154219019Sgabor uint16_t *ret_length) 155219019Sgabor{ 156219019Sgabor usb_ohci_hc_t *hc = (usb_ohci_hc_t *) device->controller->hc_control; 157219019Sgabor 158219019Sgabor const void *data = (const void *) hc->root_hub_desc.temp; 159219019Sgabor uint16_t length = 0; 160219019Sgabor 161219019Sgabor uint16_t req_value = req->wValue; 162219019Sgabor uint16_t req_index = req->wIndex; 163219019Sgabor 164219019Sgabor const char *str_ptr; 165219019Sgabor 166219019Sgabor /* 167219019Sgabor * execute the request for the USB root hub 168219019Sgabor */ 169219019Sgabor switch (req->bRequest) { 170219019Sgabor 171219019Sgabor case USB_REQUEST_CLEAR_FEATURE: 172219019Sgabor /* 173219019Sgabor * ClearFeature() Request 174219019Sgabor * 175219019Sgabor * The only clear feature request is the clear port feature 176219019Sgabor * for an existing port 1..num_ports 177219019Sgabor */ 178219019Sgabor if (req->bType.recipient == USB_REQUEST_RECIPIENT_OTHER) { 179219019Sgabor if ((req_index < 1) || (req_index > hc->root_hub_num_ports)) { 180219019Sgabor *ret_length = length; 181219019Sgabor *ret_data = data; 182219019Sgabor return USB_ERR_IOERROR; 183219019Sgabor } 184219019Sgabor // get the current value of the register 185219019Sgabor ohci_rh_portstat_t ps = ohci_rh_portstat_rd(hc->ohci_base, 186219019Sgabor req_index); 187219019Sgabor 188219019Sgabor switch (req_value) { 189219019Sgabor case USB_HUB_FEATURE_PORT_ENABLE: 190219019Sgabor ohci_rh_portstat_ccs_insert(ps, 1); 191219019Sgabor break; 192219019Sgabor case USB_HUB_FEATURE_PORT_SUSPEND: 193219019Sgabor ohci_rh_portstat_poci_insert(ps, 1); 194219019Sgabor break; 195219019Sgabor case USB_HUB_FEATURE_PORT_POWER: 196219019Sgabor ohci_rh_portstat_lsda_insert(ps, 1); 197219019Sgabor break; 198219019Sgabor case USB_HUB_FEATURE_C_PORT_CONNECTION: 199219019Sgabor ohci_rh_portstat_csc_insert(ps, 1); 200219019Sgabor break; 201219019Sgabor case USB_HUB_FEATURE_C_PORT_ENABLE: 202219019Sgabor ohci_rh_portstat_pesc_insert(ps, 1); 203219019Sgabor break; 204219019Sgabor case USB_HUB_FEATURE_C_PORT_SUSPEND: 205219019Sgabor ohci_rh_portstat_pssc_insert(ps, 1); 206219019Sgabor break; 207219019Sgabor case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: 208219019Sgabor ohci_rh_portstat_ocic_insert(ps, 1); 209219019Sgabor break; 210219019Sgabor case USB_HUB_FEATURE_C_PORT_RESET: 211219019Sgabor ohci_rh_portstat_prsc_insert(ps, 1); 212219019Sgabor break; 213219019Sgabor default: 214219019Sgabor *ret_length = length; 215219019Sgabor *ret_data = data; 216219019Sgabor return USB_ERR_IOERROR; 217219019Sgabor } 218219019Sgabor // write the value to the register 219219019Sgabor ohci_rh_portctrl_rawwr(hc->ohci_base, req_index, ps); 220219019Sgabor 221219019Sgabor switch (req_value) { 222219019Sgabor case USB_HUB_FEATURE_C_PORT_CONNECTION: 223219019Sgabor case USB_HUB_FEATURE_C_PORT_ENABLE: 224219019Sgabor case USB_HUB_FEATURE_C_PORT_SUSPEND: 225219019Sgabor case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: 226219019Sgabor case USB_HUB_FEATURE_C_PORT_RESET: 227219019Sgabor ps = ohci_rh_portstat_rd(hc->ohci_base, req_index); 228219019Sgabor if ((ps >> 16) == 0) { 229219019Sgabor usb_ohci_root_hub_sc_intr_enable(hc); 230219019Sgabor } 231219019Sgabor break; 232219019Sgabor default: 233219019Sgabor break; 234219019Sgabor } 235219019Sgabor } 236219019Sgabor break; 237219019Sgabor 238219019Sgabor case USB_REQUEST_GET_CONFIG: 239219019Sgabor /* 240219019Sgabor * GetConfiguration() Request 241219019Sgabor */ 242219019Sgabor if ((req->bType.recipient == USB_REQUEST_RECIPIENT_DEVICE) 243219019Sgabor && req->bType.direction == USB_REQUEST_READ) { 244219019Sgabor length = 1; 245219019Sgabor hc->root_hub_desc.temp[0] = hc->root_hub_config; 246219019Sgabor } 247219019Sgabor break; 248219019Sgabor 249219019Sgabor case USB_REQUEST_GET_DESCRIPTOR: 250219019Sgabor /* 251219019Sgabor * GetDescriptor() Request 252219019Sgabor * 253219019Sgabor * There are 3 different kind of standard descriptors we can 254219019Sgabor * return: Device, Interface and String 255219019Sgabor * 256219019Sgabor * and also a class specific request 257219019Sgabor */ 258219019Sgabor if ((req->bType.recipient == USB_REQUEST_RECIPIENT_DEVICE) 259219019Sgabor && req->bType.direction == USB_REQUEST_READ) { 260219019Sgabor 261219019Sgabor /* hub class specific request */ 262219019Sgabor if (req->bType.type == USB_REQUEST_TYPE_CLASS) { 263219019Sgabor if ((req_value & 0xFF) != 0) { 264219019Sgabor *ret_length = length; 265219019Sgabor *ret_data = data; 266219019Sgabor return USB_ERR_IOERROR; 267219019Sgabor } 268219019Sgabor ohci_rh_descra_t cda; 269219019Sgabor cda = ohci_rh_descra_rd(hc->ohci_base); 270219019Sgabor 271219019Sgabor // get the standard hub descriptor to fill in data 272219019Sgabor hc->root_hub_desc.hub_descriptor = usb_ohci_root_hub_desc; 273219019Sgabor 274219019Sgabor struct usb_hub_descriptor *hub = &(hc->root_hub_desc 275219019Sgabor .hub_descriptor); 276219019Sgabor hub->bNbrPorts = hc->root_hub_num_ports; 277219019Sgabor 278219019Sgabor hub->wHubCharacteristics.power_mode = 279219019Sgabor ohci_rh_descra_nps_extract(cda); 280219019Sgabor hub->bPwrOn2PwrGood = ohci_rh_descra_potpgt_extract(cda); 281219019Sgabor 282219019Sgabor /* update device removable stats */ 283219019Sgabor ohci_rh_descra_t cdb; 284219019Sgabor cdb = ohci_rh_descrb_rd(hc->ohci_base); 285219019Sgabor for (uint16_t i = 0; i < hc->root_hub_num_ports; i++) { 286219019Sgabor if (cdb & 1) { 287219019Sgabor hub->bDeviceRemovable[i / 8] |= (1 << (i % 8)); 288219019Sgabor } 289219019Sgabor i >>= 1; 290219019Sgabor } 291219019Sgabor hub->bDescLength = 8 + ((hc->root_hub_num_ports + 7 / 8)); 292219019Sgabor length = hub->bDescLength; 293219019Sgabor break; 294219019Sgabor } 295219019Sgabor /* standard usb request */ 296219019Sgabor switch (req_value >> 8) { 297219019Sgabor case USB_DESCRIPTOR_TYPE_DEVICE: 298219019Sgabor if ((req_value & 0xFF) != 0) { 299219019Sgabor *ret_length = length; 300219019Sgabor *ret_data = data; 301219019Sgabor return USB_ERR_IOERROR; 302219019Sgabor } 303219019Sgabor length = sizeof(usb_ohci_root_hub_device_desc); 304219019Sgabor data = (const void *) &usb_ohci_root_hub_device_desc; 305219019Sgabor break; 306219019Sgabor case USB_DESCRIPTOR_TYPE_CONFIG: 307219019Sgabor if ((req_value & 0xFF) != 0) { 308219019Sgabor *ret_length = length; 309219019Sgabor *ret_data = data; 310219019Sgabor return USB_ERR_IOERROR; 311219019Sgabor } 312219019Sgabor length = sizeof(usb_ohci_root_hub_config_desc); 313219019Sgabor data = (const void *) &usb_ohci_root_hub_config_desc; 314219019Sgabor break; 315219019Sgabor case USB_DESCRIPTOR_TYPE_STRING: 316219019Sgabor switch (req_value & 0xFF) { 317219019Sgabor case 0: 318219019Sgabor str_ptr = "\001"; 319219019Sgabor break; 320219019Sgabor case 1: 321219019Sgabor break; 322219019Sgabor str_ptr = hc->vendor; 323219019Sgabor case 2: 324219019Sgabor break; 325219019Sgabor str_ptr = "OHCI root HUB"; 326219019Sgabor default: 327219019Sgabor str_ptr = ""; 328219019Sgabor break; 329219019Sgabor } 330219019Sgabor /* TODO: Make string descriptor */ 331219019Sgabor assert(!"NYI: Make string descriptor"); 332219019Sgabor break; 333219019Sgabor default: 334219019Sgabor *ret_length = length; 335219019Sgabor *ret_data = data; 336 return USB_ERR_IOERROR; 337 break; 338 } 339 } 340 break; 341 342 case USB_REQUEST_GET_INTERFACE: 343 /* 344 * GetInterface() Request 345 * 346 * Root hub has just one interface and no alternative one 347 */ 348 if ((req->bType.recipient == USB_REQUEST_RECIPIENT_DEVICE) 349 && req->bType.direction == USB_REQUEST_READ) { 350 length = 1; 351 hc->root_hub_desc.temp[0] = 0; 352 } 353 break; 354 355 case USB_REQUEST_GET_STATUS: 356 /* 357 * GetStatus() Request 358 */ 359 if (req->bType.direction == USB_REQUEST_WRITE) { 360 *ret_data = data; 361 *ret_length = length; 362 return USB_ERR_IOERROR; 363 } 364 365 if (req->bType.type == USB_REQUEST_TYPE_CLASS) { 366 if (req->bType.recipient == USB_REQUEST_RECIPIENT_DEVICE) { 367 length = 16; 368 memset(hc->root_hub_desc.temp, 0, 16); 369 break; 370 } else if (req->bType.recipient == USB_REQUEST_RECIPIENT_OTHER) { 371 /* get port status */ 372 if ((req_index < 1) || req_index > hc->root_hub_num_ports) { 373 // invalid port number; 374 *ret_length = length; 375 *ret_data = data; 376 return USB_ERR_IOERROR; 377 } 378 ohci_rh_portstat_t ps = ohci_rh_portstat_rawrd( 379 hc->ohci_base, req_index); 380 memcpy(&hc->root_hub_desc.port_status.wPortChange, &ps, 2); 381 ps <<= 16; 382 memcpy(&hc->root_hub_desc.port_status.wPortStatus, &ps, 2); 383 //hc->root_hub_desc.port_status.wPortChange = (ps >> 16); 384 //hc->root_hub_desc.port_status.wPortStatus = (ps & 0xFFFF); 385 length = sizeof(hc->root_hub_desc.port_status); 386 break; 387 } 388 } 389 390 if ((req->bType.recipient == USB_REQUEST_RECIPIENT_DEVICE)) { 391 length = 2; 392 hc->root_hub_desc.status.wStatus = USB_STATUS_SELF_POWERED; 393 } else { 394 length = 2; 395 hc->root_hub_desc.status.wStatus = 0; 396 } 397 398 break; 399 400 case USB_REQUEST_SET_ADDRESS: 401 /* 402 * SetAddress() Request 403 * 404 * we can set the address of the root hub if it is 405 * withint the maximum devices range 406 */ 407 if (req_value > USB_OHCI_MAX_DEVICES) { 408 *ret_length = length; 409 *ret_data = data; 410 return USB_ERR_IOERROR; 411 } 412 hc->root_hub_address = req_value; 413 break; 414 415 case USB_REQUEST_SET_CONFIG: 416 /* 417 * SetConfiguration() Request 418 * 419 * We have only two two options (0, 1) that we can set 420 */ 421 if (req_value > 1) { 422 *ret_length = length; 423 *ret_data = data; 424 return USB_ERR_IOERROR; 425 } 426 hc->root_hub_config = req_value; 427 break; 428 429 case USB_REQUEST_SET_DESCRIPTOR: 430 /* 431 * SetDescriptor() Request 432 * 433 * We do not allow to change the USB root hub descriptor 434 * so this is a no-op for standard requests 435 * 436 * but is is an error for hub class requests 437 */ 438 if (req->bType.type == USB_REQUEST_TYPE_CLASS) { 439 *ret_length = length; 440 *ret_data = data; 441 return USB_ERR_IOERROR; 442 } 443 break; 444 445 case USB_REQUEST_SET_FEATURE: 446 /* 447 * SetFeature() Request 448 * 449 * Setting a feature on the root hub is an error, 450 * so we reply with USB_ERR_IOERROR 451 */ 452 if (req->bType.type != USB_REQUEST_TYPE_CLASS) { 453 *ret_length = length; 454 *ret_data = data; 455 return USB_ERR_IOERROR; 456 break; 457 } 458 /* handling of hub cpass specific port request */ 459 460 if (req->bType.recipient == USB_REQUEST_RECIPIENT_OTHER) { 461 if ((req_index < 1) || (req_index > hc->root_hub_num_ports)) { 462 *ret_length = length; 463 *ret_data = data; 464 return USB_ERR_IOERROR; 465 break; 466 } 467 ohci_rh_portstat_t ps = ohci_rh_portstat_rawrd(hc->ohci_base, 468 req_index); 469 switch (req_value) { 470 case USB_HUB_FEATURE_PORT_ENABLE: 471 ohci_rh_portstat_pes_insert(ps, 1); 472 break; 473 case USB_HUB_FEATURE_PORT_SUSPEND: 474 ohci_rh_portstat_pss_insert(ps, 1); 475 break; 476 case USB_HUB_FEATURE_PORT_RESET: 477 ohci_rh_portstat_prs_insert(ps, 1); 478 break; 479 case USB_HUB_FEATURE_PORT_POWER: 480 ohci_rh_portstat_pps_insert(ps, 1); 481 break; 482 default: 483 *ret_length = length; 484 *ret_data = data; 485 return USB_ERR_IOERROR; 486 break; 487 } 488 ohci_rh_portctrl_rawwr(hc->ohci_base, req_index, ps); 489 /* 490 * handle the reset of the port 491 */ 492 if (req_value == USB_HUB_FEATURE_PORT_RESET) { 493 for (uint32_t i = 0;; i++) { 494 if (ohci_rh_portstat_prs_rdf(hc->ohci_base, 495 req_index)) { 496 /* 497 * bit has not been cleared, that means the 498 * reset is not completed yet 499 */ 500 /* TODO: WAIT SOME TIME */ 501 if (i > 12) { 502 *ret_data = data; 503 *ret_length = length; 504 return USB_ERR_TIMEOUT; 505 } 506 } else { 507 // reset complete 508 break; 509 } 510 } 511 } 512 } 513 break; 514 515 case USB_REQUEST_SET_INTERFACE: 516 /* 517 * SetInterface() Request 518 * 519 * we have just one interface, so this is a no-op 520 */ 521 break; 522 523 case USB_REQUEST_SYNCH_FRAME: 524 /* 525 * SetSynchFrame() Request 526 * 527 * No-op 528 */ 529 break; 530 default: 531 *ret_length = length; 532 *ret_data = data; 533 return USB_ERR_IOERROR; 534 break; 535 } 536 *ret_length = length; 537 *ret_data = data; 538 return USB_ERR_OK; 539} 540 541