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