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