1 /* 2 * Copyright 2006-2011, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 * Jérôme Duval <korli@users.berlios.de> 8 */ 9 10 11 #include <driver_settings.h> 12 #include <module.h> 13 #include <PCI.h> 14 #include <USB3.h> 15 #include <KernelExport.h> 16 17 #include "ehci.h" 18 19 #define USB_MODULE_NAME "ehci" 20 21 pci_module_info *EHCI::sPCIModule = NULL; 22 23 24 static int32 25 ehci_std_ops(int32 op, ...) 26 { 27 switch (op) { 28 case B_MODULE_INIT: 29 TRACE_MODULE("ehci init module\n"); 30 return B_OK; 31 case B_MODULE_UNINIT: 32 TRACE_MODULE("ehci uninit module\n"); 33 return B_OK; 34 } 35 36 return EINVAL; 37 } 38 39 40 usb_host_controller_info ehci_module = { 41 { 42 "busses/usb/ehci", 43 0, 44 ehci_std_ops 45 }, 46 NULL, 47 EHCI::AddTo 48 }; 49 50 51 module_info *modules[] = { 52 (module_info *)&ehci_module, 53 NULL 54 }; 55 56 57 // 58 // #pragma mark - 59 // 60 61 62 #ifdef TRACE_USB 63 64 void 65 print_descriptor_chain(ehci_qtd *descriptor) 66 { 67 while (descriptor) { 68 dprintf(" %08lx n%08lx a%08lx t%08lx %08lx %08lx %08lx %08lx %08lx s%ld\n", 69 descriptor->this_phy, descriptor->next_phy, 70 descriptor->alt_next_phy, descriptor->token, 71 descriptor->buffer_phy[0], descriptor->buffer_phy[1], 72 descriptor->buffer_phy[2], descriptor->buffer_phy[3], 73 descriptor->buffer_phy[4], descriptor->buffer_size); 74 75 if (descriptor->next_phy & EHCI_ITEM_TERMINATE) 76 break; 77 78 descriptor = descriptor->next_log; 79 } 80 } 81 82 void 83 print_queue(ehci_qh *queueHead) 84 { 85 dprintf("queue: t%08lx n%08lx ch%08lx ca%08lx cu%08lx\n", 86 queueHead->this_phy, queueHead->next_phy, queueHead->endpoint_chars, 87 queueHead->endpoint_caps, queueHead->current_qtd_phy); 88 dprintf("overlay: n%08lx a%08lx t%08lx %08lx %08lx %08lx %08lx %08lx\n", 89 queueHead->overlay.next_phy, queueHead->overlay.alt_next_phy, 90 queueHead->overlay.token, queueHead->overlay.buffer_phy[0], 91 queueHead->overlay.buffer_phy[1], queueHead->overlay.buffer_phy[2], 92 queueHead->overlay.buffer_phy[3], queueHead->overlay.buffer_phy[4]); 93 print_descriptor_chain(queueHead->element_log); 94 } 95 96 #endif // TRACE_USB 97 98 99 // 100 // #pragma mark - 101 // 102 103 104 EHCI::EHCI(pci_info *info, Stack *stack) 105 : BusManager(stack), 106 fCapabilityRegisters(NULL), 107 fOperationalRegisters(NULL), 108 fRegisterArea(-1), 109 fPCIInfo(info), 110 fStack(stack), 111 fEnabledInterrupts(0), 112 fPeriodicFrameListArea(-1), 113 fPeriodicFrameList(NULL), 114 fInterruptEntries(NULL), 115 fAsyncQueueHead(NULL), 116 fAsyncAdvanceSem(-1), 117 fFirstTransfer(NULL), 118 fLastTransfer(NULL), 119 fFinishTransfersSem(-1), 120 fFinishThread(-1), 121 fProcessingPipe(NULL), 122 fFreeListHead(NULL), 123 fCleanupSem(-1), 124 fCleanupThread(-1), 125 fStopThreads(false), 126 fFrameBandwidth(NULL), 127 fFirstIsochronousTransfer(NULL), 128 fLastIsochronousTransfer(NULL), 129 fFinishIsochronousTransfersSem(-1), 130 fFinishIsochronousThread(-1), 131 fRootHub(NULL), 132 fRootHubAddress(0), 133 fPortCount(0), 134 fPortResetChange(0), 135 fPortSuspendChange(0), 136 fInterruptPollThread(-1) 137 { 138 if (BusManager::InitCheck() < B_OK) { 139 TRACE_ERROR("bus manager failed to init\n"); 140 return; 141 } 142 143 TRACE("constructing new EHCI host controller driver\n"); 144 fInitOK = false; 145 146 // ATI/AMD SB600/SB700 periodic list cache workaround 147 // Logic kindly borrowed from NetBSD PR 40056 148 if (fPCIInfo->vendor_id == AMD_SBX00_VENDOR) { 149 bool applyWorkaround = false; 150 151 if (fPCIInfo->device_id == AMD_SB600_EHCI_CONTROLLER) { 152 // always apply on SB600 153 applyWorkaround = true; 154 } else if (fPCIInfo->device_id == AMD_SB700_SB800_EHCI_CONTROLLER) { 155 // only apply on certain chipsets, determined by SMBus revision 156 pci_info smbus; 157 int32 index = 0; 158 while (sPCIModule->get_nth_pci_info(index++, &smbus) >= B_OK) { 159 if (smbus.vendor_id == AMD_SBX00_VENDOR 160 && smbus.device_id == AMD_SBX00_SMBUS_CONTROLLER) { 161 162 // Only applies to chipsets < SB710 (rev A14) 163 if (smbus.revision == 0x3a || smbus.revision == 0x3b) 164 applyWorkaround = true; 165 166 break; 167 } 168 } 169 } 170 171 if (applyWorkaround) { 172 // According to AMD errata of SB700 and SB600 register documentation 173 // this disables the Periodic List Cache on SB600 and the Advanced 174 // Periodic List Cache on early SB700. Both the BSDs and Linux use 175 // this workaround. 176 177 TRACE_ALWAYS("disabling SB600/SB700 periodic list cache\n"); 178 uint32 workaround = sPCIModule->read_pci_config(fPCIInfo->bus, 179 fPCIInfo->device, fPCIInfo->function, 180 AMD_SBX00_EHCI_MISC_REGISTER, 4); 181 182 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 183 fPCIInfo->function, AMD_SBX00_EHCI_MISC_REGISTER, 4, 184 workaround | AMD_SBX00_EHCI_MISC_DISABLE_PERIODIC_LIST_CACHE); 185 } 186 } 187 188 // enable busmaster and memory mapped access 189 uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus, 190 fPCIInfo->device, fPCIInfo->function, PCI_command, 2); 191 command &= ~PCI_command_io; 192 command |= PCI_command_master | PCI_command_memory; 193 194 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 195 fPCIInfo->function, PCI_command, 2, command); 196 197 // map the registers 198 uint32 offset = fPCIInfo->u.h0.base_registers[0] & (B_PAGE_SIZE - 1); 199 addr_t physicalAddress = fPCIInfo->u.h0.base_registers[0] - offset; 200 size_t mapSize = (fPCIInfo->u.h0.base_register_sizes[0] + offset 201 + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 202 203 TRACE("map physical memory 0x%08lx (base: 0x%08lx; offset: %lx); size: %ld\n", 204 fPCIInfo->u.h0.base_registers[0], physicalAddress, offset, 205 fPCIInfo->u.h0.base_register_sizes[0]); 206 207 fRegisterArea = map_physical_memory("EHCI memory mapped registers", 208 physicalAddress, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS, 209 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, 210 (void **)&fCapabilityRegisters); 211 if (fRegisterArea < B_OK) { 212 TRACE("failed to map register memory\n"); 213 return; 214 } 215 216 fCapabilityRegisters += offset; 217 fOperationalRegisters = fCapabilityRegisters + ReadCapReg8(EHCI_CAPLENGTH); 218 TRACE("mapped capability registers: 0x%08lx\n", (uint32)fCapabilityRegisters); 219 TRACE("mapped operational registers: 0x%08lx\n", (uint32)fOperationalRegisters); 220 221 TRACE("structural parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCSPARAMS)); 222 TRACE("capability parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCCPARAMS)); 223 224 // read port count from capability register 225 fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f; 226 227 uint32 extendedCapPointer = ReadCapReg32(EHCI_HCCPARAMS) >> EHCI_ECP_SHIFT; 228 extendedCapPointer &= EHCI_ECP_MASK; 229 if (extendedCapPointer > 0) { 230 TRACE("extended capabilities register at %ld\n", extendedCapPointer); 231 232 uint32 legacySupport = sPCIModule->read_pci_config(fPCIInfo->bus, 233 fPCIInfo->device, fPCIInfo->function, extendedCapPointer, 4); 234 if ((legacySupport & EHCI_LEGSUP_CAPID_MASK) == EHCI_LEGSUP_CAPID) { 235 if ((legacySupport & EHCI_LEGSUP_BIOSOWNED) != 0) { 236 TRACE_ALWAYS("the host controller is bios owned, claiming" 237 " ownership\n"); 238 239 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 240 fPCIInfo->function, extendedCapPointer + 3, 1, 1); 241 242 for (int32 i = 0; i < 20; i++) { 243 legacySupport = sPCIModule->read_pci_config(fPCIInfo->bus, 244 fPCIInfo->device, fPCIInfo->function, 245 extendedCapPointer, 4); 246 247 if ((legacySupport & EHCI_LEGSUP_BIOSOWNED) == 0) 248 break; 249 250 TRACE_ALWAYS("controller is still bios owned, waiting\n"); 251 snooze(50000); 252 } 253 } 254 255 if (legacySupport & EHCI_LEGSUP_BIOSOWNED) { 256 TRACE_ERROR("bios won't give up control over the host controller (ignoring)\n"); 257 } else if (legacySupport & EHCI_LEGSUP_OSOWNED) { 258 TRACE_ALWAYS("successfully took ownership of the host controller\n"); 259 } 260 261 // Force off the BIOS owned flag, and clear all SMIs. Some BIOSes 262 // do indicate a successful handover but do not remove their SMIs 263 // and then freeze the system when interrupts are generated. 264 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 265 fPCIInfo->function, extendedCapPointer + 2, 1, 0); 266 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 267 fPCIInfo->function, extendedCapPointer + 4, 4, 0); 268 } else { 269 TRACE_ALWAYS("extended capability is not a legacy support register\n"); 270 } 271 } else { 272 TRACE_ALWAYS("no extended capabilities register\n"); 273 } 274 275 // disable interrupts 276 WriteOpReg(EHCI_USBINTR, 0); 277 278 // reset the host controller 279 if (ControllerReset() < B_OK) { 280 TRACE_ERROR("host controller failed to reset\n"); 281 return; 282 } 283 284 // reset the segment register 285 WriteOpReg(EHCI_CTRDSSEGMENT, 0); 286 287 // create semaphores the finisher thread will wait for 288 fAsyncAdvanceSem = create_sem(0, "EHCI Async Advance"); 289 fFinishTransfersSem = create_sem(0, "EHCI Finish Transfers"); 290 fCleanupSem = create_sem(0, "EHCI Cleanup"); 291 if (fFinishTransfersSem < B_OK || fAsyncAdvanceSem < B_OK 292 || fCleanupSem < B_OK) { 293 TRACE_ERROR("failed to create semaphores\n"); 294 return; 295 } 296 297 // create finisher service thread 298 fFinishThread = spawn_kernel_thread(FinishThread, "ehci finish thread", 299 B_NORMAL_PRIORITY, (void *)this); 300 resume_thread(fFinishThread); 301 302 // Create a lock for the isochronous transfer list 303 mutex_init(&fIsochronousLock, "EHCI isochronous lock"); 304 305 // Create semaphore the isochronous finisher thread will wait for 306 fFinishIsochronousTransfersSem = create_sem(0, 307 "EHCI Isochronous Finish Transfers"); 308 if (fFinishIsochronousTransfersSem < B_OK) { 309 TRACE_ERROR("failed to create isochronous finisher semaphore\n"); 310 return; 311 } 312 313 // Create the isochronous finisher service thread 314 fFinishIsochronousThread = spawn_kernel_thread(FinishIsochronousThread, 315 "ehci isochronous finish thread", B_URGENT_DISPLAY_PRIORITY, 316 (void *)this); 317 resume_thread(fFinishIsochronousThread); 318 319 // create cleanup service thread 320 fCleanupThread = spawn_kernel_thread(CleanupThread, "ehci cleanup thread", 321 B_NORMAL_PRIORITY, (void *)this); 322 resume_thread(fCleanupThread); 323 324 // set up interrupts or interrupt polling now that the controller is ready 325 bool polling = false; 326 void *settings = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS); 327 if (settings != NULL) { 328 polling = get_driver_boolean_parameter(settings, "ehci_polling", false, 329 false); 330 unload_driver_settings(settings); 331 } 332 333 if (polling) { 334 // create and run the polling thread 335 TRACE_ALWAYS("enabling ehci polling\n"); 336 fInterruptPollThread = spawn_kernel_thread(InterruptPollThread, 337 "ehci interrupt poll thread", B_NORMAL_PRIORITY, (void *)this); 338 resume_thread(fInterruptPollThread); 339 } else { 340 // install the interrupt handler and enable interrupts 341 install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, 342 InterruptHandler, (void *)this, 0); 343 } 344 345 // ensure that interrupts are en-/disabled on the PCI device 346 command = sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device, 347 fPCIInfo->function, PCI_command, 2); 348 if (polling == ((command & PCI_command_int_disable) == 0)) { 349 if (polling) 350 command &= ~PCI_command_int_disable; 351 else 352 command |= PCI_command_int_disable; 353 354 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 355 fPCIInfo->function, PCI_command, 2, command); 356 } 357 358 fEnabledInterrupts = EHCI_USBINTR_HOSTSYSERR | EHCI_USBINTR_USBERRINT 359 | EHCI_USBINTR_USBINT | EHCI_USBINTR_INTONAA; 360 WriteOpReg(EHCI_USBINTR, fEnabledInterrupts); 361 362 // structures don't span page boundaries 363 size_t itdListSize = EHCI_VFRAMELIST_ENTRIES_COUNT 364 / (B_PAGE_SIZE / sizeof(itd_entry)) * B_PAGE_SIZE; 365 size_t sitdListSize = EHCI_VFRAMELIST_ENTRIES_COUNT 366 / (B_PAGE_SIZE / sizeof(sitd_entry)) * B_PAGE_SIZE; 367 size_t frameListSize = B_PAGE_SIZE + B_PAGE_SIZE + itdListSize 368 + sitdListSize; 369 370 // allocate the periodic frame list 371 fPeriodicFrameListArea = fStack->AllocateArea((void **)&fPeriodicFrameList, 372 (void **)&physicalAddress, frameListSize, "USB EHCI Periodic Framelist"); 373 if (fPeriodicFrameListArea < B_OK) { 374 TRACE_ERROR("unable to allocate periodic framelist\n"); 375 return; 376 } 377 378 if ((physicalAddress & 0xfff) != 0) 379 panic("EHCI_PERIODICLISTBASE not aligned on 4k: 0x%lx\n", physicalAddress); 380 // set the periodic frame list base on the controller 381 WriteOpReg(EHCI_PERIODICLISTBASE, (uint32)physicalAddress); 382 383 // create the interrupt entries to support different polling intervals 384 TRACE("creating interrupt entries\n"); 385 addr_t physicalBase = physicalAddress + B_PAGE_SIZE; 386 uint8 *logicalBase = (uint8 *)fPeriodicFrameList + B_PAGE_SIZE; 387 memset(logicalBase, 0, B_PAGE_SIZE); 388 389 fInterruptEntries = (interrupt_entry *)logicalBase; 390 for (int32 i = 0; i < EHCI_INTERRUPT_ENTRIES_COUNT; i++) { 391 ehci_qh *queueHead = &fInterruptEntries[i].queue_head; 392 queueHead->this_phy = physicalBase | EHCI_ITEM_TYPE_QH; 393 queueHead->current_qtd_phy = EHCI_ITEM_TERMINATE; 394 queueHead->overlay.next_phy = EHCI_ITEM_TERMINATE; 395 queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE; 396 queueHead->overlay.token = EHCI_QTD_STATUS_HALTED; 397 398 // set dummy endpoint information 399 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH 400 | (3 << EHCI_QH_CHARS_RL_SHIFT) | (64 << EHCI_QH_CHARS_MPL_SHIFT) 401 | EHCI_QH_CHARS_TOGGLE; 402 queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT) 403 | (0xff << EHCI_QH_CAPS_ISM_SHIFT); 404 405 physicalBase += sizeof(interrupt_entry); 406 } 407 408 // create the itd and sitd entries 409 TRACE("build up iso entries\n"); 410 addr_t itdPhysicalBase = physicalAddress + B_PAGE_SIZE + B_PAGE_SIZE; 411 itd_entry* itds = (itd_entry *)((uint8 *)fPeriodicFrameList + B_PAGE_SIZE 412 + B_PAGE_SIZE); 413 memset(itds, 0, itdListSize); 414 415 addr_t sitdPhysicalBase = itdPhysicalBase + itdListSize; 416 sitd_entry* sitds = (sitd_entry *)((uint8 *)fPeriodicFrameList + B_PAGE_SIZE 417 + B_PAGE_SIZE + itdListSize); 418 memset(sitds, 0, sitdListSize); 419 420 fItdEntries = new(std::nothrow) ehci_itd *[EHCI_VFRAMELIST_ENTRIES_COUNT]; 421 fSitdEntries = new(std::nothrow) ehci_sitd *[EHCI_VFRAMELIST_ENTRIES_COUNT]; 422 423 for (int32 i = 0; i < EHCI_VFRAMELIST_ENTRIES_COUNT; i++) { 424 ehci_sitd *sitd = &sitds[i].sitd; 425 sitd->this_phy = sitdPhysicalBase | EHCI_ITEM_TYPE_SITD; 426 sitd->back_phy = EHCI_ITEM_TERMINATE; 427 fSitdEntries[i] = sitd; 428 TRACE("sitd entry %ld %p 0x%lx\n", i, sitd, sitd->this_phy); 429 430 ehci_itd *itd = &itds[i].itd; 431 itd->this_phy = itdPhysicalBase | EHCI_ITEM_TYPE_ITD; 432 itd->next_phy = sitd->this_phy; 433 fItdEntries[i] = itd; 434 TRACE("itd entry %ld %p 0x%lx\n", i, itd, itd->this_phy); 435 436 sitdPhysicalBase += sizeof(sitd_entry); 437 itdPhysicalBase += sizeof(itd_entry); 438 if ((sitdPhysicalBase & 0x10) != 0 || (itdPhysicalBase & 0x10) != 0) 439 panic("physical base for entry %ld not aligned on 32\n", i); 440 } 441 442 // build flat interrupt tree 443 TRACE("build up interrupt links\n"); 444 uint32 interval = EHCI_VFRAMELIST_ENTRIES_COUNT; 445 uint32 intervalIndex = EHCI_INTERRUPT_ENTRIES_COUNT - 1; 446 while (interval > 1) { 447 for (uint32 insertIndex = interval / 2; 448 insertIndex < EHCI_VFRAMELIST_ENTRIES_COUNT; 449 insertIndex += interval) { 450 fSitdEntries[insertIndex]->next_phy = 451 fInterruptEntries[intervalIndex].queue_head.this_phy; 452 } 453 454 intervalIndex--; 455 interval /= 2; 456 } 457 458 // setup the empty slot in the list and linking of all -> first 459 ehci_qh *firstLogical = &fInterruptEntries[0].queue_head; 460 fSitdEntries[0]->next_phy = firstLogical->this_phy; 461 for (int32 i = 1; i < EHCI_INTERRUPT_ENTRIES_COUNT; i++) { 462 fInterruptEntries[i].queue_head.next_phy = firstLogical->this_phy; 463 fInterruptEntries[i].queue_head.next_log = firstLogical; 464 fInterruptEntries[i].queue_head.prev_log = NULL; 465 } 466 467 // terminate the first entry 468 firstLogical->next_phy = EHCI_ITEM_TERMINATE; 469 firstLogical->next_log = NULL; 470 firstLogical->prev_log = NULL; 471 472 for (int32 i = 0; i < EHCI_FRAMELIST_ENTRIES_COUNT; i++) { 473 fPeriodicFrameList[i] = 474 fItdEntries[i & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1)]->this_phy; 475 TRACE("periodic entry %ld linked to 0x%lx\n", i, fPeriodicFrameList[i]); 476 } 477 478 // Create the array that will keep bandwidth information 479 fFrameBandwidth = new(std::nothrow) uint16[EHCI_VFRAMELIST_ENTRIES_COUNT]; 480 for (int32 i = 0; i < EHCI_VFRAMELIST_ENTRIES_COUNT; i++) { 481 fFrameBandwidth[i] = MAX_AVAILABLE_BANDWIDTH; 482 } 483 484 // allocate a queue head that will always stay in the async frame list 485 fAsyncQueueHead = CreateQueueHead(); 486 if (!fAsyncQueueHead) { 487 TRACE_ERROR("unable to allocate stray async queue head\n"); 488 return; 489 } 490 491 fAsyncQueueHead->next_phy = fAsyncQueueHead->this_phy; 492 fAsyncQueueHead->next_log = fAsyncQueueHead; 493 fAsyncQueueHead->prev_log = fAsyncQueueHead; 494 fAsyncQueueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH | EHCI_QH_CHARS_RECHEAD; 495 fAsyncQueueHead->endpoint_caps = 1 << EHCI_QH_CAPS_MULT_SHIFT; 496 fAsyncQueueHead->current_qtd_phy = EHCI_ITEM_TERMINATE; 497 fAsyncQueueHead->overlay.next_phy = EHCI_ITEM_TERMINATE; 498 499 WriteOpReg(EHCI_ASYNCLISTADDR, (uint32)fAsyncQueueHead->this_phy); 500 TRACE("set the async list addr to 0x%08lx\n", ReadOpReg(EHCI_ASYNCLISTADDR)); 501 502 fInitOK = true; 503 TRACE("EHCI host controller driver constructed\n"); 504 } 505 506 507 EHCI::~EHCI() 508 { 509 TRACE("tear down EHCI host controller driver\n"); 510 511 WriteOpReg(EHCI_USBCMD, 0); 512 WriteOpReg(EHCI_CONFIGFLAG, 0); 513 CancelAllPendingTransfers(); 514 515 int32 result = 0; 516 fStopThreads = true; 517 delete_sem(fAsyncAdvanceSem); 518 delete_sem(fFinishTransfersSem); 519 delete_sem(fFinishIsochronousTransfersSem); 520 wait_for_thread(fFinishThread, &result); 521 wait_for_thread(fCleanupThread, &result); 522 wait_for_thread(fFinishIsochronousThread, &result); 523 524 if (fInterruptPollThread >= 0) 525 wait_for_thread(fInterruptPollThread, &result); 526 527 LockIsochronous(); 528 isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer; 529 while (isoTransfer) { 530 isochronous_transfer_data *next = isoTransfer->link; 531 delete isoTransfer; 532 isoTransfer = next; 533 } 534 mutex_destroy(&fIsochronousLock); 535 536 delete fRootHub; 537 delete [] fFrameBandwidth; 538 delete [] fItdEntries; 539 delete [] fSitdEntries; 540 delete_area(fPeriodicFrameListArea); 541 delete_area(fRegisterArea); 542 put_module(B_PCI_MODULE_NAME); 543 } 544 545 546 status_t 547 EHCI::Start() 548 { 549 TRACE("starting EHCI host controller\n"); 550 TRACE("usbcmd: 0x%08lx; usbsts: 0x%08lx\n", ReadOpReg(EHCI_USBCMD), 551 ReadOpReg(EHCI_USBSTS)); 552 553 bool hasPerPortChangeEvent = (ReadCapReg32(EHCI_HCCPARAMS) 554 & EHCI_HCCPARAMS_PPCEC) != 0; 555 556 uint32 config = ReadOpReg(EHCI_USBCMD); 557 config &= ~((EHCI_USBCMD_ITC_MASK << EHCI_USBCMD_ITC_SHIFT) 558 | EHCI_USBCMD_PPCEE); 559 uint32 frameListSize = (config >> EHCI_USBCMD_FLS_SHIFT) 560 & EHCI_USBCMD_FLS_MASK; 561 562 WriteOpReg(EHCI_USBCMD, config | EHCI_USBCMD_RUNSTOP 563 | (hasPerPortChangeEvent ? EHCI_USBCMD_PPCEE : 0) 564 | EHCI_USBCMD_ASENABLE | EHCI_USBCMD_PSENABLE 565 | (frameListSize << EHCI_USBCMD_FLS_SHIFT) 566 | (1 << EHCI_USBCMD_ITC_SHIFT)); 567 568 switch (frameListSize) { 569 case 0: 570 TRACE("frame list size 1024\n"); 571 break; 572 case 1: 573 TRACE("frame list size 512\n"); 574 break; 575 case 2: 576 TRACE("frame list size 256\n"); 577 break; 578 default: 579 TRACE("unknown frame list size\n"); 580 } 581 582 bool running = false; 583 for (int32 i = 0; i < 10; i++) { 584 uint32 status = ReadOpReg(EHCI_USBSTS); 585 TRACE("try %ld: status 0x%08lx\n", i, status); 586 587 if (status & EHCI_USBSTS_HCHALTED) { 588 snooze(10000); 589 } else { 590 running = true; 591 break; 592 } 593 } 594 595 if (!running) { 596 TRACE("host controller didn't start\n"); 597 return B_ERROR; 598 } 599 600 // route all ports to us 601 WriteOpReg(EHCI_CONFIGFLAG, EHCI_CONFIGFLAG_FLAG); 602 snooze(10000); 603 604 fRootHubAddress = AllocateAddress(); 605 fRootHub = new(std::nothrow) EHCIRootHub(RootObject(), fRootHubAddress); 606 if (!fRootHub) { 607 TRACE_ERROR("no memory to allocate root hub\n"); 608 return B_NO_MEMORY; 609 } 610 611 if (fRootHub->InitCheck() < B_OK) { 612 TRACE_ERROR("root hub failed init check\n"); 613 return fRootHub->InitCheck(); 614 } 615 616 SetRootHub(fRootHub); 617 618 TRACE_ALWAYS("successfully started the controller\n"); 619 return BusManager::Start(); 620 } 621 622 623 status_t 624 EHCI::SubmitTransfer(Transfer *transfer) 625 { 626 // short circuit the root hub 627 if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress) 628 return fRootHub->ProcessTransfer(this, transfer); 629 630 Pipe *pipe = transfer->TransferPipe(); 631 if (pipe->Type() & USB_OBJECT_ISO_PIPE) 632 return SubmitIsochronous(transfer); 633 634 ehci_qh *queueHead = CreateQueueHead(); 635 if (!queueHead) { 636 TRACE_ERROR("failed to allocate queue head\n"); 637 return B_NO_MEMORY; 638 } 639 640 status_t result = InitQueueHead(queueHead, pipe); 641 if (result < B_OK) { 642 TRACE_ERROR("failed to init queue head\n"); 643 FreeQueueHead(queueHead); 644 return result; 645 } 646 647 bool directionIn; 648 ehci_qtd *dataDescriptor; 649 if (pipe->Type() & USB_OBJECT_CONTROL_PIPE) { 650 result = FillQueueWithRequest(transfer, queueHead, &dataDescriptor, 651 &directionIn); 652 } else { 653 result = FillQueueWithData(transfer, queueHead, &dataDescriptor, 654 &directionIn); 655 } 656 657 if (result < B_OK) { 658 TRACE_ERROR("failed to fill transfer queue with data\n"); 659 FreeQueueHead(queueHead); 660 return result; 661 } 662 663 result = AddPendingTransfer(transfer, queueHead, dataDescriptor, directionIn); 664 if (result < B_OK) { 665 TRACE_ERROR("failed to add pending transfer\n"); 666 FreeQueueHead(queueHead); 667 return result; 668 } 669 670 #ifdef TRACE_USB 671 TRACE("linking queue\n"); 672 print_queue(queueHead); 673 #endif 674 675 if (pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) 676 result = LinkInterruptQueueHead(queueHead, pipe); 677 else 678 result = LinkQueueHead(queueHead); 679 680 if (result < B_OK) { 681 TRACE_ERROR("failed to link queue head\n"); 682 FreeQueueHead(queueHead); 683 return result; 684 } 685 686 return B_OK; 687 } 688 689 690 status_t 691 EHCI::SubmitIsochronous(Transfer *transfer) 692 { 693 Pipe *pipe = transfer->TransferPipe(); 694 bool directionIn = (pipe->Direction() == Pipe::In); 695 usb_isochronous_data *isochronousData = transfer->IsochronousData(); 696 size_t packetSize = transfer->DataLength(); 697 #ifdef TRACE_USB 698 size_t restSize = packetSize % isochronousData->packet_count; 699 #endif 700 packetSize /= isochronousData->packet_count; 701 uint16 currentFrame; 702 703 if (packetSize > pipe->MaxPacketSize()) { 704 TRACE_ERROR("isochronous packetSize is bigger than pipe MaxPacketSize\n"); 705 return B_BAD_VALUE; 706 } 707 708 // Ignore the fact that the last descriptor might need less bandwidth. 709 // The overhead is not worthy. 710 uint16 bandwidth = transfer->Bandwidth() / isochronousData->packet_count; 711 712 TRACE("isochronous transfer descriptor bandwidth %d\n", bandwidth); 713 714 // The following holds the list of transfer descriptor of the 715 // isochronous request. It is used to quickly remove all the isochronous 716 // descriptors from the frame list, as descriptors are not link to each 717 // other in a queue like for every other transfer. 718 ehci_itd **isoRequest 719 = new(std::nothrow) ehci_itd *[isochronousData->packet_count]; 720 if (isoRequest == NULL) { 721 TRACE("failed to create isoRequest array!\n"); 722 return B_NO_MEMORY; 723 } 724 725 TRACE("isochronous submitted size=%ld bytes, TDs=%ld, " 726 "maxPacketSize=%ld, packetSize=%ld, restSize=%ld\n", transfer->DataLength(), 727 isochronousData->packet_count, pipe->MaxPacketSize(), packetSize, restSize); 728 729 // Find the entry where to start inserting the first Isochronous descriptor 730 if (isochronousData->flags & USB_ISO_ASAP || 731 isochronousData->starting_frame_number == NULL) { 732 733 uint32 threshold = (ReadCapReg32(EHCI_HCCPARAMS) 734 >> EHCI_HCCPARAMS_IPT_SHIFT) & EHCI_HCCPARAMS_IPT_MASK; 735 TRACE("threshold: %ld\n", threshold); 736 737 // find the first available frame with enough bandwidth. 738 // This should always be the case, as defining the starting frame 739 // number in the driver makes no sense for many reason, one of which 740 // is that frame numbers value are host controller specific, and the 741 // driver does not know which host controller is running. 742 currentFrame = (ReadOpReg(EHCI_FRINDEX) / 8) 743 & (EHCI_FRAMELIST_ENTRIES_COUNT - 1); 744 745 // Make sure that: 746 // 1. We are at least 5ms ahead the controller 747 // 2. We stay in the range 0-127 748 // 3. There is enough bandwidth in the first entry 749 currentFrame = (currentFrame + threshold) 750 & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1); 751 } else { 752 // Find out if the frame number specified has enough bandwidth, 753 // otherwise find the first next available frame with enough bandwidth 754 currentFrame = *isochronousData->starting_frame_number; 755 } 756 757 TRACE("isochronous starting frame=%d\n", currentFrame); 758 759 uint16 itdIndex = 0; 760 size_t dataLength = transfer->DataLength(); 761 void* bufferLog; 762 addr_t bufferPhy; 763 if (fStack->AllocateChunk(&bufferLog, (void**)&bufferPhy, dataLength) < B_OK) { 764 TRACE_ERROR("unable to allocate itd buffer\n"); 765 return B_NO_MEMORY; 766 } 767 768 memset(bufferLog, 0, dataLength); 769 770 addr_t currentPhy = bufferPhy; 771 uint32 frameCount = 0; 772 while (dataLength > 0) { 773 ehci_itd* itd = CreateItdDescriptor(); 774 isoRequest[itdIndex++] = itd; 775 uint16 pg = 0; 776 itd->buffer_phy[pg] = currentPhy & 0xfffff000; 777 uint32 offset = currentPhy & 0xfff; 778 TRACE("isochronous created itd, filling it with phy %lx\n", currentPhy); 779 for (int32 i = 0; i < 8 && dataLength > 0; i++) { 780 size_t length = min_c(dataLength, packetSize); 781 itd->token[i] = (EHCI_ITD_STATUS_ACTIVE << EHCI_ITD_STATUS_SHIFT) 782 | (length << EHCI_ITD_TLENGTH_SHIFT) | (pg << EHCI_ITD_PG_SHIFT) 783 | (offset << EHCI_ITD_TOFFSET_SHIFT); 784 itd->last_token = i; 785 TRACE("isochronous filled slot %ld 0x%lx\n", i, itd->token[i]); 786 dataLength -= length; 787 offset += length; 788 if (dataLength > 0 && offset > 0xfff) { 789 offset -= B_PAGE_SIZE; 790 currentPhy += B_PAGE_SIZE; 791 itd->buffer_phy[pg + 1] = currentPhy & 0xfffff000; 792 pg++; 793 } 794 } 795 796 currentPhy += (offset & 0xfff) - (currentPhy & 0xfff); 797 798 itd->buffer_phy[0] |= (pipe->EndpointAddress() << EHCI_ITD_ENDPOINT_SHIFT) 799 | (pipe->DeviceAddress() << EHCI_ITD_ADDRESS_SHIFT); 800 itd->buffer_phy[1] |= (pipe->MaxPacketSize() & EHCI_ITD_MAXPACKETSIZE_MASK) 801 | (directionIn << EHCI_ITD_DIR_SHIFT); 802 itd->buffer_phy[2] |= (1 << EHCI_ITD_MUL_SHIFT); 803 804 TRACE("isochronous filled itd buffer_phy[0,1,2] 0x%lx, 0x%lx 0x%lx\n", 805 itd->buffer_phy[0], itd->buffer_phy[1], itd->buffer_phy[2]); 806 807 LinkITDescriptors(itd, &fItdEntries[currentFrame]); 808 fFrameBandwidth[currentFrame] -= bandwidth; 809 currentFrame = (currentFrame + 1) & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1); 810 frameCount++; 811 } 812 813 TRACE("isochronous filled itds count %d\n", itdIndex); 814 815 // Add transfer to the list 816 status_t result = AddPendingIsochronousTransfer(transfer, isoRequest, 817 itdIndex - 1, directionIn, bufferPhy, bufferLog, 818 transfer->DataLength()); 819 if (result < B_OK) { 820 TRACE_ERROR("failed to add pending isochronous transfer\n"); 821 return result; 822 } 823 824 TRACE("appended isochronous transfer by starting at frame number %d\n", 825 currentFrame); 826 827 // Wake up the isochronous finisher thread 828 release_sem_etc(fFinishIsochronousTransfersSem, 1 /*frameCount*/, B_DO_NOT_RESCHEDULE); 829 830 return B_OK; 831 } 832 833 834 isochronous_transfer_data * 835 EHCI::FindIsochronousTransfer(ehci_itd *itd) 836 { 837 // Simply check every last descriptor of the isochronous transfer list 838 if (LockIsochronous()) { 839 isochronous_transfer_data *transfer = fFirstIsochronousTransfer; 840 if (transfer) { 841 while (transfer->descriptors[transfer->last_to_process] 842 != itd) { 843 transfer = transfer->link; 844 if (!transfer) 845 break; 846 } 847 } 848 UnlockIsochronous(); 849 return transfer; 850 } 851 return NULL; 852 } 853 854 855 status_t 856 EHCI::NotifyPipeChange(Pipe *pipe, usb_change change) 857 { 858 TRACE("pipe change %d for pipe %p\n", change, pipe); 859 switch (change) { 860 case USB_CHANGE_CREATED: 861 case USB_CHANGE_DESTROYED: { 862 // ToDo: we should create and keep a single queue head 863 // for all transfers to/from this pipe 864 break; 865 } 866 867 case USB_CHANGE_PIPE_POLICY_CHANGED: { 868 // ToDo: for isochronous pipes we might need to adapt to new 869 // pipe policy settings here 870 break; 871 } 872 } 873 874 return B_OK; 875 } 876 877 878 status_t 879 EHCI::AddTo(Stack *stack) 880 { 881 #ifdef TRACE_USB 882 set_dprintf_enabled(true); 883 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 884 load_driver_symbols("ehci"); 885 #endif 886 #endif 887 888 if (!sPCIModule) { 889 status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule); 890 if (status < B_OK) { 891 TRACE_MODULE_ERROR("getting pci module failed! 0x%08lx\n", status); 892 return status; 893 } 894 } 895 896 TRACE_MODULE("searching devices\n"); 897 bool found = false; 898 pci_info *item = new(std::nothrow) pci_info; 899 if (!item) { 900 sPCIModule = NULL; 901 put_module(B_PCI_MODULE_NAME); 902 return B_NO_MEMORY; 903 } 904 905 for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) { 906 if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb 907 && item->class_api == PCI_usb_ehci) { 908 if (item->u.h0.interrupt_line == 0 909 || item->u.h0.interrupt_line == 0xFF) { 910 TRACE_MODULE_ERROR("found device with invalid IRQ - check IRQ assignement\n"); 911 continue; 912 } 913 914 TRACE_MODULE("found device at IRQ %u\n", item->u.h0.interrupt_line); 915 EHCI *bus = new(std::nothrow) EHCI(item, stack); 916 if (!bus) { 917 delete item; 918 sPCIModule = NULL; 919 put_module(B_PCI_MODULE_NAME); 920 return B_NO_MEMORY; 921 } 922 923 if (bus->InitCheck() < B_OK) { 924 TRACE_MODULE_ERROR("bus failed init check\n"); 925 delete bus; 926 continue; 927 } 928 929 // the bus took it away 930 item = new(std::nothrow) pci_info; 931 932 bus->Start(); 933 stack->AddBusManager(bus); 934 found = true; 935 } 936 } 937 938 if (!found) { 939 TRACE_MODULE_ERROR("no devices found\n"); 940 delete item; 941 sPCIModule = NULL; 942 put_module(B_PCI_MODULE_NAME); 943 return ENODEV; 944 } 945 946 delete item; 947 return B_OK; 948 } 949 950 951 status_t 952 EHCI::GetPortStatus(uint8 index, usb_port_status *status) 953 { 954 if (index >= fPortCount) 955 return B_BAD_INDEX; 956 957 status->status = status->change = 0; 958 uint32 portStatus = ReadOpReg(EHCI_PORTSC + index * sizeof(uint32)); 959 960 // build the status 961 if (portStatus & EHCI_PORTSC_CONNSTATUS) 962 status->status |= PORT_STATUS_CONNECTION; 963 if (portStatus & EHCI_PORTSC_ENABLE) 964 status->status |= PORT_STATUS_ENABLE; 965 if (portStatus & EHCI_PORTSC_ENABLE) 966 status->status |= PORT_STATUS_HIGH_SPEED; 967 if (portStatus & EHCI_PORTSC_OCACTIVE) 968 status->status |= PORT_STATUS_OVER_CURRENT; 969 if (portStatus & EHCI_PORTSC_PORTRESET) 970 status->status |= PORT_STATUS_RESET; 971 if (portStatus & EHCI_PORTSC_PORTPOWER) 972 status->status |= PORT_STATUS_POWER; 973 if (portStatus & EHCI_PORTSC_SUSPEND) 974 status->status |= PORT_STATUS_SUSPEND; 975 if (portStatus & EHCI_PORTSC_DMINUS) 976 status->status |= PORT_STATUS_LOW_SPEED; 977 978 // build the change 979 if (portStatus & EHCI_PORTSC_CONNCHANGE) 980 status->change |= PORT_STATUS_CONNECTION; 981 if (portStatus & EHCI_PORTSC_ENABLECHANGE) 982 status->change |= PORT_STATUS_ENABLE; 983 if (portStatus & EHCI_PORTSC_OCCHANGE) 984 status->change |= PORT_STATUS_OVER_CURRENT; 985 986 // there are no bits to indicate suspend and reset change 987 if (fPortResetChange & (1 << index)) 988 status->change |= PORT_STATUS_RESET; 989 if (fPortSuspendChange & (1 << index)) 990 status->change |= PORT_STATUS_SUSPEND; 991 992 return B_OK; 993 } 994 995 996 status_t 997 EHCI::SetPortFeature(uint8 index, uint16 feature) 998 { 999 if (index >= fPortCount) 1000 return B_BAD_INDEX; 1001 1002 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32); 1003 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; 1004 1005 switch (feature) { 1006 case PORT_SUSPEND: 1007 return SuspendPort(index); 1008 1009 case PORT_RESET: 1010 return ResetPort(index); 1011 1012 case PORT_POWER: 1013 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTPOWER); 1014 return B_OK; 1015 } 1016 1017 return B_BAD_VALUE; 1018 } 1019 1020 1021 status_t 1022 EHCI::ClearPortFeature(uint8 index, uint16 feature) 1023 { 1024 if (index >= fPortCount) 1025 return B_BAD_INDEX; 1026 1027 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32); 1028 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; 1029 1030 switch (feature) { 1031 case PORT_ENABLE: 1032 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_ENABLE); 1033 return B_OK; 1034 1035 case PORT_POWER: 1036 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTPOWER); 1037 return B_OK; 1038 1039 case C_PORT_CONNECTION: 1040 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_CONNCHANGE); 1041 return B_OK; 1042 1043 case C_PORT_ENABLE: 1044 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_ENABLECHANGE); 1045 return B_OK; 1046 1047 case C_PORT_OVER_CURRENT: 1048 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_OCCHANGE); 1049 return B_OK; 1050 1051 case C_PORT_RESET: 1052 fPortResetChange &= ~(1 << index); 1053 return B_OK; 1054 1055 case C_PORT_SUSPEND: 1056 fPortSuspendChange &= ~(1 << index); 1057 return B_OK; 1058 } 1059 1060 return B_BAD_VALUE; 1061 } 1062 1063 1064 status_t 1065 EHCI::ResetPort(uint8 index) 1066 { 1067 TRACE("reset port %d\n", index); 1068 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32); 1069 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; 1070 1071 if (portStatus & EHCI_PORTSC_DMINUS) { 1072 TRACE_ALWAYS("lowspeed device connected, giving up port ownership\n"); 1073 // there is a lowspeed device connected. 1074 // we give the ownership to a companion controller. 1075 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER); 1076 fPortResetChange |= (1 << index); 1077 return B_OK; 1078 } 1079 1080 // enable reset signaling 1081 WriteOpReg(portRegister, (portStatus & ~EHCI_PORTSC_ENABLE) 1082 | EHCI_PORTSC_PORTRESET); 1083 snooze(50000); 1084 1085 // disable reset signaling 1086 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; 1087 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTRESET); 1088 snooze(2000); 1089 1090 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; 1091 if (portStatus & EHCI_PORTSC_PORTRESET) { 1092 TRACE_ERROR("port reset won't complete\n"); 1093 return B_ERROR; 1094 } 1095 1096 if ((portStatus & EHCI_PORTSC_ENABLE) == 0) { 1097 TRACE_ALWAYS("fullspeed device connected, giving up port ownership\n"); 1098 // the port was not enabled, this means that no high speed device is 1099 // attached to this port. we give up ownership to a companion controler 1100 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER); 1101 } 1102 1103 fPortResetChange |= (1 << index); 1104 return B_OK; 1105 } 1106 1107 1108 status_t 1109 EHCI::SuspendPort(uint8 index) 1110 { 1111 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32); 1112 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; 1113 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_SUSPEND); 1114 fPortSuspendChange |= (1 << index); 1115 return B_OK; 1116 } 1117 1118 1119 status_t 1120 EHCI::ControllerReset() 1121 { 1122 // halt the controller first 1123 WriteOpReg(EHCI_USBCMD, 0); 1124 snooze(10000); 1125 1126 // then reset it 1127 WriteOpReg(EHCI_USBCMD, EHCI_USBCMD_HCRESET); 1128 1129 int32 tries = 5; 1130 while (ReadOpReg(EHCI_USBCMD) & EHCI_USBCMD_HCRESET) { 1131 snooze(10000); 1132 if (tries-- < 0) 1133 return B_ERROR; 1134 } 1135 1136 return B_OK; 1137 } 1138 1139 1140 status_t 1141 EHCI::LightReset() 1142 { 1143 return B_ERROR; 1144 } 1145 1146 1147 int32 1148 EHCI::InterruptHandler(void *data) 1149 { 1150 return ((EHCI *)data)->Interrupt(); 1151 } 1152 1153 1154 int32 1155 EHCI::Interrupt() 1156 { 1157 static spinlock lock = B_SPINLOCK_INITIALIZER; 1158 acquire_spinlock(&lock); 1159 1160 // check if any interrupt was generated 1161 uint32 status = ReadOpReg(EHCI_USBSTS) & EHCI_USBSTS_INTMASK; 1162 if ((status & fEnabledInterrupts) == 0) { 1163 if (status != 0) { 1164 TRACE("discarding not enabled interrupts 0x%08lx\n", status); 1165 WriteOpReg(EHCI_USBSTS, status); 1166 } 1167 1168 release_spinlock(&lock); 1169 return B_UNHANDLED_INTERRUPT; 1170 } 1171 1172 bool asyncAdvance = false; 1173 bool finishTransfers = false; 1174 int32 result = B_HANDLED_INTERRUPT; 1175 1176 if (status & EHCI_USBSTS_USBINT) { 1177 TRACE("transfer finished\n"); 1178 result = B_INVOKE_SCHEDULER; 1179 finishTransfers = true; 1180 } 1181 1182 if (status & EHCI_USBSTS_USBERRINT) { 1183 TRACE("transfer error\n"); 1184 result = B_INVOKE_SCHEDULER; 1185 finishTransfers = true; 1186 } 1187 1188 if (status & EHCI_USBSTS_FLROLLOVER) 1189 TRACE("frame list rollover\n"); 1190 1191 if (status & EHCI_USBSTS_PORTCHANGE) 1192 TRACE("port change detected\n"); 1193 1194 if (status & EHCI_USBSTS_INTONAA) { 1195 TRACE("interrupt on async advance\n"); 1196 asyncAdvance = true; 1197 result = B_INVOKE_SCHEDULER; 1198 } 1199 1200 if (status & EHCI_USBSTS_HOSTSYSERR) 1201 TRACE_ERROR("host system error!\n"); 1202 1203 WriteOpReg(EHCI_USBSTS, status); 1204 release_spinlock(&lock); 1205 1206 if (asyncAdvance) 1207 release_sem_etc(fAsyncAdvanceSem, 1, B_DO_NOT_RESCHEDULE); 1208 if (finishTransfers) 1209 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); 1210 1211 return result; 1212 } 1213 1214 1215 int32 1216 EHCI::InterruptPollThread(void *data) 1217 { 1218 EHCI *ehci = (EHCI *)data; 1219 1220 while (!ehci->fStopThreads) { 1221 // TODO: this could be handled much better by only polling when there 1222 // are actual transfers going on... 1223 snooze(1000); 1224 1225 cpu_status status = disable_interrupts(); 1226 ehci->Interrupt(); 1227 restore_interrupts(status); 1228 } 1229 1230 return 0; 1231 } 1232 1233 1234 status_t 1235 EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead, 1236 ehci_qtd *dataDescriptor, bool directionIn) 1237 { 1238 transfer_data *data = new(std::nothrow) transfer_data; 1239 if (!data) 1240 return B_NO_MEMORY; 1241 1242 status_t result = transfer->InitKernelAccess(); 1243 if (result < B_OK) { 1244 delete data; 1245 return result; 1246 } 1247 1248 data->transfer = transfer; 1249 data->queue_head = queueHead; 1250 data->data_descriptor = dataDescriptor; 1251 data->incoming = directionIn; 1252 data->canceled = false; 1253 data->link = NULL; 1254 1255 if (!Lock()) { 1256 delete data; 1257 return B_ERROR; 1258 } 1259 1260 if (fLastTransfer) 1261 fLastTransfer->link = data; 1262 else 1263 fFirstTransfer = data; 1264 1265 fLastTransfer = data; 1266 Unlock(); 1267 1268 return B_OK; 1269 } 1270 1271 1272 status_t 1273 EHCI::AddPendingIsochronousTransfer(Transfer *transfer, ehci_itd **isoRequest, 1274 uint32 lastIndex, bool directionIn, addr_t bufferPhy, void* bufferLog, 1275 size_t bufferSize) 1276 { 1277 if (!transfer || !isoRequest) 1278 return B_BAD_VALUE; 1279 1280 isochronous_transfer_data *data 1281 = new(std::nothrow) isochronous_transfer_data; 1282 if (!data) 1283 return B_NO_MEMORY; 1284 1285 status_t result = transfer->InitKernelAccess(); 1286 if (result < B_OK) { 1287 delete data; 1288 return result; 1289 } 1290 1291 data->transfer = transfer; 1292 data->descriptors = isoRequest; 1293 data->last_to_process = lastIndex; 1294 data->incoming = directionIn; 1295 data->is_active = true; 1296 data->link = NULL; 1297 data->buffer_phy = bufferPhy; 1298 data->buffer_log = bufferLog; 1299 data->buffer_size = bufferSize; 1300 1301 // Put in the isochronous transfer list 1302 if (!LockIsochronous()) { 1303 delete data; 1304 return B_ERROR; 1305 } 1306 1307 if (fLastIsochronousTransfer) 1308 fLastIsochronousTransfer->link = data; 1309 else if (!fFirstIsochronousTransfer) 1310 fFirstIsochronousTransfer = data; 1311 1312 fLastIsochronousTransfer = data; 1313 UnlockIsochronous(); 1314 return B_OK; 1315 } 1316 1317 1318 status_t 1319 EHCI::CancelQueuedTransfers(Pipe *pipe, bool force) 1320 { 1321 if (pipe->Type() & USB_OBJECT_ISO_PIPE) 1322 return CancelQueuedIsochronousTransfers(pipe, force); 1323 1324 if (!Lock()) 1325 return B_ERROR; 1326 1327 struct transfer_entry { 1328 Transfer * transfer; 1329 transfer_entry * next; 1330 }; 1331 1332 transfer_entry *list = NULL; 1333 transfer_data *current = fFirstTransfer; 1334 while (current) { 1335 if (current->transfer && current->transfer->TransferPipe() == pipe) { 1336 // clear the active bit so the descriptors are canceled 1337 ehci_qtd *descriptor = current->queue_head->element_log; 1338 while (descriptor) { 1339 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE; 1340 descriptor = descriptor->next_log; 1341 } 1342 1343 if (!force) { 1344 // if the transfer is canceled by force, the one causing the 1345 // cancel is probably not the one who initiated the transfer 1346 // and the callback is likely not safe anymore 1347 transfer_entry *entry 1348 = (transfer_entry *)malloc(sizeof(transfer_entry)); 1349 if (entry != NULL) { 1350 entry->transfer = current->transfer; 1351 current->transfer = NULL; 1352 entry->next = list; 1353 list = entry; 1354 } 1355 } 1356 1357 current->canceled = true; 1358 } 1359 1360 current = current->link; 1361 } 1362 1363 Unlock(); 1364 1365 while (list != NULL) { 1366 transfer_entry *next = list->next; 1367 list->transfer->Finished(B_CANCELED, 0); 1368 delete list->transfer; 1369 free(list); 1370 list = next; 1371 } 1372 1373 // wait for any transfers that might have made it before canceling 1374 while (fProcessingPipe == pipe) 1375 snooze(1000); 1376 1377 // notify the finisher so it can clean up the canceled transfers 1378 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); 1379 return B_OK; 1380 } 1381 1382 1383 status_t 1384 EHCI::CancelQueuedIsochronousTransfers(Pipe *pipe, bool force) 1385 { 1386 isochronous_transfer_data *current = fFirstIsochronousTransfer; 1387 1388 while (current) { 1389 if (current->transfer->TransferPipe() == pipe) { 1390 // TODO implement 1391 1392 // TODO: Use the force paramater in order to avoid calling 1393 // invalid callbacks 1394 current->is_active = false; 1395 } 1396 1397 current = current->link; 1398 } 1399 1400 TRACE_ERROR("no isochronous transfer found!\n"); 1401 return B_ERROR; 1402 } 1403 1404 1405 status_t 1406 EHCI::CancelAllPendingTransfers() 1407 { 1408 if (!Lock()) 1409 return B_ERROR; 1410 1411 transfer_data *transfer = fFirstTransfer; 1412 while (transfer) { 1413 transfer->transfer->Finished(B_CANCELED, 0); 1414 delete transfer->transfer; 1415 1416 transfer_data *next = transfer->link; 1417 delete transfer; 1418 transfer = next; 1419 } 1420 1421 fFirstTransfer = NULL; 1422 fLastTransfer = NULL; 1423 Unlock(); 1424 return B_OK; 1425 } 1426 1427 1428 int32 1429 EHCI::FinishThread(void *data) 1430 { 1431 ((EHCI *)data)->FinishTransfers(); 1432 return B_OK; 1433 } 1434 1435 1436 void 1437 EHCI::FinishTransfers() 1438 { 1439 while (!fStopThreads) { 1440 if (acquire_sem(fFinishTransfersSem) < B_OK) 1441 continue; 1442 1443 // eat up sems that have been released by multiple interrupts 1444 int32 semCount = 0; 1445 get_sem_count(fFinishTransfersSem, &semCount); 1446 if (semCount > 0) 1447 acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); 1448 1449 if (!Lock()) 1450 continue; 1451 1452 TRACE("finishing transfers\n"); 1453 transfer_data *lastTransfer = NULL; 1454 transfer_data *transfer = fFirstTransfer; 1455 Unlock(); 1456 1457 while (transfer) { 1458 bool transferDone = false; 1459 ehci_qtd *descriptor = transfer->queue_head->element_log; 1460 status_t callbackStatus = B_OK; 1461 1462 while (descriptor) { 1463 uint32 status = descriptor->token; 1464 if (status & EHCI_QTD_STATUS_ACTIVE) { 1465 // still in progress 1466 TRACE("qtd (0x%08lx) still active\n", descriptor->this_phy); 1467 break; 1468 } 1469 1470 if (status & EHCI_QTD_STATUS_ERRMASK) { 1471 // a transfer error occured 1472 TRACE_ERROR("qtd (0x%08lx) error: 0x%08lx\n", descriptor->this_phy, status); 1473 1474 uint8 errorCount = status >> EHCI_QTD_ERRCOUNT_SHIFT; 1475 errorCount &= EHCI_QTD_ERRCOUNT_MASK; 1476 if (errorCount == 0) { 1477 // the error counter counted down to zero, report why 1478 int32 reasons = 0; 1479 if (status & EHCI_QTD_STATUS_BUFFER) { 1480 callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN; 1481 reasons++; 1482 } 1483 if (status & EHCI_QTD_STATUS_TERROR) { 1484 callbackStatus = B_DEV_CRC_ERROR; 1485 reasons++; 1486 } 1487 1488 if (reasons > 1) 1489 callbackStatus = B_DEV_MULTIPLE_ERRORS; 1490 } else if (status & EHCI_QTD_STATUS_BABBLE) { 1491 // there is a babble condition 1492 callbackStatus = transfer->incoming ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN; 1493 } else { 1494 // if the error counter didn't count down to zero 1495 // and there was no babble, then this halt was caused 1496 // by a stall handshake 1497 callbackStatus = B_DEV_STALLED; 1498 } 1499 1500 transferDone = true; 1501 break; 1502 } 1503 1504 if (descriptor->next_phy & EHCI_ITEM_TERMINATE) { 1505 // we arrived at the last (stray) descriptor, we're done 1506 TRACE("qtd (0x%08lx) done\n", descriptor->this_phy); 1507 callbackStatus = B_OK; 1508 transferDone = true; 1509 break; 1510 } 1511 1512 descriptor = descriptor->next_log; 1513 } 1514 1515 if (!transferDone) { 1516 lastTransfer = transfer; 1517 transfer = transfer->link; 1518 continue; 1519 } 1520 1521 // remove the transfer from the list first so we are sure 1522 // it doesn't get canceled while we still process it 1523 transfer_data *next = transfer->link; 1524 if (Lock()) { 1525 if (lastTransfer) 1526 lastTransfer->link = transfer->link; 1527 1528 if (transfer == fFirstTransfer) 1529 fFirstTransfer = transfer->link; 1530 if (transfer == fLastTransfer) 1531 fLastTransfer = lastTransfer; 1532 1533 // store the currently processing pipe here so we can wait 1534 // in cancel if we are processing something on the target pipe 1535 if (!transfer->canceled) 1536 fProcessingPipe = transfer->transfer->TransferPipe(); 1537 1538 transfer->link = NULL; 1539 Unlock(); 1540 } 1541 1542 // if canceled the callback has already been called 1543 if (!transfer->canceled) { 1544 size_t actualLength = 0; 1545 1546 if (callbackStatus == B_OK) { 1547 bool nextDataToggle = false; 1548 if (transfer->data_descriptor && transfer->incoming) { 1549 // data to read out 1550 iovec *vector = transfer->transfer->Vector(); 1551 size_t vectorCount = transfer->transfer->VectorCount(); 1552 transfer->transfer->PrepareKernelAccess(); 1553 actualLength = ReadDescriptorChain( 1554 transfer->data_descriptor, 1555 vector, vectorCount, 1556 &nextDataToggle); 1557 } else if (transfer->data_descriptor) { 1558 // calculate transfered length 1559 actualLength = ReadActualLength( 1560 transfer->data_descriptor, &nextDataToggle); 1561 } 1562 1563 transfer->transfer->TransferPipe()->SetDataToggle(nextDataToggle); 1564 1565 if (transfer->transfer->IsFragmented()) { 1566 // this transfer may still have data left 1567 transfer->transfer->AdvanceByFragment(actualLength); 1568 if (transfer->transfer->VectorLength() > 0) { 1569 FreeDescriptorChain(transfer->data_descriptor); 1570 transfer->transfer->PrepareKernelAccess(); 1571 status_t result = FillQueueWithData( 1572 transfer->transfer, 1573 transfer->queue_head, 1574 &transfer->data_descriptor, NULL); 1575 1576 if (result == B_OK && Lock()) { 1577 // reappend the transfer 1578 if (fLastTransfer) 1579 fLastTransfer->link = transfer; 1580 if (!fFirstTransfer) 1581 fFirstTransfer = transfer; 1582 1583 fLastTransfer = transfer; 1584 Unlock(); 1585 1586 transfer = next; 1587 continue; 1588 } 1589 } 1590 1591 // the transfer is done, but we already set the 1592 // actualLength with AdvanceByFragment() 1593 actualLength = 0; 1594 } 1595 } 1596 1597 transfer->transfer->Finished(callbackStatus, actualLength); 1598 fProcessingPipe = NULL; 1599 } 1600 1601 // unlink hardware queue and delete the transfer 1602 UnlinkQueueHead(transfer->queue_head, &fFreeListHead); 1603 delete transfer->transfer; 1604 delete transfer; 1605 transfer = next; 1606 release_sem(fCleanupSem); 1607 } 1608 } 1609 } 1610 1611 1612 int32 1613 EHCI::CleanupThread(void *data) 1614 { 1615 ((EHCI *)data)->Cleanup(); 1616 return B_OK; 1617 } 1618 1619 1620 void 1621 EHCI::Cleanup() 1622 { 1623 ehci_qh *lastFreeListHead = NULL; 1624 1625 while (!fStopThreads) { 1626 if (acquire_sem(fCleanupSem) < B_OK) 1627 continue; 1628 1629 ehci_qh *freeListHead = fFreeListHead; 1630 if (freeListHead == lastFreeListHead) 1631 continue; 1632 1633 // set the doorbell and wait for the host controller to notify us 1634 WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD); 1635 if (acquire_sem(fAsyncAdvanceSem) < B_OK) 1636 continue; 1637 1638 ehci_qh *current = freeListHead; 1639 while (current != lastFreeListHead) { 1640 ehci_qh *next = current->next_log; 1641 FreeQueueHead(current); 1642 current = next; 1643 } 1644 1645 lastFreeListHead = freeListHead; 1646 } 1647 } 1648 1649 1650 int32 1651 EHCI::FinishIsochronousThread(void *data) 1652 { 1653 ((EHCI *)data)->FinishIsochronousTransfers(); 1654 return B_OK; 1655 } 1656 1657 1658 void 1659 EHCI::FinishIsochronousTransfers() 1660 { 1661 /* This thread stays one position behind the controller and processes every 1662 * isochronous descriptor. Once it finds the last isochronous descriptor 1663 * of a transfer, it processes the entire transfer. 1664 */ 1665 while (!fStopThreads) { 1666 // Go to sleep if there are not isochronous transfer to process 1667 if (acquire_sem(fFinishIsochronousTransfersSem) < B_OK) 1668 return; 1669 1670 bool transferDone = false; 1671 1672 uint32 frame = (ReadOpReg(EHCI_FRINDEX) / 8 ) 1673 & (EHCI_FRAMELIST_ENTRIES_COUNT - 1); 1674 uint32 currentFrame = (frame + EHCI_VFRAMELIST_ENTRIES_COUNT - 5) 1675 & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1); 1676 uint32 loop = 0; 1677 1678 // Process the frame list until one transfer is processed 1679 while (!transferDone && loop++ < EHCI_VFRAMELIST_ENTRIES_COUNT) { 1680 // wait 1ms in order to be sure to be one position behind 1681 // the controller 1682 while (currentFrame == (((ReadOpReg(EHCI_FRINDEX) / 8) 1683 & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1)))) { 1684 snooze(1000); 1685 } 1686 1687 ehci_itd *itd = fItdEntries[currentFrame]; 1688 1689 TRACE("FinishIsochronousTransfers itd %p phy 0x%lx prev (%p/0x%lx)" 1690 " at frame %ld\n", itd, itd->this_phy, itd->prev, 1691 itd->prev != NULL ? itd->prev->this_phy : 0, currentFrame); 1692 1693 // Process the frame till it has isochronous descriptors in it. 1694 while (!(itd->next_phy & EHCI_ITEM_TERMINATE) && itd->prev != NULL) { 1695 TRACE("FinishIsochronousTransfers checking itd %p last_token" 1696 " %ld\n", itd, itd->last_token); 1697 TRACE("FinishIsochronousTransfers tokens 0x%lx 0x%lx 0x%lx " 1698 "0x%lx 0x%lx 0x%lx 0x%lx 0x%lx\n", 1699 itd->token[0], itd->token[1], itd->token[2], itd->token[3], 1700 itd->token[4], itd->token[5], itd->token[6], itd->token[7]); 1701 if (((itd->token[itd->last_token] >> EHCI_ITD_STATUS_SHIFT) 1702 & EHCI_ITD_STATUS_ACTIVE) == EHCI_ITD_STATUS_ACTIVE) { 1703 TRACE("FinishIsochronousTransfers unprocessed active itd\n"); 1704 } 1705 UnlinkITDescriptors(itd, &fItdEntries[currentFrame]); 1706 1707 // Process the transfer if we found the last descriptor 1708 isochronous_transfer_data *transfer 1709 = FindIsochronousTransfer(itd); 1710 // Process the descriptors only if it is still active and 1711 // belongs to an inbound transfer. If the transfer is not 1712 // active, it means the request has been removed, so simply 1713 // remove the descriptors. 1714 if (transfer && transfer->is_active) { 1715 TRACE("FinishIsochronousTransfers active transfer\n"); 1716 size_t actualLength = 0; 1717 if (((itd->buffer_phy[1] >> EHCI_ITD_DIR_SHIFT) & 1) != 0) { 1718 transfer->transfer->PrepareKernelAccess(); 1719 actualLength = ReadIsochronousDescriptorChain(transfer); 1720 } 1721 1722 // Remove the transfer 1723 if (LockIsochronous()) { 1724 if (transfer == fFirstIsochronousTransfer) { 1725 fFirstIsochronousTransfer = transfer->link; 1726 if (transfer == fLastIsochronousTransfer) 1727 fLastIsochronousTransfer = NULL; 1728 } else { 1729 isochronous_transfer_data *temp 1730 = fFirstIsochronousTransfer; 1731 while (temp != NULL && transfer != temp->link) 1732 temp = temp->link; 1733 1734 if (transfer == fLastIsochronousTransfer) 1735 fLastIsochronousTransfer = temp; 1736 if (temp != NULL && temp->link != NULL) 1737 temp->link = temp->link->link; 1738 } 1739 transfer->link = NULL; 1740 UnlockIsochronous(); 1741 } 1742 1743 transfer->transfer->Finished(B_OK, actualLength); 1744 1745 for (uint32 i = 0; i <= transfer->last_to_process; i++) 1746 FreeDescriptor(transfer->descriptors[i]); 1747 1748 TRACE("FinishIsochronousTransfers descriptors freed\n"); 1749 1750 delete [] transfer->descriptors; 1751 delete transfer->transfer; 1752 fStack->FreeChunk(transfer->buffer_log, 1753 (void *)transfer->buffer_phy, transfer->buffer_size); 1754 delete transfer; 1755 transferDone = true; 1756 } else { 1757 TRACE("FinishIsochronousTransfers not end of transfer\n"); 1758 } 1759 itd = itd->prev; 1760 } 1761 1762 TRACE("FinishIsochronousTransfers next frame\n"); 1763 1764 // Make sure to reset the frame bandwidth 1765 fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH; 1766 currentFrame = (currentFrame + 1) % EHCI_VFRAMELIST_ENTRIES_COUNT; 1767 } 1768 } 1769 } 1770 1771 1772 ehci_qh * 1773 EHCI::CreateQueueHead() 1774 { 1775 ehci_qh *result; 1776 void *physicalAddress; 1777 if (fStack->AllocateChunk((void **)&result, &physicalAddress, 1778 sizeof(ehci_qh)) < B_OK) { 1779 TRACE_ERROR("failed to allocate queue head\n"); 1780 return NULL; 1781 } 1782 1783 result->this_phy = (addr_t)physicalAddress | EHCI_ITEM_TYPE_QH; 1784 result->next_phy = EHCI_ITEM_TERMINATE; 1785 result->next_log = NULL; 1786 result->prev_log = NULL; 1787 1788 ehci_qtd *descriptor = CreateDescriptor(0, 0); 1789 if (!descriptor) { 1790 TRACE_ERROR("failed to allocate initial qtd for queue head\n"); 1791 fStack->FreeChunk(result, physicalAddress, sizeof(ehci_qh)); 1792 return NULL; 1793 } 1794 1795 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE; 1796 result->stray_log = descriptor; 1797 result->element_log = descriptor; 1798 result->current_qtd_phy = EHCI_ITEM_TERMINATE; 1799 result->overlay.next_phy = descriptor->this_phy; 1800 result->overlay.alt_next_phy = EHCI_ITEM_TERMINATE; 1801 result->overlay.token = 0; 1802 for (int32 i = 0; i < 5; i++) { 1803 result->overlay.buffer_phy[i] = 0; 1804 result->overlay.ext_buffer_phy[i] = 0; 1805 } 1806 1807 return result; 1808 } 1809 1810 1811 status_t 1812 EHCI::InitQueueHead(ehci_qh *queueHead, Pipe *pipe) 1813 { 1814 switch (pipe->Speed()) { 1815 case USB_SPEED_LOWSPEED: 1816 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_LOW; 1817 break; 1818 case USB_SPEED_FULLSPEED: 1819 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_FULL; 1820 break; 1821 case USB_SPEED_HIGHSPEED: 1822 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH; 1823 break; 1824 default: 1825 TRACE_ERROR("unknown pipe speed\n"); 1826 return B_ERROR; 1827 } 1828 1829 queueHead->endpoint_chars |= (3 << EHCI_QH_CHARS_RL_SHIFT) 1830 | (pipe->MaxPacketSize() << EHCI_QH_CHARS_MPL_SHIFT) 1831 | (pipe->EndpointAddress() << EHCI_QH_CHARS_EPT_SHIFT) 1832 | (pipe->DeviceAddress() << EHCI_QH_CHARS_DEV_SHIFT) 1833 | EHCI_QH_CHARS_TOGGLE; 1834 1835 queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT); 1836 if (pipe->Speed() != USB_SPEED_HIGHSPEED) { 1837 if (pipe->Type() & USB_OBJECT_CONTROL_PIPE) 1838 queueHead->endpoint_chars |= EHCI_QH_CHARS_CONTROL; 1839 1840 queueHead->endpoint_caps |= (pipe->HubPort() << EHCI_QH_CAPS_PORT_SHIFT) 1841 | (pipe->HubAddress() << EHCI_QH_CAPS_HUB_SHIFT); 1842 } 1843 1844 return B_OK; 1845 } 1846 1847 1848 void 1849 EHCI::FreeQueueHead(ehci_qh *queueHead) 1850 { 1851 if (!queueHead) 1852 return; 1853 1854 FreeDescriptorChain(queueHead->element_log); 1855 FreeDescriptor(queueHead->stray_log); 1856 fStack->FreeChunk(queueHead, (void *)queueHead->this_phy, sizeof(ehci_qh)); 1857 } 1858 1859 1860 status_t 1861 EHCI::LinkQueueHead(ehci_qh *queueHead) 1862 { 1863 if (!Lock()) 1864 return B_ERROR; 1865 1866 ehci_qh *prevHead = fAsyncQueueHead->prev_log; 1867 queueHead->next_phy = fAsyncQueueHead->this_phy; 1868 queueHead->next_log = fAsyncQueueHead; 1869 queueHead->prev_log = prevHead; 1870 fAsyncQueueHead->prev_log = queueHead; 1871 prevHead->next_log = queueHead; 1872 prevHead->next_phy = queueHead->this_phy; 1873 1874 Unlock(); 1875 return B_OK; 1876 } 1877 1878 1879 status_t 1880 EHCI::LinkInterruptQueueHead(ehci_qh *queueHead, Pipe *pipe) 1881 { 1882 if (!Lock()) 1883 return B_ERROR; 1884 1885 uint8 interval = pipe->Interval(); 1886 if (pipe->Speed() == USB_SPEED_HIGHSPEED) { 1887 // Allow interrupts to be scheduled on each possible micro frame. 1888 queueHead->endpoint_caps |= (0xff << EHCI_QH_CAPS_ISM_SHIFT); 1889 } else { 1890 // As we do not yet support FSTNs to correctly reference low/full 1891 // speed interrupt transfers, we simply put them into the 1 interval 1892 // queue. This way we ensure that we reach them on every micro frame 1893 // and can do the corresponding start/complete split transactions. 1894 // ToDo: use FSTNs to correctly link non high speed interrupt transfers 1895 interval = 1; 1896 1897 // For now we also force start splits to be in micro frame 0 and 1898 // complete splits to be in micro frame 2, 3 and 4. 1899 queueHead->endpoint_caps |= (0x01 << EHCI_QH_CAPS_ISM_SHIFT); 1900 queueHead->endpoint_caps |= (0x1c << EHCI_QH_CAPS_SCM_SHIFT); 1901 } 1902 1903 // this should not happen 1904 if (interval < 1) 1905 interval = 1; 1906 1907 // this may happen as intervals can go up to 16; we limit the value to 1908 // EHCI_INTERRUPT_ENTRIES_COUNT as you cannot support intervals above 1909 // that with a frame list of just EHCI_VFRAMELIST_ENTRIES_COUNT entries... 1910 if (interval > EHCI_INTERRUPT_ENTRIES_COUNT) 1911 interval = EHCI_INTERRUPT_ENTRIES_COUNT; 1912 1913 ehci_qh *interruptQueue = &fInterruptEntries[interval - 1].queue_head; 1914 queueHead->next_phy = interruptQueue->next_phy; 1915 queueHead->next_log = interruptQueue->next_log; 1916 queueHead->prev_log = interruptQueue; 1917 if (interruptQueue->next_log) 1918 interruptQueue->next_log->prev_log = queueHead; 1919 interruptQueue->next_log = queueHead; 1920 interruptQueue->next_phy = queueHead->this_phy; 1921 1922 Unlock(); 1923 return B_OK; 1924 } 1925 1926 1927 status_t 1928 EHCI::UnlinkQueueHead(ehci_qh *queueHead, ehci_qh **freeListHead) 1929 { 1930 if (!Lock()) 1931 return B_ERROR; 1932 1933 ehci_qh *prevHead = queueHead->prev_log; 1934 ehci_qh *nextHead = queueHead->next_log; 1935 if (prevHead) { 1936 prevHead->next_phy = queueHead->next_phy; 1937 prevHead->next_log = queueHead->next_log; 1938 } 1939 1940 if (nextHead) 1941 nextHead->prev_log = queueHead->prev_log; 1942 1943 queueHead->next_phy = fAsyncQueueHead->this_phy; 1944 queueHead->prev_log = NULL; 1945 1946 queueHead->next_log = *freeListHead; 1947 *freeListHead = queueHead; 1948 1949 Unlock(); 1950 return B_OK; 1951 } 1952 1953 1954 status_t 1955 EHCI::FillQueueWithRequest(Transfer *transfer, ehci_qh *queueHead, 1956 ehci_qtd **_dataDescriptor, bool *_directionIn) 1957 { 1958 Pipe *pipe = transfer->TransferPipe(); 1959 usb_request_data *requestData = transfer->RequestData(); 1960 bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0; 1961 1962 ehci_qtd *setupDescriptor = CreateDescriptor(sizeof(usb_request_data), 1963 EHCI_QTD_PID_SETUP); 1964 ehci_qtd *statusDescriptor = CreateDescriptor(0, 1965 directionIn ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN); 1966 1967 if (!setupDescriptor || !statusDescriptor) { 1968 TRACE_ERROR("failed to allocate descriptors\n"); 1969 FreeDescriptor(setupDescriptor); 1970 FreeDescriptor(statusDescriptor); 1971 return B_NO_MEMORY; 1972 } 1973 1974 iovec vector; 1975 vector.iov_base = requestData; 1976 vector.iov_len = sizeof(usb_request_data); 1977 WriteDescriptorChain(setupDescriptor, &vector, 1); 1978 1979 ehci_qtd *strayDescriptor = queueHead->stray_log; 1980 statusDescriptor->token |= EHCI_QTD_IOC | EHCI_QTD_DATA_TOGGLE; 1981 1982 ehci_qtd *dataDescriptor = NULL; 1983 if (transfer->VectorCount() > 0) { 1984 ehci_qtd *lastDescriptor = NULL; 1985 status_t result = CreateDescriptorChain(pipe, &dataDescriptor, 1986 &lastDescriptor, strayDescriptor, transfer->VectorLength(), 1987 directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT); 1988 1989 if (result < B_OK) { 1990 FreeDescriptor(setupDescriptor); 1991 FreeDescriptor(statusDescriptor); 1992 return result; 1993 } 1994 1995 if (!directionIn) { 1996 WriteDescriptorChain(dataDescriptor, transfer->Vector(), 1997 transfer->VectorCount()); 1998 } 1999 2000 LinkDescriptors(setupDescriptor, dataDescriptor, strayDescriptor); 2001 LinkDescriptors(lastDescriptor, statusDescriptor, strayDescriptor); 2002 } else { 2003 // no data: link setup and status descriptors directly 2004 LinkDescriptors(setupDescriptor, statusDescriptor, strayDescriptor); 2005 } 2006 2007 queueHead->element_log = setupDescriptor; 2008 queueHead->overlay.next_phy = setupDescriptor->this_phy; 2009 queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE; 2010 2011 *_dataDescriptor = dataDescriptor; 2012 *_directionIn = directionIn; 2013 return B_OK; 2014 } 2015 2016 2017 status_t 2018 EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead, 2019 ehci_qtd **_dataDescriptor, bool *_directionIn) 2020 { 2021 Pipe *pipe = transfer->TransferPipe(); 2022 bool directionIn = (pipe->Direction() == Pipe::In); 2023 2024 ehci_qtd *firstDescriptor = NULL; 2025 ehci_qtd *lastDescriptor = NULL; 2026 ehci_qtd *strayDescriptor = queueHead->stray_log; 2027 status_t result = CreateDescriptorChain(pipe, &firstDescriptor, 2028 &lastDescriptor, strayDescriptor, transfer->VectorLength(), 2029 directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT); 2030 2031 if (result < B_OK) 2032 return result; 2033 2034 lastDescriptor->token |= EHCI_QTD_IOC; 2035 if (!directionIn) { 2036 WriteDescriptorChain(firstDescriptor, transfer->Vector(), 2037 transfer->VectorCount()); 2038 } 2039 2040 queueHead->element_log = firstDescriptor; 2041 queueHead->overlay.next_phy = firstDescriptor->this_phy; 2042 queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE; 2043 2044 *_dataDescriptor = firstDescriptor; 2045 if (_directionIn) 2046 *_directionIn = directionIn; 2047 return B_OK; 2048 } 2049 2050 2051 ehci_qtd * 2052 EHCI::CreateDescriptor(size_t bufferSize, uint8 pid) 2053 { 2054 ehci_qtd *result; 2055 void *physicalAddress; 2056 if (fStack->AllocateChunk((void **)&result, &physicalAddress, 2057 sizeof(ehci_qtd)) < B_OK) { 2058 TRACE_ERROR("failed to allocate a qtd\n"); 2059 return NULL; 2060 } 2061 2062 result->this_phy = (addr_t)physicalAddress; 2063 result->next_phy = EHCI_ITEM_TERMINATE; 2064 result->next_log = NULL; 2065 result->alt_next_phy = EHCI_ITEM_TERMINATE; 2066 result->alt_next_log = NULL; 2067 result->buffer_size = bufferSize; 2068 result->token = bufferSize << EHCI_QTD_BYTES_SHIFT; 2069 result->token |= 3 << EHCI_QTD_ERRCOUNT_SHIFT; 2070 result->token |= pid << EHCI_QTD_PID_SHIFT; 2071 result->token |= EHCI_QTD_STATUS_ACTIVE; 2072 if (bufferSize == 0) { 2073 result->buffer_log = NULL; 2074 for (int32 i = 0; i < 5; i++) { 2075 result->buffer_phy[i] = 0; 2076 result->ext_buffer_phy[i] = 0; 2077 } 2078 2079 return result; 2080 } 2081 2082 if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress, 2083 bufferSize) < B_OK) { 2084 TRACE_ERROR("unable to allocate qtd buffer\n"); 2085 fStack->FreeChunk(result, (void *)result->this_phy, sizeof(ehci_qtd)); 2086 return NULL; 2087 } 2088 2089 addr_t physicalBase = (addr_t)physicalAddress; 2090 result->buffer_phy[0] = physicalBase; 2091 result->ext_buffer_phy[0] = 0; 2092 for (int32 i = 1; i < 5; i++) { 2093 physicalBase += B_PAGE_SIZE; 2094 result->buffer_phy[i] = physicalBase & EHCI_QTD_PAGE_MASK; 2095 result->ext_buffer_phy[i] = 0; 2096 } 2097 2098 return result; 2099 } 2100 2101 2102 status_t 2103 EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor, 2104 ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize, 2105 uint8 pid) 2106 { 2107 size_t packetSize = B_PAGE_SIZE * 4; 2108 int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize; 2109 2110 bool dataToggle = pipe->DataToggle(); 2111 ehci_qtd *firstDescriptor = NULL; 2112 ehci_qtd *lastDescriptor = *_firstDescriptor; 2113 for (int32 i = 0; i < descriptorCount; i++) { 2114 ehci_qtd *descriptor = CreateDescriptor(min_c(packetSize, bufferSize), 2115 pid); 2116 2117 if (!descriptor) { 2118 FreeDescriptorChain(firstDescriptor); 2119 return B_NO_MEMORY; 2120 } 2121 2122 if (dataToggle) 2123 descriptor->token |= EHCI_QTD_DATA_TOGGLE; 2124 2125 if (lastDescriptor) 2126 LinkDescriptors(lastDescriptor, descriptor, strayDescriptor); 2127 2128 bufferSize -= packetSize; 2129 lastDescriptor = descriptor; 2130 if (!firstDescriptor) 2131 firstDescriptor = descriptor; 2132 } 2133 2134 *_firstDescriptor = firstDescriptor; 2135 *_lastDescriptor = lastDescriptor; 2136 return B_OK; 2137 } 2138 2139 2140 void 2141 EHCI::FreeDescriptor(ehci_qtd *descriptor) 2142 { 2143 if (!descriptor) 2144 return; 2145 2146 if (descriptor->buffer_log) { 2147 fStack->FreeChunk(descriptor->buffer_log, 2148 (void *)descriptor->buffer_phy[0], descriptor->buffer_size); 2149 } 2150 2151 fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(ehci_qtd)); 2152 } 2153 2154 2155 void 2156 EHCI::FreeDescriptorChain(ehci_qtd *topDescriptor) 2157 { 2158 ehci_qtd *current = topDescriptor; 2159 ehci_qtd *next = NULL; 2160 2161 while (current) { 2162 next = current->next_log; 2163 FreeDescriptor(current); 2164 current = next; 2165 } 2166 } 2167 2168 2169 ehci_itd * 2170 EHCI::CreateItdDescriptor() 2171 { 2172 ehci_itd *result; 2173 void *physicalAddress; 2174 if (fStack->AllocateChunk((void **)&result, &physicalAddress, 2175 sizeof(ehci_itd)) < B_OK) { 2176 TRACE_ERROR("failed to allocate a itd\n"); 2177 return NULL; 2178 } 2179 2180 memset(result, 0, sizeof(ehci_itd)); 2181 result->this_phy = (addr_t)physicalAddress; 2182 result->next_phy = EHCI_ITEM_TERMINATE; 2183 2184 return result; 2185 } 2186 2187 2188 ehci_sitd * 2189 EHCI::CreateSitdDescriptor() 2190 { 2191 ehci_sitd *result; 2192 void *physicalAddress; 2193 if (fStack->AllocateChunk((void **)&result, &physicalAddress, 2194 sizeof(ehci_sitd)) < B_OK) { 2195 TRACE_ERROR("failed to allocate a sitd\n"); 2196 return NULL; 2197 } 2198 2199 memset(result, 0, sizeof(ehci_sitd)); 2200 result->this_phy = (addr_t)physicalAddress | EHCI_ITEM_TYPE_SITD; 2201 result->next_phy = EHCI_ITEM_TERMINATE; 2202 2203 return result; 2204 } 2205 2206 2207 void 2208 EHCI::FreeDescriptor(ehci_itd *descriptor) 2209 { 2210 if (!descriptor) 2211 return; 2212 2213 fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(ehci_itd)); 2214 } 2215 2216 2217 void 2218 EHCI::FreeDescriptor(ehci_sitd *descriptor) 2219 { 2220 if (!descriptor) 2221 return; 2222 2223 fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(ehci_sitd)); 2224 } 2225 2226 2227 void 2228 EHCI::LinkDescriptors(ehci_qtd *first, ehci_qtd *last, ehci_qtd *alt) 2229 { 2230 first->next_phy = last->this_phy; 2231 first->next_log = last; 2232 2233 if (alt) { 2234 first->alt_next_phy = alt->this_phy; 2235 first->alt_next_log = alt; 2236 } else { 2237 first->alt_next_phy = EHCI_ITEM_TERMINATE; 2238 first->alt_next_log = NULL; 2239 } 2240 } 2241 2242 2243 void 2244 EHCI::LinkITDescriptors(ehci_itd *itd, ehci_itd **_last) 2245 { 2246 ehci_itd *last = *_last; 2247 itd->next_phy = last->next_phy; 2248 itd->next = NULL; 2249 itd->prev = last; 2250 last->next = itd; 2251 last->next_phy = itd->this_phy; 2252 *_last = itd; 2253 } 2254 2255 2256 void 2257 EHCI::LinkSITDescriptors(ehci_sitd *sitd, ehci_sitd **_last) 2258 { 2259 ehci_sitd *last = *_last; 2260 sitd->next_phy = last->next_phy; 2261 sitd->next = NULL; 2262 sitd->prev = last; 2263 last->next = sitd; 2264 last->next_phy = sitd->this_phy; 2265 *_last = sitd; 2266 } 2267 2268 void 2269 EHCI::UnlinkITDescriptors(ehci_itd *itd, ehci_itd **last) 2270 { 2271 itd->prev->next_phy = itd->next_phy; 2272 itd->prev->next = itd->next; 2273 if (itd->next != NULL) 2274 itd->next->prev = itd->prev; 2275 if (itd == *last) 2276 *last = itd->prev; 2277 } 2278 2279 2280 void 2281 EHCI::UnlinkSITDescriptors(ehci_sitd *sitd, ehci_sitd **last) 2282 { 2283 sitd->prev->next_phy = sitd->next_phy; 2284 sitd->prev->next = sitd->next; 2285 if (sitd->next != NULL) 2286 sitd->next->prev = sitd->prev; 2287 if (sitd == *last) 2288 *last = sitd->prev; 2289 } 2290 2291 2292 size_t 2293 EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, 2294 size_t vectorCount) 2295 { 2296 ehci_qtd *current = topDescriptor; 2297 size_t actualLength = 0; 2298 size_t vectorIndex = 0; 2299 size_t vectorOffset = 0; 2300 size_t bufferOffset = 0; 2301 2302 while (current) { 2303 if (!current->buffer_log) 2304 break; 2305 2306 while (true) { 2307 size_t length = min_c(current->buffer_size - bufferOffset, 2308 vector[vectorIndex].iov_len - vectorOffset); 2309 2310 memcpy((uint8 *)current->buffer_log + bufferOffset, 2311 (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length); 2312 2313 actualLength += length; 2314 vectorOffset += length; 2315 bufferOffset += length; 2316 2317 if (vectorOffset >= vector[vectorIndex].iov_len) { 2318 if (++vectorIndex >= vectorCount) { 2319 TRACE("wrote descriptor chain (%ld bytes, no more vectors)" 2320 "\n", actualLength); 2321 return actualLength; 2322 } 2323 2324 vectorOffset = 0; 2325 } 2326 2327 if (bufferOffset >= current->buffer_size) { 2328 bufferOffset = 0; 2329 break; 2330 } 2331 } 2332 2333 if (current->next_phy & EHCI_ITEM_TERMINATE) 2334 break; 2335 2336 current = current->next_log; 2337 } 2338 2339 TRACE("wrote descriptor chain (%ld bytes)\n", actualLength); 2340 return actualLength; 2341 } 2342 2343 2344 size_t 2345 EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, 2346 size_t vectorCount, bool *nextDataToggle) 2347 { 2348 uint32 dataToggle = 0; 2349 ehci_qtd *current = topDescriptor; 2350 size_t actualLength = 0; 2351 size_t vectorIndex = 0; 2352 size_t vectorOffset = 0; 2353 size_t bufferOffset = 0; 2354 2355 while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) { 2356 if (!current->buffer_log) 2357 break; 2358 2359 dataToggle = current->token & EHCI_QTD_DATA_TOGGLE; 2360 size_t bufferSize = current->buffer_size; 2361 bufferSize -= (current->token >> EHCI_QTD_BYTES_SHIFT) 2362 & EHCI_QTD_BYTES_MASK; 2363 2364 while (true) { 2365 size_t length = min_c(bufferSize - bufferOffset, 2366 vector[vectorIndex].iov_len - vectorOffset); 2367 2368 memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset, 2369 (uint8 *)current->buffer_log + bufferOffset, length); 2370 2371 actualLength += length; 2372 vectorOffset += length; 2373 bufferOffset += length; 2374 2375 if (vectorOffset >= vector[vectorIndex].iov_len) { 2376 if (++vectorIndex >= vectorCount) { 2377 TRACE("read descriptor chain (%ld bytes, no more vectors)\n", actualLength); 2378 *nextDataToggle = dataToggle > 0 ? true : false; 2379 return actualLength; 2380 } 2381 2382 vectorOffset = 0; 2383 } 2384 2385 if (bufferOffset >= bufferSize) { 2386 bufferOffset = 0; 2387 break; 2388 } 2389 } 2390 2391 if (current->next_phy & EHCI_ITEM_TERMINATE) 2392 break; 2393 2394 current = current->next_log; 2395 } 2396 2397 TRACE("read descriptor chain (%ld bytes)\n", actualLength); 2398 *nextDataToggle = dataToggle > 0 ? true : false; 2399 return actualLength; 2400 } 2401 2402 2403 size_t 2404 EHCI::ReadActualLength(ehci_qtd *topDescriptor, bool *nextDataToggle) 2405 { 2406 size_t actualLength = 0; 2407 ehci_qtd *current = topDescriptor; 2408 uint32 dataToggle = 0; 2409 2410 while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) { 2411 dataToggle = current->token & EHCI_QTD_DATA_TOGGLE; 2412 size_t length = current->buffer_size; 2413 length -= (current->token >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK; 2414 actualLength += length; 2415 2416 if (current->next_phy & EHCI_ITEM_TERMINATE) 2417 break; 2418 2419 current = current->next_log; 2420 } 2421 2422 TRACE("read actual length (%ld bytes)\n", actualLength); 2423 *nextDataToggle = dataToggle > 0 ? true : false; 2424 return actualLength; 2425 } 2426 2427 2428 size_t 2429 EHCI::WriteIsochronousDescriptorChain(isochronous_transfer_data *transfer, 2430 uint32 packetCount, iovec *vector) 2431 { 2432 // TODO implement 2433 return 0; 2434 } 2435 2436 2437 size_t 2438 EHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer) 2439 { 2440 iovec *vector = transfer->transfer->Vector(); 2441 size_t vectorCount = transfer->transfer->VectorCount(); 2442 2443 size_t vectorOffset = 0; 2444 size_t vectorIndex = 0; 2445 usb_isochronous_data *isochronousData 2446 = transfer->transfer->IsochronousData(); 2447 uint32 packet = 0; 2448 size_t totalLength = 0; 2449 size_t bufferOffset = 0; 2450 2451 size_t packetSize = transfer->transfer->DataLength(); 2452 packetSize /= isochronousData->packet_count; 2453 2454 for (uint32 i = 0; i <= transfer->last_to_process; i++) { 2455 ehci_itd *itd = transfer->descriptors[i]; 2456 for (uint32 j = 0; j <= itd->last_token 2457 && packet < isochronousData->packet_count; j++) { 2458 2459 size_t bufferSize = (itd->token[j] >> EHCI_ITD_TLENGTH_SHIFT) 2460 & EHCI_ITD_TLENGTH_MASK; 2461 isochronousData->packet_descriptors[packet].actual_length = 2462 bufferSize; 2463 2464 if (bufferSize > 0) 2465 isochronousData->packet_descriptors[packet].status = B_OK; 2466 else 2467 isochronousData->packet_descriptors[packet].status = B_ERROR; 2468 2469 totalLength += bufferSize; 2470 2471 size_t offset = bufferOffset; 2472 while (bufferSize > 0) { 2473 size_t length = min_c(bufferSize, 2474 vector[vectorIndex].iov_len - vectorOffset); 2475 memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset, 2476 (uint8 *)transfer->buffer_log + bufferOffset, length); 2477 offset += length; 2478 vectorOffset += length; 2479 bufferSize -= length; 2480 2481 if (vectorOffset >= vector[vectorIndex].iov_len) { 2482 if (++vectorIndex >= vectorCount) { 2483 TRACE("read isodescriptor chain (%ld bytes, no more " 2484 "vectors)\n", totalLength); 2485 return totalLength; 2486 } 2487 2488 vectorOffset = 0; 2489 } 2490 } 2491 2492 bufferOffset += packetSize; 2493 if (bufferOffset >= transfer->buffer_size) 2494 return totalLength; 2495 2496 packet++; 2497 } 2498 } 2499 2500 TRACE("ReadIsochronousDescriptorChain packet count %ld\n", packet); 2501 2502 return totalLength; 2503 } 2504 2505 2506 bool 2507 EHCI::LockIsochronous() 2508 { 2509 return (mutex_lock(&fIsochronousLock) == B_OK); 2510 } 2511 2512 2513 void 2514 EHCI::UnlockIsochronous() 2515 { 2516 mutex_unlock(&fIsochronousLock); 2517 } 2518 2519 2520 inline void 2521 EHCI::WriteOpReg(uint32 reg, uint32 value) 2522 { 2523 *(volatile uint32 *)(fOperationalRegisters + reg) = value; 2524 } 2525 2526 2527 inline uint32 2528 EHCI::ReadOpReg(uint32 reg) 2529 { 2530 return *(volatile uint32 *)(fOperationalRegisters + reg); 2531 } 2532 2533 2534 inline uint8 2535 EHCI::ReadCapReg8(uint32 reg) 2536 { 2537 return *(volatile uint8 *)(fCapabilityRegisters + reg); 2538 } 2539 2540 2541 inline uint16 2542 EHCI::ReadCapReg16(uint32 reg) 2543 { 2544 return *(volatile uint16 *)(fCapabilityRegisters + reg); 2545 } 2546 2547 2548 inline uint32 2549 EHCI::ReadCapReg32(uint32 reg) 2550 { 2551 return *(volatile uint32 *)(fCapabilityRegisters + reg); 2552 } 2553