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