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