1 /* 2 * Copyright 2006, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Michael Lotz <mmlr@mlotz.ch> 7 */ 8 9 #include <module.h> 10 #include <PCI.h> 11 #include <USB3.h> 12 #include <KernelExport.h> 13 14 #include "ehci.h" 15 16 pci_module_info *EHCI::sPCIModule = NULL; 17 18 19 static int32 20 ehci_std_ops(int32 op, ...) 21 { 22 switch (op) { 23 case B_MODULE_INIT: 24 TRACE(("usb_ehci_module: init module\n")); 25 return B_OK; 26 case B_MODULE_UNINIT: 27 TRACE(("usb_ehci_module: uninit module\n")); 28 return B_OK; 29 } 30 31 return EINVAL; 32 } 33 34 35 host_controller_info ehci_module = { 36 { 37 "busses/usb/ehci", 38 0, 39 ehci_std_ops 40 }, 41 NULL, 42 EHCI::AddTo 43 }; 44 45 46 module_info *modules[] = { 47 (module_info *)&ehci_module, 48 NULL 49 }; 50 51 52 // 53 // #pragma mark - 54 // 55 56 57 #ifdef TRACE_USB 58 59 void 60 print_descriptor_chain(ehci_qtd *descriptor) 61 { 62 while (descriptor) { 63 dprintf(" %08lx n%08lx a%08lx t%08lx %08lx %08lx %08lx %08lx %08lx s%ld\n", 64 descriptor->this_phy, descriptor->next_phy, 65 descriptor->alt_next_phy, descriptor->token, 66 descriptor->buffer_phy[0], descriptor->buffer_phy[1], 67 descriptor->buffer_phy[2], descriptor->buffer_phy[3], 68 descriptor->buffer_phy[4], descriptor->buffer_size); 69 70 if (descriptor->next_phy & EHCI_QTD_TERMINATE) 71 break; 72 73 descriptor = (ehci_qtd *)descriptor->next_log; 74 } 75 } 76 77 void 78 print_queue(ehci_qh *queueHead) 79 { 80 dprintf("queue: t%08lx n%08lx ch%08lx ca%08lx cu%08lx\n", 81 queueHead->this_phy, queueHead->next_phy, queueHead->endpoint_chars, 82 queueHead->endpoint_caps, queueHead->current_qtd_phy); 83 dprintf("overlay: n%08lx a%08lx t%08lx %08lx %08lx %08lx %08lx %08lx\n", 84 queueHead->overlay.next_phy, queueHead->overlay.alt_next_phy, 85 queueHead->overlay.token, queueHead->overlay.buffer_phy[0], 86 queueHead->overlay.buffer_phy[1], queueHead->overlay.buffer_phy[2], 87 queueHead->overlay.buffer_phy[3], queueHead->overlay.buffer_phy[4]); 88 print_descriptor_chain((ehci_qtd *)queueHead->element_log); 89 } 90 91 #endif // TRACE_USB 92 93 94 // 95 // #pragma mark - 96 // 97 98 99 EHCI::EHCI(pci_info *info, Stack *stack) 100 : BusManager(stack), 101 fPCIInfo(info), 102 fStack(stack), 103 fPeriodicFrameListArea(-1), 104 fPeriodicFrameList(NULL), 105 fFirstTransfer(NULL), 106 fLastTransfer(NULL), 107 fFinishThread(-1), 108 fCleanupThread(-1), 109 fStopThreads(false), 110 fFreeListHead(NULL), 111 fRootHub(NULL), 112 fRootHubAddress(0), 113 fPortCount(0), 114 fPortResetChange(0), 115 fPortSuspendChange(0) 116 { 117 if (BusManager::InitCheck() < B_OK) { 118 TRACE_ERROR(("usb_ehci: bus manager failed to init\n")); 119 return; 120 } 121 122 TRACE(("usb_ehci: constructing new EHCI Host Controller Driver\n")); 123 fInitOK = false; 124 125 // enable busmaster and memory mapped access 126 uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus, 127 fPCIInfo->device, fPCIInfo->function, PCI_command, 2); 128 command &= ~PCI_command_io; 129 command |= PCI_command_master | PCI_command_memory; 130 131 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 132 fPCIInfo->function, PCI_command, 2, command); 133 134 // map the registers 135 uint32 offset = fPCIInfo->u.h0.base_registers[0] & (B_PAGE_SIZE - 1); 136 addr_t physicalAddress = fPCIInfo->u.h0.base_registers[0] - offset; 137 size_t mapSize = (fPCIInfo->u.h0.base_register_sizes[0] + offset 138 + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1); 139 140 TRACE(("usb_ehci: map physical memory 0x%08lx (base: 0x%08lx; offset: %lx); size: %ld\n", fPCIInfo->u.h0.base_registers[0], physicalAddress, offset, fPCIInfo->u.h0.base_register_sizes[0])); 141 fRegisterArea = map_physical_memory("EHCI memory mapped registers", 142 (void *)physicalAddress, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS, 143 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, 144 (void **)&fCapabilityRegisters); 145 if (fRegisterArea < B_OK) { 146 TRACE(("usb_ehci: failed to map register memory\n")); 147 return; 148 } 149 150 fCapabilityRegisters += offset; 151 fOperationalRegisters = fCapabilityRegisters + ReadCapReg8(EHCI_CAPLENGTH); 152 TRACE(("usb_ehci: mapped capability registers: 0x%08lx\n", (uint32)fCapabilityRegisters)); 153 TRACE(("usb_ehci: mapped operational registers: 0x%08lx\n", (uint32)fOperationalRegisters)); 154 155 TRACE(("usb_ehci: structural parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCSPARAMS))); 156 TRACE(("usb_ehci: capability parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCCPARAMS))); 157 158 // read port count from capability register 159 fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f; 160 161 uint32 extendedCapPointer = ReadCapReg32(EHCI_HCCPARAMS) >> EHCI_ECP_SHIFT; 162 extendedCapPointer &= EHCI_ECP_MASK; 163 if (extendedCapPointer > 0) { 164 TRACE(("usb_ehci: extended capabilities register at %ld\n", extendedCapPointer)); 165 166 uint32 legacySupport = sPCIModule->read_pci_config(fPCIInfo->bus, 167 fPCIInfo->device, fPCIInfo->function, extendedCapPointer, 4); 168 if ((legacySupport & EHCI_LEGSUP_CAPID_MASK) == EHCI_LEGSUP_CAPID) { 169 if (legacySupport & EHCI_LEGSUP_BIOSOWNED) { 170 TRACE(("usb_ehci: the host controller is bios owned\n")); 171 } 172 173 TRACE(("usb_ehci: claiming ownership of the host controller\n")); 174 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 175 fPCIInfo->function, extendedCapPointer, 4, EHCI_LEGSUP_OSOWNED); 176 177 for (int32 i = 0; i < 10; i++) { 178 legacySupport = sPCIModule->read_pci_config(fPCIInfo->bus, 179 fPCIInfo->device, fPCIInfo->function, extendedCapPointer, 4); 180 181 if (legacySupport & EHCI_LEGSUP_BIOSOWNED) { 182 TRACE(("usb_ehci: controller is still bios owned, waiting\n")); 183 snooze(50000); 184 } else 185 break; 186 } 187 188 if (legacySupport & EHCI_LEGSUP_BIOSOWNED) { 189 TRACE_ERROR(("usb_ehci: bios won't give up control over the host controller\n")); 190 return; 191 } else if (legacySupport & EHCI_LEGSUP_OSOWNED) { 192 TRACE(("usb_ehci: successfully took ownership of the host controller\n")); 193 } 194 } else { 195 TRACE(("usb_ehci: extended capability is not a legacy support register\n")); 196 } 197 } else { 198 TRACE(("usb_ehci: no extended capabilities register\n")); 199 } 200 201 // disable interrupts 202 WriteOpReg(EHCI_USBINTR, 0); 203 204 // reset the segment register 205 WriteOpReg(EHCI_CTRDSSEGMENT, 0); 206 207 // reset the host controller 208 if (ControllerReset() < B_OK) { 209 TRACE_ERROR(("usb_ehci: host controller failed to reset\n")); 210 return; 211 } 212 213 // create semaphores the finisher thread will wait for 214 fAsyncAdvanceSem = create_sem(0, "EHCI Async Advance"); 215 fFinishTransfersSem = create_sem(0, "EHCI Finish Transfers"); 216 fCleanupSem = create_sem(0, "EHCI Cleanup"); 217 if (fFinishTransfersSem < B_OK || fAsyncAdvanceSem < B_OK 218 || fCleanupSem < B_OK) { 219 TRACE_ERROR(("usb_ehci: failed to create semaphores\n")); 220 return; 221 } 222 223 // create finisher service thread 224 fFinishThread = spawn_kernel_thread(FinishThread, "ehci finish thread", 225 B_NORMAL_PRIORITY, (void *)this); 226 resume_thread(fFinishThread); 227 228 // create cleanup service thread 229 fCleanupThread = spawn_kernel_thread(CleanupThread, "ehci cleanup thread", 230 B_NORMAL_PRIORITY, (void *)this); 231 resume_thread(fCleanupThread); 232 233 // install the interrupt handler and enable interrupts 234 install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, 235 InterruptHandler, (void *)this, 0); 236 WriteOpReg(EHCI_USBINTR, EHCI_USBINTR_HOSTSYSERR 237 | EHCI_USBINTR_USBERRINT | EHCI_USBINTR_USBINT | EHCI_USBINTR_INTONAA); 238 239 // allocate the periodic frame list 240 fPeriodicFrameListArea = fStack->AllocateArea((void **)&fPeriodicFrameList, 241 (void **)&physicalAddress, B_PAGE_SIZE, "USB EHCI Periodic Framelist"); 242 if (fPeriodicFrameListArea < B_OK) { 243 TRACE_ERROR(("usb_ehci: unable to allocate periodic framelist\n")); 244 return; 245 } 246 247 // terminate all elements 248 for (int32 i = 0; i < 1024; i++) 249 fPeriodicFrameList[i] = EHCI_PFRAMELIST_TERM; 250 251 WriteOpReg(EHCI_PERIODICLISTBASE, (uint32)physicalAddress); 252 253 // allocate a queue head that will always stay in the async frame list 254 fAsyncQueueHead = CreateQueueHead(); 255 if (!fAsyncQueueHead) { 256 TRACE_ERROR(("usb_ehci: unable to allocate stray async queue head\n")); 257 return; 258 } 259 260 fAsyncQueueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH; 261 fAsyncQueueHead->next_log = fAsyncQueueHead; 262 fAsyncQueueHead->prev_log = fAsyncQueueHead; 263 fAsyncQueueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH | EHCI_QH_CHARS_RECHEAD; 264 fAsyncQueueHead->endpoint_caps = 1 << EHCI_QH_CAPS_MULT_SHIFT; 265 fAsyncQueueHead->current_qtd_phy = EHCI_QTD_TERMINATE; 266 fAsyncQueueHead->overlay.next_phy = EHCI_QTD_TERMINATE; 267 268 WriteOpReg(EHCI_ASYNCLISTADDR, (uint32)fAsyncQueueHead->this_phy 269 | EHCI_QH_TYPE_QH); 270 TRACE(("usb_ehci: set the async list addr to 0x%08lx\n", ReadOpReg(EHCI_ASYNCLISTADDR))); 271 272 fInitOK = true; 273 TRACE(("usb_ehci: EHCI Host Controller Driver constructed\n")); 274 } 275 276 277 EHCI::~EHCI() 278 { 279 TRACE(("usb_ehci: tear down EHCI Host Controller Driver\n")); 280 281 WriteOpReg(EHCI_USBCMD, 0); 282 WriteOpReg(EHCI_CONFIGFLAG, 0); 283 CancelAllPendingTransfers(); 284 285 int32 result = 0; 286 fStopThreads = true; 287 delete_sem(fAsyncAdvanceSem); 288 delete_sem(fFinishTransfersSem); 289 wait_for_thread(fFinishThread, &result); 290 wait_for_thread(fCleanupThread, &result); 291 292 delete fRootHub; 293 delete_area(fPeriodicFrameListArea); 294 delete_area(fRegisterArea); 295 put_module(B_PCI_MODULE_NAME); 296 } 297 298 299 status_t 300 EHCI::Start() 301 { 302 TRACE(("usb_ehci: starting EHCI Host Controller\n")); 303 TRACE(("usb_ehci: usbcmd: 0x%08lx; usbsts: 0x%08lx\n", ReadOpReg(EHCI_USBCMD), ReadOpReg(EHCI_USBSTS))); 304 305 uint32 frameListSize = (ReadOpReg(EHCI_USBCMD) >> EHCI_USBCMD_FLS_SHIFT) 306 & EHCI_USBCMD_FLS_MASK; 307 WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_RUNSTOP 308 | EHCI_USBCMD_ASENABLE /*| EHCI_USBCMD_PSENABLE*/ 309 | (frameListSize << EHCI_USBCMD_FLS_SHIFT) 310 | (2 << EHCI_USBCMD_ITC_SHIFT)); 311 312 // route all ports to us 313 WriteOpReg(EHCI_CONFIGFLAG, EHCI_CONFIGFLAG_FLAG); 314 315 bool running = false; 316 for (int32 i = 0; i < 10; i++) { 317 uint32 status = ReadOpReg(EHCI_USBSTS); 318 TRACE(("usb_ehci: try %ld: status 0x%08lx\n", i, status)); 319 320 if (status & EHCI_USBSTS_HCHALTED) { 321 snooze(10000); 322 } else { 323 running = true; 324 break; 325 } 326 } 327 328 // set the interrupt threshold 329 WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) 330 | (1 << EHCI_USBCMD_ITC_SHIFT)); 331 332 if (!running) { 333 TRACE(("usb_ehci: Host Controller didn't start\n")); 334 return B_ERROR; 335 } 336 337 fRootHubAddress = AllocateAddress(); 338 fRootHub = new(std::nothrow) EHCIRootHub(RootObject(), fRootHubAddress); 339 if (!fRootHub) { 340 TRACE_ERROR(("usb_ehci: no memory to allocate root hub\n")); 341 return B_NO_MEMORY; 342 } 343 344 if (fRootHub->InitCheck() < B_OK) { 345 TRACE_ERROR(("usb_ehci: root hub failed init check\n")); 346 return fRootHub->InitCheck(); 347 } 348 349 SetRootHub(fRootHub); 350 TRACE(("usb_ehci: Host Controller started\n")); 351 return BusManager::Start(); 352 } 353 354 355 status_t 356 EHCI::SubmitTransfer(Transfer *transfer) 357 { 358 // short circuit the root hub 359 if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress) 360 return fRootHub->ProcessTransfer(this, transfer); 361 362 uint32 type = transfer->TransferPipe()->Type(); 363 if ((type & USB_OBJECT_CONTROL_PIPE) > 0 364 || (type & USB_OBJECT_BULK_PIPE) > 0) { 365 TRACE(("usb_ehci: submitting async transfer\n")); 366 return SubmitAsyncTransfer(transfer); 367 } 368 369 if ((type & USB_OBJECT_INTERRUPT_PIPE) > 0 370 || (type & USB_OBJECT_ISO_PIPE) > 0) { 371 TRACE(("usb_ehci: submitting periodic transfer\n")); 372 return SubmitPeriodicTransfer(transfer); 373 } 374 375 TRACE_ERROR(("usb_ehci: tried to submit transfer for unknown pipe type %lu\n", type)); 376 return B_ERROR; 377 } 378 379 380 status_t 381 EHCI::SubmitAsyncTransfer(Transfer *transfer) 382 { 383 ehci_qh *queueHead = CreateQueueHead(); 384 if (!queueHead) { 385 TRACE_ERROR(("usb_ehci: failed to allocate async queue head\n")); 386 return B_NO_MEMORY; 387 } 388 389 Pipe *pipe = transfer->TransferPipe(); 390 switch (pipe->Speed()) { 391 case USB_SPEED_LOWSPEED: 392 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_LOW; 393 break; 394 case USB_SPEED_FULLSPEED: 395 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_FULL; 396 break; 397 case USB_SPEED_HIGHSPEED: 398 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH; 399 break; 400 default: 401 TRACE_ERROR(("usb_ehci: unknown pipe speed\n")); 402 FreeQueueHead(queueHead); 403 return B_ERROR; 404 } 405 406 if (pipe->Type() & USB_OBJECT_CONTROL_PIPE) { 407 queueHead->endpoint_chars |= 408 (pipe->Speed() != USB_SPEED_HIGHSPEED ? EHCI_QH_CHARS_CONTROL : 0); 409 } 410 411 queueHead->endpoint_chars |= (3 << EHCI_QH_CHARS_RL_SHIFT) 412 | (pipe->MaxPacketSize() << EHCI_QH_CHARS_MPL_SHIFT) 413 | (pipe->EndpointAddress() << EHCI_QH_CHARS_EPT_SHIFT) 414 | (pipe->DeviceAddress() << EHCI_QH_CHARS_DEV_SHIFT) 415 | EHCI_QH_CHARS_TOGGLE; 416 queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT) 417 | (0x1c << EHCI_QH_CAPS_SCM_SHIFT); 418 419 status_t result; 420 bool directionIn; 421 ehci_qtd *dataDescriptor; 422 if (pipe->Type() & USB_OBJECT_CONTROL_PIPE) 423 result = FillQueueWithRequest(transfer, queueHead, &dataDescriptor, 424 &directionIn); 425 else 426 result = FillQueueWithData(transfer, queueHead, &dataDescriptor, 427 &directionIn); 428 429 if (result < B_OK) { 430 TRACE_ERROR(("usb_ehci: failed to fill transfer queue with data\n")); 431 FreeQueueHead(queueHead); 432 return result; 433 } 434 435 result = AddPendingTransfer(transfer, queueHead, dataDescriptor, directionIn); 436 if (result < B_OK) { 437 TRACE_ERROR(("usb_ehci: failed to add pending transfer\n")); 438 FreeQueueHead(queueHead); 439 return result; 440 } 441 442 #ifdef TRACE_USB 443 TRACE(("usb_ehci: linking queue\n")); 444 print_queue(queueHead); 445 #endif 446 447 result = LinkQueueHead(queueHead); 448 if (result < B_OK) { 449 TRACE_ERROR(("usb_ehci: failed to link queue head to the async list\n")); 450 FreeQueueHead(queueHead); 451 return result; 452 } 453 454 return B_OK; 455 } 456 457 458 status_t 459 EHCI::SubmitPeriodicTransfer(Transfer *transfer) 460 { 461 return B_ERROR; 462 } 463 464 465 status_t 466 EHCI::NotifyPipeChange(Pipe *pipe, usb_change change) 467 { 468 TRACE_ERROR(("usb_ehci: pipe change %d for pipe 0x%08lx\n", change, (uint32)pipe)); 469 switch (change) { 470 case USB_CHANGE_CREATED: 471 case USB_CHANGE_DESTROYED: { 472 // ToDo: we should create and keep a single queue head 473 // for all transfers to/from this pipe 474 break; 475 } 476 477 case USB_CHANGE_PIPE_POLICY_CHANGED: { 478 // ToDo: for isochronous pipes we might need to adapt to new 479 // pipe policy settings here 480 break; 481 } 482 } 483 484 return B_OK; 485 } 486 487 488 status_t 489 EHCI::AddTo(Stack *stack) 490 { 491 #ifdef TRACE_USB 492 set_dprintf_enabled(true); 493 load_driver_symbols("ehci"); 494 #endif 495 496 if (!sPCIModule) { 497 status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule); 498 if (status < B_OK) { 499 TRACE_ERROR(("usb_ehci: getting pci module failed! 0x%08lx\n", status)); 500 return status; 501 } 502 } 503 504 TRACE(("usb_ehci: searching devices\n")); 505 bool found = false; 506 pci_info *item = new(std::nothrow) pci_info; 507 if (!item) { 508 sPCIModule = NULL; 509 put_module(B_PCI_MODULE_NAME); 510 return B_NO_MEMORY; 511 } 512 513 for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) { 514 515 if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb 516 && item->class_api == PCI_usb_ehci) { 517 if (item->u.h0.interrupt_line == 0 518 || item->u.h0.interrupt_line == 0xFF) { 519 TRACE_ERROR(("usb_ehci: found device with invalid IRQ - check IRQ assignement\n")); 520 continue; 521 } 522 523 TRACE(("usb_ehci: found device at IRQ %u\n", item->u.h0.interrupt_line)); 524 EHCI *bus = new(std::nothrow) EHCI(item, stack); 525 if (!bus) { 526 delete item; 527 sPCIModule = NULL; 528 put_module(B_PCI_MODULE_NAME); 529 return B_NO_MEMORY; 530 } 531 532 if (bus->InitCheck() < B_OK) { 533 TRACE_ERROR(("usb_ehci: bus failed init check\n")); 534 delete bus; 535 continue; 536 } 537 538 // the bus took it away 539 item = new(std::nothrow) pci_info; 540 541 bus->Start(); 542 stack->AddBusManager(bus); 543 found = true; 544 } 545 } 546 547 if (!found) { 548 TRACE_ERROR(("usb_ehci: no devices found\n")); 549 delete item; 550 sPCIModule = NULL; 551 put_module(B_PCI_MODULE_NAME); 552 return ENODEV; 553 } 554 555 delete item; 556 return B_OK; 557 } 558 559 560 status_t 561 EHCI::GetPortStatus(uint8 index, usb_port_status *status) 562 { 563 if (index >= fPortCount) 564 return B_BAD_INDEX; 565 566 status->status = status->change = 0; 567 uint32 portStatus = ReadOpReg(EHCI_PORTSC + index * sizeof(uint32)); 568 569 // build the status 570 if (portStatus & EHCI_PORTSC_CONNSTATUS) 571 status->status |= PORT_STATUS_CONNECTION; 572 if (portStatus & EHCI_PORTSC_ENABLE) 573 status->status |= PORT_STATUS_ENABLE; 574 if (portStatus & EHCI_PORTSC_ENABLE) 575 status->status |= PORT_STATUS_HIGH_SPEED; 576 if (portStatus & EHCI_PORTSC_OCACTIVE) 577 status->status |= PORT_STATUS_OVER_CURRENT; 578 if (portStatus & EHCI_PORTSC_PORTRESET) 579 status->status |= PORT_STATUS_RESET; 580 if (portStatus & EHCI_PORTSC_PORTPOWER) 581 status->status |= PORT_STATUS_POWER; 582 if (portStatus & EHCI_PORTSC_SUSPEND) 583 status->status |= PORT_STATUS_SUSPEND; 584 if (portStatus & EHCI_PORTSC_DMINUS) 585 status->status |= PORT_STATUS_LOW_SPEED; 586 587 // build the change 588 if (portStatus & EHCI_PORTSC_CONNCHANGE) 589 status->change |= PORT_STATUS_CONNECTION; 590 if (portStatus & EHCI_PORTSC_ENABLECHANGE) 591 status->change |= PORT_STATUS_ENABLE; 592 if (portStatus & EHCI_PORTSC_OCCHANGE) 593 status->change |= PORT_STATUS_OVER_CURRENT; 594 595 // there are no bits to indicate suspend and reset change 596 if (fPortResetChange & (1 << index)) 597 status->change |= PORT_STATUS_RESET; 598 if (fPortSuspendChange & (1 << index)) 599 status->change |= PORT_STATUS_SUSPEND; 600 601 return B_OK; 602 } 603 604 605 status_t 606 EHCI::SetPortFeature(uint8 index, uint16 feature) 607 { 608 if (index >= fPortCount) 609 return B_BAD_INDEX; 610 611 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32); 612 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; 613 614 switch (feature) { 615 case PORT_SUSPEND: 616 return SuspendPort(index); 617 618 case PORT_RESET: 619 return ResetPort(index); 620 621 case PORT_POWER: 622 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTPOWER); 623 return B_OK; 624 } 625 626 return B_BAD_VALUE; 627 } 628 629 630 status_t 631 EHCI::ClearPortFeature(uint8 index, uint16 feature) 632 { 633 if (index >= fPortCount) 634 return B_BAD_INDEX; 635 636 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32); 637 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; 638 639 switch (feature) { 640 case PORT_ENABLE: 641 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_ENABLE); 642 return B_OK; 643 644 case PORT_POWER: 645 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTPOWER); 646 return B_OK; 647 648 case C_PORT_CONNECTION: 649 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_CONNCHANGE); 650 return B_OK; 651 652 case C_PORT_ENABLE: 653 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_ENABLECHANGE); 654 return B_OK; 655 656 case C_PORT_OVER_CURRENT: 657 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_OCCHANGE); 658 return B_OK; 659 660 case C_PORT_RESET: 661 fPortResetChange &= ~(1 << index); 662 return B_OK; 663 664 case C_PORT_SUSPEND: 665 fPortSuspendChange &= ~(1 << index); 666 return B_OK; 667 } 668 669 return B_BAD_VALUE; 670 } 671 672 673 status_t 674 EHCI::ResetPort(uint8 index) 675 { 676 TRACE(("usb_ehci: reset port %d\n", index)); 677 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32); 678 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; 679 680 if (portStatus & EHCI_PORTSC_DMINUS) { 681 TRACE(("usb_ehci: lowspeed device connected, giving up port ownership\n")); 682 // there is a lowspeed device connected. 683 // we give the ownership to a companion controller. 684 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER); 685 fPortResetChange |= (1 << index); 686 return B_OK; 687 } 688 689 // enable reset signaling 690 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTRESET); 691 snooze(250000); 692 693 // disable reset signaling 694 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; 695 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTRESET); 696 snooze(2000); 697 698 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; 699 if (portStatus & EHCI_PORTSC_PORTRESET) { 700 TRACE(("usb_ehci: port reset won't complete\n")); 701 return B_ERROR; 702 } 703 704 if ((portStatus & EHCI_PORTSC_ENABLE) == 0) { 705 TRACE(("usb_ehci: fullspeed device connected, giving up port ownership\n")); 706 // the port was not enabled, this means that no high speed device is 707 // attached to this port. we give up ownership to a companion controler 708 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER); 709 } 710 711 fPortResetChange |= (1 << index); 712 return B_OK; 713 } 714 715 716 status_t 717 EHCI::SuspendPort(uint8 index) 718 { 719 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32); 720 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK; 721 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_SUSPEND); 722 fPortSuspendChange |= (1 << index); 723 return B_OK; 724 } 725 726 727 status_t 728 EHCI::ControllerReset() 729 { 730 // halt the controller first 731 WriteOpReg(EHCI_USBCMD, 0); 732 snooze(10000); 733 734 // then reset it 735 WriteOpReg(EHCI_USBCMD, EHCI_USBCMD_HCRESET); 736 737 int32 tries = 5; 738 while (ReadOpReg(EHCI_USBCMD) & EHCI_USBCMD_HCRESET) { 739 snooze(10000); 740 if (tries-- < 0) 741 return B_ERROR; 742 } 743 744 return B_OK; 745 } 746 747 748 status_t 749 EHCI::LightReset() 750 { 751 return B_ERROR; 752 } 753 754 755 int32 756 EHCI::InterruptHandler(void *data) 757 { 758 return ((EHCI *)data)->Interrupt(); 759 } 760 761 762 int32 763 EHCI::Interrupt() 764 { 765 static spinlock lock = 0; 766 acquire_spinlock(&lock); 767 768 // check if any interrupt was generated 769 uint32 status = ReadOpReg(EHCI_USBSTS); 770 if ((status & EHCI_USBSTS_INTMASK) == 0) { 771 release_spinlock(&lock); 772 return B_UNHANDLED_INTERRUPT; 773 } 774 775 uint32 acknowledge = 0; 776 bool asyncAdvance = false; 777 bool finishTransfers = false; 778 int32 result = B_HANDLED_INTERRUPT; 779 780 if (status & EHCI_USBSTS_USBINT) { 781 TRACE(("usb_ehci: transfer finished\n")); 782 acknowledge |= EHCI_USBSTS_USBINT; 783 result = B_INVOKE_SCHEDULER; 784 finishTransfers = true; 785 } 786 787 if (status & EHCI_USBSTS_USBERRINT) { 788 TRACE(("usb_ehci: transfer error\n")); 789 acknowledge |= EHCI_USBSTS_USBERRINT; 790 result = B_INVOKE_SCHEDULER; 791 finishTransfers = true; 792 } 793 794 if (status & EHCI_USBSTS_PORTCHANGE) { 795 TRACE(("usb_ehci: port change detected\n")); 796 acknowledge |= EHCI_USBSTS_PORTCHANGE; 797 } 798 799 if (status & EHCI_USBSTS_FLROLLOVER) { 800 TRACE(("usb_ehci: frame list rolled over\n")); 801 acknowledge |= EHCI_USBSTS_FLROLLOVER; 802 } 803 804 if (status & EHCI_USBSTS_INTONAA) { 805 TRACE(("usb_ehci: interrupt on async advance\n")); 806 acknowledge |= EHCI_USBSTS_INTONAA; 807 asyncAdvance = true; 808 result = B_INVOKE_SCHEDULER; 809 } 810 811 if (status & EHCI_USBSTS_HOSTSYSERR) { 812 TRACE_ERROR(("usb_ehci: host system error!\n")); 813 acknowledge |= EHCI_USBSTS_HOSTSYSERR; 814 } 815 816 if (acknowledge) 817 WriteOpReg(EHCI_USBSTS, acknowledge); 818 819 release_spinlock(&lock); 820 821 if (asyncAdvance) 822 release_sem_etc(fAsyncAdvanceSem, 1, B_DO_NOT_RESCHEDULE); 823 if (finishTransfers) 824 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); 825 826 return result; 827 } 828 829 830 status_t 831 EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead, 832 ehci_qtd *dataDescriptor, bool directionIn) 833 { 834 transfer_data *data = new(std::nothrow) transfer_data(); 835 if (!data) 836 return B_NO_MEMORY; 837 838 status_t result = transfer->InitKernelAccess(); 839 if (result < B_OK) 840 return result; 841 842 data->transfer = transfer; 843 data->queue_head = queueHead; 844 data->data_descriptor = dataDescriptor; 845 data->user_area = -1; 846 data->incoming = directionIn; 847 data->link = NULL; 848 849 if (!Lock()) { 850 delete data; 851 return B_ERROR; 852 } 853 854 if (fLastTransfer) 855 fLastTransfer->link = data; 856 else 857 fFirstTransfer = data; 858 859 fLastTransfer = data; 860 Unlock(); 861 862 return B_OK; 863 } 864 865 866 status_t 867 EHCI::CancelQueuedTransfers(Pipe *pipe) 868 { 869 if (!Lock()) 870 return B_ERROR; 871 872 transfer_data *last = NULL; 873 transfer_data *current = fFirstTransfer; 874 while (current) { 875 if (current->transfer->TransferPipe() == pipe) { 876 UnlinkQueueHead(current->queue_head, &fFreeListHead); 877 current->transfer->Finished(B_CANCELED, 0); 878 delete current->transfer; 879 880 transfer_data *next = current->link; 881 if (last) 882 last->link = next; 883 else 884 fFirstTransfer = next; 885 886 if (fLastTransfer == current) 887 fLastTransfer = last; 888 889 delete current; 890 current = next; 891 } else { 892 last = current; 893 current = current->link; 894 } 895 } 896 897 Unlock(); 898 return B_OK; 899 } 900 901 902 status_t 903 EHCI::CancelAllPendingTransfers() 904 { 905 if (!Lock()) 906 return B_ERROR; 907 908 transfer_data *transfer = fFirstTransfer; 909 while (transfer) { 910 transfer->transfer->Finished(B_CANCELED, 0); 911 delete transfer->transfer; 912 913 transfer_data *next = transfer->link; 914 delete transfer; 915 transfer = next; 916 } 917 918 fFirstTransfer = NULL; 919 fLastTransfer = NULL; 920 Unlock(); 921 return B_OK; 922 } 923 924 925 int32 926 EHCI::FinishThread(void *data) 927 { 928 ((EHCI *)data)->FinishTransfers(); 929 return B_OK; 930 } 931 932 933 void 934 EHCI::FinishTransfers() 935 { 936 while (!fStopThreads) { 937 if (acquire_sem(fFinishTransfersSem) < B_OK) 938 continue; 939 940 // eat up sems that have been released by multiple interrupts 941 int32 semCount = 0; 942 get_sem_count(fFinishTransfersSem, &semCount); 943 if (semCount > 0) 944 acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); 945 946 if (!Lock()) 947 continue; 948 949 TRACE(("usb_ehci: finishing transfers\n")); 950 transfer_data *lastTransfer = NULL; 951 transfer_data *transfer = fFirstTransfer; 952 Unlock(); 953 954 while (transfer) { 955 bool transferDone = false; 956 ehci_qtd *descriptor = (ehci_qtd *)transfer->queue_head->element_log; 957 958 #ifdef TRACE_USB 959 print_queue(transfer->queue_head); 960 #endif 961 962 while (descriptor) { 963 uint32 status = descriptor->token; 964 if (status & EHCI_QTD_STATUS_ACTIVE) { 965 // still in progress 966 TRACE(("usb_ehci: qtd (0x%08lx) still active\n", descriptor->this_phy)); 967 break; 968 } 969 970 if (status & EHCI_QTD_STATUS_ERRMASK) { 971 // a transfer error occured 972 TRACE_ERROR(("usb_ehci: qtd (0x%08lx) error: 0x%08lx\n", descriptor->this_phy, status)); 973 974 status_t callbackStatus = B_ERROR; 975 uint8 errorCount = status >> EHCI_QTD_ERRCOUNT_SHIFT; 976 errorCount &= EHCI_QTD_ERRCOUNT_MASK; 977 if (errorCount == 0) { 978 // the error counter counted down to zero, report why 979 int32 reasons = 0; 980 if (status & EHCI_QTD_STATUS_BUFFER) { 981 callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN; 982 reasons++; 983 } 984 if (status & EHCI_QTD_STATUS_TERROR) { 985 callbackStatus = B_DEV_CRC_ERROR; 986 reasons++; 987 } 988 989 if (reasons > 1) 990 callbackStatus = B_DEV_MULTIPLE_ERRORS; 991 } else if (status & EHCI_QTD_STATUS_BABBLE) { 992 // there is a babble condition 993 callbackStatus = transfer->incoming ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN; 994 } else { 995 // if the error counter didn't count down to zero 996 // and there was no babble, then this halt was caused 997 // by a stall handshake 998 callbackStatus = B_DEV_STALLED; 999 } 1000 1001 UnlinkQueueHead(transfer->queue_head, &fFreeListHead); 1002 transfer->transfer->Finished(callbackStatus, 0); 1003 transferDone = true; 1004 break; 1005 } 1006 1007 if (descriptor->next_phy & EHCI_QTD_TERMINATE) { 1008 // we arrived at the last (stray) descriptor, we're done 1009 TRACE(("usb_ehci: qtd (0x%08lx) done\n", descriptor->this_phy)); 1010 1011 size_t actualLength = 0; 1012 bool nextDataToggle = false; 1013 if (transfer->data_descriptor && transfer->incoming) { 1014 // data to read out 1015 iovec *vector = transfer->transfer->Vector(); 1016 size_t vectorCount = transfer->transfer->VectorCount(); 1017 transfer->transfer->PrepareKernelAccess(); 1018 actualLength = ReadDescriptorChain( 1019 transfer->data_descriptor, 1020 vector, vectorCount, 1021 &nextDataToggle); 1022 } else { 1023 // calculate transfered length 1024 actualLength = ReadActualLength( 1025 (ehci_qtd *)transfer->queue_head->element_log, 1026 &nextDataToggle); 1027 } 1028 1029 transfer->transfer->TransferPipe()->SetDataToggle(nextDataToggle); 1030 if (transfer->transfer->IsFragmented()) { 1031 // this transfer may still have data left 1032 transfer->transfer->AdvanceByFragment(actualLength); 1033 if (transfer->transfer->VectorLength() > 0) { 1034 FreeDescriptorChain(transfer->data_descriptor); 1035 transfer->transfer->PrepareKernelAccess(); 1036 FillQueueWithData(transfer->transfer, 1037 transfer->queue_head, 1038 &transfer->data_descriptor, NULL); 1039 break; 1040 } 1041 1042 // the transfer is done, but we already set the 1043 // actualLength with AdvanceByFragment() 1044 actualLength = 0; 1045 } 1046 1047 UnlinkQueueHead(transfer->queue_head, &fFreeListHead); 1048 transfer->transfer->Finished(B_OK, actualLength); 1049 transferDone = true; 1050 break; 1051 } 1052 1053 descriptor = (ehci_qtd *)descriptor->next_log; 1054 } 1055 1056 if (transferDone) { 1057 if (Lock()) { 1058 if (lastTransfer) 1059 lastTransfer->link = transfer->link; 1060 1061 if (transfer == fFirstTransfer) 1062 fFirstTransfer = transfer->link; 1063 if (transfer == fLastTransfer) 1064 fLastTransfer = lastTransfer; 1065 1066 transfer_data *next = transfer->link; 1067 delete transfer->transfer; 1068 delete transfer; 1069 transfer = next; 1070 Unlock(); 1071 } 1072 } else { 1073 if (Lock()) { 1074 lastTransfer = transfer; 1075 transfer = transfer->link; 1076 Unlock(); 1077 } 1078 } 1079 1080 release_sem(fCleanupSem); 1081 } 1082 } 1083 } 1084 1085 1086 int32 1087 EHCI::CleanupThread(void *data) 1088 { 1089 ((EHCI *)data)->Cleanup(); 1090 return B_OK; 1091 } 1092 1093 1094 void 1095 EHCI::Cleanup() 1096 { 1097 ehci_qh *lastFreeListHead = NULL; 1098 1099 while (!fStopThreads) { 1100 if (acquire_sem(fCleanupSem) < B_OK) 1101 continue; 1102 1103 ehci_qh *freeListHead = fFreeListHead; 1104 if (freeListHead == lastFreeListHead) 1105 continue; 1106 1107 // set the doorbell and wait for the host controller to notify us 1108 WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD); 1109 if (acquire_sem(fAsyncAdvanceSem) < B_OK) 1110 continue; 1111 1112 ehci_qh *current = freeListHead; 1113 while (current != lastFreeListHead) { 1114 ehci_qh *next = (ehci_qh *)current->next_log; 1115 FreeQueueHead(current); 1116 current = next; 1117 } 1118 1119 lastFreeListHead = freeListHead; 1120 } 1121 } 1122 1123 1124 ehci_qh * 1125 EHCI::CreateQueueHead() 1126 { 1127 ehci_qh *result; 1128 void *physicalAddress; 1129 if (fStack->AllocateChunk((void **)&result, &physicalAddress, 1130 sizeof(ehci_qh)) < B_OK) { 1131 TRACE_ERROR(("usb_ehci: failed to allocate queue head\n")); 1132 return NULL; 1133 } 1134 1135 result->this_phy = (addr_t)physicalAddress; 1136 result->next_phy = EHCI_QH_TERMINATE; 1137 result->next_log = NULL; 1138 result->prev_log = NULL; 1139 1140 ehci_qtd *descriptor = CreateDescriptor(0, 0); 1141 if (!descriptor) { 1142 TRACE_ERROR(("usb_ehci: failed to allocate initial qtd for queue head\n")); 1143 fStack->FreeChunk(result, (void *)result->this_phy, sizeof(ehci_qh)); 1144 return NULL; 1145 } 1146 1147 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE; 1148 result->stray_log = descriptor; 1149 result->element_log = descriptor; 1150 result->current_qtd_phy = EHCI_QTD_TERMINATE; 1151 result->overlay.next_phy = descriptor->this_phy; 1152 result->overlay.alt_next_phy = EHCI_QTD_TERMINATE; 1153 result->overlay.token = 0; 1154 for (int32 i = 0; i < 5; i++) { 1155 result->overlay.buffer_phy[i] = 0; 1156 result->overlay.ext_buffer_phy[i] = 0; 1157 } 1158 1159 return result; 1160 } 1161 1162 1163 void 1164 EHCI::FreeQueueHead(ehci_qh *queueHead) 1165 { 1166 if (!queueHead) 1167 return; 1168 1169 FreeDescriptorChain((ehci_qtd *)queueHead->element_log); 1170 FreeDescriptor((ehci_qtd *)queueHead->stray_log); 1171 fStack->FreeChunk(queueHead, (void *)queueHead->this_phy, sizeof(ehci_qh)); 1172 } 1173 1174 1175 status_t 1176 EHCI::LinkQueueHead(ehci_qh *queueHead) 1177 { 1178 if (!Lock()) 1179 return B_ERROR; 1180 1181 ehci_qh *prevHead = (ehci_qh *)fAsyncQueueHead->prev_log; 1182 queueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH; 1183 queueHead->next_log = fAsyncQueueHead; 1184 queueHead->prev_log = prevHead; 1185 fAsyncQueueHead->prev_log = queueHead; 1186 prevHead->next_log = queueHead; 1187 prevHead->next_phy = queueHead->this_phy | EHCI_QH_TYPE_QH; 1188 1189 Unlock(); 1190 return B_OK; 1191 } 1192 1193 1194 status_t 1195 EHCI::UnlinkQueueHead(ehci_qh *queueHead, ehci_qh **freeListHead) 1196 { 1197 if (!Lock()) 1198 return B_ERROR; 1199 1200 ehci_qh *prevHead = (ehci_qh *)queueHead->prev_log; 1201 ehci_qh *nextHead = (ehci_qh *)queueHead->next_log; 1202 prevHead->next_phy = queueHead->next_phy | EHCI_QH_TYPE_QH; 1203 prevHead->next_log = queueHead->next_log; 1204 nextHead->prev_log = queueHead->prev_log; 1205 queueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH; 1206 queueHead->next_log = NULL; 1207 queueHead->prev_log = NULL; 1208 1209 queueHead->next_log = *freeListHead; 1210 *freeListHead = queueHead; 1211 1212 Unlock(); 1213 return B_OK; 1214 } 1215 1216 1217 status_t 1218 EHCI::FillQueueWithRequest(Transfer *transfer, ehci_qh *queueHead, 1219 ehci_qtd **_dataDescriptor, bool *_directionIn) 1220 { 1221 Pipe *pipe = transfer->TransferPipe(); 1222 usb_request_data *requestData = transfer->RequestData(); 1223 bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0; 1224 1225 ehci_qtd *setupDescriptor = CreateDescriptor(sizeof(usb_request_data), 1226 EHCI_QTD_PID_SETUP); 1227 ehci_qtd *statusDescriptor = CreateDescriptor(0, 1228 directionIn ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN); 1229 1230 if (!setupDescriptor || !statusDescriptor) { 1231 TRACE_ERROR(("usb_ehci: failed to allocate descriptors\n")); 1232 FreeDescriptor(setupDescriptor); 1233 FreeDescriptor(statusDescriptor); 1234 return B_NO_MEMORY; 1235 } 1236 1237 iovec vector; 1238 vector.iov_base = requestData; 1239 vector.iov_len = sizeof(usb_request_data); 1240 WriteDescriptorChain(setupDescriptor, &vector, 1); 1241 1242 ehci_qtd *strayDescriptor = (ehci_qtd *)queueHead->stray_log; 1243 statusDescriptor->token |= EHCI_QTD_IOC | EHCI_QTD_DATA_TOGGLE; 1244 1245 ehci_qtd *dataDescriptor = NULL; 1246 if (transfer->VectorCount() > 0) { 1247 ehci_qtd *lastDescriptor = NULL; 1248 status_t result = CreateDescriptorChain(pipe, &dataDescriptor, 1249 &lastDescriptor, strayDescriptor, transfer->VectorLength(), 1250 directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT); 1251 1252 if (result < B_OK) { 1253 FreeDescriptor(setupDescriptor); 1254 FreeDescriptor(statusDescriptor); 1255 return result; 1256 } 1257 1258 if (!directionIn) { 1259 WriteDescriptorChain(dataDescriptor, transfer->Vector(), 1260 transfer->VectorCount()); 1261 } 1262 1263 LinkDescriptors(setupDescriptor, dataDescriptor, strayDescriptor); 1264 LinkDescriptors(lastDescriptor, statusDescriptor, strayDescriptor); 1265 } else { 1266 // no data: link setup and status descriptors directly 1267 LinkDescriptors(setupDescriptor, statusDescriptor, strayDescriptor); 1268 } 1269 1270 queueHead->element_log = setupDescriptor; 1271 queueHead->overlay.next_phy = setupDescriptor->this_phy; 1272 queueHead->overlay.alt_next_phy = EHCI_QTD_TERMINATE; 1273 1274 *_dataDescriptor = dataDescriptor; 1275 *_directionIn = directionIn; 1276 return B_OK; 1277 } 1278 1279 1280 status_t 1281 EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead, 1282 ehci_qtd **_dataDescriptor, bool *_directionIn) 1283 { 1284 Pipe *pipe = transfer->TransferPipe(); 1285 bool directionIn = (pipe->Direction() == Pipe::In); 1286 1287 ehci_qtd *firstDescriptor = NULL; 1288 ehci_qtd *lastDescriptor = NULL; 1289 ehci_qtd *strayDescriptor = (ehci_qtd *)queueHead->stray_log; 1290 status_t result = CreateDescriptorChain(pipe, &firstDescriptor, 1291 &lastDescriptor, strayDescriptor, transfer->VectorLength(), 1292 directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT); 1293 1294 if (result < B_OK) 1295 return result; 1296 1297 lastDescriptor->token |= EHCI_QTD_IOC; 1298 if (!directionIn) { 1299 WriteDescriptorChain(firstDescriptor, transfer->Vector(), 1300 transfer->VectorCount()); 1301 } 1302 1303 queueHead->element_log = firstDescriptor; 1304 queueHead->overlay.next_phy = firstDescriptor->this_phy; 1305 queueHead->overlay.alt_next_phy = EHCI_QTD_TERMINATE; 1306 1307 *_dataDescriptor = firstDescriptor; 1308 if (_directionIn) 1309 *_directionIn = directionIn; 1310 return B_OK; 1311 } 1312 1313 1314 ehci_qtd * 1315 EHCI::CreateDescriptor(size_t bufferSize, uint8 pid) 1316 { 1317 ehci_qtd *result; 1318 void *physicalAddress; 1319 if (fStack->AllocateChunk((void **)&result, &physicalAddress, 1320 sizeof(ehci_qtd)) < B_OK) { 1321 TRACE_ERROR(("usb_ehci: failed to allocate a qtd\n")); 1322 return NULL; 1323 } 1324 1325 result->this_phy = (addr_t)physicalAddress; 1326 result->next_phy = EHCI_QTD_TERMINATE; 1327 result->next_log = NULL; 1328 result->alt_next_phy = EHCI_QTD_TERMINATE; 1329 result->alt_next_log = NULL; 1330 result->buffer_size = bufferSize; 1331 result->token = bufferSize << EHCI_QTD_BYTES_SHIFT; 1332 result->token |= 3 << EHCI_QTD_ERRCOUNT_SHIFT; 1333 result->token |= pid << EHCI_QTD_PID_SHIFT; 1334 result->token |= EHCI_QTD_STATUS_ACTIVE; 1335 if (bufferSize == 0) { 1336 result->buffer_log = NULL; 1337 for (int32 i = 0; i < 5; i++) { 1338 result->buffer_phy[i] = 0; 1339 result->ext_buffer_phy[i] = 0; 1340 } 1341 1342 return result; 1343 } 1344 1345 if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress, 1346 bufferSize) < B_OK) { 1347 TRACE_ERROR(("usb_ehci: unable to allocate qtd buffer\n")); 1348 fStack->FreeChunk(result, (void *)result->this_phy, sizeof(ehci_qtd)); 1349 return NULL; 1350 } 1351 1352 addr_t physicalBase = (addr_t)physicalAddress; 1353 result->buffer_phy[0] = physicalBase; 1354 result->ext_buffer_phy[0] = 0; 1355 for (int32 i = 1; i < 5; i++) { 1356 physicalBase += B_PAGE_SIZE; 1357 result->buffer_phy[i] = physicalBase & EHCI_QTD_PAGE_MASK; 1358 result->ext_buffer_phy[i] = 0; 1359 } 1360 1361 return result; 1362 } 1363 1364 1365 status_t 1366 EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor, 1367 ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize, 1368 uint8 pid) 1369 { 1370 size_t packetSize = B_PAGE_SIZE * 4; 1371 int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize; 1372 1373 bool dataToggle = pipe->DataToggle(); 1374 ehci_qtd *firstDescriptor = NULL; 1375 ehci_qtd *lastDescriptor = *_firstDescriptor; 1376 for (int32 i = 0; i < descriptorCount; i++) { 1377 ehci_qtd *descriptor = CreateDescriptor(min_c(packetSize, bufferSize), 1378 pid); 1379 1380 if (!descriptor) { 1381 FreeDescriptorChain(firstDescriptor); 1382 return B_NO_MEMORY; 1383 } 1384 1385 if (dataToggle) 1386 descriptor->token |= EHCI_QTD_DATA_TOGGLE; 1387 1388 if (lastDescriptor) 1389 LinkDescriptors(lastDescriptor, descriptor, strayDescriptor); 1390 1391 bufferSize -= packetSize; 1392 lastDescriptor = descriptor; 1393 if (!firstDescriptor) 1394 firstDescriptor = descriptor; 1395 } 1396 1397 *_firstDescriptor = firstDescriptor; 1398 *_lastDescriptor = lastDescriptor; 1399 return B_OK; 1400 } 1401 1402 1403 void 1404 EHCI::FreeDescriptor(ehci_qtd *descriptor) 1405 { 1406 if (!descriptor) 1407 return; 1408 1409 if (descriptor->buffer_log) { 1410 fStack->FreeChunk(descriptor->buffer_log, 1411 (void *)descriptor->buffer_phy[0], descriptor->buffer_size); 1412 } 1413 1414 fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(ehci_qtd)); 1415 } 1416 1417 1418 void 1419 EHCI::FreeDescriptorChain(ehci_qtd *topDescriptor) 1420 { 1421 ehci_qtd *current = topDescriptor; 1422 ehci_qtd *next = NULL; 1423 1424 while (current) { 1425 next = (ehci_qtd *)current->next_log; 1426 FreeDescriptor(current); 1427 current = next; 1428 } 1429 } 1430 1431 1432 void 1433 EHCI::LinkDescriptors(ehci_qtd *first, ehci_qtd *last, ehci_qtd *alt) 1434 { 1435 first->next_phy = last->this_phy; 1436 first->next_log = last; 1437 1438 if (alt) { 1439 first->alt_next_phy = alt->this_phy; 1440 first->alt_next_log = alt; 1441 } else { 1442 first->alt_next_phy = EHCI_QTD_TERMINATE; 1443 first->alt_next_log = NULL; 1444 } 1445 } 1446 1447 1448 size_t 1449 EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, 1450 size_t vectorCount) 1451 { 1452 ehci_qtd *current = topDescriptor; 1453 size_t actualLength = 0; 1454 size_t vectorIndex = 0; 1455 size_t vectorOffset = 0; 1456 size_t bufferOffset = 0; 1457 1458 while (current) { 1459 if (!current->buffer_log) 1460 break; 1461 1462 while (true) { 1463 size_t length = min_c(current->buffer_size - bufferOffset, 1464 vector[vectorIndex].iov_len - vectorOffset); 1465 1466 memcpy((uint8 *)current->buffer_log + bufferOffset, 1467 (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length); 1468 1469 actualLength += length; 1470 vectorOffset += length; 1471 bufferOffset += length; 1472 1473 if (vectorOffset >= vector[vectorIndex].iov_len) { 1474 if (++vectorIndex >= vectorCount) { 1475 TRACE(("usb_ehci: wrote descriptor chain (%ld bytes, no more vectors)\n", actualLength)); 1476 return actualLength; 1477 } 1478 1479 vectorOffset = 0; 1480 } 1481 1482 if (bufferOffset >= current->buffer_size) { 1483 bufferOffset = 0; 1484 break; 1485 } 1486 } 1487 1488 if (current->next_phy & EHCI_QTD_TERMINATE) 1489 break; 1490 1491 current = (ehci_qtd *)current->next_log; 1492 } 1493 1494 TRACE(("usb_ehci: wrote descriptor chain (%ld bytes)\n", actualLength)); 1495 return actualLength; 1496 } 1497 1498 1499 size_t 1500 EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, 1501 size_t vectorCount, bool *nextDataToggle) 1502 { 1503 uint32 dataToggle = 0; 1504 ehci_qtd *current = topDescriptor; 1505 size_t actualLength = 0; 1506 size_t vectorIndex = 0; 1507 size_t vectorOffset = 0; 1508 size_t bufferOffset = 0; 1509 1510 while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) { 1511 if (!current->buffer_log) 1512 break; 1513 1514 dataToggle = current->token & EHCI_QTD_DATA_TOGGLE; 1515 size_t bufferSize = current->buffer_size; 1516 bufferSize -= (current->token >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK; 1517 1518 while (true) { 1519 size_t length = min_c(bufferSize - bufferOffset, 1520 vector[vectorIndex].iov_len - vectorOffset); 1521 1522 memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset, 1523 (uint8 *)current->buffer_log + bufferOffset, length); 1524 1525 actualLength += length; 1526 vectorOffset += length; 1527 bufferOffset += length; 1528 1529 if (vectorOffset >= vector[vectorIndex].iov_len) { 1530 if (++vectorIndex >= vectorCount) { 1531 TRACE(("usb_ehci: read descriptor chain (%ld bytes, no more vectors)\n", actualLength)); 1532 *nextDataToggle = dataToggle > 0 ? true : false; 1533 return actualLength; 1534 } 1535 1536 vectorOffset = 0; 1537 } 1538 1539 if (bufferOffset >= bufferSize) { 1540 bufferOffset = 0; 1541 break; 1542 } 1543 } 1544 1545 if (current->next_phy & EHCI_QTD_TERMINATE) 1546 break; 1547 1548 current = (ehci_qtd *)current->next_log; 1549 } 1550 1551 TRACE(("usb_ehci: read descriptor chain (%ld bytes)\n", actualLength)); 1552 *nextDataToggle = dataToggle > 0 ? true : false; 1553 return actualLength; 1554 } 1555 1556 1557 size_t 1558 EHCI::ReadActualLength(ehci_qtd *topDescriptor, bool *nextDataToggle) 1559 { 1560 size_t actualLength = 0; 1561 ehci_qtd *current = topDescriptor; 1562 uint32 dataToggle = 0; 1563 1564 while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) { 1565 dataToggle = current->token & EHCI_QTD_DATA_TOGGLE; 1566 size_t length = current->buffer_size; 1567 length -= (current->token >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK; 1568 actualLength += length; 1569 1570 if (current->next_phy & EHCI_QTD_TERMINATE) 1571 break; 1572 1573 current = (ehci_qtd *)current->next_log; 1574 } 1575 1576 TRACE(("usb_ehci: read actual length (%ld bytes)\n", actualLength)); 1577 *nextDataToggle = dataToggle > 0 ? true : false; 1578 return actualLength; 1579 } 1580 1581 1582 inline void 1583 EHCI::WriteOpReg(uint32 reg, uint32 value) 1584 { 1585 *(volatile uint32 *)(fOperationalRegisters + reg) = value; 1586 } 1587 1588 1589 inline uint32 1590 EHCI::ReadOpReg(uint32 reg) 1591 { 1592 return *(volatile uint32 *)(fOperationalRegisters + reg); 1593 } 1594 1595 1596 inline uint8 1597 EHCI::ReadCapReg8(uint32 reg) 1598 { 1599 return *(volatile uint8 *)(fCapabilityRegisters + reg); 1600 } 1601 1602 1603 inline uint16 1604 EHCI::ReadCapReg16(uint32 reg) 1605 { 1606 return *(volatile uint16 *)(fCapabilityRegisters + reg); 1607 } 1608 1609 1610 inline uint32 1611 EHCI::ReadCapReg32(uint32 reg) 1612 { 1613 return *(volatile uint32 *)(fCapabilityRegisters + reg); 1614 } 1615