1 /* 2 * Copyright 2004-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 * Niels S. Reedijk 8 * Salvatore Benedetto <salvatore.benedetto@gmail.com> 9 */ 10 11 #include <module.h> 12 #include <PCI.h> 13 #include <USB3.h> 14 #include <KernelExport.h> 15 16 #include "uhci.h" 17 18 #define USB_MODULE_NAME "uhci" 19 20 pci_module_info *UHCI::sPCIModule = NULL; 21 22 static int32 sDebuggerCommandAdded = 0; 23 24 25 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 26 static int 27 debug_process_transfer(int argc, char **argv) 28 { 29 Pipe *pipe = (Pipe *)get_debug_variable("_usbPipe", 0); 30 if (pipe == NULL) 31 return 2; 32 33 // check if we have a UHCI bus at all 34 if (pipe->GetBusManager()->TypeName()[0] != 'u') 35 return 3; 36 37 uint8 *data = (uint8 *)get_debug_variable("_usbTransferData", 0); 38 if (data == NULL) 39 return 4; 40 41 size_t length = (size_t)get_debug_variable("_usbTransferLength", 0); 42 if (length == 0) 43 return 5; 44 45 Transfer transfer(pipe); 46 transfer.SetData(data, length); 47 return ((UHCI *)pipe->GetBusManager())->ProcessDebugTransfer(&transfer); 48 } 49 #endif 50 51 52 static int32 53 uhci_std_ops(int32 op, ...) 54 { 55 switch (op) { 56 case B_MODULE_INIT: 57 TRACE_MODULE("init module\n"); 58 return B_OK; 59 case B_MODULE_UNINIT: 60 TRACE_MODULE("uninit module\n"); 61 break; 62 default: 63 return EINVAL; 64 } 65 66 return B_OK; 67 } 68 69 70 usb_host_controller_info uhci_module = { 71 { 72 "busses/usb/uhci", 73 0, 74 uhci_std_ops 75 }, 76 NULL, 77 UHCI::AddTo 78 }; 79 80 81 module_info *modules[] = { 82 (module_info *)&uhci_module, 83 NULL 84 }; 85 86 87 // 88 // #pragma mark - 89 // 90 91 92 #ifdef TRACE_USB 93 94 void 95 print_descriptor_chain(uhci_td *descriptor) 96 { 97 while (descriptor) { 98 dprintf("ph: 0x%08lx; lp: 0x%08lx; vf: %s; q: %s; t: %s; st: 0x%08lx; to: 0x%08lx\n", 99 descriptor->this_phy & 0xffffffff, descriptor->link_phy & 0xfffffff0, 100 descriptor->link_phy & 0x4 ? "y" : "n", 101 descriptor->link_phy & 0x2 ? "qh" : "td", 102 descriptor->link_phy & 0x1 ? "y" : "n", 103 descriptor->status, descriptor->token); 104 105 if (descriptor->link_phy & TD_TERMINATE) 106 break; 107 108 descriptor = (uhci_td *)descriptor->link_log; 109 } 110 } 111 112 #endif // TRACE_USB 113 114 115 // 116 // #pragma mark - 117 // 118 119 120 Queue::Queue(Stack *stack) 121 { 122 fStack = stack; 123 124 mutex_init(&fLock, "uhci queue lock"); 125 126 void *physicalAddress; 127 fStatus = fStack->AllocateChunk((void **)&fQueueHead, &physicalAddress, 128 sizeof(uhci_qh)); 129 if (fStatus < B_OK) 130 return; 131 132 fQueueHead->this_phy = (addr_t)physicalAddress; 133 fQueueHead->element_phy = QH_TERMINATE; 134 135 fStrayDescriptor = NULL; 136 fQueueTop = NULL; 137 } 138 139 140 Queue::~Queue() 141 { 142 Lock(); 143 mutex_destroy(&fLock); 144 145 fStack->FreeChunk(fQueueHead, (void *)fQueueHead->this_phy, sizeof(uhci_qh)); 146 147 if (fStrayDescriptor) 148 fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy, 149 sizeof(uhci_td)); 150 } 151 152 153 status_t 154 Queue::InitCheck() 155 { 156 return fStatus; 157 } 158 159 160 bool 161 Queue::Lock() 162 { 163 return (mutex_lock(&fLock) == B_OK); 164 } 165 166 167 void 168 Queue::Unlock() 169 { 170 mutex_unlock(&fLock); 171 } 172 173 174 status_t 175 Queue::LinkTo(Queue *other) 176 { 177 if (!other) 178 return B_BAD_VALUE; 179 180 if (!Lock()) 181 return B_ERROR; 182 183 fQueueHead->link_phy = other->fQueueHead->this_phy | QH_NEXT_IS_QH; 184 fQueueHead->link_log = other->fQueueHead; 185 Unlock(); 186 187 return B_OK; 188 } 189 190 191 status_t 192 Queue::TerminateByStrayDescriptor() 193 { 194 // According to the *BSD USB sources, there needs to be a stray transfer 195 // descriptor in order to get some chipset to work nicely (like the PIIX). 196 void *physicalAddress; 197 status_t result = fStack->AllocateChunk((void **)&fStrayDescriptor, 198 &physicalAddress, sizeof(uhci_td)); 199 if (result < B_OK) { 200 TRACE_ERROR("failed to allocate a stray transfer descriptor\n"); 201 return result; 202 } 203 204 fStrayDescriptor->status = 0; 205 fStrayDescriptor->this_phy = (addr_t)physicalAddress; 206 fStrayDescriptor->link_phy = TD_TERMINATE; 207 fStrayDescriptor->link_log = NULL; 208 fStrayDescriptor->buffer_phy = 0; 209 fStrayDescriptor->buffer_log = NULL; 210 fStrayDescriptor->buffer_size = 0; 211 fStrayDescriptor->token = TD_TOKEN_NULL_DATA 212 | (0x7f << TD_TOKEN_DEVADDR_SHIFT) | TD_TOKEN_IN; 213 214 if (!Lock()) { 215 fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy, 216 sizeof(uhci_td)); 217 return B_ERROR; 218 } 219 220 fQueueHead->link_phy = fStrayDescriptor->this_phy; 221 fQueueHead->link_log = fStrayDescriptor; 222 Unlock(); 223 224 return B_OK; 225 } 226 227 228 status_t 229 Queue::AppendTransfer(uhci_qh *transfer, bool lock) 230 { 231 if (lock && !Lock()) 232 return B_ERROR; 233 234 transfer->link_log = NULL; 235 transfer->link_phy = fQueueHead->link_phy; 236 237 if (!fQueueTop) { 238 // the list is empty, make this the first element 239 fQueueTop = transfer; 240 fQueueHead->element_phy = transfer->this_phy | QH_NEXT_IS_QH; 241 } else { 242 // append the transfer queue to the list 243 uhci_qh *element = fQueueTop; 244 while (element && element->link_log) 245 element = (uhci_qh *)element->link_log; 246 247 element->link_log = transfer; 248 element->link_phy = transfer->this_phy | QH_NEXT_IS_QH; 249 } 250 251 if (lock) 252 Unlock(); 253 return B_OK; 254 } 255 256 257 status_t 258 Queue::RemoveTransfer(uhci_qh *transfer, bool lock) 259 { 260 if (lock && !Lock()) 261 return B_ERROR; 262 263 if (fQueueTop == transfer) { 264 // this was the top element 265 fQueueTop = (uhci_qh *)transfer->link_log; 266 if (!fQueueTop) { 267 // this was the only element, terminate this queue 268 fQueueHead->element_phy = QH_TERMINATE; 269 } else { 270 // there are elements left, adjust the element pointer 271 fQueueHead->element_phy = transfer->link_phy; 272 } 273 274 if (lock) 275 Unlock(); 276 return B_OK; 277 } else { 278 uhci_qh *element = fQueueTop; 279 while (element) { 280 if (element->link_log == transfer) { 281 element->link_log = transfer->link_log; 282 element->link_phy = transfer->link_phy; 283 if (lock) 284 Unlock(); 285 return B_OK; 286 } 287 288 element = (uhci_qh *)element->link_log; 289 } 290 } 291 292 if (lock) 293 Unlock(); 294 return B_BAD_VALUE; 295 } 296 297 298 addr_t 299 Queue::PhysicalAddress() 300 { 301 return fQueueHead->this_phy; 302 } 303 304 305 void 306 Queue::PrintToStream() 307 { 308 #ifdef TRACE_USB 309 TRACE("queue:\n"); 310 dprintf("link phy: 0x%08lx; link type: %s; terminate: %s\n", fQueueHead->link_phy & 0xfff0, fQueueHead->link_phy & 0x0002 ? "QH" : "TD", fQueueHead->link_phy & 0x0001 ? "yes" : "no"); 311 dprintf("elem phy: 0x%08lx; elem type: %s; terminate: %s\n", fQueueHead->element_phy & 0xfff0, fQueueHead->element_phy & 0x0002 ? "QH" : "TD", fQueueHead->element_phy & 0x0001 ? "yes" : "no"); 312 #endif 313 } 314 315 316 // 317 // #pragma mark - 318 // 319 320 321 UHCI::UHCI(pci_info *info, Stack *stack) 322 : BusManager(stack), 323 fPCIInfo(info), 324 fStack(stack), 325 fEnabledInterrupts(0), 326 fFrameArea(-1), 327 fFrameList(NULL), 328 fFrameBandwidth(NULL), 329 fFirstIsochronousDescriptor(NULL), 330 fLastIsochronousDescriptor(NULL), 331 fQueueCount(0), 332 fQueues(NULL), 333 fFirstTransfer(NULL), 334 fLastTransfer(NULL), 335 fFinishTransfersSem(-1), 336 fFinishThread(-1), 337 fStopThreads(false), 338 fFreeList(NULL), 339 fCleanupThread(-1), 340 fCleanupSem(-1), 341 fCleanupCount(0), 342 fFirstIsochronousTransfer(NULL), 343 fLastIsochronousTransfer(NULL), 344 fFinishIsochronousTransfersSem(-1), 345 fFinishIsochronousThread(-1), 346 fRootHub(NULL), 347 fRootHubAddress(0), 348 fPortResetChange(0) 349 { 350 if (!fInitOK) { 351 TRACE_ERROR("bus manager failed to init\n"); 352 return; 353 } 354 355 TRACE("constructing new UHCI host controller driver\n"); 356 fInitOK = false; 357 358 fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus, 359 fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4); 360 fRegisterBase &= PCI_address_io_mask; 361 TRACE("iospace offset: 0x%08lx\n", fRegisterBase); 362 363 if (fRegisterBase == 0) { 364 fRegisterBase = fPCIInfo->u.h0.base_registers[0]; 365 TRACE_ALWAYS("register base: 0x%08lx\n", fRegisterBase); 366 } 367 368 // enable pci address access 369 uint16 command = PCI_command_io | PCI_command_master | PCI_command_memory; 370 command |= sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device, 371 fPCIInfo->function, PCI_command, 2); 372 373 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 374 fPCIInfo->function, PCI_command, 2, command); 375 376 // disable interrupts 377 WriteReg16(UHCI_USBINTR, 0); 378 379 // make sure we gain control of the UHCI controller instead of the BIOS 380 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 381 fPCIInfo->function, PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN 382 | PCI_LEGSUP_CLEAR_SMI); 383 384 // do a global and host reset 385 GlobalReset(); 386 if (ControllerReset() < B_OK) { 387 TRACE_ERROR("host failed to reset\n"); 388 return; 389 } 390 391 // Setup the frame list 392 void *physicalAddress; 393 fFrameArea = fStack->AllocateArea((void **)&fFrameList, 394 (void **)&physicalAddress, 4096, "USB UHCI framelist"); 395 396 if (fFrameArea < B_OK) { 397 TRACE_ERROR("unable to create an area for the frame pointer list\n"); 398 return; 399 } 400 401 // Set base pointer and reset frame number 402 WriteReg32(UHCI_FRBASEADD, (uint32)physicalAddress); 403 WriteReg16(UHCI_FRNUM, 0); 404 405 // Set the max packet size for bandwidth reclamation to 64 bytes 406 WriteReg16(UHCI_USBCMD, ReadReg16(UHCI_USBCMD) | UHCI_USBCMD_MAXP); 407 408 // we will create four queues: 409 // 0: interrupt transfers 410 // 1: low speed control transfers 411 // 2: full speed control transfers 412 // 3: bulk transfers 413 // 4: debug queue 414 // TODO: 4: bandwidth reclamation queue 415 fQueueCount = 5; 416 fQueues = new(std::nothrow) Queue *[fQueueCount]; 417 if (!fQueues) { 418 delete_area(fFrameArea); 419 return; 420 } 421 422 for (int32 i = 0; i < fQueueCount; i++) { 423 fQueues[i] = new(std::nothrow) Queue(fStack); 424 if (!fQueues[i] || fQueues[i]->InitCheck() < B_OK) { 425 TRACE_ERROR("cannot create queues\n"); 426 delete_area(fFrameArea); 427 return; 428 } 429 430 if (i > 0) 431 fQueues[i - 1]->LinkTo(fQueues[i]); 432 } 433 434 // Make sure the last queue terminates 435 fQueues[fQueueCount - 1]->TerminateByStrayDescriptor(); 436 437 // Create the array that will keep bandwidth information 438 fFrameBandwidth = new(std::nothrow) uint16[NUMBER_OF_FRAMES]; 439 440 // Create lists for managing isochronous transfer descriptors 441 fFirstIsochronousDescriptor = new(std::nothrow) uhci_td *[NUMBER_OF_FRAMES]; 442 if (!fFirstIsochronousDescriptor) { 443 TRACE_ERROR("faild to allocate memory for first isochronous descriptor\n"); 444 return; 445 } 446 447 fLastIsochronousDescriptor = new(std::nothrow) uhci_td *[NUMBER_OF_FRAMES]; 448 if (!fLastIsochronousDescriptor) { 449 TRACE_ERROR("failed to allocate memory for last isochronous descriptor\n"); 450 delete [] fFirstIsochronousDescriptor; 451 return; 452 } 453 454 for (int32 i = 0; i < NUMBER_OF_FRAMES; i++) { 455 fFrameList[i] = fQueues[UHCI_INTERRUPT_QUEUE]->PhysicalAddress() 456 | FRAMELIST_NEXT_IS_QH; 457 fFrameBandwidth[i] = MAX_AVAILABLE_BANDWIDTH; 458 fFirstIsochronousDescriptor[i] = NULL; 459 fLastIsochronousDescriptor[i] = NULL; 460 } 461 462 // Create semaphore the finisher and cleanup threads will wait for 463 fFinishTransfersSem = create_sem(0, "UHCI Finish Transfers"); 464 if (fFinishTransfersSem < B_OK) { 465 TRACE_ERROR("failed to create finisher semaphore\n"); 466 return; 467 } 468 469 fCleanupSem = create_sem(0, "UHCI Cleanup"); 470 if (fCleanupSem < B_OK) { 471 TRACE_ERROR("failed to create cleanup semaphore\n"); 472 return; 473 } 474 475 // Create the finisher service and cleanup threads 476 fFinishThread = spawn_kernel_thread(FinishThread, 477 "uhci finish thread", B_URGENT_DISPLAY_PRIORITY, (void *)this); 478 resume_thread(fFinishThread); 479 480 fCleanupThread = spawn_kernel_thread(CleanupThread, 481 "uhci cleanup thread", B_NORMAL_PRIORITY, (void *)this); 482 resume_thread(fCleanupThread); 483 484 // Create a lock for the isochronous transfer list 485 mutex_init(&fIsochronousLock, "UHCI isochronous lock"); 486 487 // Create semaphore the isochronous finisher thread will wait for 488 fFinishIsochronousTransfersSem = create_sem(0, 489 "UHCI Isochronous Finish Transfers"); 490 if (fFinishIsochronousTransfersSem < B_OK) { 491 TRACE_ERROR("failed to create isochronous finisher semaphore\n"); 492 return; 493 } 494 495 // Create the isochronous finisher service thread 496 fFinishIsochronousThread = spawn_kernel_thread(FinishIsochronousThread, 497 "uhci isochronous finish thread", B_URGENT_DISPLAY_PRIORITY, 498 (void *)this); 499 resume_thread(fFinishIsochronousThread); 500 501 // Install the interrupt handler 502 TRACE("installing interrupt handler\n"); 503 install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, 504 InterruptHandler, (void *)this, 0); 505 506 // Enable interrupts 507 fEnabledInterrupts = UHCI_USBSTS_USBINT | UHCI_USBSTS_ERRINT 508 | UHCI_USBSTS_HOSTERR | UHCI_USBSTS_HCPRERR | UHCI_USBSTS_HCHALT; 509 WriteReg16(UHCI_USBINTR, UHCI_USBINTR_CRC | UHCI_USBINTR_IOC 510 | UHCI_USBINTR_SHORT); 511 512 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 513 if (atomic_add(&sDebuggerCommandAdded, 1) == 0) { 514 add_debugger_command("uhci_process_transfer", 515 &debug_process_transfer, 516 "Processes a USB transfer with the given variables"); 517 } 518 #endif 519 520 TRACE("UHCI host controller driver constructed\n"); 521 fInitOK = true; 522 } 523 524 525 UHCI::~UHCI() 526 { 527 #ifdef HAIKU_TARGET_PLATFORM_HAIKU 528 if (atomic_add(&sDebuggerCommandAdded, -1) == 1) { 529 remove_debugger_command("uhci_process_transfer", 530 &debug_process_transfer); 531 } 532 #endif 533 534 int32 result = 0; 535 fStopThreads = true; 536 delete_sem(fFinishTransfersSem); 537 delete_sem(fCleanupSem); 538 delete_sem(fFinishIsochronousTransfersSem); 539 wait_for_thread(fFinishThread, &result); 540 wait_for_thread(fCleanupThread, &result); 541 wait_for_thread(fFinishIsochronousThread, &result); 542 543 LockIsochronous(); 544 isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer; 545 while (isoTransfer) { 546 isochronous_transfer_data *next = isoTransfer->link; 547 delete isoTransfer; 548 isoTransfer = next; 549 } 550 mutex_destroy(&fIsochronousLock); 551 552 Lock(); 553 transfer_data *transfer = fFirstTransfer; 554 while (transfer) { 555 transfer->transfer->Finished(B_CANCELED, 0); 556 delete transfer->transfer; 557 558 transfer_data *next = transfer->link; 559 delete transfer; 560 transfer = next; 561 } 562 563 for (int32 i = 0; i < fQueueCount; i++) 564 delete fQueues[i]; 565 566 delete [] fQueues; 567 delete [] fFrameBandwidth; 568 delete [] fFirstIsochronousDescriptor; 569 delete [] fLastIsochronousDescriptor; 570 delete fRootHub; 571 delete_area(fFrameArea); 572 573 put_module(B_PCI_MODULE_NAME); 574 Unlock(); 575 } 576 577 578 status_t 579 UHCI::Start() 580 { 581 // Start the host controller, then start the Busmanager 582 TRACE("starting UHCI BusManager\n"); 583 TRACE("usbcmd reg 0x%04x, usbsts reg 0x%04x\n", 584 ReadReg16(UHCI_USBCMD), ReadReg16(UHCI_USBSTS)); 585 586 // Set the run bit in the command register 587 WriteReg16(UHCI_USBCMD, ReadReg16(UHCI_USBCMD) | UHCI_USBCMD_RS); 588 589 bool running = false; 590 for (int32 i = 0; i < 10; i++) { 591 uint16 status = ReadReg16(UHCI_USBSTS); 592 TRACE("current loop %ld, status 0x%04x\n", i, status); 593 594 if (status & UHCI_USBSTS_HCHALT) 595 snooze(10000); 596 else { 597 running = true; 598 break; 599 } 600 } 601 602 if (!running) { 603 TRACE_ERROR("controller won't start running\n"); 604 return B_ERROR; 605 } 606 607 fRootHubAddress = AllocateAddress(); 608 fRootHub = new(std::nothrow) UHCIRootHub(RootObject(), fRootHubAddress); 609 if (!fRootHub) { 610 TRACE_ERROR("no memory to allocate root hub\n"); 611 return B_NO_MEMORY; 612 } 613 614 if (fRootHub->InitCheck() < B_OK) { 615 TRACE_ERROR("root hub failed init check\n"); 616 delete fRootHub; 617 return B_ERROR; 618 } 619 620 SetRootHub(fRootHub); 621 622 TRACE("controller is started. status: %u curframe: %u\n", 623 ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM)); 624 TRACE_ALWAYS("successfully started the controller\n"); 625 return BusManager::Start(); 626 } 627 628 629 status_t 630 UHCI::SubmitTransfer(Transfer *transfer) 631 { 632 // Short circuit the root hub 633 Pipe *pipe = transfer->TransferPipe(); 634 if (pipe->DeviceAddress() == fRootHubAddress) 635 return fRootHub->ProcessTransfer(this, transfer); 636 637 TRACE("submit transfer called for device %d\n", pipe->DeviceAddress()); 638 if (pipe->Type() & USB_OBJECT_CONTROL_PIPE) 639 return SubmitRequest(transfer); 640 641 // Process isochronous transfers 642 if (pipe->Type() & USB_OBJECT_ISO_PIPE) 643 return SubmitIsochronous(transfer); 644 645 uhci_td *firstDescriptor = NULL; 646 uhci_qh *transferQueue = NULL; 647 status_t result = CreateFilledTransfer(transfer, &firstDescriptor, 648 &transferQueue); 649 if (result < B_OK) 650 return result; 651 652 Queue *queue = NULL; 653 if (pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) 654 queue = fQueues[UHCI_INTERRUPT_QUEUE]; 655 else 656 queue = fQueues[UHCI_BULK_QUEUE]; 657 658 bool directionIn = (pipe->Direction() == Pipe::In); 659 result = AddPendingTransfer(transfer, queue, transferQueue, 660 firstDescriptor, firstDescriptor, directionIn); 661 if (result < B_OK) { 662 TRACE_ERROR("failed to add pending transfer\n"); 663 FreeDescriptorChain(firstDescriptor); 664 FreeTransferQueue(transferQueue); 665 return result; 666 } 667 668 queue->AppendTransfer(transferQueue); 669 return B_OK; 670 } 671 672 673 status_t 674 UHCI::ProcessDebugTransfer(Transfer *transfer) 675 { 676 uhci_td *firstDescriptor = NULL; 677 uhci_qh *transferQueue = NULL; 678 status_t result = CreateFilledTransfer(transfer, &firstDescriptor, 679 &transferQueue); 680 if (result < B_OK) 681 return result; 682 683 fQueues[UHCI_DEBUG_QUEUE]->AppendTransfer(transferQueue, false); 684 685 while (true) { 686 bool transferOK = false; 687 bool transferError = false; 688 uhci_td *descriptor = firstDescriptor; 689 690 while (descriptor) { 691 uint32 status = descriptor->status; 692 if (status & TD_STATUS_ACTIVE) 693 break; 694 695 if (status & TD_ERROR_MASK) { 696 transferError = true; 697 break; 698 } 699 700 if ((descriptor->link_phy & TD_TERMINATE) 701 || uhci_td_actual_length(descriptor) 702 < uhci_td_maximum_length(descriptor)) { 703 transferOK = true; 704 break; 705 } 706 707 descriptor = (uhci_td *)descriptor->link_log; 708 } 709 710 if (!transferOK && !transferError) { 711 spin(200); 712 continue; 713 } 714 715 if (transferOK) { 716 size_t actualLength = 0; 717 uint8 lastDataToggle = 0; 718 if (transfer->TransferPipe()->Direction() == Pipe::In) { 719 // data to read out 720 iovec *vector = transfer->Vector(); 721 size_t vectorCount = transfer->VectorCount(); 722 723 actualLength = ReadDescriptorChain(firstDescriptor, 724 vector, vectorCount, &lastDataToggle); 725 } else { 726 // read the actual length that was sent 727 actualLength = ReadActualLength(firstDescriptor, 728 &lastDataToggle); 729 } 730 731 transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0); 732 } 733 734 fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transferQueue, false); 735 FreeDescriptorChain(firstDescriptor); 736 FreeTransferQueue(transferQueue); 737 return transferOK ? B_OK : B_IO_ERROR; 738 } 739 740 return B_ERROR; 741 } 742 743 744 status_t 745 UHCI::CancelQueuedTransfers(Pipe *pipe, bool force) 746 { 747 if (pipe->Type() & USB_OBJECT_ISO_PIPE) 748 return CancelQueuedIsochronousTransfers(pipe, force); 749 750 if (!Lock()) 751 return B_ERROR; 752 753 struct transfer_entry { 754 Transfer * transfer; 755 transfer_entry * next; 756 }; 757 758 transfer_entry *list = NULL; 759 transfer_data *current = fFirstTransfer; 760 while (current) { 761 if (current->transfer && current->transfer->TransferPipe() == pipe) { 762 // clear the active bit so the descriptors are canceled 763 uhci_td *descriptor = current->first_descriptor; 764 while (descriptor) { 765 descriptor->status &= ~TD_STATUS_ACTIVE; 766 descriptor = (uhci_td *)descriptor->link_log; 767 } 768 769 if (!force) { 770 // if the transfer is canceled by force, the one causing the 771 // cancel is probably not the one who initiated the transfer 772 // and the callback is likely not safe anymore 773 transfer_entry *entry 774 = (transfer_entry *)malloc(sizeof(transfer_entry)); 775 if (entry != NULL) { 776 entry->transfer = current->transfer; 777 current->transfer = NULL; 778 entry->next = list; 779 list = entry; 780 } 781 } 782 783 current->canceled = true; 784 } 785 current = current->link; 786 } 787 788 Unlock(); 789 790 while (list != NULL) { 791 transfer_entry *next = list->next; 792 list->transfer->Finished(B_CANCELED, 0); 793 delete list->transfer; 794 free(list); 795 list = next; 796 } 797 798 // notify the finisher so it can clean up the canceled transfers 799 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); 800 return B_OK; 801 } 802 803 804 status_t 805 UHCI::CancelQueuedIsochronousTransfers(Pipe *pipe, bool force) 806 { 807 isochronous_transfer_data *current = fFirstIsochronousTransfer; 808 809 while (current) { 810 if (current->transfer->TransferPipe() == pipe) { 811 int32 packetCount 812 = current->transfer->IsochronousData()->packet_count; 813 // Set the active bit off on every descriptor in order to prevent 814 // the controller from processing them. Then set off the is_active 815 // field of the transfer in order to make the finisher thread skip 816 // the transfer. The FinishIsochronousThread will do the rest. 817 for (int32 i = 0; i < packetCount; i++) 818 current->descriptors[i]->status &= ~TD_STATUS_ACTIVE; 819 820 // TODO: Use the force paramater in order to avoid calling 821 // invalid callbacks 822 current->is_active = false; 823 } 824 825 current = current->link; 826 } 827 828 TRACE_ERROR("no isochronous transfer found!\n"); 829 return B_ERROR; 830 } 831 832 833 status_t 834 UHCI::SubmitRequest(Transfer *transfer) 835 { 836 Pipe *pipe = transfer->TransferPipe(); 837 usb_request_data *requestData = transfer->RequestData(); 838 bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0; 839 840 uhci_td *setupDescriptor = CreateDescriptor(pipe, TD_TOKEN_SETUP, 841 sizeof(usb_request_data)); 842 843 uhci_td *statusDescriptor = CreateDescriptor(pipe, 844 directionIn ? TD_TOKEN_OUT : TD_TOKEN_IN, 0); 845 846 if (!setupDescriptor || !statusDescriptor) { 847 TRACE_ERROR("failed to allocate descriptors\n"); 848 FreeDescriptor(setupDescriptor); 849 FreeDescriptor(statusDescriptor); 850 return B_NO_MEMORY; 851 } 852 853 iovec vector; 854 vector.iov_base = requestData; 855 vector.iov_len = sizeof(usb_request_data); 856 WriteDescriptorChain(setupDescriptor, &vector, 1); 857 858 statusDescriptor->status |= TD_CONTROL_IOC; 859 statusDescriptor->token |= TD_TOKEN_DATA1; 860 statusDescriptor->link_phy = TD_TERMINATE; 861 statusDescriptor->link_log = NULL; 862 863 uhci_td *dataDescriptor = NULL; 864 if (transfer->VectorCount() > 0) { 865 uhci_td *lastDescriptor = NULL; 866 status_t result = CreateDescriptorChain(pipe, &dataDescriptor, 867 &lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, 868 transfer->VectorLength()); 869 870 if (result < B_OK) { 871 FreeDescriptor(setupDescriptor); 872 FreeDescriptor(statusDescriptor); 873 return result; 874 } 875 876 if (!directionIn) { 877 WriteDescriptorChain(dataDescriptor, transfer->Vector(), 878 transfer->VectorCount()); 879 } 880 881 LinkDescriptors(setupDescriptor, dataDescriptor); 882 LinkDescriptors(lastDescriptor, statusDescriptor); 883 } else { 884 // Link transfer and status descriptors directly 885 LinkDescriptors(setupDescriptor, statusDescriptor); 886 } 887 888 Queue *queue = NULL; 889 if (pipe->Speed() == USB_SPEED_LOWSPEED) 890 queue = fQueues[UHCI_LOW_SPEED_CONTROL_QUEUE]; 891 else 892 queue = fQueues[UHCI_FULL_SPEED_CONTROL_QUEUE]; 893 894 uhci_qh *transferQueue = CreateTransferQueue(setupDescriptor); 895 status_t result = AddPendingTransfer(transfer, queue, transferQueue, 896 setupDescriptor, dataDescriptor, directionIn); 897 if (result < B_OK) { 898 TRACE_ERROR("failed to add pending transfer\n"); 899 FreeDescriptorChain(setupDescriptor); 900 FreeTransferQueue(transferQueue); 901 return result; 902 } 903 904 queue->AppendTransfer(transferQueue); 905 return B_OK; 906 } 907 908 909 status_t 910 UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue, 911 uhci_qh *transferQueue, uhci_td *firstDescriptor, uhci_td *dataDescriptor, 912 bool directionIn) 913 { 914 if (!transfer || !queue || !transferQueue || !firstDescriptor) 915 return B_BAD_VALUE; 916 917 transfer_data *data = new(std::nothrow) transfer_data; 918 if (!data) 919 return B_NO_MEMORY; 920 921 status_t result = transfer->InitKernelAccess(); 922 if (result < B_OK) { 923 delete data; 924 return result; 925 } 926 927 data->transfer = transfer; 928 data->queue = queue; 929 data->transfer_queue = transferQueue; 930 data->first_descriptor = firstDescriptor; 931 data->data_descriptor = dataDescriptor; 932 data->incoming = directionIn; 933 data->canceled = false; 934 data->link = NULL; 935 936 if (!Lock()) { 937 delete data; 938 return B_ERROR; 939 } 940 941 if (fLastTransfer) 942 fLastTransfer->link = data; 943 if (!fFirstTransfer) 944 fFirstTransfer = data; 945 946 fLastTransfer = data; 947 Unlock(); 948 return B_OK; 949 } 950 951 952 status_t 953 UHCI::AddPendingIsochronousTransfer(Transfer *transfer, uhci_td **isoRequest, 954 bool directionIn) 955 { 956 if (!transfer || !isoRequest) 957 return B_BAD_VALUE; 958 959 isochronous_transfer_data *data 960 = new(std::nothrow) isochronous_transfer_data; 961 if (!data) 962 return B_NO_MEMORY; 963 964 status_t result = transfer->InitKernelAccess(); 965 if (result < B_OK) { 966 delete data; 967 return result; 968 } 969 970 data->transfer = transfer; 971 data->descriptors = isoRequest; 972 data->last_to_process = transfer->IsochronousData()->packet_count - 1; 973 data->incoming = directionIn; 974 data->is_active = true; 975 data->link = NULL; 976 977 // Put in the isochronous transfer list 978 if (!LockIsochronous()) { 979 delete data; 980 return B_ERROR; 981 } 982 983 if (fLastIsochronousTransfer) 984 fLastIsochronousTransfer->link = data; 985 if (!fFirstIsochronousTransfer) 986 fFirstIsochronousTransfer = data; 987 988 fLastIsochronousTransfer = data; 989 UnlockIsochronous(); 990 return B_OK; 991 } 992 993 994 status_t 995 UHCI::SubmitIsochronous(Transfer *transfer) 996 { 997 Pipe *pipe = transfer->TransferPipe(); 998 bool directionIn = (pipe->Direction() == Pipe::In); 999 usb_isochronous_data *isochronousData = transfer->IsochronousData(); 1000 size_t packetSize = transfer->DataLength(); 1001 size_t restSize = packetSize % isochronousData->packet_count; 1002 packetSize /= isochronousData->packet_count; 1003 uint16 currentFrame; 1004 1005 if (packetSize > pipe->MaxPacketSize()) { 1006 TRACE_ERROR("isochronous packetSize is bigger than pipe MaxPacketSize\n"); 1007 return B_BAD_VALUE; 1008 } 1009 1010 // Ignore the fact that the last descriptor might need less bandwidth. 1011 // The overhead is not worthy. 1012 uint16 bandwidth = transfer->Bandwidth() / isochronousData->packet_count; 1013 1014 TRACE("isochronous transfer descriptor bandwdith %d\n", bandwidth); 1015 1016 // The following holds the list of transfer descriptor of the 1017 // isochronous request. It is used to quickly remove all the isochronous 1018 // descriptors from the frame list, as descriptors are not link to each 1019 // other in a queue like for every other transfer. 1020 uhci_td **isoRequest 1021 = new(std::nothrow) uhci_td *[isochronousData->packet_count]; 1022 if (isoRequest == NULL) { 1023 TRACE("failed to create isoRequest array!\n"); 1024 return B_NO_MEMORY; 1025 } 1026 1027 // Create the list of transfer descriptors 1028 for (uint32 i = 0; i < (isochronousData->packet_count - 1); i++) { 1029 isoRequest[i] = CreateDescriptor(pipe, 1030 directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, packetSize); 1031 // If we ran out of memory, clean up and return 1032 if (isoRequest[i] == NULL) { 1033 for (uint32 j = 0; j < i; j++) 1034 FreeDescriptor(isoRequest[j]); 1035 delete [] isoRequest; 1036 return B_NO_MEMORY; 1037 } 1038 // Make sure data toggle is set to zero 1039 isoRequest[i]->token &= ~TD_TOKEN_DATA1; 1040 } 1041 1042 // Create the last transfer descriptor which should be of smaller size 1043 // and set the IOC bit 1044 isoRequest[isochronousData->packet_count - 1] = CreateDescriptor(pipe, 1045 directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, 1046 (restSize) ? restSize : packetSize); 1047 // If we are that unlucky... 1048 if (!isoRequest[isochronousData->packet_count - 1]) { 1049 for (uint32 i = 0; i < (isochronousData->packet_count - 2); i++) 1050 FreeDescriptor(isoRequest[i]); 1051 delete [] isoRequest; 1052 return B_NO_MEMORY; 1053 } 1054 isoRequest[isochronousData->packet_count - 1]->token &= ~TD_TOKEN_DATA1; 1055 1056 // If direction is out set every descriptor data 1057 if (!directionIn) { 1058 iovec *vector = transfer->Vector(); 1059 WriteIsochronousDescriptorChain(isoRequest, 1060 isochronousData->packet_count, vector); 1061 } else { 1062 // Initialize the packet descriptors 1063 for (uint32 i = 0; i < isochronousData->packet_count; i++) { 1064 isochronousData->packet_descriptors[i].actual_length = 0; 1065 isochronousData->packet_descriptors[i].status = B_NO_INIT; 1066 } 1067 } 1068 1069 TRACE("isochronous submitted size=%ld bytes, TDs=%ld, " 1070 "packetSize=%ld, restSize=%ld\n", transfer->DataLength(), 1071 isochronousData->packet_count, packetSize, restSize); 1072 1073 // Find the entry where to start inserting the first Isochronous descriptor 1074 if (isochronousData->flags & USB_ISO_ASAP || 1075 isochronousData->starting_frame_number == NULL) { 1076 // find the first available frame with enough bandwidth. 1077 // This should always be the case, as defining the starting frame 1078 // number in the driver makes no sense for many reason, one of which 1079 // is that frame numbers value are host controller specific, and the 1080 // driver does not know which host controller is running. 1081 currentFrame = ReadReg16(UHCI_FRNUM); 1082 1083 // Make sure that: 1084 // 1. We are at least 5ms ahead the controller 1085 // 2. We stay in the range 0-1023 1086 // 3. There is enough bandwidth in the first entry 1087 currentFrame = (currentFrame + 5) % NUMBER_OF_FRAMES; 1088 } else { 1089 // Find out if the frame number specified has enough bandwidth, 1090 // otherwise find the first next available frame with enough bandwidth 1091 currentFrame = *isochronousData->starting_frame_number; 1092 } 1093 1094 // Find the first entry with enough bandwidth 1095 // TODO: should we also check the bandwidth of the following packet_count frames? 1096 uint16 startSeekingFromFrame = currentFrame; 1097 while (fFrameBandwidth[currentFrame] < bandwidth) { 1098 currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES; 1099 if (currentFrame == startSeekingFromFrame) { 1100 TRACE_ERROR("not enough bandwidth to queue the isochronous request"); 1101 for (uint32 i = 0; i < isochronousData->packet_count; i++) 1102 FreeDescriptor(isoRequest[i]); 1103 delete [] isoRequest; 1104 return B_ERROR; 1105 } 1106 } 1107 1108 if (isochronousData->starting_frame_number) 1109 *isochronousData->starting_frame_number = currentFrame; 1110 1111 // Add transfer to the list 1112 status_t result = AddPendingIsochronousTransfer(transfer, isoRequest, 1113 directionIn); 1114 if (result < B_OK) { 1115 TRACE_ERROR("failed to add pending isochronous transfer\n"); 1116 for (uint32 i = 0; i < isochronousData->packet_count; i++) 1117 FreeDescriptor(isoRequest[i]); 1118 delete [] isoRequest; 1119 return result; 1120 } 1121 1122 TRACE("appended isochronous transfer by starting at frame number %d\n", 1123 currentFrame); 1124 1125 // Insert the Transfer Descriptor by starting at 1126 // the starting_frame_number entry 1127 // TODO: We don't consider bInterval, and assume it's 1! 1128 for (uint32 i = 0; i < isochronousData->packet_count; i++) { 1129 result = LinkIsochronousDescriptor(isoRequest[i], currentFrame); 1130 if (result < B_OK) { 1131 TRACE_ERROR("failed to add pending isochronous transfer\n"); 1132 for (uint32 i = 0; i < isochronousData->packet_count; i++) 1133 FreeDescriptor(isoRequest[i]); 1134 delete [] isoRequest; 1135 return result; 1136 } 1137 1138 fFrameBandwidth[currentFrame] -= bandwidth; 1139 currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES; 1140 } 1141 1142 // Wake up the isochronous finisher thread 1143 release_sem_etc(fFinishIsochronousTransfersSem, 1, B_DO_NOT_RESCHEDULE); 1144 1145 return B_OK; 1146 } 1147 1148 1149 isochronous_transfer_data * 1150 UHCI::FindIsochronousTransfer(uhci_td *descriptor) 1151 { 1152 // Simply check every last descriptor of the isochronous transfer list 1153 if (LockIsochronous()) { 1154 isochronous_transfer_data *transfer = fFirstIsochronousTransfer; 1155 if (transfer) { 1156 while (transfer->descriptors[transfer->last_to_process] 1157 != descriptor) { 1158 transfer = transfer->link; 1159 if (!transfer) 1160 break; 1161 } 1162 } 1163 UnlockIsochronous(); 1164 return transfer; 1165 } 1166 return NULL; 1167 } 1168 1169 1170 status_t 1171 UHCI::LinkIsochronousDescriptor(uhci_td *descriptor, uint16 frame) 1172 { 1173 // The transfer descriptor is appended to the last 1174 // existing isochronous transfer descriptor (if any) 1175 // in that frame. 1176 if (LockIsochronous()) { 1177 if (!fFirstIsochronousDescriptor[frame]) { 1178 // Insert the transfer descriptor in the first position 1179 fFrameList[frame] = descriptor->this_phy & ~FRAMELIST_NEXT_IS_QH; 1180 fFirstIsochronousDescriptor[frame] = descriptor; 1181 fLastIsochronousDescriptor[frame] = descriptor; 1182 } else { 1183 // Append to the last transfer descriptor 1184 fLastIsochronousDescriptor[frame]->link_log = descriptor; 1185 fLastIsochronousDescriptor[frame]->link_phy 1186 = descriptor->this_phy & ~TD_NEXT_IS_QH; 1187 fLastIsochronousDescriptor[frame] = descriptor; 1188 } 1189 1190 descriptor->link_phy 1191 = fQueues[UHCI_INTERRUPT_QUEUE]->PhysicalAddress() | TD_NEXT_IS_QH; 1192 UnlockIsochronous(); 1193 return B_OK; 1194 } 1195 return B_ERROR; 1196 } 1197 1198 1199 uhci_td * 1200 UHCI::UnlinkIsochronousDescriptor(uint16 frame) 1201 { 1202 // We always unlink from the top 1203 if (LockIsochronous()) { 1204 uhci_td *descriptor = fFirstIsochronousDescriptor[frame]; 1205 if (descriptor) { 1206 // The descriptor will be freed later. 1207 fFrameList[frame] = descriptor->link_phy; 1208 if (descriptor->link_log) { 1209 fFirstIsochronousDescriptor[frame] 1210 = (uhci_td *)descriptor->link_log; 1211 } else { 1212 fFirstIsochronousDescriptor[frame] = NULL; 1213 fLastIsochronousDescriptor[frame] = NULL; 1214 } 1215 } 1216 UnlockIsochronous(); 1217 return descriptor; 1218 } 1219 return NULL; 1220 } 1221 1222 1223 int32 1224 UHCI::FinishThread(void *data) 1225 { 1226 ((UHCI *)data)->FinishTransfers(); 1227 return B_OK; 1228 } 1229 1230 1231 void 1232 UHCI::FinishTransfers() 1233 { 1234 while (!fStopThreads) { 1235 if (acquire_sem(fFinishTransfersSem) < B_OK) 1236 continue; 1237 1238 // eat up sems that have been released by multiple interrupts 1239 int32 semCount = 0; 1240 get_sem_count(fFinishTransfersSem, &semCount); 1241 if (semCount > 0) 1242 acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); 1243 1244 if (!Lock()) 1245 continue; 1246 1247 TRACE("finishing transfers (first transfer: 0x%08lx; last" 1248 " transfer: 0x%08lx)\n", (uint32)fFirstTransfer, 1249 (uint32)fLastTransfer); 1250 transfer_data *lastTransfer = NULL; 1251 transfer_data *transfer = fFirstTransfer; 1252 Unlock(); 1253 1254 while (transfer) { 1255 bool transferDone = false; 1256 uhci_td *descriptor = transfer->first_descriptor; 1257 status_t callbackStatus = B_OK; 1258 1259 while (descriptor) { 1260 uint32 status = descriptor->status; 1261 if (status & TD_STATUS_ACTIVE) { 1262 // still in progress 1263 TRACE("td (0x%08lx) still active\n", descriptor->this_phy); 1264 break; 1265 } 1266 1267 if (status & TD_ERROR_MASK) { 1268 // an error occured 1269 TRACE_ERROR("td (0x%08lx) error: status: 0x%08lx;" 1270 " token: 0x%08lx;\n", descriptor->this_phy, status, 1271 descriptor->token); 1272 1273 uint8 errorCount = status >> TD_ERROR_COUNT_SHIFT; 1274 errorCount &= TD_ERROR_COUNT_MASK; 1275 if (errorCount == 0) { 1276 // the error counter counted down to zero, report why 1277 int32 reasons = 0; 1278 if (status & TD_STATUS_ERROR_BUFFER) { 1279 callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN; 1280 reasons++; 1281 } 1282 if (status & TD_STATUS_ERROR_TIMEOUT) { 1283 callbackStatus = transfer->incoming ? B_DEV_CRC_ERROR : B_TIMED_OUT; 1284 reasons++; 1285 } 1286 if (status & TD_STATUS_ERROR_NAK) { 1287 callbackStatus = B_DEV_UNEXPECTED_PID; 1288 reasons++; 1289 } 1290 if (status & TD_STATUS_ERROR_BITSTUFF) { 1291 callbackStatus = B_DEV_CRC_ERROR; 1292 reasons++; 1293 } 1294 1295 if (reasons > 1) 1296 callbackStatus = B_DEV_MULTIPLE_ERRORS; 1297 } else if (status & TD_STATUS_ERROR_BABBLE) { 1298 // there is a babble condition 1299 callbackStatus = transfer->incoming ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN; 1300 } else { 1301 // if the error counter didn't count down to zero 1302 // and there was no babble, then this halt was caused 1303 // by a stall handshake 1304 callbackStatus = B_DEV_STALLED; 1305 } 1306 1307 transferDone = true; 1308 break; 1309 } 1310 1311 if ((descriptor->link_phy & TD_TERMINATE) 1312 || ((descriptor->status & TD_CONTROL_SPD) != 0 1313 && uhci_td_actual_length(descriptor) 1314 < uhci_td_maximum_length(descriptor))) { 1315 // all descriptors are done, or we have a short packet 1316 TRACE("td (0x%08lx) ok\n", descriptor->this_phy); 1317 callbackStatus = B_OK; 1318 transferDone = true; 1319 break; 1320 } 1321 1322 descriptor = (uhci_td *)descriptor->link_log; 1323 } 1324 1325 if (!transferDone) { 1326 lastTransfer = transfer; 1327 transfer = transfer->link; 1328 continue; 1329 } 1330 1331 // remove the transfer from the list first so we are sure 1332 // it doesn't get canceled while we still process it 1333 transfer_data *next = transfer->link; 1334 if (Lock()) { 1335 if (lastTransfer) 1336 lastTransfer->link = transfer->link; 1337 1338 if (transfer == fFirstTransfer) 1339 fFirstTransfer = transfer->link; 1340 if (transfer == fLastTransfer) 1341 fLastTransfer = lastTransfer; 1342 1343 transfer->link = NULL; 1344 Unlock(); 1345 } 1346 1347 // if canceled the callback has already been called 1348 if (!transfer->canceled) { 1349 size_t actualLength = 0; 1350 if (callbackStatus == B_OK) { 1351 uint8 lastDataToggle = 0; 1352 if (transfer->data_descriptor && transfer->incoming) { 1353 // data to read out 1354 iovec *vector = transfer->transfer->Vector(); 1355 size_t vectorCount = transfer->transfer->VectorCount(); 1356 1357 transfer->transfer->PrepareKernelAccess(); 1358 actualLength = ReadDescriptorChain( 1359 transfer->data_descriptor, 1360 vector, vectorCount, 1361 &lastDataToggle); 1362 } else if (transfer->data_descriptor) { 1363 // read the actual length that was sent 1364 actualLength = ReadActualLength( 1365 transfer->data_descriptor, &lastDataToggle); 1366 } 1367 1368 transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0); 1369 1370 if (transfer->transfer->IsFragmented()) { 1371 // this transfer may still have data left 1372 TRACE("advancing fragmented transfer\n"); 1373 transfer->transfer->AdvanceByFragment(actualLength); 1374 if (transfer->transfer->VectorLength() > 0) { 1375 TRACE("still %ld bytes left on transfer\n", 1376 transfer->transfer->VectorLength()); 1377 1378 Transfer *resubmit = transfer->transfer; 1379 1380 // free the used descriptors 1381 transfer->queue->RemoveTransfer( 1382 transfer->transfer_queue); 1383 AddToFreeList(transfer); 1384 1385 // resubmit the advanced transfer so the rest 1386 // of the buffers are transmitted over the bus 1387 resubmit->PrepareKernelAccess(); 1388 if (SubmitTransfer(resubmit) != B_OK) 1389 resubmit->Finished(B_ERROR, 0); 1390 1391 transfer = next; 1392 continue; 1393 } 1394 1395 // the transfer is done, but we already set the 1396 // actualLength with AdvanceByFragment() 1397 actualLength = 0; 1398 } 1399 } 1400 1401 transfer->transfer->Finished(callbackStatus, actualLength); 1402 } 1403 1404 // remove and free the hardware queue and its descriptors 1405 transfer->queue->RemoveTransfer(transfer->transfer_queue); 1406 delete transfer->transfer; 1407 AddToFreeList(transfer); 1408 transfer = next; 1409 } 1410 } 1411 } 1412 1413 1414 void 1415 UHCI::AddToFreeList(transfer_data *transfer) 1416 { 1417 transfer->free_after_frame = ReadReg16(UHCI_FRNUM); 1418 if (!Lock()) 1419 return; 1420 1421 transfer->link = fFreeList; 1422 fFreeList = transfer; 1423 Unlock(); 1424 1425 if (atomic_add(&fCleanupCount, 1) == 0) 1426 release_sem(fCleanupSem); 1427 } 1428 1429 1430 int32 1431 UHCI::CleanupThread(void *data) 1432 { 1433 ((UHCI *)data)->Cleanup(); 1434 return B_OK; 1435 } 1436 1437 1438 void 1439 UHCI::Cleanup() 1440 { 1441 while (!fStopThreads) { 1442 if (acquire_sem(fCleanupSem) != B_OK) 1443 continue; 1444 1445 bigtime_t nextTime = system_time() + 1000; 1446 while (atomic_get(&fCleanupCount) != 0) { 1447 // wait for the frame to pass 1448 snooze_until(nextTime, B_SYSTEM_TIMEBASE); 1449 nextTime += 1000; 1450 1451 if (!Lock()) 1452 continue; 1453 1454 // find the first entry we may free 1455 transfer_data **link = &fFreeList; 1456 transfer_data *transfer = fFreeList; 1457 uint16 frameNumber = ReadReg16(UHCI_FRNUM); 1458 while (transfer) { 1459 if (transfer->free_after_frame != frameNumber) { 1460 *link = NULL; 1461 break; 1462 } 1463 1464 link = &transfer->link; 1465 transfer = transfer->link; 1466 } 1467 1468 Unlock(); 1469 1470 // the transfers below this one are all freeable 1471 while (transfer) { 1472 transfer_data *next = transfer->link; 1473 FreeDescriptorChain(transfer->first_descriptor); 1474 FreeTransferQueue(transfer->transfer_queue); 1475 delete transfer; 1476 atomic_add(&fCleanupCount, -1); 1477 transfer = next; 1478 } 1479 } 1480 } 1481 } 1482 1483 1484 int32 1485 UHCI::FinishIsochronousThread(void *data) 1486 { 1487 ((UHCI *)data)->FinishIsochronousTransfers(); 1488 return B_OK; 1489 } 1490 1491 1492 void 1493 UHCI::FinishIsochronousTransfers() 1494 { 1495 /* This thread stays one position behind the controller and processes every 1496 * isochronous descriptor. Once it finds the last isochronous descriptor 1497 * of a transfer, it processes the entire transfer. 1498 */ 1499 1500 while (!fStopThreads) { 1501 // Go to sleep if there are not isochronous transfer to process 1502 if (acquire_sem(fFinishIsochronousTransfersSem) < B_OK) 1503 return; 1504 1505 bool transferDone = false; 1506 uint16 currentFrame = ReadReg16(UHCI_FRNUM); 1507 1508 // Process the frame list until one transfer is processed 1509 while (!transferDone) { 1510 // wait 1ms in order to be sure to be one position behind 1511 // the controller 1512 if (currentFrame == ReadReg16(UHCI_FRNUM)) 1513 snooze(1000); 1514 1515 // Process the frame till it has isochronous descriptors in it. 1516 while (!(fFrameList[currentFrame] & FRAMELIST_NEXT_IS_QH)) { 1517 uhci_td *current = UnlinkIsochronousDescriptor(currentFrame); 1518 1519 // Process the transfer if we found the last descriptor 1520 isochronous_transfer_data *transfer 1521 = FindIsochronousTransfer(current); 1522 // Process the descriptors only if it is still active and 1523 // belongs to an inbound transfer. If the transfer is not 1524 // active, it means the request has been removed, so simply 1525 // remove the descriptors. 1526 if (transfer && transfer->is_active) { 1527 if (current->token & TD_TOKEN_IN) { 1528 iovec *vector = transfer->transfer->Vector(); 1529 transfer->transfer->PrepareKernelAccess(); 1530 ReadIsochronousDescriptorChain(transfer, vector); 1531 } 1532 1533 // Remove the transfer 1534 if (LockIsochronous()) { 1535 if (transfer == fFirstIsochronousTransfer) 1536 fFirstIsochronousTransfer = transfer->link; 1537 else { 1538 isochronous_transfer_data *temp 1539 = fFirstIsochronousTransfer; 1540 while (transfer != temp->link) 1541 temp = temp->link; 1542 1543 if (transfer == fLastIsochronousTransfer) 1544 fLastIsochronousTransfer = temp; 1545 temp->link = temp->link->link; 1546 } 1547 UnlockIsochronous(); 1548 } 1549 1550 transfer->transfer->Finished(B_OK, 0); 1551 1552 uint32 packetCount = 1553 transfer->transfer->IsochronousData()->packet_count; 1554 for (uint32 i = 0; i < packetCount; i++) 1555 FreeDescriptor(transfer->descriptors[i]); 1556 1557 delete [] transfer->descriptors; 1558 delete transfer->transfer; 1559 delete transfer; 1560 transferDone = true; 1561 } 1562 } 1563 1564 // Make sure to reset the frame bandwidth 1565 fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH; 1566 currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES; 1567 } 1568 } 1569 } 1570 1571 1572 void 1573 UHCI::GlobalReset() 1574 { 1575 uint8 sofValue = ReadReg8(UHCI_SOFMOD); 1576 1577 WriteReg16(UHCI_USBCMD, UHCI_USBCMD_GRESET); 1578 snooze(100000); 1579 WriteReg16(UHCI_USBCMD, 0); 1580 snooze(10000); 1581 1582 WriteReg8(UHCI_SOFMOD, sofValue); 1583 } 1584 1585 1586 status_t 1587 UHCI::ControllerReset() 1588 { 1589 WriteReg16(UHCI_USBCMD, UHCI_USBCMD_HCRESET); 1590 1591 int32 tries = 5; 1592 while (ReadReg16(UHCI_USBCMD) & UHCI_USBCMD_HCRESET) { 1593 snooze(10000); 1594 if (tries-- < 0) 1595 return B_ERROR; 1596 } 1597 1598 return B_OK; 1599 } 1600 1601 1602 status_t 1603 UHCI::GetPortStatus(uint8 index, usb_port_status *status) 1604 { 1605 if (index > 1) 1606 return B_BAD_INDEX; 1607 1608 status->status = status->change = 0; 1609 uint16 portStatus = ReadReg16(UHCI_PORTSC1 + index * 2); 1610 1611 // build the status 1612 if (portStatus & UHCI_PORTSC_CURSTAT) 1613 status->status |= PORT_STATUS_CONNECTION; 1614 if (portStatus & UHCI_PORTSC_ENABLED) 1615 status->status |= PORT_STATUS_ENABLE; 1616 if (portStatus & UHCI_PORTSC_RESET) 1617 status->status |= PORT_STATUS_RESET; 1618 if (portStatus & UHCI_PORTSC_LOWSPEED) 1619 status->status |= PORT_STATUS_LOW_SPEED; 1620 1621 // build the change 1622 if (portStatus & UHCI_PORTSC_STATCHA) 1623 status->change |= PORT_STATUS_CONNECTION; 1624 if (portStatus & UHCI_PORTSC_ENABCHA) 1625 status->change |= PORT_STATUS_ENABLE; 1626 1627 // ToDo: work out suspended/resume 1628 1629 // there are no bits to indicate reset change 1630 if (fPortResetChange & (1 << index)) 1631 status->change |= PORT_STATUS_RESET; 1632 1633 // the port is automagically powered on 1634 status->status |= PORT_STATUS_POWER; 1635 return B_OK; 1636 } 1637 1638 1639 status_t 1640 UHCI::SetPortFeature(uint8 index, uint16 feature) 1641 { 1642 if (index > 1) 1643 return B_BAD_INDEX; 1644 1645 switch (feature) { 1646 case PORT_RESET: 1647 return ResetPort(index); 1648 1649 case PORT_POWER: 1650 // the ports are automatically powered 1651 return B_OK; 1652 } 1653 1654 return B_BAD_VALUE; 1655 } 1656 1657 1658 status_t 1659 UHCI::ClearPortFeature(uint8 index, uint16 feature) 1660 { 1661 if (index > 1) 1662 return B_BAD_INDEX; 1663 1664 uint32 portRegister = UHCI_PORTSC1 + index * 2; 1665 uint16 portStatus = ReadReg16(portRegister) & UHCI_PORTSC_DATAMASK; 1666 1667 switch (feature) { 1668 case C_PORT_RESET: 1669 fPortResetChange &= ~(1 << index); 1670 return B_OK; 1671 1672 case C_PORT_CONNECTION: 1673 WriteReg16(portRegister, portStatus | UHCI_PORTSC_STATCHA); 1674 return B_OK; 1675 1676 case C_PORT_ENABLE: 1677 WriteReg16(portRegister, portStatus | UHCI_PORTSC_ENABCHA); 1678 return B_OK; 1679 } 1680 1681 return B_BAD_VALUE; 1682 } 1683 1684 1685 status_t 1686 UHCI::ResetPort(uint8 index) 1687 { 1688 if (index > 1) 1689 return B_BAD_INDEX; 1690 1691 TRACE("reset port %d\n", index); 1692 1693 uint32 port = UHCI_PORTSC1 + index * 2; 1694 uint16 status = ReadReg16(port); 1695 status &= UHCI_PORTSC_DATAMASK; 1696 WriteReg16(port, status | UHCI_PORTSC_RESET); 1697 snooze(250000); 1698 1699 status = ReadReg16(port); 1700 status &= UHCI_PORTSC_DATAMASK; 1701 WriteReg16(port, status & ~UHCI_PORTSC_RESET); 1702 snooze(1000); 1703 1704 for (int32 i = 10; i > 0; i--) { 1705 // try to enable the port 1706 status = ReadReg16(port); 1707 status &= UHCI_PORTSC_DATAMASK; 1708 WriteReg16(port, status | UHCI_PORTSC_ENABLED); 1709 snooze(50000); 1710 1711 status = ReadReg16(port); 1712 1713 if ((status & UHCI_PORTSC_CURSTAT) == 0) { 1714 // no device connected. since we waited long enough we can assume 1715 // that the port was reset and no device is connected. 1716 break; 1717 } 1718 1719 if (status & (UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA)) { 1720 // port enabled changed or connection status were set. 1721 // acknowledge either / both and wait again. 1722 status &= UHCI_PORTSC_DATAMASK; 1723 WriteReg16(port, status | UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA); 1724 continue; 1725 } 1726 1727 if (status & UHCI_PORTSC_ENABLED) { 1728 // the port is enabled 1729 break; 1730 } 1731 } 1732 1733 fPortResetChange |= (1 << index); 1734 TRACE("port was reset: 0x%04x\n", ReadReg16(port)); 1735 return B_OK; 1736 } 1737 1738 1739 int32 1740 UHCI::InterruptHandler(void *data) 1741 { 1742 return ((UHCI *)data)->Interrupt(); 1743 } 1744 1745 1746 int32 1747 UHCI::Interrupt() 1748 { 1749 static spinlock lock = B_SPINLOCK_INITIALIZER; 1750 acquire_spinlock(&lock); 1751 1752 // Check if we really had an interrupt 1753 uint16 status = ReadReg16(UHCI_USBSTS); 1754 if ((status & fEnabledInterrupts) == 0) { 1755 if (status != 0) { 1756 TRACE("discarding not enabled interrupts 0x%08lx\n", status); 1757 WriteReg16(UHCI_USBSTS, status); 1758 } 1759 1760 release_spinlock(&lock); 1761 return B_UNHANDLED_INTERRUPT; 1762 } 1763 1764 uint16 acknowledge = 0; 1765 bool finishTransfers = false; 1766 int32 result = B_HANDLED_INTERRUPT; 1767 1768 if (status & UHCI_USBSTS_USBINT) { 1769 TRACE_MODULE("transfer finished\n"); 1770 acknowledge |= UHCI_USBSTS_USBINT; 1771 result = B_INVOKE_SCHEDULER; 1772 finishTransfers = true; 1773 } 1774 1775 if (status & UHCI_USBSTS_ERRINT) { 1776 TRACE_MODULE("transfer error\n"); 1777 acknowledge |= UHCI_USBSTS_ERRINT; 1778 result = B_INVOKE_SCHEDULER; 1779 finishTransfers = true; 1780 } 1781 1782 if (status & UHCI_USBSTS_RESDET) { 1783 TRACE_MODULE("resume detected\n"); 1784 acknowledge |= UHCI_USBSTS_RESDET; 1785 } 1786 1787 if (status & UHCI_USBSTS_HOSTERR) { 1788 TRACE_MODULE_ERROR("host system error\n"); 1789 acknowledge |= UHCI_USBSTS_HOSTERR; 1790 } 1791 1792 if (status & UHCI_USBSTS_HCPRERR) { 1793 TRACE_MODULE_ERROR("process error\n"); 1794 acknowledge |= UHCI_USBSTS_HCPRERR; 1795 } 1796 1797 if (status & UHCI_USBSTS_HCHALT) { 1798 TRACE_MODULE_ERROR("host controller halted\n"); 1799 // at least disable interrupts so we do not flood the system 1800 WriteReg16(UHCI_USBINTR, 0); 1801 fEnabledInterrupts = 0; 1802 // ToDo: cancel all transfers and reset the host controller 1803 // acknowledge not needed 1804 } 1805 1806 if (acknowledge) 1807 WriteReg16(UHCI_USBSTS, acknowledge); 1808 1809 release_spinlock(&lock); 1810 1811 if (finishTransfers) 1812 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); 1813 1814 return result; 1815 } 1816 1817 1818 status_t 1819 UHCI::AddTo(Stack *stack) 1820 { 1821 #ifdef TRACE_USB 1822 set_dprintf_enabled(true); 1823 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 1824 load_driver_symbols("uhci"); 1825 #endif 1826 #endif 1827 1828 if (!sPCIModule) { 1829 status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule); 1830 if (status < B_OK) { 1831 TRACE_MODULE_ERROR("AddTo(): getting pci module failed! 0x%08lx\n", 1832 status); 1833 return status; 1834 } 1835 } 1836 1837 TRACE_MODULE("AddTo(): setting up hardware\n"); 1838 1839 bool found = false; 1840 pci_info *item = new(std::nothrow) pci_info; 1841 if (!item) { 1842 sPCIModule = NULL; 1843 put_module(B_PCI_MODULE_NAME); 1844 return B_NO_MEMORY; 1845 } 1846 1847 for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) { 1848 1849 if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb 1850 && item->class_api == PCI_usb_uhci) { 1851 if (item->u.h0.interrupt_line == 0 1852 || item->u.h0.interrupt_line == 0xFF) { 1853 TRACE_MODULE_ERROR("AddTo(): found with invalid IRQ - check IRQ assignement\n"); 1854 continue; 1855 } 1856 1857 TRACE_MODULE("AddTo(): found at IRQ %u\n", 1858 item->u.h0.interrupt_line); 1859 UHCI *bus = new(std::nothrow) UHCI(item, stack); 1860 if (!bus) { 1861 delete item; 1862 sPCIModule = NULL; 1863 put_module(B_PCI_MODULE_NAME); 1864 return B_NO_MEMORY; 1865 } 1866 1867 if (bus->InitCheck() < B_OK) { 1868 TRACE_MODULE_ERROR("AddTo(): InitCheck() failed 0x%08lx\n", 1869 bus->InitCheck()); 1870 delete bus; 1871 continue; 1872 } 1873 1874 // the bus took it away 1875 item = new(std::nothrow) pci_info; 1876 1877 bus->Start(); 1878 stack->AddBusManager(bus); 1879 found = true; 1880 } 1881 } 1882 1883 if (!found) { 1884 TRACE_MODULE_ERROR("no devices found\n"); 1885 delete item; 1886 sPCIModule = NULL; 1887 put_module(B_PCI_MODULE_NAME); 1888 return ENODEV; 1889 } 1890 1891 delete item; 1892 return B_OK; 1893 } 1894 1895 1896 status_t 1897 UHCI::CreateFilledTransfer(Transfer *transfer, uhci_td **_firstDescriptor, 1898 uhci_qh **_transferQueue) 1899 { 1900 Pipe *pipe = transfer->TransferPipe(); 1901 bool directionIn = (pipe->Direction() == Pipe::In); 1902 1903 uhci_td *firstDescriptor = NULL; 1904 uhci_td *lastDescriptor = NULL; 1905 status_t result = CreateDescriptorChain(pipe, &firstDescriptor, 1906 &lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, 1907 transfer->VectorLength()); 1908 1909 if (result < B_OK) 1910 return result; 1911 if (!firstDescriptor || !lastDescriptor) 1912 return B_NO_MEMORY; 1913 1914 lastDescriptor->status |= TD_CONTROL_IOC; 1915 lastDescriptor->link_phy = TD_TERMINATE; 1916 lastDescriptor->link_log = NULL; 1917 1918 if (!directionIn) { 1919 WriteDescriptorChain(firstDescriptor, transfer->Vector(), 1920 transfer->VectorCount()); 1921 } 1922 1923 uhci_qh *transferQueue = CreateTransferQueue(firstDescriptor); 1924 if (!transferQueue) { 1925 FreeDescriptorChain(firstDescriptor); 1926 return B_NO_MEMORY; 1927 } 1928 1929 *_firstDescriptor = firstDescriptor; 1930 *_transferQueue = transferQueue; 1931 return B_OK; 1932 } 1933 1934 1935 uhci_qh * 1936 UHCI::CreateTransferQueue(uhci_td *descriptor) 1937 { 1938 uhci_qh *queueHead; 1939 void *physicalAddress; 1940 if (fStack->AllocateChunk((void **)&queueHead, 1941 &physicalAddress, sizeof(uhci_qh)) < B_OK) 1942 return NULL; 1943 1944 queueHead->this_phy = (addr_t)physicalAddress; 1945 queueHead->element_phy = descriptor->this_phy; 1946 return queueHead; 1947 } 1948 1949 1950 void 1951 UHCI::FreeTransferQueue(uhci_qh *queueHead) 1952 { 1953 if (!queueHead) 1954 return; 1955 1956 fStack->FreeChunk(queueHead, (void *)queueHead->this_phy, sizeof(uhci_qh)); 1957 } 1958 1959 1960 uhci_td * 1961 UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, size_t bufferSize) 1962 { 1963 uhci_td *result; 1964 void *physicalAddress; 1965 1966 if (fStack->AllocateChunk((void **)&result, &physicalAddress, 1967 sizeof(uhci_td)) < B_OK) { 1968 TRACE_ERROR("failed to allocate a transfer descriptor\n"); 1969 return NULL; 1970 } 1971 1972 result->this_phy = (addr_t)physicalAddress; 1973 result->status = TD_STATUS_ACTIVE; 1974 if (pipe->Type() & USB_OBJECT_ISO_PIPE) 1975 result->status |= TD_CONTROL_ISOCHRONOUS; 1976 else { 1977 result->status |= TD_CONTROL_3_ERRORS; 1978 if (direction == TD_TOKEN_IN 1979 && (pipe->Type() & USB_OBJECT_CONTROL_PIPE) == 0) 1980 result->status |= TD_CONTROL_SPD; 1981 } 1982 if (pipe->Speed() == USB_SPEED_LOWSPEED) 1983 result->status |= TD_CONTROL_LOWSPEED; 1984 1985 result->buffer_size = bufferSize; 1986 if (bufferSize == 0) 1987 result->token = TD_TOKEN_NULL_DATA; 1988 else 1989 result->token = (bufferSize - 1) << TD_TOKEN_MAXLEN_SHIFT; 1990 1991 result->token |= (pipe->EndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT) 1992 | (pipe->DeviceAddress() << 8) | direction; 1993 1994 result->link_phy = 0; 1995 result->link_log = NULL; 1996 if (bufferSize <= 0) { 1997 result->buffer_log = NULL; 1998 result->buffer_phy = 0; 1999 return result; 2000 } 2001 2002 if (fStack->AllocateChunk(&result->buffer_log, (void **)&result->buffer_phy, 2003 bufferSize) < B_OK) { 2004 TRACE_ERROR("unable to allocate space for the buffer\n"); 2005 fStack->FreeChunk(result, (void *)result->this_phy, sizeof(uhci_td)); 2006 return NULL; 2007 } 2008 2009 return result; 2010 } 2011 2012 2013 status_t 2014 UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor, 2015 uhci_td **_lastDescriptor, uint8 direction, size_t bufferSize) 2016 { 2017 size_t packetSize = pipe->MaxPacketSize(); 2018 int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize; 2019 if (descriptorCount == 0) 2020 descriptorCount = 1; 2021 2022 bool dataToggle = pipe->DataToggle(); 2023 uhci_td *firstDescriptor = NULL; 2024 uhci_td *lastDescriptor = *_firstDescriptor; 2025 for (int32 i = 0; i < descriptorCount; i++) { 2026 uhci_td *descriptor = CreateDescriptor(pipe, direction, 2027 min_c(packetSize, bufferSize)); 2028 2029 if (!descriptor) { 2030 FreeDescriptorChain(firstDescriptor); 2031 return B_NO_MEMORY; 2032 } 2033 2034 if (dataToggle) 2035 descriptor->token |= TD_TOKEN_DATA1; 2036 2037 // link to previous 2038 if (lastDescriptor) 2039 LinkDescriptors(lastDescriptor, descriptor); 2040 2041 dataToggle = !dataToggle; 2042 bufferSize -= packetSize; 2043 lastDescriptor = descriptor; 2044 if (!firstDescriptor) 2045 firstDescriptor = descriptor; 2046 } 2047 2048 *_firstDescriptor = firstDescriptor; 2049 *_lastDescriptor = lastDescriptor; 2050 return B_OK; 2051 } 2052 2053 2054 void 2055 UHCI::FreeDescriptor(uhci_td *descriptor) 2056 { 2057 if (!descriptor) 2058 return; 2059 2060 if (descriptor->buffer_log) { 2061 fStack->FreeChunk(descriptor->buffer_log, 2062 (void *)descriptor->buffer_phy, descriptor->buffer_size); 2063 } 2064 2065 fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(uhci_td)); 2066 } 2067 2068 2069 void 2070 UHCI::FreeDescriptorChain(uhci_td *topDescriptor) 2071 { 2072 uhci_td *current = topDescriptor; 2073 uhci_td *next = NULL; 2074 2075 while (current) { 2076 next = (uhci_td *)current->link_log; 2077 FreeDescriptor(current); 2078 current = next; 2079 } 2080 } 2081 2082 2083 void 2084 UHCI::LinkDescriptors(uhci_td *first, uhci_td *second) 2085 { 2086 first->link_phy = second->this_phy | TD_DEPTH_FIRST; 2087 first->link_log = second; 2088 } 2089 2090 2091 size_t 2092 UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector, 2093 size_t vectorCount) 2094 { 2095 uhci_td *current = topDescriptor; 2096 size_t actualLength = 0; 2097 size_t vectorIndex = 0; 2098 size_t vectorOffset = 0; 2099 size_t bufferOffset = 0; 2100 2101 while (current) { 2102 if (!current->buffer_log) 2103 break; 2104 2105 while (true) { 2106 size_t length = min_c(current->buffer_size - bufferOffset, 2107 vector[vectorIndex].iov_len - vectorOffset); 2108 2109 TRACE("copying %ld bytes to bufferOffset %ld from" 2110 " vectorOffset %ld at index %ld of %ld\n", length, bufferOffset, 2111 vectorOffset, vectorIndex, vectorCount); 2112 memcpy((uint8 *)current->buffer_log + bufferOffset, 2113 (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length); 2114 2115 actualLength += length; 2116 vectorOffset += length; 2117 bufferOffset += length; 2118 2119 if (vectorOffset >= vector[vectorIndex].iov_len) { 2120 if (++vectorIndex >= vectorCount) { 2121 TRACE("wrote descriptor chain (%ld bytes, no more vectors)\n", 2122 actualLength); 2123 return actualLength; 2124 } 2125 2126 vectorOffset = 0; 2127 } 2128 2129 if (bufferOffset >= current->buffer_size) { 2130 bufferOffset = 0; 2131 break; 2132 } 2133 } 2134 2135 if (current->link_phy & TD_TERMINATE) 2136 break; 2137 2138 current = (uhci_td *)current->link_log; 2139 } 2140 2141 TRACE("wrote descriptor chain (%ld bytes)\n", actualLength); 2142 return actualLength; 2143 } 2144 2145 2146 size_t 2147 UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector, 2148 size_t vectorCount, uint8 *lastDataToggle) 2149 { 2150 uint8 dataToggle = 0; 2151 uhci_td *current = topDescriptor; 2152 size_t actualLength = 0; 2153 size_t vectorIndex = 0; 2154 size_t vectorOffset = 0; 2155 size_t bufferOffset = 0; 2156 2157 while (current && (current->status & TD_STATUS_ACTIVE) == 0) { 2158 if (!current->buffer_log) 2159 break; 2160 2161 dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01; 2162 size_t bufferSize = uhci_td_actual_length(current); 2163 2164 while (true) { 2165 size_t length = min_c(bufferSize - bufferOffset, 2166 vector[vectorIndex].iov_len - vectorOffset); 2167 2168 TRACE("copying %ld bytes to vectorOffset %ld from" 2169 " bufferOffset %ld at index %ld of %ld\n", length, vectorOffset, 2170 bufferOffset, vectorIndex, vectorCount); 2171 memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset, 2172 (uint8 *)current->buffer_log + bufferOffset, length); 2173 2174 actualLength += length; 2175 vectorOffset += length; 2176 bufferOffset += length; 2177 2178 if (vectorOffset >= vector[vectorIndex].iov_len) { 2179 if (++vectorIndex >= vectorCount) { 2180 TRACE("read descriptor chain (%ld bytes, no more vectors)\n", 2181 actualLength); 2182 if (lastDataToggle) 2183 *lastDataToggle = dataToggle; 2184 return actualLength; 2185 } 2186 2187 vectorOffset = 0; 2188 } 2189 2190 if (bufferOffset >= bufferSize) { 2191 bufferOffset = 0; 2192 break; 2193 } 2194 } 2195 2196 if (current->link_phy & TD_TERMINATE) 2197 break; 2198 2199 current = (uhci_td *)current->link_log; 2200 } 2201 2202 if (lastDataToggle) 2203 *lastDataToggle = dataToggle; 2204 2205 TRACE("read descriptor chain (%ld bytes)\n", actualLength); 2206 return actualLength; 2207 } 2208 2209 2210 size_t 2211 UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle) 2212 { 2213 size_t actualLength = 0; 2214 uhci_td *current = topDescriptor; 2215 uint8 dataToggle = 0; 2216 2217 while (current && (current->status & TD_STATUS_ACTIVE) == 0) { 2218 actualLength += uhci_td_actual_length(current); 2219 dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01; 2220 2221 if (current->link_phy & TD_TERMINATE) 2222 break; 2223 2224 current = (uhci_td *)current->link_log; 2225 } 2226 2227 if (lastDataToggle) 2228 *lastDataToggle = dataToggle; 2229 2230 TRACE("read actual length (%ld bytes)\n", actualLength); 2231 return actualLength; 2232 } 2233 2234 2235 void 2236 UHCI::WriteIsochronousDescriptorChain(uhci_td **isoRequest, uint32 packetCount, 2237 iovec *vector) 2238 { 2239 size_t vectorOffset = 0; 2240 for (uint32 i = 0; i < packetCount; i++) { 2241 size_t bufferSize = isoRequest[i]->buffer_size; 2242 memcpy((uint8 *)isoRequest[i]->buffer_log, 2243 (uint8 *)vector->iov_base + vectorOffset, bufferSize); 2244 vectorOffset += bufferSize; 2245 } 2246 } 2247 2248 2249 void 2250 UHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer, 2251 iovec *vector) 2252 { 2253 size_t vectorOffset = 0; 2254 usb_isochronous_data *isochronousData 2255 = transfer->transfer->IsochronousData(); 2256 2257 for (uint32 i = 0; i < isochronousData->packet_count; i++) { 2258 uhci_td *current = transfer->descriptors[i]; 2259 2260 size_t bufferSize = current->buffer_size; 2261 size_t actualLength = uhci_td_actual_length(current); 2262 2263 isochronousData->packet_descriptors[i].actual_length = actualLength; 2264 2265 if (actualLength > 0) 2266 isochronousData->packet_descriptors[i].status = B_OK; 2267 else { 2268 isochronousData->packet_descriptors[i].status = B_ERROR; 2269 vectorOffset += bufferSize; 2270 continue; 2271 } 2272 memcpy((uint8 *)vector->iov_base + vectorOffset, 2273 (uint8 *)current->buffer_log, bufferSize); 2274 2275 vectorOffset += bufferSize; 2276 } 2277 } 2278 2279 2280 bool 2281 UHCI::LockIsochronous() 2282 { 2283 return (mutex_lock(&fIsochronousLock) == B_OK); 2284 } 2285 2286 2287 void 2288 UHCI::UnlockIsochronous() 2289 { 2290 mutex_unlock(&fIsochronousLock); 2291 } 2292 2293 2294 inline void 2295 UHCI::WriteReg8(uint32 reg, uint8 value) 2296 { 2297 sPCIModule->write_io_8(fRegisterBase + reg, value); 2298 } 2299 2300 2301 inline void 2302 UHCI::WriteReg16(uint32 reg, uint16 value) 2303 { 2304 sPCIModule->write_io_16(fRegisterBase + reg, value); 2305 } 2306 2307 2308 inline void 2309 UHCI::WriteReg32(uint32 reg, uint32 value) 2310 { 2311 sPCIModule->write_io_32(fRegisterBase + reg, value); 2312 } 2313 2314 2315 inline uint8 2316 UHCI::ReadReg8(uint32 reg) 2317 { 2318 return sPCIModule->read_io_8(fRegisterBase + reg); 2319 } 2320 2321 2322 inline uint16 2323 UHCI::ReadReg16(uint32 reg) 2324 { 2325 return sPCIModule->read_io_16(fRegisterBase + reg); 2326 } 2327 2328 2329 inline uint32 2330 UHCI::ReadReg32(uint32 reg) 2331 { 2332 return sPCIModule->read_io_32(fRegisterBase + reg); 2333 } 2334