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