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