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