1/* 2 * Copyright (c) 2007-2013 ETH Zurich. 3 * All rights reserved. 4 * 5 * This file is distributed under the terms in the attached LICENSE file. 6 * If you do not find this file, copies can be found by writing to: 7 * ETH Zurich D-INFK, Haldeneggsteig 4, CH-8092 Zurich. Attn: Systems Group. 8 */ 9 10#include <stdlib.h> 11#include <stdio.h> 12#include <string.h> 13#include <barrelfish/barrelfish.h> 14 15#include "ohci_device.h" 16 17#include <usb/usb.h> 18#include <usb/usb_descriptor.h> 19#include <usb/usb_error.h> 20#include <usb/usb_request.h> 21#include <usb_device.h> 22#include <usb_hub.h> 23#include <usb_controller.h> 24#include "usb_ohci.h" 25#include "usb_ohci_root_hub.h" 26 27 28static const struct usb_device_descriptor usb_ohci_root_hub_device_desc = { 29 .bLength = sizeof(struct usb_device_descriptor), 30 .bDescriptorType = USB_DESCRIPTOR_TYPE_DEVICE, 31 .bcdUSB = 0x0100, 32 .bDeviceClass = USB_HUB_CLASS_CODE, 33 .bDeviceSubClass = USB_HUB_SUBCLASS_CODE, 34 .bDeviceProtocol = USB_HUB_PROTOCOL_FSHUB, 35 .bMaxPacketSize0 = 64, 36 .idVendor = 0, 37 .idProduct = 0, 38 .bcdDevice = 0x0100, 39 .iManufacturer = 1, 40 .iProduct = 2, 41 .iSerialNumber = 0, 42 .bNumConfigurations = 1, 43}; 44 45static const struct usb_ohci_config_desc usb_ohci_root_hub_config_desc = { 46.config_desc = { 47 .bLength = sizeof(struct usb_config_descriptor), 48 .bDescriptorType = USB_DESCRIPTOR_TYPE_CONFIG, 49 .wTotalLength = sizeof(usb_ohci_root_hub_config_desc), 50 .bNumInterfaces = 1, 51 .bConfigurationValue = 1, 52 .iConfiguration = 0, 53 .bmAttributes = USB_CONFIG_SELF_POWERED, 54 .bMaxPower = 0, 55}, .iface_desc = { 56.bLength = sizeof(struct usb_interface_descriptor), .bDescriptorType = 57 USB_DESCRIPTOR_TYPE_INTERFACE, .bNumEndpoints = 1, .bInterfaceClass = 58 USB_HUB_IFACE_CLASS_CODE, .bInterfaceSubClass = 59 USB_HUB_IFACE_SUBCLASS_CODE, .bInterfaceProtocol = 0, 60}, .ep_desc = { 61 .bLength = sizeof(struct usb_endpoint_descriptor), 62 .bDescriptorType = USB_DESCRIPTOR_TYPE_ENDPOINT, 63 .bEndpointAddress = {USB_ENDPOINT_DIRECTION_IN,0,1}, 64 .bmAttributes = {0,0,0,USB_ENDPOINT_TYPE_INTR}, 65 .wMaxPacketSize = 32, 66 .bInterval = 255, 67}, 68}; 69 70static const struct usb_hub_descriptor usb_ohci_root_hub_desc = { 71 .bDescLength = 0, 72 .bDescriptorType = USB_DESCRIPTOR_TYPE_HUB, 73 .bNbrPorts = 0, 74 .wHubCharacteristics = {0, 0, 0, 0, 0, 0}, 75 .bPwrOn2PwrGood = 0, 76 .bHubContrCurrent = 0, 77 .bDeviceRemovable = {0} 78}; 79 80/** 81 * \brief this function clears the old interrupt data and reads the 82 * status from the ports 83 * 84 * \param hc the host controller 85 */ 86void usb_ohci_root_hub_interrupt(usb_ohci_hc_t *hc) 87{ 88 /* clear old interrupt data */ 89 memset(hc->root_hub_intr_data, 0, sizeof(hc->root_hub_intr_data)); 90 91 /* get the root hub status */ 92 //ohci_rh_status_t hstatus = ohci_rh_status_rd(hc->ohci_base); 93 94 95 /* get the number of ports */ 96 uint16_t num_ports = hc->root_hub_num_ports + 1; 97 if (num_ports > (8 * sizeof(hc->root_hub_intr_data))) { 98 num_ports = (8 * sizeof(hc->root_hub_intr_data)); 99 } 100 101 //char buf[4048]; 102 // ohci_rh_portstat_pr(buf, 4047, hc->ohci_base); 103 // printf(buf); 104 ohci_rh_portstat_t ps; 105 /* set the bits in the interrupt data field */ 106 for (uint16_t i = 0; i < num_ports; i++) { 107 108 ps = ohci_rh_portstat_rd(hc->ohci_base, i); 109 if (ps >> 16) { 110 /* port i has changed */ 111 USB_DEBUG("port %u, has changed..\n", i); 112 hc->root_hub_intr_data[i / 8] |= (1 << (i % 8)); 113 } 114 } 115 116 /* TODO: Handle the hub interrupts */ 117 // assert(!"NYI: Root hub interrupt handling"); 118 //uhub_root_intr(&sc->sc_bus, sc->sc_hub_idata, sizeof(sc->sc_hub_idata)); 119} 120 121/* 122 * \brief this function enables the status change interrupt 123 * of the root hub and updates the enabled_intrs field 124 * of the host controller. 125 * 126 * \param hc the host controller 127 */ 128static void usb_ohci_root_hub_sc_intr_enable(usb_ohci_hc_t *hc) 129{ 130 /* update the enabled interrupt field in our hc */ 131 ohci_interrupt_t ie = ohci_intenable_rd(hc->ohci_base); 132 ohci_interrupt_rhsc_insert(ie, 1); 133 hc->enabled_intrs = ie; 134 135 /* enable the interrupt */ 136 ohci_intenable_rhsc_wrf(hc->ohci_base, 1); 137 138 /* acknowledge any RHSC interrupts */ 139 ohci_intstatus_rhsc_wrf(hc->ohci_base, 1); 140 141 usb_ohci_root_hub_interrupt(hc); 142} 143 144/** 145 * \brief this function emulates the USB root hub device by software 146 * 147 * \param device the USB device we want to issue the request for 148 * \param req the USB request to execute 149 * \param ret_data pointer to the returned data 150 * \param ret_length the returned length 151 */ 152usb_error_t usb_ohci_roothub_exec(struct usb_device *device, 153 struct usb_device_request *req, const void **ret_data, 154 uint16_t *ret_length) 155{ 156 usb_ohci_hc_t *hc = (usb_ohci_hc_t *) device->controller->hc_control; 157 158 const void *data = (const void *) hc->root_hub_desc.temp; 159 uint16_t length = 0; 160 161 uint16_t req_value = req->wValue; 162 uint16_t req_index = req->wIndex; 163 164 const char *str_ptr; 165 166 /* 167 * execute the request for the USB root hub 168 */ 169 switch (req->bRequest) { 170 171 case USB_REQUEST_CLEAR_FEATURE: 172 /* 173 * ClearFeature() Request 174 * 175 * The only clear feature request is the clear port feature 176 * for an existing port 1..num_ports 177 */ 178 if (req->bType.recipient == USB_REQUEST_RECIPIENT_OTHER) { 179 if ((req_index < 1) || (req_index > hc->root_hub_num_ports)) { 180 *ret_length = length; 181 *ret_data = data; 182 return USB_ERR_IOERROR; 183 } 184 // get the current value of the register 185 ohci_rh_portstat_t ps = ohci_rh_portstat_rd(hc->ohci_base, 186 req_index); 187 188 switch (req_value) { 189 case USB_HUB_FEATURE_PORT_ENABLE: 190 ohci_rh_portstat_ccs_insert(ps, 1); 191 break; 192 case USB_HUB_FEATURE_PORT_SUSPEND: 193 ohci_rh_portstat_poci_insert(ps, 1); 194 break; 195 case USB_HUB_FEATURE_PORT_POWER: 196 ohci_rh_portstat_lsda_insert(ps, 1); 197 break; 198 case USB_HUB_FEATURE_C_PORT_CONNECTION: 199 ohci_rh_portstat_csc_insert(ps, 1); 200 break; 201 case USB_HUB_FEATURE_C_PORT_ENABLE: 202 ohci_rh_portstat_pesc_insert(ps, 1); 203 break; 204 case USB_HUB_FEATURE_C_PORT_SUSPEND: 205 ohci_rh_portstat_pssc_insert(ps, 1); 206 break; 207 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: 208 ohci_rh_portstat_ocic_insert(ps, 1); 209 break; 210 case USB_HUB_FEATURE_C_PORT_RESET: 211 ohci_rh_portstat_prsc_insert(ps, 1); 212 break; 213 default: 214 *ret_length = length; 215 *ret_data = data; 216 return USB_ERR_IOERROR; 217 } 218 // write the value to the register 219 ohci_rh_portctrl_rawwr(hc->ohci_base, req_index, ps); 220 221 switch (req_value) { 222 case USB_HUB_FEATURE_C_PORT_CONNECTION: 223 case USB_HUB_FEATURE_C_PORT_ENABLE: 224 case USB_HUB_FEATURE_C_PORT_SUSPEND: 225 case USB_HUB_FEATURE_C_PORT_OVER_CURRENT: 226 case USB_HUB_FEATURE_C_PORT_RESET: 227 ps = ohci_rh_portstat_rd(hc->ohci_base, req_index); 228 if ((ps >> 16) == 0) { 229 usb_ohci_root_hub_sc_intr_enable(hc); 230 } 231 break; 232 default: 233 break; 234 } 235 } 236 break; 237 238 case USB_REQUEST_GET_CONFIG: 239 /* 240 * GetConfiguration() Request 241 */ 242 if ((req->bType.recipient == USB_REQUEST_RECIPIENT_DEVICE) 243 && req->bType.direction == USB_REQUEST_READ) { 244 length = 1; 245 hc->root_hub_desc.temp[0] = hc->root_hub_config; 246 } 247 break; 248 249 case USB_REQUEST_GET_DESCRIPTOR: 250 /* 251 * GetDescriptor() Request 252 * 253 * There are 3 different kind of standard descriptors we can 254 * return: Device, Interface and String 255 * 256 * and also a class specific request 257 */ 258 if ((req->bType.recipient == USB_REQUEST_RECIPIENT_DEVICE) 259 && req->bType.direction == USB_REQUEST_READ) { 260 261 /* hub class specific request */ 262 if (req->bType.type == USB_REQUEST_TYPE_CLASS) { 263 if ((req_value & 0xFF) != 0) { 264 *ret_length = length; 265 *ret_data = data; 266 return USB_ERR_IOERROR; 267 } 268 ohci_rh_descra_t cda; 269 cda = ohci_rh_descra_rd(hc->ohci_base); 270 271 // get the standard hub descriptor to fill in data 272 hc->root_hub_desc.hub_descriptor = usb_ohci_root_hub_desc; 273 274 struct usb_hub_descriptor *hub = &(hc->root_hub_desc 275 .hub_descriptor); 276 hub->bNbrPorts = hc->root_hub_num_ports; 277 278 hub->wHubCharacteristics.power_mode = 279 ohci_rh_descra_nps_extract(cda); 280 hub->bPwrOn2PwrGood = ohci_rh_descra_potpgt_extract(cda); 281 282 /* update device removable stats */ 283 ohci_rh_descra_t cdb; 284 cdb = ohci_rh_descrb_rd(hc->ohci_base); 285 for (uint16_t i = 0; i < hc->root_hub_num_ports; i++) { 286 if (cdb & 1) { 287 hub->bDeviceRemovable[i / 8] |= (1 << (i % 8)); 288 } 289 i >>= 1; 290 } 291 hub->bDescLength = 8 + ((hc->root_hub_num_ports + 7 / 8)); 292 length = hub->bDescLength; 293 break; 294 } 295 /* standard usb request */ 296 switch (req_value >> 8) { 297 case USB_DESCRIPTOR_TYPE_DEVICE: 298 if ((req_value & 0xFF) != 0) { 299 *ret_length = length; 300 *ret_data = data; 301 return USB_ERR_IOERROR; 302 } 303 length = sizeof(usb_ohci_root_hub_device_desc); 304 data = (const void *) &usb_ohci_root_hub_device_desc; 305 break; 306 case USB_DESCRIPTOR_TYPE_CONFIG: 307 if ((req_value & 0xFF) != 0) { 308 *ret_length = length; 309 *ret_data = data; 310 return USB_ERR_IOERROR; 311 } 312 length = sizeof(usb_ohci_root_hub_config_desc); 313 data = (const void *) &usb_ohci_root_hub_config_desc; 314 break; 315 case USB_DESCRIPTOR_TYPE_STRING: 316 switch (req_value & 0xFF) { 317 case 0: 318 str_ptr = "\001"; 319 break; 320 case 1: 321 break; 322 str_ptr = hc->vendor; 323 case 2: 324 break; 325 str_ptr = "OHCI root HUB"; 326 default: 327 str_ptr = ""; 328 break; 329 } 330 /* TODO: Make string descriptor */ 331 assert(!"NYI: Make string descriptor"); 332 break; 333 default: 334 *ret_length = length; 335 *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