1 /* 2 * Copyright 2005-2008, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Jan-Rixt Van Hoye 7 * Salvatore Benedetto <salvatore.benedetto@gmail.com> 8 */ 9 10 #include <module.h> 11 #include <PCI.h> 12 #include <USB3.h> 13 #include <KernelExport.h> 14 15 #include "ohci.h" 16 17 pci_module_info *OHCI::sPCIModule = NULL; 18 19 20 static int32 21 ohci_std_ops(int32 op, ...) 22 { 23 switch (op) { 24 case B_MODULE_INIT: 25 TRACE(("usb_ohci_module: init module\n")); 26 return B_OK; 27 case B_MODULE_UNINIT: 28 TRACE(("usb_ohci_module: uninit module\n")); 29 return B_OK; 30 } 31 32 return EINVAL; 33 } 34 35 36 host_controller_info ohci_module = { 37 { 38 "busses/usb/ohci", 39 0, 40 ohci_std_ops 41 }, 42 NULL, 43 OHCI::AddTo 44 }; 45 46 47 module_info *modules[] = { 48 (module_info *)&ohci_module, 49 NULL 50 }; 51 52 53 //------------------------------------------------------ 54 // OHCI:: Reverse the bits in a value between 0 and 31 55 // (Section 3.3.2) 56 //------------------------------------------------------ 57 static uint8 revbits[OHCI_NUMBER_OF_INTERRUPTS] = 58 { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c, 59 0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e, 60 0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d, 61 0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f }; 62 63 64 OHCI::OHCI(pci_info *info, Stack *stack) 65 : BusManager(stack), 66 fPCIInfo(info), 67 fStack(stack), 68 fRegisterArea(-1), 69 fHccaArea(-1), 70 fDummyControl(NULL), 71 fDummyBulk(NULL), 72 fDummyIsochronous(NULL), 73 fFirstTransfer(NULL), 74 fLastTransfer(NULL), 75 fFinishThread(-1), 76 fStopFinishThread(false), 77 fRootHub(NULL), 78 fRootHubAddress(0), 79 fPortCount(0) 80 { 81 if (!fInitOK) { 82 TRACE_ERROR(("usb_ohci: bus manager failed to init\n")); 83 return; 84 } 85 86 TRACE(("usb_ohci: constructing new OHCI Host Controller Driver\n")); 87 fInitOK = false; 88 89 // enable busmaster and memory mapped access 90 uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus, 91 fPCIInfo->device, fPCIInfo->function, PCI_command, 2); 92 command &= ~PCI_command_io; 93 command |= PCI_command_master | PCI_command_memory; 94 95 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 96 fPCIInfo->function, PCI_command, 2, command); 97 98 // map the registers 99 uint32 offset = sPCIModule->read_pci_config(fPCIInfo->bus, 100 fPCIInfo->device, fPCIInfo->function, PCI_base_registers, 4); 101 offset &= PCI_address_memory_32_mask; 102 TRACE(("usb_ohci: iospace offset: %lx\n", offset)); 103 fRegisterArea = map_physical_memory("OHCI memory mapped registers", 104 (void *)offset, B_PAGE_SIZE, B_ANY_KERNEL_BLOCK_ADDRESS, 105 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, 106 (void **)&fOperationalRegisters); 107 if (fRegisterArea < B_OK) { 108 TRACE_ERROR(("usb_ohci: failed to map register memory\n")); 109 return; 110 } 111 112 TRACE(("usb_ohci: mapped operational registers: 0x%08lx\n", 113 *fOperationalRegisters)); 114 115 // Check the revision of the controller, which should be 10h 116 uint32 revision = _ReadReg(OHCI_REVISION) & 0xff; 117 TRACE(("usb_ohci: version %ld.%ld%s\n", OHCI_REVISION_HIGH(revision), 118 OHCI_REVISION_LOW(revision), OHCI_REVISION_LEGACY(revision) 119 ? ", legacy support" : "")); 120 if (OHCI_REVISION_HIGH(revision) != 1 || OHCI_REVISION_LOW(revision) != 0) { 121 TRACE_ERROR(("usb_ohci: unsupported OHCI revision\n")); 122 return; 123 } 124 125 // Set up the Host Controller Communications Area 126 // which is 256 bytes (2048 bits) and must be aligned 127 void *hccaPhysicalAddress; 128 fHccaArea = fStack->AllocateArea((void **)&fHcca, &hccaPhysicalAddress, 129 2048, "USB OHCI Host Controller Communication Area"); 130 131 if (fHccaArea < B_OK) { 132 TRACE_ERROR(("usb_ohci: unable to create the HCCA block area\n")); 133 return; 134 } 135 136 memset((void *)fHcca, 0, sizeof(ohci_hcca)); 137 138 // Allocate hash tables 139 fHashGenericTable = (ohci_general_td **) 140 malloc(sizeof(ohci_general_td *) * OHCI_HASH_SIZE); 141 if (fHashGenericTable == NULL) { 142 TRACE_ERROR(("usb_ohci: unable to allocate hash generic table\n")); 143 return; 144 } 145 fHashIsochronousTable = (ohci_isochronous_td **) 146 malloc(sizeof(ohci_isochronous_td *) * OHCI_HASH_SIZE); 147 if (fHashIsochronousTable == NULL) { 148 free(fHashGenericTable); 149 TRACE_ERROR(("usb_ohci: unable to allocate hash isochronous table\n")); 150 return; 151 } 152 153 // Set Up Host controller 154 // Dummy endpoints 155 fDummyControl = _AllocateEndpoint(); 156 if (!fDummyControl) 157 return; 158 fDummyControl->flags |= OHCI_ENDPOINT_SKIP; 159 160 fDummyBulk = _AllocateEndpoint(); 161 if (!fDummyBulk) { 162 _FreeEndpoint(fDummyControl); 163 return; 164 } 165 fDummyBulk->flags |= OHCI_ENDPOINT_SKIP; 166 167 fDummyIsochronous = _AllocateEndpoint(); 168 if (!fDummyIsochronous) { 169 _FreeEndpoint(fDummyControl); 170 _FreeEndpoint(fDummyBulk); 171 return; 172 } 173 fDummyIsochronous->flags |= OHCI_ENDPOINT_SKIP; 174 175 // Static endpoints that get linked in the HCCA 176 fInterruptEndpoints = new(std::nothrow) 177 ohci_endpoint_descriptor *[OHCI_NUMBER_OF_INTERRUPTS]; 178 if (!fInterruptEndpoints) { 179 TRACE_ERROR(("ohci_usb: cannot allocate memory for" 180 " fInterruptEndpoints array\n")); 181 _FreeEndpoint(fDummyControl); 182 _FreeEndpoint(fDummyBulk); 183 _FreeEndpoint(fDummyIsochronous); 184 return; 185 } 186 for (uint32 i = 0; i < OHCI_NUMBER_OF_INTERRUPTS; i++) { 187 fInterruptEndpoints[i] = _AllocateEndpoint(); 188 if (!fInterruptEndpoints[i]) { 189 TRACE_ERROR(("ohci_usb: cannot allocate memory for" 190 " fInterruptEndpoints[%ld] endpoint\n", i)); 191 while (--i >= 0) 192 _FreeEndpoint(fInterruptEndpoints[i]); 193 _FreeEndpoint(fDummyBulk); 194 _FreeEndpoint(fDummyControl); 195 _FreeEndpoint(fDummyIsochronous); 196 return; 197 } 198 // Make them point all to the dummy isochronous endpoint 199 fInterruptEndpoints[i]->flags |= OHCI_ENDPOINT_SKIP; 200 fInterruptEndpoints[i]->next_physical_endpoint 201 = fDummyIsochronous->physical_address; 202 } 203 204 // Fill HCCA interrupt table. 205 for (uint32 i = 0; i < OHCI_NUMBER_OF_INTERRUPTS; i++) 206 fHcca->interrupt_table[i] = fInterruptEndpoints[i]->physical_address; 207 208 // Determine in what context we are running (Kindly copied from FreeBSD) 209 uint32 control = _ReadReg(OHCI_CONTROL); 210 if (control & OHCI_INTERRUPT_ROUTING) { 211 TRACE(("usb_ohci: SMM is in control of the host controller\n")); 212 uint32 status = _ReadReg(OHCI_COMMAND_STATUS); 213 _WriteReg(OHCI_COMMAND_STATUS, status | OHCI_OWNERSHIP_CHANGE_REQUEST); 214 for (uint32 i = 0; i < 100 && (control & OHCI_INTERRUPT_ROUTING); i++) { 215 snooze(1000); 216 control = _ReadReg(OHCI_CONTROL); 217 } 218 if (!(control & OHCI_INTERRUPT_ROUTING)) { 219 TRACE(("usb_ohci: SMM does not respond. Resetting...\n")); 220 _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); 221 snooze(USB_DELAY_BUS_RESET); 222 } 223 } else { 224 TRACE(("usb_ohci: cold started\n")); 225 snooze(USB_DELAY_BUS_RESET); 226 } 227 228 // This reset should not be necessary according to the OHCI spec, but 229 // without it some controllers do not start. 230 _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); 231 snooze(USB_DELAY_BUS_RESET); 232 233 // We now own the host controller and the bus has been reset 234 uint32 frameInterval = _ReadReg(OHCI_FRAME_INTERVAL); 235 uint32 intervalValue = OHCI_GET_INTERVAL_VALUE(frameInterval); 236 237 // Disable interrupts right before we reset 238 cpu_status former = disable_interrupts(); 239 _WriteReg(OHCI_COMMAND_STATUS, OHCI_HOST_CONTROLLER_RESET); 240 // Nominal time for a reset is 10 us 241 uint32 reset = 0; 242 for (uint32 i = 0; i < 10; i++) { 243 spin(10); 244 reset = _ReadReg(OHCI_COMMAND_STATUS) & OHCI_HOST_CONTROLLER_RESET; 245 if (!reset) 246 break; 247 } 248 if (reset) { 249 TRACE_ERROR(("usb_ohci: Error resetting the host controller (timeout)\n")); 250 restore_interrupts(former); 251 return; 252 } 253 254 // The controller is now in SUSPEND state, we have 2ms to go OPERATIONAL. 255 // Interrupts are disabled. 256 257 // Set up host controller register 258 _WriteReg(OHCI_HCCA, (uint32)hccaPhysicalAddress); 259 _WriteReg(OHCI_CONTROL_HEAD_ED, (uint32)fDummyControl->physical_address); 260 _WriteReg(OHCI_BULK_HEAD_ED, (uint32)fDummyBulk->physical_address); 261 // Disable all interrupts and then switch on all desired interrupts 262 _WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTERRUPTS); 263 _WriteReg(OHCI_INTERRUPT_ENABLE, OHCI_NORMAL_INTERRUPTS 264 | OHCI_MASTER_INTERRUPT_ENABLE); 265 // Switch on desired functional features 266 control = _ReadReg(OHCI_CONTROL); 267 control &= ~(OHCI_CONTROL_BULK_SERVICE_RATIO_MASK | OHCI_ENABLE_LIST 268 | OHCI_HC_FUNCTIONAL_STATE_MASK | OHCI_INTERRUPT_ROUTING); 269 control |= OHCI_ENABLE_LIST | OHCI_CONTROL_BULK_RATIO_1_4 270 | OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL; 271 // And finally start the controller 272 _WriteReg(OHCI_CONTROL, control); 273 274 restore_interrupts(former); 275 276 // The controller is now OPERATIONAL. 277 frameInterval = (_ReadReg(OHCI_FRAME_INTERVAL) & OHCI_FRAME_INTERVAL_TOGGLE) 278 ^ OHCI_FRAME_INTERVAL_TOGGLE; 279 frameInterval |= OHCI_FSMPS(intervalValue) | intervalValue; 280 _WriteReg(OHCI_FRAME_INTERVAL, frameInterval); 281 // 90% periodic 282 uint32 periodic = OHCI_PERIODIC(intervalValue); 283 _WriteReg(OHCI_PERIODIC_START, periodic); 284 285 // Fiddle the No Over Current Protection bit to avoid chip bug 286 uint32 desca = _ReadReg(OHCI_RH_DESCRIPTOR_A); 287 _WriteReg(OHCI_RH_DESCRIPTOR_A, desca | OHCI_RH_NO_OVER_CURRENT_PROTECTION); 288 _WriteReg(OHCI_RH_STATUS, OHCI_RH_LOCAL_POWER_STATUS_CHANGE); 289 snooze(OHCI_ENABLE_POWER_DELAY); 290 _WriteReg(OHCI_RH_DESCRIPTOR_A, desca); 291 292 // The AMD756 requires a delay before re-reading the register, 293 // otherwise it will occasionally report 0 ports. 294 uint32 numberOfPorts = 0; 295 for (uint32 i = 0; i < 10 && numberOfPorts == 0; i++) { 296 snooze(OHCI_READ_DESC_DELAY); 297 uint32 descriptor = _ReadReg(OHCI_RH_DESCRIPTOR_A); 298 numberOfPorts = OHCI_RH_GET_PORT_COUNT(descriptor); 299 } 300 fPortCount = numberOfPorts; 301 302 // Create semaphore the finisher thread will wait for 303 fFinishTransfersSem = create_sem(0, "OHCI Finish Transfers"); 304 if (fFinishTransfersSem < B_OK) { 305 TRACE_ERROR(("usb_ohci: failed to create semaphore\n")); 306 return; 307 } 308 309 // Create the finisher service thread 310 fFinishThread = spawn_kernel_thread(_FinishThread, "ohci finish thread", 311 B_URGENT_DISPLAY_PRIORITY, (void *)this); 312 resume_thread(fFinishThread); 313 314 // Install the interrupt handler 315 TRACE(("usb_ohci: installing interrupt handler\n")); 316 install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, 317 _InterruptHandler, (void *)this, 0); 318 319 TRACE(("usb_ohci: OHCI Host Controller Driver constructed\n")); 320 fInitOK = true; 321 } 322 323 324 OHCI::~OHCI() 325 { 326 int32 result = 0; 327 fStopFinishThread = true; 328 delete_sem(fFinishTransfersSem); 329 wait_for_thread(fFinishThread, &result); 330 331 if (fHccaArea > 0) 332 delete_area(fHccaArea); 333 if (fRegisterArea > 0) 334 delete_area(fRegisterArea); 335 if (fHashGenericTable) 336 free(fHashGenericTable); 337 if (fHashIsochronousTable) 338 free(fHashIsochronousTable); 339 if (fDummyControl) 340 _FreeEndpoint(fDummyControl); 341 if (fDummyBulk) 342 _FreeEndpoint(fDummyBulk); 343 if (fDummyIsochronous) 344 _FreeEndpoint(fDummyIsochronous); 345 if (fRootHub) 346 delete fRootHub; 347 for (int i = 0; i < OHCI_NUMBER_OF_INTERRUPTS; i++) 348 if (fInterruptEndpoints[i]) 349 _FreeEndpoint(fInterruptEndpoints[i]); 350 delete [] fInterruptEndpoints; 351 put_module(B_PCI_MODULE_NAME); 352 } 353 354 355 int32 356 OHCI::_InterruptHandler(void *data) 357 { 358 return ((OHCI *)data)->_Interrupt(); 359 } 360 361 362 int32 363 OHCI::_Interrupt() 364 { 365 static spinlock lock = 0; 366 acquire_spinlock(&lock); 367 368 uint32 status = 0; 369 uint32 acknowledge = 0; 370 bool finishTransfers = false; 371 int32 result = B_HANDLED_INTERRUPT; 372 373 // The LSb of done_head is used to inform the HCD that an interrupt 374 // condition exists for both the done list and for another event recorded in 375 // the HcInterruptStatus register. If done_head is 0, then the interrupt 376 // was caused by other than the HccaDoneHead update and the 377 // HcInterruptStatus register needs to be accessed to determine that exact 378 // interrupt cause. If HccDoneHead is nonzero, then a done list update 379 // interrupt is indicated and if the LSb of the Dword is nonzero, then an 380 // additional interrupt event is indicated and HcInterruptStatus shuold be 381 // checked to determine its cause. 382 uint32 doneHead = fHcca->done_head; 383 if (doneHead != 0) { 384 status = OHCI_WRITEBACK_DONE_HEAD; 385 if (doneHead & OHCI_DONE_INTERRUPTS) 386 status |= _ReadReg(OHCI_INTERRUPT_STATUS) 387 & _ReadReg(OHCI_INTERRUPT_ENABLE); 388 } else { 389 status = _ReadReg(OHCI_INTERRUPT_STATUS) & _ReadReg(OHCI_INTERRUPT_ENABLE) 390 & ~OHCI_WRITEBACK_DONE_HEAD; 391 if (status == 0) { 392 // Nothing to be done (PCI shared interrupt) 393 release_spinlock(&lock); 394 return B_UNHANDLED_INTERRUPT; 395 } 396 } 397 398 if (status & OHCI_SCHEDULING_OVERRUN) { 399 // TODO 400 TRACE(("usb_ohci: scheduling overrun occured\n")); 401 } 402 403 if (status & OHCI_WRITEBACK_DONE_HEAD) { 404 TRACE(("usb_ohci: transfer descriptor processed\n")); 405 // Ack it in the finisher thread, not here. 406 result = B_INVOKE_SCHEDULER; 407 finishTransfers = true; 408 } 409 410 if (status & OHCI_RESUME_DETECTED) { 411 // TODO 412 TRACE(("usb_ohci: resume detected\n")); 413 } 414 415 if (status & OHCI_UNRECOVERABLE_ERROR) { 416 TRACE(("usb_ohci: unrecoverable error. Controller halted\n")); 417 _WriteReg(OHCI_CONTROL, OHCI_HC_FUNCTIONAL_STATE_RESET); 418 // TODO: what else? 419 // Perhaps, clean up all the memory. 420 } 421 422 if (status & OHCI_ROOT_HUB_STATUS_CHANGE) { 423 // TODO 424 TRACE(("usb_ohci: root hub status change\n")); 425 } 426 427 release_spinlock(&lock); 428 429 if (finishTransfers) 430 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); 431 432 return result; 433 } 434 435 436 int32 437 OHCI::_FinishThread(void *data) 438 { 439 ((OHCI *)data)->_FinishTransfer(); 440 return B_OK; 441 } 442 443 444 void 445 OHCI::_FinishTransfer() 446 { 447 while (!fStopFinishThread) { 448 if (acquire_sem(fFinishTransfersSem) < B_OK) 449 continue; 450 451 // eat up sems that have been released by multiple interrupts 452 int32 semCount = 0; 453 get_sem_count(fFinishTransfersSem, &semCount); 454 if (semCount > 0) 455 acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); 456 457 // Pull out the done list and reverse its order 458 // for both general and isochronous descriptors 459 ohci_general_td *current, *top; 460 ohci_isochronous_td *isoCurrent, *isoTop; 461 uint32 done_list = fHcca->done_head & ~OHCI_DONE_INTERRUPTS; 462 for ( top = NULL, isoTop = NULL ; done_list != 0; ) { 463 if ((current = _FindDescriptorInHash(done_list))) { 464 done_list = current->next_physical_descriptor; 465 current->next_done_descriptor = (void *)top; 466 top = current; 467 continue; 468 } 469 if ((isoCurrent = _FindIsoDescriptorInHash(done_list))) { 470 done_list = isoCurrent->next_physical_descriptor; 471 isoCurrent->next_done_descriptor = (void *)isoTop; 472 isoTop = isoCurrent; 473 continue; 474 } 475 // TODO: Should I panic here? :) 476 TRACE_ERROR(("usb_ohci: address 0x%08lx not found!\n",done_list)); 477 break; 478 } 479 480 // Acknowledge the interrupt 481 // TODO: Move the acknowledgement in the interrupt handler. The done_head 482 // value can be passed through a shared variable. 483 fHcca->done_head = 0; 484 _WriteReg(OHCI_INTERRUPT_ENABLE, OHCI_WRITEBACK_DONE_HEAD); 485 486 // Process isochronous list first 487 for (isoCurrent = isoTop; isoCurrent != NULL; isoCurrent 488 = (ohci_isochronous_td *)isoCurrent->next_done_descriptor) { 489 // TODO: Process isochronous descriptors 490 } 491 // Now process the general list 492 for (current = top; current != NULL; ) { 493 ohci_general_td *next = (ohci_general_td *)current->next_done_descriptor; 494 // TODO: Handle cancelled and timeout 495 uint32 conditionCode = OHCI_TD_GET_CONDITION_CODE(current->flags); 496 if (conditionCode != OHCI_NO_ERROR) { 497 // Endpoint is halted 498 // 1. Unlink the transfer 499 // 2. Free all descriptors of the transfer 500 // 3. Notify the caller. 501 // 4. Restart the endpoint 502 // NOTE: There can(should) not be more than one 503 // invalid descriptor from the same transfer in the 504 // done list, as the controller halt the endpoint right 505 // away if a descriptor fails. This means that, if we reversed 506 // the order of the done list (which we did), there is 507 // not reason to look for more failed descriptors in the 508 // done list from the same transfer, as *BSD code does. 509 TRACE(("usb_ohci: transfer failed! ohci error code: %d\n", 510 conditionCode)); 511 512 // Unlink the transfer 513 // TODO: check the return value 514 transfer_data *transfer = (transfer_data *)current->transfer; 515 _UnlinkTransfer(transfer); 516 517 // Free all descriptors of this transfer 518 next = (ohci_general_td *)current->next_done_descriptor; 519 _FreeDescriptorChain(transfer->first_descriptor); 520 521 // Restart the endpoint 522 // TODO: what if there are other transfer to this endpoint? 523 ohci_endpoint_descriptor *endpoint 524 = (ohci_endpoint_descriptor *)transfer->endpoint; 525 endpoint->head_physical_descriptor = 0; 526 527 // Notify the caller 528 transfer->transfer->Finished(B_CANCELED, 0); 529 delete transfer->transfer; 530 delete transfer; 531 continue; 532 } 533 534 if (current->is_last) { 535 // TODO: Trasfer completed 536 } 537 538 current = next; 539 } 540 } 541 } 542 543 544 status_t 545 OHCI::_UnlinkTransfer(transfer_data *transfer) 546 { 547 if (Lock()) { 548 if (transfer == fFirstTransfer) { 549 // It was the first element 550 fFirstTransfer = fFirstTransfer->link; 551 if (transfer == fLastTransfer) 552 // Also the only one 553 fLastTransfer = NULL; 554 } else { 555 transfer_data *data = fFirstTransfer->link; 556 transfer_data *previous = fFirstTransfer; 557 while (data != NULL) { 558 if (data == transfer) { 559 previous->link = data->link; 560 if (data == fLastTransfer) 561 fLastTransfer = previous; 562 break; 563 } 564 previous = data; 565 data = data->link; 566 } 567 } 568 Unlock(); 569 return B_OK; 570 } 571 return B_ERROR; 572 } 573 574 575 void 576 OHCI::_AddDescriptorToHash(ohci_general_td *descriptor) 577 { 578 // TODO 579 } 580 581 582 void 583 OHCI::_RemoveDescriptorFromHash(ohci_general_td *descriptor) 584 { 585 // TODO 586 } 587 588 589 ohci_general_td* 590 OHCI::_FindDescriptorInHash(uint32 physicalAddress) 591 { 592 // TODO 593 return NULL; 594 } 595 596 597 void 598 OHCI::_AddIsoDescriptorToHash(ohci_isochronous_td *descriptor) 599 { 600 // TODO 601 } 602 603 604 void 605 OHCI::_RemoveIsoDescriptorFromHash(ohci_isochronous_td *descriptor) 606 { 607 // TODO 608 } 609 610 611 ohci_isochronous_td* 612 OHCI::_FindIsoDescriptorInHash(uint32 physicalAddress) 613 { 614 // TODO 615 return NULL; 616 } 617 618 619 status_t 620 OHCI::Start() 621 { 622 TRACE(("usb_ohci: starting OHCI Host Controller\n")); 623 624 if ((_ReadReg(OHCI_CONTROL) & OHCI_HC_FUNCTIONAL_STATE_MASK) 625 != OHCI_HC_FUNCTIONAL_STATE_OPERATIONAL) { 626 TRACE_ERROR(("usb_ohci: Controller not started!\n")); 627 return B_ERROR; 628 } else { 629 TRACE(("usb_ohci: Controller is OPERATIONAL!\n")); 630 } 631 632 fRootHubAddress = AllocateAddress(); 633 fRootHub = new(std::nothrow) OHCIRootHub(RootObject(), fRootHubAddress); 634 if (!fRootHub) { 635 TRACE_ERROR(("usb_ohci: no memory to allocate root hub\n")); 636 return B_NO_MEMORY; 637 } 638 639 if (fRootHub->InitCheck() < B_OK) { 640 TRACE_ERROR(("usb_ohci: root hub failed init check\n")); 641 return B_ERROR; 642 } 643 644 SetRootHub(fRootHub); 645 TRACE(("usb_ohci: Host Controller started\n")); 646 return BusManager::Start(); 647 } 648 649 650 status_t 651 OHCI::SubmitTransfer(Transfer *transfer) 652 { 653 // short circuit the root hub 654 if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress) 655 return fRootHub->ProcessTransfer(this, transfer); 656 657 uint32 type = transfer->TransferPipe()->Type(); 658 if ((type & USB_OBJECT_CONTROL_PIPE)) { 659 TRACE(("usb_ohci: submitting control request\n")); 660 return _SubmitControlRequest(transfer); 661 } 662 663 if ((type & USB_OBJECT_INTERRUPT_PIPE) || (type & USB_OBJECT_BULK_PIPE)) { 664 // TODO 665 return B_OK; 666 } 667 668 if ((type & USB_OBJECT_ISO_PIPE)) { 669 TRACE(("usb_ohci: submitting isochronous transfer\n")); 670 return _SubmitIsochronousTransfer(transfer); 671 } 672 673 TRACE_ERROR(("usb_ohci: tried to submit transfer for unknown pipe" 674 " type %lu\n", type)); 675 return B_ERROR; 676 } 677 678 679 status_t 680 OHCI::_SubmitControlRequest(Transfer *transfer) 681 { 682 usb_request_data *requestData = transfer->RequestData(); 683 bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0; 684 685 ohci_general_td *setupDescriptor 686 = _CreateGeneralDescriptor(sizeof(usb_request_data)); 687 if (!setupDescriptor) { 688 TRACE_ERROR(("usb_ohci: failed to allocate setup descriptor\n")); 689 return B_NO_MEMORY; 690 } 691 // Flags set up could be moved into _CreateGeneralDescriptor 692 setupDescriptor->flags |= OHCI_TD_DIRECTION_PID_SETUP 693 | OHCI_TD_NO_CONDITION_CODE 694 | OHCI_TD_TOGGLE_0 695 | OHCI_TD_SET_DELAY_INTERRUPT(6); // Not sure about this. 696 697 ohci_general_td *statusDescriptor 698 = _CreateGeneralDescriptor(0); 699 if (!statusDescriptor) { 700 TRACE_ERROR(("usb_ohci: failed to allocate status descriptor\n")); 701 _FreeGeneralDescriptor(setupDescriptor); 702 return B_NO_MEMORY; 703 } 704 statusDescriptor->flags 705 |= (directionIn ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN) 706 | OHCI_TD_NO_CONDITION_CODE 707 | OHCI_TD_TOGGLE_1 708 | OHCI_TD_SET_DELAY_INTERRUPT(1); 709 710 iovec vector; 711 vector.iov_base = requestData; 712 vector.iov_len = sizeof(usb_request_data); 713 _WriteDescriptorChain(setupDescriptor, &vector, 1); 714 715 status_t result; 716 ohci_general_td *dataDescriptor = NULL; 717 if (transfer->VectorCount() > 0) { 718 ohci_general_td *lastDescriptor = NULL; 719 result = _CreateDescriptorChain(&dataDescriptor, 720 &lastDescriptor, 721 directionIn ? OHCI_TD_DIRECTION_PID_OUT : OHCI_TD_DIRECTION_PID_IN, 722 transfer->VectorLength()); 723 if (result < B_OK) { 724 _FreeGeneralDescriptor(setupDescriptor); 725 _FreeGeneralDescriptor(statusDescriptor); 726 return result; 727 } 728 729 if (!directionIn) { 730 _WriteDescriptorChain(dataDescriptor, transfer->Vector(), 731 transfer->VectorCount()); 732 } 733 734 _LinkDescriptors(setupDescriptor, dataDescriptor); 735 _LinkDescriptors(lastDescriptor, statusDescriptor); 736 } else { 737 _LinkDescriptors(setupDescriptor, statusDescriptor); 738 } 739 740 // 1. Insert the chain descriptors to the endpoint 741 ohci_endpoint_descriptor *endpoint 742 = (ohci_endpoint_descriptor *)transfer->TransferPipe()->ControllerCookie(); 743 endpoint->tail_physical_descriptor = statusDescriptor->physical_address; 744 endpoint->head_physical_descriptor = setupDescriptor->physical_address; 745 // 2. Clear the Skip bit in the enpoint 746 endpoint->flags &= ~OHCI_ENDPOINT_SKIP; 747 // 3. Tell the controller to process the control list 748 _WriteReg(OHCI_COMMAND_STATUS, OHCI_CONTROL_LIST_FILLED); 749 750 result = _AddPendingTransfer(transfer, endpoint, setupDescriptor, 751 dataDescriptor, directionIn); 752 if (result < B_OK) { 753 TRACE_ERROR(("usb_ohci: failed to add pending transfer\n")); 754 _FreeDescriptorChain(setupDescriptor); 755 return result; 756 } 757 758 return B_OK; 759 } 760 761 762 status_t 763 OHCI::_AddPendingTransfer(Transfer *transfer, ohci_endpoint_descriptor *endpoint, 764 ohci_general_td *firstDescriptor, ohci_general_td *dataDescriptor, bool directionIn) 765 { 766 if (!transfer || !endpoint || !firstDescriptor) 767 return B_BAD_VALUE; 768 769 transfer_data *data = new(std::nothrow) transfer_data; 770 if (!data) 771 return B_NO_MEMORY; 772 773 status_t result = transfer->InitKernelAccess(); 774 if (result < B_OK) { 775 delete data; 776 return result; 777 } 778 779 data->transfer = transfer; 780 data->endpoint = endpoint; 781 data->first_descriptor = firstDescriptor; 782 data->data_descriptor = dataDescriptor; 783 data->incoming = directionIn; 784 data->canceled = false; 785 data->link = NULL; 786 787 if (!Lock()) { 788 delete data; 789 return B_ERROR; 790 } 791 792 if (fLastTransfer) 793 fLastTransfer->link = data; 794 else 795 fFirstTransfer = data; 796 797 fLastTransfer = data; 798 Unlock(); 799 800 return B_OK; 801 } 802 803 804 status_t 805 OHCI::_SubmitIsochronousTransfer(Transfer *transfer) 806 { 807 return B_ERROR; 808 } 809 810 811 void 812 OHCI::_LinkDescriptors(ohci_general_td *first, ohci_general_td *second) 813 { 814 first->next_physical_descriptor = second->physical_address; 815 first->next_logical_descriptor = second; 816 } 817 818 819 status_t 820 OHCI::_CreateDescriptorChain(ohci_general_td **_firstDescriptor, 821 ohci_general_td **_lastDescriptor, uint8 direction, size_t bufferSize) 822 { 823 return B_ERROR; 824 } 825 826 827 void 828 OHCI::_FreeDescriptorChain(ohci_general_td *topDescriptor) 829 { 830 ohci_general_td *current = topDescriptor; 831 ohci_general_td *next = NULL; 832 833 while (current) { 834 next = (ohci_general_td *)current->next_logical_descriptor; 835 _FreeGeneralDescriptor(current); 836 current = next; 837 } 838 839 } 840 841 842 size_t 843 OHCI::_WriteDescriptorChain(ohci_general_td *topDescriptor, iovec *vector, 844 size_t vectorCount) 845 { 846 ohci_general_td *current = topDescriptor; 847 size_t actualLength = 0; 848 size_t vectorIndex = 0; 849 size_t vectorOffset = 0; 850 size_t bufferOffset = 0; 851 852 while (current) { 853 if (!current->buffer_logical) 854 break; 855 856 while (true) { 857 size_t length = min_c(current->buffer_size - bufferOffset, 858 vector[vectorIndex].iov_len - vectorOffset); 859 860 TRACE(("usb_ohci: copying %ld bytes to bufferOffset %ld from" 861 " vectorOffset %ld at index %ld of %ld\n", length, bufferOffset, 862 vectorOffset, vectorIndex, vectorCount)); 863 memcpy((uint8 *)current->buffer_logical + bufferOffset, 864 (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length); 865 866 actualLength += length; 867 vectorOffset += length; 868 bufferOffset += length; 869 870 if (vectorOffset >= vector[vectorIndex].iov_len) { 871 if (++vectorIndex >= vectorCount) { 872 TRACE(("usb_ohci: wrote descriptor chain (%ld bytes, no" 873 " more vectors)\n", actualLength)); 874 return actualLength; 875 } 876 877 vectorOffset = 0; 878 } 879 880 if (bufferOffset >= current->buffer_size) { 881 bufferOffset = 0; 882 break; 883 } 884 } 885 886 if (!current->next_logical_descriptor) 887 break; 888 889 current = (ohci_general_td *)current->next_logical_descriptor; 890 } 891 892 TRACE(("usb_ohci: wrote descriptor chain (%ld bytes)\n", actualLength)); 893 return actualLength; 894 } 895 896 897 status_t 898 OHCI::NotifyPipeChange(Pipe *pipe, usb_change change) 899 { 900 TRACE(("usb_ohci: pipe change %d for pipe 0x%08lx\n", change, (uint32)pipe)); 901 switch (change) { 902 case USB_CHANGE_CREATED: { 903 TRACE(("usb_ohci: inserting endpoint\n")); 904 return _InsertEndpointForPipe(pipe); 905 } 906 case USB_CHANGE_DESTROYED: { 907 TRACE(("usb_ohci: removing endpoint\n")); 908 return _RemoveEndpointForPipe(pipe); 909 } 910 case USB_CHANGE_PIPE_POLICY_CHANGED: { 911 TRACE(("usb_ohci: pipe policy changing unhandled!\n")); 912 break; 913 } 914 default: { 915 TRACE_ERROR(("usb_ohci: unknown pipe change!\n")); 916 return B_ERROR; 917 } 918 } 919 return B_OK; 920 } 921 922 923 status_t 924 OHCI::AddTo(Stack *stack) 925 { 926 #ifdef TRACE_USB 927 set_dprintf_enabled(true); 928 load_driver_symbols("ohci"); 929 #endif 930 931 if (!sPCIModule) { 932 status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule); 933 if (status < B_OK) { 934 TRACE_ERROR(("usb_ohci: getting pci module failed! 0x%08lx\n", 935 status)); 936 return status; 937 } 938 } 939 940 TRACE(("usb_ohci: searching devices\n")); 941 bool found = false; 942 pci_info *item = new(std::nothrow) pci_info; 943 if (!item) { 944 sPCIModule = NULL; 945 put_module(B_PCI_MODULE_NAME); 946 return B_NO_MEMORY; 947 } 948 949 for (uint32 i = 0 ; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) { 950 951 if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb 952 && item->class_api == PCI_usb_ohci) { 953 if (item->u.h0.interrupt_line == 0 954 || item->u.h0.interrupt_line == 0xFF) { 955 TRACE_ERROR(("usb_ohci: found device with invalid IRQ -" 956 " check IRQ assignement\n")); 957 continue; 958 } 959 960 TRACE(("usb_ohci: found device at IRQ %u\n", 961 item->u.h0.interrupt_line)); 962 OHCI *bus = new(std::nothrow) OHCI(item, stack); 963 if (!bus) { 964 delete item; 965 sPCIModule = NULL; 966 put_module(B_PCI_MODULE_NAME); 967 return B_NO_MEMORY; 968 } 969 970 if (bus->InitCheck() < B_OK) { 971 TRACE_ERROR(("usb_ohci: bus failed init check\n")); 972 delete bus; 973 continue; 974 } 975 976 // the bus took it away 977 item = new(std::nothrow) pci_info; 978 979 bus->Start(); 980 stack->AddBusManager(bus); 981 found = true; 982 } 983 } 984 985 if (!found) { 986 TRACE_ERROR(("usb_ohci: no devices found\n")); 987 delete item; 988 sPCIModule = NULL; 989 put_module(B_PCI_MODULE_NAME); 990 return ENODEV; 991 } 992 993 delete item; 994 return B_OK; 995 } 996 997 998 status_t 999 OHCI::GetPortStatus(uint8 index, usb_port_status *status) 1000 { 1001 TRACE(("usb_ohci::%s(%ud, )\n", __FUNCTION__, index)); 1002 if (index >= fPortCount) 1003 return B_BAD_INDEX; 1004 1005 status->status = status->change = 0; 1006 uint32 portStatus = _ReadReg(OHCI_RH_PORT_STATUS(index)); 1007 1008 TRACE(("usb_ohci: RootHub::GetPortStatus: Port %i Value 0x%lx\n", OHCI_RH_PORT_STATUS(index), portStatus)); 1009 1010 // status 1011 if (portStatus & OHCI_RH_PORTSTATUS_CCS) 1012 status->status |= PORT_STATUS_CONNECTION; 1013 if (portStatus & OHCI_RH_PORTSTATUS_PES) 1014 status->status |= PORT_STATUS_ENABLE; 1015 if (portStatus & OHCI_RH_PORTSTATUS_PRS) 1016 status->status |= PORT_STATUS_RESET; 1017 if (portStatus & OHCI_RH_PORTSTATUS_LSDA) 1018 status->status |= PORT_STATUS_LOW_SPEED; 1019 if (portStatus & OHCI_RH_PORTSTATUS_PSS) 1020 status->status |= PORT_STATUS_SUSPEND; 1021 if (portStatus & OHCI_RH_PORTSTATUS_POCI) 1022 status->status |= PORT_STATUS_OVER_CURRENT; 1023 if (portStatus & OHCI_RH_PORTSTATUS_PPS) 1024 status->status |= PORT_STATUS_POWER; 1025 1026 1027 // change 1028 if (portStatus & OHCI_RH_PORTSTATUS_CSC) 1029 status->change |= PORT_STATUS_CONNECTION; 1030 if (portStatus & OHCI_RH_PORTSTATUS_PESC) 1031 status->change |= PORT_STATUS_ENABLE; 1032 if (portStatus & OHCI_RH_PORTSTATUS_PSSC) 1033 status->change |= PORT_STATUS_SUSPEND; 1034 if (portStatus & OHCI_RH_PORTSTATUS_OCIC) 1035 status->change |= PORT_STATUS_OVER_CURRENT; 1036 if (portStatus & OHCI_RH_PORTSTATUS_PRSC) 1037 status->change |= PORT_STATUS_RESET; 1038 1039 return B_OK; 1040 } 1041 1042 1043 status_t 1044 OHCI::SetPortFeature(uint8 index, uint16 feature) 1045 { 1046 TRACE(("OHCI::%s(%ud, %ud)\n", __FUNCTION__, index, feature)); 1047 if (index > fPortCount) 1048 return B_BAD_INDEX; 1049 1050 switch (feature) { 1051 case PORT_RESET: 1052 _WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_RH_PORTSTATUS_PRS); 1053 return B_OK; 1054 1055 case PORT_POWER: 1056 _WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_RH_PORTSTATUS_PPS); 1057 return B_OK; 1058 } 1059 1060 return B_BAD_VALUE; 1061 } 1062 1063 1064 status_t 1065 OHCI::ClearPortFeature(uint8 index, uint16 feature) 1066 { 1067 TRACE(("OHCI::%s(%ud, %ud)\n", __FUNCTION__, index, feature)); 1068 if (index > fPortCount) 1069 return B_BAD_INDEX; 1070 1071 switch (feature) { 1072 case C_PORT_RESET: 1073 _WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_RH_PORTSTATUS_CSC); 1074 return B_OK; 1075 1076 case C_PORT_CONNECTION: 1077 _WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_RH_PORTSTATUS_CSC); 1078 return B_OK; 1079 } 1080 1081 return B_BAD_VALUE; 1082 } 1083 1084 1085 ohci_endpoint_descriptor* 1086 OHCI::_AllocateEndpoint() 1087 { 1088 ohci_endpoint_descriptor *endpoint; 1089 void* physicalAddress; 1090 1091 // Allocate memory chunk 1092 if (fStack->AllocateChunk((void **)&endpoint, &physicalAddress, 1093 sizeof(ohci_endpoint_descriptor)) < B_OK) { 1094 TRACE_ERROR(("usb_ohci: failed to allocate endpoint descriptor\n")); 1095 return NULL; 1096 } 1097 memset((void *)endpoint, 0, sizeof(ohci_endpoint_descriptor)); 1098 1099 endpoint->physical_address = (addr_t)physicalAddress; 1100 1101 endpoint->head_physical_descriptor = NULL; 1102 endpoint->tail_physical_descriptor = NULL; 1103 1104 endpoint->head_logical_descriptor = NULL; 1105 endpoint->tail_logical_descriptor = NULL; 1106 1107 return endpoint; 1108 } 1109 1110 1111 void 1112 OHCI::_FreeEndpoint(ohci_endpoint_descriptor *endpoint) 1113 { 1114 if (!endpoint) 1115 return; 1116 1117 fStack->FreeChunk((void *)endpoint, (void *)endpoint->physical_address, 1118 sizeof(ohci_endpoint_descriptor)); 1119 } 1120 1121 1122 ohci_general_td* 1123 OHCI::_CreateGeneralDescriptor(size_t bufferSize) 1124 { 1125 ohci_general_td *descriptor; 1126 void *physicalAddress; 1127 1128 if (fStack->AllocateChunk((void **)&descriptor, &physicalAddress, 1129 sizeof(ohci_general_td)) != B_OK) { 1130 TRACE_ERROR(("usb_ohci: failed to allocate general descriptor\n")); 1131 return NULL; 1132 } 1133 memset((void *)descriptor, 0, sizeof(ohci_general_td)); 1134 descriptor->physical_address = (addr_t)physicalAddress; 1135 1136 if (!bufferSize) { 1137 descriptor->buffer_physical = 0; 1138 descriptor->buffer_logical = NULL; 1139 descriptor->last_physical_byte_address = 0; 1140 return descriptor; 1141 } 1142 1143 if (fStack->AllocateChunk(&descriptor->buffer_logical, 1144 (void **)&descriptor->buffer_physical, bufferSize) != B_OK) { 1145 TRACE_ERROR(("usb_ohci: failed to allocate space for buffer\n")); 1146 fStack->FreeChunk(descriptor, (void *)descriptor->physical_address, 1147 sizeof(ohci_general_td)); 1148 return NULL; 1149 } 1150 descriptor->last_physical_byte_address 1151 = descriptor->buffer_physical + bufferSize - 1; 1152 1153 return descriptor; 1154 } 1155 1156 1157 void 1158 OHCI::_FreeGeneralDescriptor(ohci_general_td *descriptor) 1159 { 1160 if (!descriptor) 1161 return; 1162 1163 if (descriptor->buffer_logical) { 1164 fStack->FreeChunk(descriptor->buffer_logical, 1165 (void *)descriptor->buffer_physical, descriptor->buffer_size); 1166 } 1167 1168 fStack->FreeChunk((void *)descriptor, (void *)descriptor->physical_address, 1169 sizeof(ohci_general_td)); 1170 } 1171 1172 1173 ohci_isochronous_td* 1174 _CreateIsochronousDescriptor() 1175 { 1176 // TODO 1177 return NULL; 1178 } 1179 1180 1181 void _FreeIsochronousDescriptor(ohci_isochronous_td *descriptor) 1182 { 1183 // TODO 1184 } 1185 1186 1187 status_t 1188 OHCI::_InsertEndpointForPipe(Pipe *pipe) 1189 { 1190 TRACE(("OHCI: Inserting Endpoint for device %u function %u\n", 1191 pipe->DeviceAddress(), pipe->EndpointAddress())); 1192 1193 ohci_endpoint_descriptor *endpoint = _AllocateEndpoint(); 1194 if (!endpoint) { 1195 TRACE_ERROR(("usb_ohci: cannot allocate memory for endpoint\n")); 1196 return B_NO_MEMORY; 1197 } 1198 1199 uint32 flags = 0; 1200 flags |= OHCI_ENDPOINT_SKIP; 1201 1202 // Set up flag field for the endpoint 1203 flags |= OHCI_ENDPOINT_SET_DEVICE_ADDRESS(pipe->DeviceAddress()) 1204 | OHCI_ENDPOINT_SET_ENDPOINT_NUMBER(pipe->EndpointAddress()); 1205 1206 // Set the direction 1207 switch (pipe->Direction()) { 1208 case Pipe::In: 1209 flags |= OHCI_ENDPOINT_DIRECTION_IN; 1210 break; 1211 case Pipe::Out: 1212 flags |= OHCI_ENDPOINT_DIRECTION_OUT; 1213 break; 1214 case Pipe::Default: 1215 flags |= OHCI_ENDPOINT_DIRECTION_DESCRIPTOR; 1216 break; 1217 default: 1218 TRACE_ERROR(("usb_ohci: direction unknown. Wrong value!\n")); 1219 _FreeEndpoint(endpoint); 1220 return B_ERROR; 1221 } 1222 1223 // Set up the speed 1224 switch (pipe->Speed()) { 1225 case USB_SPEED_LOWSPEED: 1226 flags |= OHCI_ENDPOINT_LOW_SPEED; 1227 break; 1228 case USB_SPEED_FULLSPEED: 1229 flags |= OHCI_ENDPOINT_FULL_SPEED; 1230 break; 1231 case USB_SPEED_HIGHSPEED: 1232 default: 1233 TRACE_ERROR(("usb_ohci: unaccetable speed. Wrong value!\n")); 1234 _FreeEndpoint(endpoint); 1235 return B_ERROR; 1236 } 1237 1238 // Set the maximum packet size 1239 flags |= OHCI_ENDPOINT_SET_MAX_PACKET_SIZE(pipe->MaxPacketSize()); 1240 1241 endpoint->flags = flags; 1242 1243 // Add the endpoint to the appropriate list 1244 ohci_endpoint_descriptor *head = NULL; 1245 switch (pipe->Type()) { 1246 case USB_OBJECT_CONTROL_PIPE: 1247 head = fDummyControl; 1248 break; 1249 case USB_OBJECT_BULK_PIPE: 1250 head = fDummyBulk; 1251 break; 1252 case USB_OBJECT_ISO_PIPE: 1253 // Set the isochronous bit format 1254 endpoint->flags = OHCI_ENDPOINT_ISOCHRONOUS_FORMAT; 1255 head = fDummyIsochronous; 1256 break; 1257 case USB_OBJECT_INTERRUPT_PIPE: 1258 head = _FindInterruptEndpoint(pipe->Interval()); 1259 break; 1260 default: 1261 TRACE_ERROR(("usb_ohci: unknown type of pipe. Wrong value!\n")); 1262 _FreeEndpoint(endpoint); 1263 return B_ERROR; 1264 } 1265 1266 Lock(); 1267 pipe->SetControllerCookie((void *)endpoint); 1268 endpoint->next_logical_endpoint = head->next_logical_endpoint; 1269 endpoint->next_physical_endpoint = head->next_physical_endpoint; 1270 head->next_logical_endpoint = (void *)endpoint; 1271 head->next_physical_endpoint = (uint32)endpoint->physical_address; 1272 Unlock(); 1273 1274 return B_OK; 1275 } 1276 1277 1278 ohci_endpoint_descriptor* 1279 OHCI::_FindInterruptEndpoint(uint8 interval) 1280 { 1281 return NULL; 1282 } 1283 1284 1285 status_t 1286 OHCI::_RemoveEndpointForPipe(Pipe *pipe) 1287 { 1288 return B_ERROR; 1289 } 1290 1291 1292 inline void 1293 OHCI::_WriteReg(uint32 reg, uint32 value) 1294 { 1295 *(volatile uint32 *)(fOperationalRegisters + reg) = value; 1296 } 1297 1298 1299 inline uint32 1300 OHCI::_ReadReg(uint32 reg) 1301 { 1302 return *(volatile uint32 *)(fOperationalRegisters + reg); 1303 } 1304 1305 1306 status_t 1307 OHCI::CancelQueuedTransfers(Pipe *pipe, bool force) 1308 { 1309 return B_ERROR; 1310 } 1311