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 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 data->transfer = transfer; 839 data->queue_head = queueHead; 840 data->data_descriptor = dataDescriptor; 841 data->user_area = -1; 842 data->incoming = directionIn; 843 data->link = NULL; 844 845 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 846 if (directionIn) { 847 // we might need to access a buffer in userspace. this will not 848 // be possible in the kernel space finisher thread unless we 849 // get the proper area id for the space we need and then clone it 850 // before writing to it. this is of course terribly inefficient... 851 iovec *vector = transfer->Vector(); 852 size_t vectorCount = transfer->VectorCount(); 853 for (size_t i = 0; i < vectorCount; i++) { 854 if (IS_USER_ADDRESS(vector[i].iov_base)) { 855 data->user_area = area_for(vector[i].iov_base); 856 if (data->user_area < B_OK) { 857 TRACE_ERROR(("usb_ehci: failed to get area of userspace buffer\n")); 858 delete data; 859 return B_BAD_ADDRESS; 860 } 861 862 break; 863 } 864 } 865 866 if (data->user_area >= B_OK) { 867 area_info areaInfo; 868 if (get_area_info(data->user_area, &areaInfo) < B_OK) { 869 TRACE_ERROR(("usb_ehci: failed to get info about user area\n")); 870 delete data; 871 return B_BAD_ADDRESS; 872 } 873 874 for (size_t i = 0; i < vectorCount; i++) { 875 (uint8 *)vector[i].iov_base -= (uint8 *)areaInfo.address; 876 877 if ((size_t)vector[i].iov_base > areaInfo.size 878 || (size_t)vector[i].iov_base + vector[i].iov_len > areaInfo.size) { 879 TRACE_ERROR(("usb_ehci: output data buffer spans across multiple areas!\n")); 880 delete data; 881 return B_BAD_ADDRESS; 882 } 883 } 884 } 885 } 886 #endif // !HAIKU_TARGET_PLATFORM_HAIKU 887 888 if (!Lock()) { 889 delete data; 890 return B_ERROR; 891 } 892 893 if (fLastTransfer) 894 fLastTransfer->link = data; 895 else 896 fFirstTransfer = data; 897 898 fLastTransfer = data; 899 Unlock(); 900 901 return B_OK; 902 } 903 904 905 status_t 906 EHCI::CancelPendingTransfer(Transfer *transfer) 907 { 908 if (!Lock()) 909 return B_ERROR; 910 911 transfer_data *last = NULL; 912 transfer_data *current = fFirstTransfer; 913 while (current) { 914 if (current->transfer == transfer) { 915 current->transfer->Finished(B_CANCELED, 0); 916 delete current->transfer; 917 918 if (last) 919 last->link = current->link; 920 else 921 fFirstTransfer = current->link; 922 923 if (fLastTransfer == current) 924 fLastTransfer = last; 925 926 delete current; 927 Unlock(); 928 return B_OK; 929 } 930 931 last = current; 932 current = current->link; 933 } 934 935 Unlock(); 936 return B_BAD_VALUE; 937 } 938 939 940 status_t 941 EHCI::CancelAllPendingTransfers() 942 { 943 if (!Lock()) 944 return B_ERROR; 945 946 transfer_data *transfer = fFirstTransfer; 947 while (transfer) { 948 transfer->transfer->Finished(B_CANCELED, 0); 949 delete transfer->transfer; 950 951 transfer_data *next = transfer->link; 952 delete transfer; 953 transfer = next; 954 } 955 956 fFirstTransfer = NULL; 957 fLastTransfer = NULL; 958 Unlock(); 959 return B_OK; 960 } 961 962 963 int32 964 EHCI::FinishThread(void *data) 965 { 966 ((EHCI *)data)->FinishTransfers(); 967 return B_OK; 968 } 969 970 971 void 972 EHCI::FinishTransfers() 973 { 974 while (!fStopThreads) { 975 if (acquire_sem(fFinishTransfersSem) < B_OK) 976 continue; 977 978 // eat up sems that have been released by multiple interrupts 979 int32 semCount = 0; 980 get_sem_count(fFinishTransfersSem, &semCount); 981 if (semCount > 0) 982 acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); 983 984 if (!Lock()) 985 continue; 986 987 TRACE(("usb_ehci: finishing transfers\n")); 988 transfer_data *lastTransfer = NULL; 989 transfer_data *transfer = fFirstTransfer; 990 Unlock(); 991 992 while (transfer) { 993 bool transferDone = false; 994 ehci_qtd *descriptor = (ehci_qtd *)transfer->queue_head->element_log; 995 996 #ifdef TRACE_USB 997 print_queue(transfer->queue_head); 998 #endif 999 1000 while (descriptor) { 1001 uint32 status = descriptor->token; 1002 if (status & EHCI_QTD_STATUS_ACTIVE) { 1003 // still in progress 1004 TRACE(("usb_ehci: qtd (0x%08lx) still active\n", descriptor->this_phy)); 1005 break; 1006 } 1007 1008 if (status & EHCI_QTD_STATUS_ERRMASK) { 1009 // a transfer error occured 1010 TRACE_ERROR(("usb_ehci: qtd (0x%08lx) error: 0x%08lx\n", descriptor->this_phy, status)); 1011 1012 status_t callbackStatus = B_ERROR; 1013 uint8 errorCount = status >> EHCI_QTD_ERRCOUNT_SHIFT; 1014 errorCount &= EHCI_QTD_ERRCOUNT_MASK; 1015 if (errorCount == 0) { 1016 // the error counter counted down to zero, report why 1017 int32 reasons = 0; 1018 if (status & EHCI_QTD_STATUS_BUFFER) { 1019 callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN; 1020 reasons++; 1021 } 1022 if (status & EHCI_QTD_STATUS_TERROR) { 1023 callbackStatus = B_DEV_CRC_ERROR; 1024 reasons++; 1025 } 1026 1027 if (reasons > 1) 1028 callbackStatus = B_DEV_MULTIPLE_ERRORS; 1029 } else if (status & EHCI_QTD_STATUS_BABBLE) { 1030 // there is a babble condition 1031 callbackStatus = transfer->incoming ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN; 1032 } else { 1033 // if the error counter didn't count down to zero 1034 // and there was no babble, then this halt was caused 1035 // by a stall handshake 1036 callbackStatus = B_DEV_STALLED; 1037 } 1038 1039 UnlinkQueueHead(transfer->queue_head, &fFreeListHead); 1040 transfer->transfer->Finished(callbackStatus, 0); 1041 transferDone = true; 1042 break; 1043 } 1044 1045 if (descriptor->next_phy & EHCI_QTD_TERMINATE) { 1046 // we arrived at the last (stray) descriptor, we're done 1047 TRACE(("usb_ehci: qtd (0x%08lx) done\n", descriptor->this_phy)); 1048 1049 size_t actualLength = 0; 1050 bool nextDataToggle = false; 1051 if (transfer->data_descriptor && transfer->incoming) { 1052 // data to read out 1053 iovec *vector = transfer->transfer->Vector(); 1054 size_t vectorCount = transfer->transfer->VectorCount(); 1055 1056 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 1057 area_id clonedArea = -1; 1058 if (transfer->user_area >= B_OK) { 1059 // we got a userspace output buffer, need to clone 1060 // the area for that space first and map the iovecs 1061 // to this cloned area. 1062 void *clonedMemory = NULL; 1063 clonedArea = clone_area("userspace accessor", 1064 &clonedMemory, B_ANY_ADDRESS, 1065 B_WRITE_AREA | B_KERNEL_WRITE_AREA, 1066 transfer->user_area); 1067 1068 for (size_t i = 0; i < vectorCount; i++) 1069 (uint8 *)vector[i].iov_base += (addr_t)clonedMemory; 1070 } 1071 #endif // !HAIKU_TARGET_PLATFORM_HAIKU 1072 1073 actualLength = ReadDescriptorChain( 1074 transfer->data_descriptor, 1075 vector, vectorCount, 1076 &nextDataToggle); 1077 1078 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 1079 if (clonedArea >= B_OK) 1080 delete_area(clonedArea); 1081 #endif // !HAIKU_TARGET_PLATFORM_HAIKU 1082 } else { 1083 // calculate transfered length 1084 actualLength = ReadActualLength( 1085 (ehci_qtd *)transfer->queue_head->element_log, 1086 &nextDataToggle); 1087 } 1088 1089 UnlinkQueueHead(transfer->queue_head, &fFreeListHead); 1090 transfer->transfer->TransferPipe()->SetDataToggle(nextDataToggle); 1091 transfer->transfer->Finished(B_OK, actualLength); 1092 transferDone = true; 1093 break; 1094 } 1095 1096 descriptor = (ehci_qtd *)descriptor->next_log; 1097 } 1098 1099 if (transferDone) { 1100 if (Lock()) { 1101 if (lastTransfer) 1102 lastTransfer->link = transfer->link; 1103 1104 if (transfer == fFirstTransfer) 1105 fFirstTransfer = transfer->link; 1106 if (transfer == fLastTransfer) 1107 fLastTransfer = lastTransfer; 1108 1109 transfer_data *next = transfer->link; 1110 delete transfer->transfer; 1111 delete transfer; 1112 transfer = next; 1113 Unlock(); 1114 } 1115 } else { 1116 if (Lock()) { 1117 lastTransfer = transfer; 1118 transfer = transfer->link; 1119 Unlock(); 1120 } 1121 } 1122 1123 release_sem(fCleanupSem); 1124 } 1125 } 1126 } 1127 1128 1129 int32 1130 EHCI::CleanupThread(void *data) 1131 { 1132 ((EHCI *)data)->Cleanup(); 1133 return B_OK; 1134 } 1135 1136 1137 void 1138 EHCI::Cleanup() 1139 { 1140 ehci_qh *lastFreeListHead = NULL; 1141 1142 while (!fStopThreads) { 1143 if (acquire_sem(fCleanupSem) < B_OK) 1144 continue; 1145 1146 ehci_qh *freeListHead = fFreeListHead; 1147 if (freeListHead == lastFreeListHead) 1148 continue; 1149 1150 // set the doorbell and wait for the host controller to notify us 1151 WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD); 1152 if (acquire_sem(fAsyncAdvanceSem) < B_OK) 1153 continue; 1154 1155 ehci_qh *current = freeListHead; 1156 while (current != lastFreeListHead) { 1157 ehci_qh *next = (ehci_qh *)current->next_log; 1158 FreeQueueHead(current); 1159 current = next; 1160 } 1161 1162 lastFreeListHead = freeListHead; 1163 } 1164 } 1165 1166 1167 ehci_qh * 1168 EHCI::CreateQueueHead() 1169 { 1170 ehci_qh *result; 1171 void *physicalAddress; 1172 if (fStack->AllocateChunk((void **)&result, &physicalAddress, 1173 sizeof(ehci_qh)) < B_OK) { 1174 TRACE_ERROR(("usb_ehci: failed to allocate queue head\n")); 1175 return NULL; 1176 } 1177 1178 result->this_phy = (addr_t)physicalAddress; 1179 result->next_phy = EHCI_QH_TERMINATE; 1180 result->next_log = NULL; 1181 result->prev_log = NULL; 1182 1183 ehci_qtd *descriptor = CreateDescriptor(0, 0); 1184 if (!descriptor) { 1185 TRACE_ERROR(("usb_ehci: failed to allocate initial qtd for queue head\n")); 1186 fStack->FreeChunk(result, (void *)result->this_phy, sizeof(ehci_qh)); 1187 return NULL; 1188 } 1189 1190 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE; 1191 result->stray_log = descriptor; 1192 result->element_log = descriptor; 1193 result->current_qtd_phy = EHCI_QTD_TERMINATE; 1194 result->overlay.next_phy = descriptor->this_phy; 1195 result->overlay.alt_next_phy = EHCI_QTD_TERMINATE; 1196 result->overlay.token = 0; 1197 for (int32 i = 0; i < 5; i++) { 1198 result->overlay.buffer_phy[i] = 0; 1199 result->overlay.ext_buffer_phy[i] = 0; 1200 } 1201 1202 return result; 1203 } 1204 1205 1206 void 1207 EHCI::FreeQueueHead(ehci_qh *queueHead) 1208 { 1209 if (!queueHead) 1210 return; 1211 1212 FreeDescriptorChain((ehci_qtd *)queueHead->element_log); 1213 FreeDescriptor((ehci_qtd *)queueHead->stray_log); 1214 fStack->FreeChunk(queueHead, (void *)queueHead->this_phy, sizeof(ehci_qh)); 1215 } 1216 1217 1218 status_t 1219 EHCI::LinkQueueHead(ehci_qh *queueHead) 1220 { 1221 if (!Lock()) 1222 return B_ERROR; 1223 1224 ehci_qh *prevHead = (ehci_qh *)fAsyncQueueHead->prev_log; 1225 queueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH; 1226 queueHead->next_log = fAsyncQueueHead; 1227 queueHead->prev_log = prevHead; 1228 fAsyncQueueHead->prev_log = queueHead; 1229 prevHead->next_log = queueHead; 1230 prevHead->next_phy = queueHead->this_phy | EHCI_QH_TYPE_QH; 1231 1232 Unlock(); 1233 return B_OK; 1234 } 1235 1236 1237 status_t 1238 EHCI::UnlinkQueueHead(ehci_qh *queueHead, ehci_qh **freeListHead) 1239 { 1240 if (!Lock()) 1241 return B_ERROR; 1242 1243 ehci_qh *prevHead = (ehci_qh *)queueHead->prev_log; 1244 ehci_qh *nextHead = (ehci_qh *)queueHead->next_log; 1245 prevHead->next_phy = queueHead->next_phy | EHCI_QH_TYPE_QH; 1246 prevHead->next_log = queueHead->next_log; 1247 nextHead->prev_log = queueHead->prev_log; 1248 queueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH; 1249 queueHead->next_log = NULL; 1250 queueHead->prev_log = NULL; 1251 1252 queueHead->next_log = *freeListHead; 1253 *freeListHead = queueHead; 1254 1255 Unlock(); 1256 return B_OK; 1257 } 1258 1259 1260 status_t 1261 EHCI::FillQueueWithRequest(Transfer *transfer, ehci_qh *queueHead, 1262 ehci_qtd **_dataDescriptor, bool *_directionIn) 1263 { 1264 Pipe *pipe = transfer->TransferPipe(); 1265 usb_request_data *requestData = transfer->RequestData(); 1266 bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0; 1267 1268 ehci_qtd *setupDescriptor = CreateDescriptor(sizeof(usb_request_data), 1269 EHCI_QTD_PID_SETUP); 1270 ehci_qtd *statusDescriptor = CreateDescriptor(0, 1271 directionIn ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN); 1272 1273 if (!setupDescriptor || !statusDescriptor) { 1274 TRACE_ERROR(("usb_ehci: failed to allocate descriptors\n")); 1275 FreeDescriptor(setupDescriptor); 1276 FreeDescriptor(statusDescriptor); 1277 return B_NO_MEMORY; 1278 } 1279 1280 iovec vector; 1281 vector.iov_base = requestData; 1282 vector.iov_len = sizeof(usb_request_data); 1283 WriteDescriptorChain(setupDescriptor, &vector, 1); 1284 1285 ehci_qtd *strayDescriptor = (ehci_qtd *)queueHead->stray_log; 1286 statusDescriptor->token |= EHCI_QTD_IOC | EHCI_QTD_DATA_TOGGLE; 1287 1288 ehci_qtd *dataDescriptor = NULL; 1289 if (transfer->VectorCount() > 0) { 1290 ehci_qtd *lastDescriptor = NULL; 1291 status_t result = CreateDescriptorChain(pipe, &dataDescriptor, 1292 &lastDescriptor, strayDescriptor, transfer->VectorLength(), 1293 directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT); 1294 1295 if (result < B_OK) { 1296 FreeDescriptor(setupDescriptor); 1297 FreeDescriptor(statusDescriptor); 1298 return result; 1299 } 1300 1301 if (!directionIn) { 1302 WriteDescriptorChain(dataDescriptor, transfer->Vector(), 1303 transfer->VectorCount()); 1304 } 1305 1306 LinkDescriptors(setupDescriptor, dataDescriptor, strayDescriptor); 1307 LinkDescriptors(lastDescriptor, statusDescriptor, strayDescriptor); 1308 } else { 1309 // no data: link setup and status descriptors directly 1310 LinkDescriptors(setupDescriptor, statusDescriptor, strayDescriptor); 1311 } 1312 1313 queueHead->element_log = setupDescriptor; 1314 queueHead->overlay.next_phy = setupDescriptor->this_phy; 1315 queueHead->overlay.alt_next_phy = EHCI_QTD_TERMINATE; 1316 1317 *_dataDescriptor = dataDescriptor; 1318 *_directionIn = directionIn; 1319 return B_OK; 1320 } 1321 1322 1323 status_t 1324 EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead, 1325 ehci_qtd **_dataDescriptor, bool *_directionIn) 1326 { 1327 Pipe *pipe = transfer->TransferPipe(); 1328 bool directionIn = (pipe->Direction() == Pipe::In); 1329 1330 ehci_qtd *firstDescriptor = NULL; 1331 ehci_qtd *lastDescriptor = NULL; 1332 ehci_qtd *strayDescriptor = (ehci_qtd *)queueHead->stray_log; 1333 status_t result = CreateDescriptorChain(pipe, &firstDescriptor, 1334 &lastDescriptor, strayDescriptor, transfer->VectorLength(), 1335 directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT); 1336 1337 if (result < B_OK) 1338 return result; 1339 1340 lastDescriptor->token |= EHCI_QTD_IOC; 1341 if (!directionIn) { 1342 WriteDescriptorChain(firstDescriptor, transfer->Vector(), 1343 transfer->VectorCount()); 1344 } 1345 1346 queueHead->element_log = firstDescriptor; 1347 queueHead->overlay.next_phy = firstDescriptor->this_phy; 1348 queueHead->overlay.alt_next_phy = EHCI_QTD_TERMINATE; 1349 1350 *_dataDescriptor = firstDescriptor; 1351 *_directionIn = directionIn; 1352 return B_OK; 1353 } 1354 1355 1356 ehci_qtd * 1357 EHCI::CreateDescriptor(size_t bufferSize, uint8 pid) 1358 { 1359 ehci_qtd *result; 1360 void *physicalAddress; 1361 if (fStack->AllocateChunk((void **)&result, &physicalAddress, 1362 sizeof(ehci_qtd)) < B_OK) { 1363 TRACE_ERROR(("usb_ehci: failed to allocate a qtd\n")); 1364 return NULL; 1365 } 1366 1367 result->this_phy = (addr_t)physicalAddress; 1368 result->next_phy = EHCI_QTD_TERMINATE; 1369 result->next_log = NULL; 1370 result->alt_next_phy = EHCI_QTD_TERMINATE; 1371 result->alt_next_log = NULL; 1372 result->buffer_size = bufferSize; 1373 result->token = bufferSize << EHCI_QTD_BYTES_SHIFT; 1374 result->token |= 3 << EHCI_QTD_ERRCOUNT_SHIFT; 1375 result->token |= pid << EHCI_QTD_PID_SHIFT; 1376 result->token |= EHCI_QTD_STATUS_ACTIVE; 1377 if (bufferSize == 0) { 1378 result->buffer_log = NULL; 1379 for (int32 i = 0; i < 5; i++) { 1380 result->buffer_phy[i] = 0; 1381 result->ext_buffer_phy[i] = 0; 1382 } 1383 1384 return result; 1385 } 1386 1387 if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress, 1388 bufferSize) < B_OK) { 1389 TRACE_ERROR(("usb_ehci: unable to allocate qtd buffer\n")); 1390 fStack->FreeChunk(result, (void *)result->this_phy, sizeof(ehci_qtd)); 1391 return NULL; 1392 } 1393 1394 addr_t physicalBase = (addr_t)physicalAddress; 1395 result->buffer_phy[0] = physicalBase; 1396 result->ext_buffer_phy[0] = 0; 1397 for (int32 i = 1; i < 5; i++) { 1398 physicalBase += B_PAGE_SIZE; 1399 result->buffer_phy[i] = physicalBase & EHCI_QTD_PAGE_MASK; 1400 result->ext_buffer_phy[i] = 0; 1401 } 1402 1403 return result; 1404 } 1405 1406 1407 status_t 1408 EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor, 1409 ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize, 1410 uint8 pid) 1411 { 1412 size_t packetSize = B_PAGE_SIZE * 4; 1413 int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize; 1414 1415 bool dataToggle = pipe->DataToggle(); 1416 ehci_qtd *firstDescriptor = NULL; 1417 ehci_qtd *lastDescriptor = *_firstDescriptor; 1418 for (int32 i = 0; i < descriptorCount; i++) { 1419 ehci_qtd *descriptor = CreateDescriptor(min_c(packetSize, bufferSize), 1420 pid); 1421 1422 if (!descriptor) { 1423 FreeDescriptorChain(firstDescriptor); 1424 return B_NO_MEMORY; 1425 } 1426 1427 if (dataToggle) 1428 descriptor->token |= EHCI_QTD_DATA_TOGGLE; 1429 1430 if (lastDescriptor) 1431 LinkDescriptors(lastDescriptor, descriptor, strayDescriptor); 1432 1433 bufferSize -= packetSize; 1434 lastDescriptor = descriptor; 1435 if (!firstDescriptor) 1436 firstDescriptor = descriptor; 1437 } 1438 1439 *_firstDescriptor = firstDescriptor; 1440 *_lastDescriptor = lastDescriptor; 1441 return B_OK; 1442 } 1443 1444 1445 void 1446 EHCI::FreeDescriptor(ehci_qtd *descriptor) 1447 { 1448 if (!descriptor) 1449 return; 1450 1451 if (descriptor->buffer_log) { 1452 fStack->FreeChunk(descriptor->buffer_log, 1453 (void *)descriptor->buffer_phy[0], descriptor->buffer_size); 1454 } 1455 1456 fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(ehci_qtd)); 1457 } 1458 1459 1460 void 1461 EHCI::FreeDescriptorChain(ehci_qtd *topDescriptor) 1462 { 1463 ehci_qtd *current = topDescriptor; 1464 ehci_qtd *next = NULL; 1465 1466 while (current) { 1467 next = (ehci_qtd *)current->next_log; 1468 FreeDescriptor(current); 1469 current = next; 1470 } 1471 } 1472 1473 1474 void 1475 EHCI::LinkDescriptors(ehci_qtd *first, ehci_qtd *last, ehci_qtd *alt) 1476 { 1477 first->next_phy = last->this_phy; 1478 first->next_log = last; 1479 1480 if (alt) { 1481 first->alt_next_phy = alt->this_phy; 1482 first->alt_next_log = alt; 1483 } else { 1484 first->alt_next_phy = EHCI_QTD_TERMINATE; 1485 first->alt_next_log = NULL; 1486 } 1487 } 1488 1489 1490 size_t 1491 EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, 1492 size_t vectorCount) 1493 { 1494 ehci_qtd *current = topDescriptor; 1495 size_t actualLength = 0; 1496 size_t vectorIndex = 0; 1497 size_t vectorOffset = 0; 1498 size_t bufferOffset = 0; 1499 1500 while (current) { 1501 if (!current->buffer_log) 1502 break; 1503 1504 while (true) { 1505 size_t length = min_c(current->buffer_size - bufferOffset, 1506 vector[vectorIndex].iov_len - vectorOffset); 1507 1508 memcpy((uint8 *)current->buffer_log + bufferOffset, 1509 (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length); 1510 1511 actualLength += length; 1512 vectorOffset += length; 1513 bufferOffset += length; 1514 1515 if (vectorOffset >= vector[vectorIndex].iov_len) { 1516 if (++vectorIndex >= vectorCount) { 1517 TRACE(("usb_ehci: wrote descriptor chain (%ld bytes, no more vectors)\n", actualLength)); 1518 return actualLength; 1519 } 1520 1521 vectorOffset = 0; 1522 } 1523 1524 if (bufferOffset >= current->buffer_size) { 1525 bufferOffset = 0; 1526 break; 1527 } 1528 } 1529 1530 if (current->next_phy & EHCI_QTD_TERMINATE) 1531 break; 1532 1533 current = (ehci_qtd *)current->next_log; 1534 } 1535 1536 TRACE(("usb_ehci: wrote descriptor chain (%ld bytes)\n", actualLength)); 1537 return actualLength; 1538 } 1539 1540 1541 size_t 1542 EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector, 1543 size_t vectorCount, bool *nextDataToggle) 1544 { 1545 uint32 dataToggle = 0; 1546 ehci_qtd *current = topDescriptor; 1547 size_t actualLength = 0; 1548 size_t vectorIndex = 0; 1549 size_t vectorOffset = 0; 1550 size_t bufferOffset = 0; 1551 1552 while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) { 1553 if (!current->buffer_log) 1554 break; 1555 1556 dataToggle = current->token & EHCI_QTD_DATA_TOGGLE; 1557 size_t bufferSize = current->buffer_size; 1558 bufferSize -= (current->token >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK; 1559 1560 while (true) { 1561 size_t length = min_c(bufferSize - bufferOffset, 1562 vector[vectorIndex].iov_len - vectorOffset); 1563 1564 memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset, 1565 (uint8 *)current->buffer_log + bufferOffset, length); 1566 1567 actualLength += length; 1568 vectorOffset += length; 1569 bufferOffset += length; 1570 1571 if (vectorOffset >= vector[vectorIndex].iov_len) { 1572 if (++vectorIndex >= vectorCount) { 1573 TRACE(("usb_ehci: read descriptor chain (%ld bytes, no more vectors)\n", actualLength)); 1574 *nextDataToggle = dataToggle > 0 ? true : false; 1575 return actualLength; 1576 } 1577 1578 vectorOffset = 0; 1579 } 1580 1581 if (bufferOffset >= bufferSize) { 1582 bufferOffset = 0; 1583 break; 1584 } 1585 } 1586 1587 if (current->next_phy & EHCI_QTD_TERMINATE) 1588 break; 1589 1590 current = (ehci_qtd *)current->next_log; 1591 } 1592 1593 TRACE(("usb_ehci: read descriptor chain (%ld bytes)\n", actualLength)); 1594 *nextDataToggle = dataToggle > 0 ? true : false; 1595 return actualLength; 1596 } 1597 1598 1599 size_t 1600 EHCI::ReadActualLength(ehci_qtd *topDescriptor, bool *nextDataToggle) 1601 { 1602 size_t actualLength = 0; 1603 ehci_qtd *current = topDescriptor; 1604 uint32 dataToggle = 0; 1605 1606 while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) { 1607 dataToggle = current->token & EHCI_QTD_DATA_TOGGLE; 1608 size_t length = current->buffer_size; 1609 length -= (current->token >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK; 1610 actualLength += length; 1611 1612 if (current->next_phy & EHCI_QTD_TERMINATE) 1613 break; 1614 1615 current = (ehci_qtd *)current->next_log; 1616 } 1617 1618 TRACE(("usb_ehci: read actual length (%ld bytes)\n", actualLength)); 1619 *nextDataToggle = dataToggle > 0 ? true : false; 1620 return actualLength; 1621 } 1622 1623 1624 inline void 1625 EHCI::WriteOpReg(uint32 reg, uint32 value) 1626 { 1627 *(volatile uint32 *)(fOperationalRegisters + reg) = value; 1628 } 1629 1630 1631 inline uint32 1632 EHCI::ReadOpReg(uint32 reg) 1633 { 1634 return *(volatile uint32 *)(fOperationalRegisters + reg); 1635 } 1636 1637 1638 inline uint8 1639 EHCI::ReadCapReg8(uint32 reg) 1640 { 1641 return *(volatile uint8 *)(fCapabilityRegisters + reg); 1642 } 1643 1644 1645 inline uint16 1646 EHCI::ReadCapReg16(uint32 reg) 1647 { 1648 return *(volatile uint16 *)(fCapabilityRegisters + reg); 1649 } 1650 1651 1652 inline uint32 1653 EHCI::ReadCapReg32(uint32 reg) 1654 { 1655 return *(volatile uint32 *)(fCapabilityRegisters + reg); 1656 } 1657