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 */ 9 10 #include <module.h> 11 #include <PCI.h> 12 #include <USB3.h> 13 #include <KernelExport.h> 14 #include <stdlib.h> 15 16 #include "uhci.h" 17 #include "uhci_hardware.h" 18 #include "usb_p.h" 19 20 21 pci_module_info *UHCI::sPCIModule = NULL; 22 23 24 static int32 25 uhci_std_ops(int32 op, ...) 26 { 27 switch (op) { 28 case B_MODULE_INIT: 29 TRACE(("usb_uhci_module: init module\n")); 30 return B_OK; 31 case B_MODULE_UNINIT: 32 TRACE(("usb_uhci_module: uninit module\n")); 33 break; 34 default: 35 return EINVAL; 36 } 37 38 return B_OK; 39 } 40 41 42 host_controller_info uhci_module = { 43 { 44 "busses/usb/uhci/nielx", 45 NULL, 46 uhci_std_ops 47 }, 48 NULL, 49 UHCI::AddTo 50 }; 51 52 53 module_info *modules[] = { 54 (module_info *)&uhci_module, 55 NULL 56 }; 57 58 59 // 60 // #pragma mark - 61 // 62 63 64 #ifdef TRACE_USB 65 66 void 67 print_descriptor_chain(uhci_td *descriptor) 68 { 69 while (descriptor) { 70 dprintf("ph: 0x%08x; lp: 0x%08x; vf: %s; q: %s; t: %s; st: 0x%08x; to: 0x%08x\n", 71 descriptor->this_phy & 0xffffffff, descriptor->link_phy & 0xfffffff0, 72 descriptor->link_phy & 0x4 ? "y" : "n", 73 descriptor->link_phy & 0x2 ? "qh" : "td", 74 descriptor->link_phy & 0x1 ? "y" : "n", 75 descriptor->status, descriptor->token); 76 77 if (descriptor->link_phy & TD_TERMINATE) 78 break; 79 80 descriptor = (uhci_td *)descriptor->link_log; 81 } 82 } 83 84 #endif // TRACE_USB 85 86 87 // 88 // #pragma mark - 89 // 90 91 92 Queue::Queue(Stack *stack) 93 { 94 fStack = stack; 95 96 if (benaphore_init(&fLock, "uhci queue lock") < B_OK) { 97 TRACE_ERROR(("usb_uhci: failed to create queue lock\n")); 98 return; 99 } 100 101 void *physicalAddress; 102 fStatus = fStack->AllocateChunk((void **)&fQueueHead, &physicalAddress, 32); 103 if (fStatus < B_OK) 104 return; 105 106 fQueueHead->this_phy = (addr_t)physicalAddress; 107 fQueueHead->element_phy = QH_TERMINATE; 108 109 fStrayDescriptor = NULL; 110 fQueueTop = NULL; 111 } 112 113 114 Queue::~Queue() 115 { 116 Lock(); 117 benaphore_destroy(&fLock); 118 119 fStack->FreeChunk(fQueueHead, (void *)fQueueHead->this_phy, 32); 120 121 if (fStrayDescriptor) 122 fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy, 32); 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, 32); 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 = 0; 181 fStrayDescriptor->buffer_phy = 0; 182 fStrayDescriptor->buffer_log = 0; 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 32); 190 return B_ERROR; 191 } 192 193 fQueueHead->link_phy = fStrayDescriptor->this_phy; 194 fQueueHead->link_log = fStrayDescriptor; 195 fQueueHead->element_phy = QH_TERMINATE; 196 Unlock(); 197 198 return B_OK; 199 } 200 201 202 status_t 203 Queue::AppendDescriptorChain(uhci_td *descriptor) 204 { 205 TRACE(("usb_uhci: appending descriptor chain\n")); 206 207 if (!Lock()) 208 return B_ERROR; 209 210 #ifdef TRACE_USB 211 print_descriptor_chain(descriptor); 212 #endif 213 214 if (fQueueTop == NULL) { 215 // the queue is empty, make this the first element 216 fQueueTop = descriptor; 217 fQueueHead->element_phy = descriptor->this_phy; 218 TRACE(("usb_uhci: first transfer in queue\n")); 219 } else { 220 // there are transfers linked, append to the queue 221 uhci_td *element = fQueueTop; 222 while ((element->link_phy & TD_TERMINATE) == 0) 223 element = (uhci_td *)element->link_log; 224 225 element->link_log = descriptor; 226 element->link_phy = descriptor->this_phy | TD_DEPTH_FIRST; 227 TRACE(("usb_uhci: appended transfer to queue\n")); 228 } 229 230 Unlock(); 231 return B_OK; 232 } 233 234 235 status_t 236 Queue::RemoveDescriptorChain(uhci_td *firstDescriptor, uhci_td *lastDescriptor) 237 { 238 TRACE(("usb_uhci: removing descriptor chain\n")); 239 240 if (!Lock()) 241 return B_ERROR; 242 243 if (fQueueTop == firstDescriptor) { 244 // it is the first chain in this queue 245 if ((lastDescriptor->link_phy & TD_TERMINATE) > 0) { 246 // it is the only chain in this queue 247 fQueueTop = NULL; 248 fQueueHead->element_phy = QH_TERMINATE; 249 } else { 250 // there are still linked transfers 251 fQueueTop = (uhci_td *)lastDescriptor->link_log; 252 fQueueHead->element_phy = fQueueTop->this_phy & TD_LINK_MASK; 253 } 254 } else { 255 // unlink the chain 256 uhci_td *element = fQueueTop; 257 while (element) { 258 if (element->link_log == firstDescriptor) { 259 element->link_log = lastDescriptor->link_log; 260 element->link_phy = lastDescriptor->link_phy; 261 break; 262 } 263 264 element = (uhci_td *)element->link_log; 265 } 266 267 element = firstDescriptor; 268 while (element && element != lastDescriptor) { 269 if ((fQueueHead->element_phy & TD_LINK_MASK) == element->this_phy) { 270 fQueueHead->element_phy = lastDescriptor->link_phy; 271 break; 272 } 273 274 element = (uhci_td *)element->link_log; 275 } 276 } 277 278 lastDescriptor->link_log = NULL; 279 lastDescriptor->link_phy = TD_TERMINATE; 280 281 #ifdef TRACE_USB 282 print_descriptor_chain(firstDescriptor); 283 #endif 284 285 Unlock(); 286 return B_OK; 287 } 288 289 290 addr_t 291 Queue::PhysicalAddress() 292 { 293 return fQueueHead->this_phy; 294 } 295 296 297 void 298 Queue::PrintToStream() 299 { 300 #ifdef TRACE_USB 301 dprintf("USB UHCI Queue:\n"); 302 dprintf("link phy: 0x%08x; link type: %s; terminate: %s\n", fQueueHead->link_phy & 0xfff0, fQueueHead->link_phy & 0x0002 ? "QH" : "TD", fQueueHead->link_phy & 0x0001 ? "yes" : "no"); 303 dprintf("elem phy: 0x%08x; elem type: %s; terminate: %s\n", fQueueHead->element_phy & 0xfff0, fQueueHead->element_phy & 0x0002 ? "QH" : "TD", fQueueHead->element_phy & 0x0001 ? "yes" : "no"); 304 dprintf("elements:\n"); 305 print_descriptor_chain(fQueueTop); 306 #endif 307 } 308 309 310 // 311 // #pragma mark - 312 // 313 314 315 UHCI::UHCI(pci_info *info, Stack *stack) 316 : BusManager(stack), 317 fPCIInfo(info), 318 fStack(stack), 319 fFrameArea(-1), 320 fFrameList(NULL), 321 fQueueCount(0), 322 fQueues(NULL), 323 fFirstTransfer(NULL), 324 fLastTransfer(NULL), 325 fFinishTransfers(false), 326 fFinishThread(-1), 327 fStopFinishThread(false), 328 fRootHub(NULL), 329 fRootHubAddress(0) 330 { 331 if (!fInitOK) { 332 TRACE_ERROR(("usb_uhci: bus manager failed to init\n")); 333 return; 334 } 335 336 TRACE(("usb_uhci: constructing new UHCI Host Controller Driver\n")); 337 fInitOK = false; 338 339 fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus, 340 fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4); 341 fRegisterBase &= PCI_address_io_mask; 342 TRACE_ERROR(("usb_uhci: iospace offset: 0x%08x\n", fRegisterBase)); 343 344 if (fRegisterBase == 0) { 345 fRegisterBase = fPCIInfo->u.h0.base_registers[0]; 346 TRACE_ERROR(("usb_uhci: register base: 0x%08x\n", fRegisterBase)); 347 } 348 349 // enable pci address access 350 uint16 command = PCI_command_io | PCI_command_master | PCI_command_memory; 351 command |= sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device, 352 fPCIInfo->function, PCI_command, 2); 353 354 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 355 fPCIInfo->function, PCI_command, 2, command); 356 357 // make sure we gain controll of the UHCI controller instead of the BIOS 358 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 2, 359 PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN); 360 361 // disable interrupts 362 WriteReg16(UHCI_USBINTR, 0); 363 364 // do a global and host reset 365 GlobalReset(); 366 if (ControllerReset() < B_OK) { 367 TRACE_ERROR(("usb_uhci: host failed to reset\n")); 368 return; 369 } 370 371 // Setup the frame list 372 void *physicalAddress; 373 fFrameArea = fStack->AllocateArea((void **)&fFrameList, 374 (void **)&physicalAddress, 4096, "USB UHCI framelist"); 375 376 if (fFrameArea < B_OK) { 377 TRACE_ERROR(("usb_uhci: unable to create an area for the frame pointer list\n")); 378 return; 379 } 380 381 // Set base pointer and reset frame number 382 WriteReg32(UHCI_FRBASEADD, (uint32)physicalAddress); 383 WriteReg16(UHCI_FRNUM, 0); 384 385 fQueueCount = 4; 386 fQueues = new(std::nothrow) Queue *[fQueueCount]; 387 if (!fQueues) { 388 delete_area(fFrameArea); 389 return; 390 } 391 392 for (int32 i = 0; i < fQueueCount; i++) { 393 fQueues[i] = new(std::nothrow) Queue(fStack); 394 if (!fQueues[i] || fQueues[i]->InitCheck() < B_OK) { 395 TRACE_ERROR(("usb_uhci: cannot create queues\n")); 396 delete_area(fFrameArea); 397 return; 398 } 399 400 if (i > 0) 401 fQueues[i - 1]->LinkTo(fQueues[i]); 402 } 403 404 // Make sure the last queue terminates 405 fQueues[fQueueCount - 1]->TerminateByStrayDescriptor(); 406 407 for (int32 i = 0; i < 1024; i++) 408 fFrameList[i] = fQueues[0]->PhysicalAddress() | FRAMELIST_NEXT_IS_QH; 409 410 // Create the finisher service thread 411 fFinishThread = spawn_kernel_thread(FinishThread, 412 "uhci finish thread", B_NORMAL_PRIORITY, (void *)this); 413 resume_thread(fFinishThread); 414 415 // Install the interrupt handler 416 TRACE(("usb_uhci: installing interrupt handler\n")); 417 install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, 418 InterruptHandler, (void *)this, 0); 419 420 // Enable interrupts 421 WriteReg16(UHCI_USBINTR, UHCI_USBINTR_CRC | UHCI_USBINTR_RESUME 422 | UHCI_USBINTR_IOC | UHCI_USBINTR_SHORT); 423 424 TRACE(("usb_uhci: UHCI Host Controller Driver constructed\n")); 425 fInitOK = true; 426 } 427 428 429 UHCI::~UHCI() 430 { 431 int32 result = 0; 432 fStopFinishThread = true; 433 wait_for_thread(fFinishThread, &result); 434 435 Lock(); 436 transfer_data *transfer = fFirstTransfer; 437 while (transfer) { 438 transfer_data *next = transfer->link; 439 delete transfer; 440 transfer = next; 441 } 442 443 for (int32 i = 0; i < fQueueCount; i++) 444 delete fQueues[i]; 445 446 delete [] fQueues; 447 delete fRootHub; 448 delete_area(fFrameArea); 449 450 put_module(B_PCI_MODULE_NAME); 451 Unlock(); 452 } 453 454 455 status_t 456 UHCI::Start() 457 { 458 // Start the host controller, then start the Busmanager 459 TRACE(("usb_uhci: starting UHCI BusManager\n")); 460 TRACE(("usb_uhci: usbcmd reg 0x%04x, usbsts reg 0x%04x\n", 461 ReadReg16(UHCI_USBCMD), ReadReg16(UHCI_USBSTS))); 462 463 // Set the run bit in the command register 464 WriteReg16(UHCI_USBCMD, ReadReg16(UHCI_USBCMD) | UHCI_USBCMD_RS); 465 466 bool running = false; 467 for (int32 i = 0; i < 10; i++) { 468 uint16 status = ReadReg16(UHCI_USBSTS); 469 TRACE(("usb_uhci: current loop %u, status 0x%04x\n", i, status)); 470 471 if (status & UHCI_USBSTS_HCHALT) 472 snooze(10000); 473 else { 474 running = true; 475 break; 476 } 477 } 478 479 if (!running) { 480 TRACE_ERROR(("usb_uhci: controller won't start running\n")); 481 return B_ERROR; 482 } 483 484 fPortResetChange[0] = fPortResetChange[1] = false; 485 fRootHubAddress = AllocateAddress(); 486 fRootHub = new(std::nothrow) UHCIRootHub(this, fRootHubAddress); 487 if (!fRootHub) { 488 TRACE_ERROR(("usb_uhci: no memory to allocate root hub\n")); 489 return B_NO_MEMORY; 490 } 491 492 if (fRootHub->InitCheck() < B_OK) { 493 TRACE_ERROR(("usb_uhci: root hub failed init check\n")); 494 delete fRootHub; 495 return B_ERROR; 496 } 497 498 SetRootHub(fRootHub); 499 500 TRACE(("usb_uhci: controller is started. status: %u curframe: %u\n", 501 ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM))); 502 return BusManager::Start(); 503 } 504 505 506 status_t 507 UHCI::SubmitTransfer(Transfer *transfer) 508 { 509 TRACE(("usb_uhci: submit transfer called for device %d\n", transfer->TransferPipe()->DeviceAddress())); 510 511 // Short circuit the root hub 512 if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress) 513 return fRootHub->SubmitTransfer(transfer); 514 515 if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) 516 return SubmitRequest(transfer); 517 518 if (transfer->VectorCount() == 0) 519 return B_BAD_VALUE; 520 521 Pipe *pipe = transfer->TransferPipe(); 522 bool directionIn = (pipe->Direction() == Pipe::In); 523 524 uhci_td *firstDescriptor = NULL; 525 uhci_td *lastDescriptor = NULL; 526 status_t result = CreateDescriptorChain(pipe, &firstDescriptor, 527 &lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, 528 transfer->VectorLength()); 529 530 if (result < B_OK) 531 return result; 532 if (!firstDescriptor || !lastDescriptor) 533 return B_NO_MEMORY; 534 535 lastDescriptor->status |= TD_CONTROL_IOC; 536 lastDescriptor->link_phy = TD_TERMINATE; 537 lastDescriptor->link_log = 0; 538 539 if (!directionIn) { 540 WriteDescriptorChain(firstDescriptor, transfer->Vector(), 541 transfer->VectorCount()); 542 } 543 544 Queue *queue = fQueues[3]; 545 if (pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) 546 queue = fQueues[2]; 547 548 result = AddPendingTransfer(transfer, queue, firstDescriptor, 549 firstDescriptor, lastDescriptor, directionIn); 550 if (result < B_OK) { 551 TRACE_ERROR(("usb_uhci: failed to add pending transfer\n")); 552 FreeDescriptorChain(firstDescriptor); 553 return result; 554 } 555 556 result = queue->AppendDescriptorChain(firstDescriptor); 557 if (result < B_OK) { 558 TRACE_ERROR(("usb_uhci: failed to append descriptor chain\n")); 559 FreeDescriptorChain(firstDescriptor); 560 return result; 561 } 562 563 return B_OK; 564 } 565 566 567 status_t 568 UHCI::SubmitRequest(Transfer *transfer) 569 { 570 Pipe *pipe = transfer->TransferPipe(); 571 usb_request_data *requestData = transfer->RequestData(); 572 bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0; 573 574 uhci_td *setupDescriptor = CreateDescriptor(pipe, TD_TOKEN_SETUP, 575 sizeof(usb_request_data)); 576 577 uhci_td *statusDescriptor = CreateDescriptor(pipe, 578 directionIn ? TD_TOKEN_OUT : TD_TOKEN_IN, 0); 579 580 if (!setupDescriptor || !statusDescriptor) { 581 TRACE_ERROR(("usb_uhci: failed to allocate descriptors\n")); 582 FreeDescriptor(setupDescriptor); 583 FreeDescriptor(statusDescriptor); 584 return B_NO_MEMORY; 585 } 586 587 iovec vector; 588 vector.iov_base = requestData; 589 vector.iov_len = sizeof(usb_request_data); 590 WriteDescriptorChain(setupDescriptor, &vector, 1); 591 592 statusDescriptor->status |= TD_CONTROL_IOC; 593 statusDescriptor->token |= TD_TOKEN_DATA1; 594 statusDescriptor->link_phy = TD_TERMINATE; 595 statusDescriptor->link_log = NULL; 596 597 uhci_td *dataDescriptor = NULL; 598 if (transfer->VectorCount() > 0) { 599 uhci_td *lastDescriptor = NULL; 600 status_t result = CreateDescriptorChain(pipe, &dataDescriptor, 601 &lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, 602 transfer->VectorLength()); 603 604 if (result < B_OK) { 605 FreeDescriptor(setupDescriptor); 606 FreeDescriptor(statusDescriptor); 607 return result; 608 } 609 610 if (!directionIn) { 611 WriteDescriptorChain(dataDescriptor, transfer->Vector(), 612 transfer->VectorCount()); 613 } 614 615 LinkDescriptors(setupDescriptor, dataDescriptor); 616 LinkDescriptors(lastDescriptor, statusDescriptor); 617 } else { 618 // Link transfer and status descriptors directly 619 LinkDescriptors(setupDescriptor, statusDescriptor); 620 } 621 622 status_t result = AddPendingTransfer(transfer, fQueues[1], setupDescriptor, 623 dataDescriptor, statusDescriptor, directionIn); 624 if (result < B_OK) { 625 TRACE_ERROR(("usb_uhci: failed to add pending transfer\n")); 626 FreeDescriptorChain(setupDescriptor); 627 return result; 628 } 629 630 result = fQueues[1]->AppendDescriptorChain(setupDescriptor); 631 if (result < B_OK) { 632 TRACE_ERROR(("usb_uhci: failed to append descriptor chain\n")); 633 FreeDescriptorChain(setupDescriptor); 634 return result; 635 } 636 637 return B_OK; 638 } 639 640 641 status_t 642 UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue, 643 uhci_td *firstDescriptor, uhci_td *dataDescriptor, uhci_td *lastDescriptor, 644 bool directionIn) 645 { 646 transfer_data *data = new(std::nothrow) transfer_data(); 647 if (!data) 648 return B_NO_MEMORY; 649 650 data->transfer = transfer; 651 data->queue = queue; 652 data->first_descriptor = firstDescriptor; 653 data->data_descriptor = dataDescriptor; 654 data->last_descriptor = lastDescriptor; 655 data->incoming = directionIn; 656 data->link = NULL; 657 658 if (!Lock()) { 659 delete data; 660 return B_ERROR; 661 } 662 663 if (fLastTransfer) 664 fLastTransfer->link = data; 665 else 666 fFirstTransfer = data; 667 668 fLastTransfer = data; 669 Unlock(); 670 671 return B_OK; 672 } 673 674 675 int32 676 UHCI::FinishThread(void *data) 677 { 678 ((UHCI *)data)->FinishTransfers(); 679 return B_OK; 680 } 681 682 683 void 684 UHCI::FinishTransfers() 685 { 686 while (!fStopFinishThread) { 687 while (!fFinishTransfers) { 688 if (fStopFinishThread) 689 return; 690 691 snooze(1000); 692 } 693 694 fFinishTransfers = false; 695 if (!Lock()) 696 continue; 697 698 TRACE(("usb_uhci: finishing transfers (first transfer: 0x%08x; last transfer: 0x%08x)\n", fFirstTransfer, fLastTransfer)); 699 transfer_data *lastTransfer = NULL; 700 transfer_data *transfer = fFirstTransfer; 701 Unlock(); 702 703 while (transfer) { 704 bool transferDone = false; 705 uhci_td *descriptor = transfer->first_descriptor; 706 707 while (descriptor) { 708 uint32 status = descriptor->status; 709 if (status & TD_STATUS_ACTIVE) { 710 TRACE(("usb_uhci: td (0x%08x) still active\n", descriptor->this_phy)); 711 // still in progress 712 break; 713 } 714 715 if (status & TD_ERROR_MASK) { 716 TRACE_ERROR(("usb_uhci: td (0x%08lx) error: 0x%08lx\n", descriptor->this_phy, status)); 717 // an error occured. we have to remove the 718 // transfer from the queue and clean up 719 720 uint32 callbackStatus = 0; 721 if (status & TD_STATUS_ERROR_STALLED) 722 callbackStatus |= B_USB_STATUS_DEVICE_STALLED; 723 if (status & TD_STATUS_ERROR_TIMEOUT) { 724 if (transfer->incoming) 725 callbackStatus |= B_USB_STATUS_DEVICE_CRC_ERROR; 726 else 727 callbackStatus |= B_USB_STATUS_DEVICE_TIMEOUT; 728 } 729 730 transfer->queue->RemoveDescriptorChain( 731 transfer->first_descriptor, 732 transfer->last_descriptor); 733 734 FreeDescriptorChain(transfer->first_descriptor); 735 transfer->transfer->Finished(callbackStatus, 0); 736 transferDone = true; 737 break; 738 } 739 740 // either all descriptors are done, or we have a short packet 741 if (descriptor == transfer->last_descriptor 742 || (descriptor->status & TD_STATUS_ACTLEN_MASK) 743 < (descriptor->token >> TD_TOKEN_MAXLEN_SHIFT)) { 744 TRACE(("usb_uhci: td (0x%08x) ok\n", descriptor->this_phy)); 745 // we got through without errors so we are finished 746 transfer->queue->RemoveDescriptorChain( 747 transfer->first_descriptor, 748 transfer->last_descriptor); 749 750 size_t actualLength = 0; 751 uint8 lastDataToggle = 0; 752 if (transfer->data_descriptor && transfer->incoming) { 753 // data to read out 754 actualLength = ReadDescriptorChain( 755 transfer->data_descriptor, 756 transfer->transfer->Vector(), 757 transfer->transfer->VectorCount(), 758 &lastDataToggle); 759 } else { 760 // read the actual length that was sent 761 actualLength = ReadActualLength( 762 transfer->first_descriptor, &lastDataToggle); 763 } 764 765 FreeDescriptorChain(transfer->first_descriptor); 766 transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0); 767 transfer->transfer->Finished(B_USB_STATUS_SUCCESS, actualLength); 768 transferDone = true; 769 break; 770 } 771 772 descriptor = (uhci_td *)descriptor->link_log; 773 } 774 775 if (transferDone) { 776 if (Lock()) { 777 if (lastTransfer) 778 lastTransfer->link = transfer->link; 779 780 if (transfer == fFirstTransfer) 781 fFirstTransfer = transfer->link; 782 if (transfer == fLastTransfer) 783 fLastTransfer = lastTransfer; 784 785 transfer_data *next = transfer->link; 786 delete transfer->transfer; 787 delete transfer; 788 transfer = next; 789 790 Unlock(); 791 } 792 } else { 793 lastTransfer = transfer; 794 transfer = transfer->link; 795 } 796 } 797 } 798 } 799 800 801 void 802 UHCI::GlobalReset() 803 { 804 uint8 sofValue = ReadReg8(UHCI_SOFMOD); 805 806 WriteReg16(UHCI_USBCMD, UHCI_USBCMD_GRESET); 807 snooze(100000); 808 WriteReg16(UHCI_USBCMD, 0); 809 snooze(10000); 810 811 WriteReg8(UHCI_SOFMOD, sofValue); 812 } 813 814 815 status_t 816 UHCI::ControllerReset() 817 { 818 WriteReg16(UHCI_USBCMD, UHCI_USBCMD_HCRESET); 819 820 int32 tries = 5; 821 while (ReadReg16(UHCI_USBCMD) & UHCI_USBCMD_HCRESET) { 822 snooze(10000); 823 if (tries-- < 0) 824 return B_ERROR; 825 } 826 827 return B_OK; 828 } 829 830 831 uint16 832 UHCI::PortStatus(int32 index) 833 { 834 if (index > 1) 835 return B_BAD_VALUE; 836 837 return ReadReg16(UHCI_PORTSC1 + index * 2); 838 } 839 840 841 status_t 842 UHCI::SetPortStatus(int32 index, uint16 status) 843 { 844 if (index > 1) 845 return B_BAD_VALUE; 846 847 TRACE(("usb_uhci: set port status of port %d: 0x%04x\n", index, status)); 848 WriteReg16(UHCI_PORTSC1 + index * 2, status); 849 snooze(1000); 850 return B_OK; 851 } 852 853 854 status_t 855 UHCI::ResetPort(int32 index) 856 { 857 if (index > 1) 858 return B_BAD_VALUE; 859 860 TRACE(("usb_uhci: reset port %d\n", index)); 861 862 uint32 port = UHCI_PORTSC1 + index * 2; 863 uint16 status = ReadReg16(port); 864 status &= UHCI_PORTSC_DATAMASK; 865 WriteReg16(port, status | UHCI_PORTSC_RESET); 866 snooze(250000); 867 868 status = ReadReg16(port); 869 status &= UHCI_PORTSC_DATAMASK; 870 WriteReg16(port, status & ~UHCI_PORTSC_RESET); 871 snooze(1000); 872 873 for (int32 i = 10; i > 0; i--) { 874 // try to enable the port 875 status = ReadReg16(port); 876 status &= UHCI_PORTSC_DATAMASK; 877 WriteReg16(port, status | UHCI_PORTSC_ENABLED); 878 snooze(50000); 879 880 status = ReadReg16(port); 881 882 if ((status & UHCI_PORTSC_CURSTAT) == 0) { 883 // no device connected. since we waited long enough we can assume 884 // that the port was reset and no device is connected. 885 break; 886 } 887 888 if (status & (UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA)) { 889 // port enabled changed or connection status were set. 890 // acknowledge either / both and wait again. 891 status &= UHCI_PORTSC_DATAMASK; 892 WriteReg16(port, status | UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA); 893 continue; 894 } 895 896 if (status & UHCI_PORTSC_ENABLED) { 897 // the port is enabled 898 break; 899 } 900 } 901 902 SetPortResetChange(index, true); 903 TRACE(("usb_uhci: port was reset: 0x%04x\n", ReadReg16(port))); 904 return B_OK; 905 } 906 907 908 bool 909 UHCI::PortResetChange(int32 index) 910 { 911 if (index > 1) 912 return false; 913 914 return fPortResetChange[index]; 915 } 916 917 918 void 919 UHCI::SetPortResetChange(int32 index, bool value) 920 { 921 if (index > 1) 922 return; 923 924 fPortResetChange[index] = value; 925 } 926 927 928 int32 929 UHCI::InterruptHandler(void *data) 930 { 931 cpu_status status = disable_interrupts(); 932 spinlock lock = 0; 933 acquire_spinlock(&lock); 934 935 int32 result = ((UHCI *)data)->Interrupt(); 936 937 release_spinlock(&lock); 938 restore_interrupts(status); 939 return result; 940 } 941 942 943 int32 944 UHCI::Interrupt() 945 { 946 // Check if we really had an interrupt 947 uint16 status = ReadReg16(UHCI_USBSTS); 948 if ((status & UHCI_INTERRUPT_MASK) == 0) 949 return B_UNHANDLED_INTERRUPT; 950 951 uint16 acknowledge = 0; 952 if (status & UHCI_USBSTS_USBINT) { 953 TRACE(("usb_uhci: transfer finished\n")); 954 acknowledge |= UHCI_USBSTS_USBINT; 955 } 956 957 if (status & UHCI_USBSTS_ERRINT) { 958 TRACE(("usb_uhci: transfer error\n")); 959 acknowledge |= UHCI_USBSTS_ERRINT; 960 } 961 962 if (status & UHCI_USBSTS_RESDET) { 963 TRACE(("usb_uhci: resume detected\n")); 964 acknowledge |= UHCI_USBSTS_RESDET; 965 } 966 967 if (status & UHCI_USBSTS_HOSTERR) { 968 TRACE(("usb_uhci: host system error\n")); 969 acknowledge |= UHCI_USBSTS_HOSTERR; 970 } 971 972 if (status & UHCI_USBSTS_HCPRERR) { 973 TRACE(("usb_uhci: process error\n")); 974 acknowledge |= UHCI_USBSTS_HCPRERR; 975 } 976 977 if (status & UHCI_USBSTS_HCHALT) { 978 TRACE(("usb_uhci: host controller halted\n")); 979 // ToDo: cancel all transfers and reset the host controller 980 // acknowledge not needed 981 } 982 983 if (acknowledge) 984 WriteReg16(UHCI_USBSTS, acknowledge); 985 986 fFinishTransfers = true; 987 return B_HANDLED_INTERRUPT; 988 } 989 990 991 status_t 992 UHCI::AddTo(Stack *stack) 993 { 994 #ifdef TRACE_USB 995 set_dprintf_enabled(true); 996 load_driver_symbols("uhci"); 997 #endif 998 999 if (!sPCIModule) { 1000 status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule); 1001 if (status < B_OK) { 1002 TRACE_ERROR(("usb_uhci: AddTo(): getting pci module failed! 0x%08lx\n", 1003 status)); 1004 return status; 1005 } 1006 } 1007 1008 TRACE(("usb_uhci: AddTo(): setting up hardware\n")); 1009 1010 bool found = false; 1011 pci_info *item = new(std::nothrow) pci_info; 1012 if (!item) { 1013 sPCIModule = NULL; 1014 put_module(B_PCI_MODULE_NAME); 1015 return B_NO_MEMORY; 1016 } 1017 1018 for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) { 1019 //class_base = 0C (serial bus) class_sub = 03 (usb) prog_int: 00 (UHCI) 1020 if (item->class_base == 0x0C && item->class_sub == 0x03 1021 && item->class_api == 0x00) { 1022 if (item->u.h0.interrupt_line == 0 1023 || item->u.h0.interrupt_line == 0xFF) { 1024 TRACE_ERROR(("usb_uhci: AddTo(): found with invalid IRQ - check IRQ assignement\n")); 1025 continue; 1026 } 1027 1028 TRACE(("usb_uhci: AddTo(): found at IRQ %u\n", item->u.h0.interrupt_line)); 1029 UHCI *bus = new(std::nothrow) UHCI(item, stack); 1030 if (!bus) { 1031 delete item; 1032 sPCIModule = NULL; 1033 put_module(B_PCI_MODULE_NAME); 1034 return B_NO_MEMORY; 1035 } 1036 1037 if (bus->InitCheck() < B_OK) { 1038 TRACE_ERROR(("usb_uhci: AddTo(): InitCheck() failed 0x%08lx\n", bus->InitCheck())); 1039 delete bus; 1040 continue; 1041 } 1042 1043 // the bus took it away 1044 item = new(std::nothrow) pci_info; 1045 1046 bus->Start(); 1047 stack->AddBusManager(bus); 1048 found = true; 1049 } 1050 } 1051 1052 if (!found) { 1053 TRACE_ERROR(("usb_uhci: no devices found\n")); 1054 delete item; 1055 sPCIModule = NULL; 1056 put_module(B_PCI_MODULE_NAME); 1057 return ENODEV; 1058 } 1059 1060 delete item; 1061 return B_OK; 1062 } 1063 1064 1065 uhci_td * 1066 UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, size_t bufferSize) 1067 { 1068 uhci_td *result; 1069 void *physicalAddress; 1070 1071 if (fStack->AllocateChunk((void **)&result, &physicalAddress, 32) < B_OK) { 1072 TRACE_ERROR(("usb_uhci: failed to allocate a transfer descriptor\n")); 1073 return NULL; 1074 } 1075 1076 result->this_phy = (addr_t)physicalAddress; 1077 result->status = TD_STATUS_ACTIVE | TD_CONTROL_3_ERRORS | TD_CONTROL_SPD; 1078 if (pipe->Speed() == Pipe::LowSpeed) 1079 result->status |= TD_CONTROL_LOWSPEED; 1080 1081 result->buffer_size = bufferSize; 1082 if (bufferSize == 0) 1083 result->token = TD_TOKEN_NULL_DATA; 1084 else 1085 result->token = (bufferSize - 1) << TD_TOKEN_MAXLEN_SHIFT; 1086 1087 result->token |= (pipe->EndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT) 1088 | (pipe->DeviceAddress() << 8) | direction; 1089 1090 result->link_phy = 0; 1091 result->link_log = NULL; 1092 if (bufferSize <= 0) { 1093 result->buffer_log = NULL; 1094 result->buffer_phy = NULL; 1095 return result; 1096 } 1097 1098 if (fStack->AllocateChunk(&result->buffer_log, &result->buffer_phy, 1099 bufferSize) < B_OK) { 1100 TRACE_ERROR(("usb_uhci: unable to allocate space for the buffer\n")); 1101 fStack->FreeChunk(result, (void *)result->this_phy, 32); 1102 return NULL; 1103 } 1104 1105 return result; 1106 } 1107 1108 1109 status_t 1110 UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor, 1111 uhci_td **_lastDescriptor, uint8 direction, size_t bufferSize) 1112 { 1113 size_t packetSize = pipe->MaxPacketSize(); 1114 int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize; 1115 1116 bool dataToggle = pipe->DataToggle(); 1117 uhci_td *firstDescriptor = NULL; 1118 uhci_td *lastDescriptor = *_firstDescriptor; 1119 for (int32 i = 0; i < descriptorCount; i++) { 1120 uhci_td *descriptor = CreateDescriptor(pipe, direction, 1121 min_c(packetSize, bufferSize)); 1122 1123 if (!descriptor) { 1124 FreeDescriptorChain(firstDescriptor); 1125 return B_NO_MEMORY; 1126 } 1127 1128 if (dataToggle) 1129 descriptor->token |= TD_TOKEN_DATA1; 1130 1131 // link to previous 1132 if (lastDescriptor) 1133 LinkDescriptors(lastDescriptor, descriptor); 1134 1135 dataToggle = !dataToggle; 1136 bufferSize -= packetSize; 1137 lastDescriptor = descriptor; 1138 if (!firstDescriptor) 1139 firstDescriptor = descriptor; 1140 } 1141 1142 *_firstDescriptor = firstDescriptor; 1143 *_lastDescriptor = lastDescriptor; 1144 return B_OK; 1145 } 1146 1147 1148 void 1149 UHCI::FreeDescriptor(uhci_td *descriptor) 1150 { 1151 if (!descriptor) 1152 return; 1153 1154 if (descriptor->buffer_log) { 1155 fStack->FreeChunk(descriptor->buffer_log, 1156 (void *)descriptor->buffer_phy, descriptor->buffer_size); 1157 } 1158 1159 fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, 32); 1160 } 1161 1162 1163 void 1164 UHCI::FreeDescriptorChain(uhci_td *topDescriptor) 1165 { 1166 uhci_td *current = topDescriptor; 1167 uhci_td *next = NULL; 1168 1169 while (current) { 1170 next = (uhci_td *)current->link_log; 1171 FreeDescriptor(current); 1172 current = next; 1173 } 1174 } 1175 1176 1177 void 1178 UHCI::LinkDescriptors(uhci_td *first, uhci_td *second) 1179 { 1180 first->link_phy = second->this_phy | TD_DEPTH_FIRST; 1181 first->link_log = second; 1182 } 1183 1184 1185 size_t 1186 UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector, 1187 size_t vectorCount) 1188 { 1189 uhci_td *current = topDescriptor; 1190 size_t actualLength = 0; 1191 size_t vectorIndex = 0; 1192 size_t vectorOffset = 0; 1193 size_t bufferOffset = 0; 1194 1195 while (current) { 1196 if (!current->buffer_log) 1197 break; 1198 1199 while (true) { 1200 size_t length = min_c(current->buffer_size - bufferOffset, 1201 vector[vectorIndex].iov_len - vectorOffset); 1202 1203 TRACE(("usb_uhci: copying %d bytes to bufferOffset %d from vectorOffset %d at index %d of %d\n", length, bufferOffset, vectorOffset, vectorIndex, vectorCount)); 1204 memcpy((uint8 *)current->buffer_log + bufferOffset, 1205 (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length); 1206 1207 actualLength += length; 1208 vectorOffset += length; 1209 bufferOffset += length; 1210 1211 if (vectorOffset >= vector[vectorIndex].iov_len) { 1212 if (++vectorIndex >= vectorCount) { 1213 TRACE(("usb_uhci: wrote descriptor chain (%d bytes, no more vectors)\n", actualLength)); 1214 return actualLength; 1215 } 1216 1217 vectorOffset = 0; 1218 } 1219 1220 if (bufferOffset >= current->buffer_size) { 1221 bufferOffset = 0; 1222 break; 1223 } 1224 } 1225 1226 if (current->link_phy & TD_TERMINATE) 1227 break; 1228 1229 current = (uhci_td *)current->link_log; 1230 } 1231 1232 TRACE(("usb_uhci: wrote descriptor chain (%d bytes)\n", actualLength)); 1233 return actualLength; 1234 } 1235 1236 1237 size_t 1238 UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector, 1239 size_t vectorCount, uint8 *lastDataToggle) 1240 { 1241 uint8 dataToggle = 0; 1242 uhci_td *current = topDescriptor; 1243 size_t actualLength = 0; 1244 size_t vectorIndex = 0; 1245 size_t vectorOffset = 0; 1246 size_t bufferOffset = 0; 1247 1248 while (current && (current->status & TD_STATUS_ACTIVE) == 0) { 1249 if (!current->buffer_log) 1250 break; 1251 1252 dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01; 1253 size_t bufferSize = (current->status & TD_STATUS_ACTLEN_MASK) + 1; 1254 if (bufferSize == TD_STATUS_ACTLEN_NULL + 1) 1255 bufferSize = 0; 1256 1257 while (true) { 1258 size_t length = min_c(bufferSize - bufferOffset, 1259 vector[vectorIndex].iov_len - vectorOffset); 1260 1261 TRACE(("usb_uhci: copying %d bytes to vectorOffset %d from bufferOffset %d at index %d of %d\n", length, vectorOffset, bufferOffset, vectorIndex, vectorCount)); 1262 memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset, 1263 (uint8 *)current->buffer_log + bufferOffset, length); 1264 1265 actualLength += length; 1266 vectorOffset += length; 1267 bufferOffset += length; 1268 1269 if (vectorOffset >= vector[vectorIndex].iov_len) { 1270 if (++vectorIndex >= vectorCount) { 1271 TRACE(("usb_uhci: read descriptor chain (%d bytes, no more vectors)\n", actualLength)); 1272 if (lastDataToggle) 1273 *lastDataToggle = dataToggle; 1274 return actualLength; 1275 } 1276 1277 vectorOffset = 0; 1278 } 1279 1280 if (bufferOffset >= bufferSize) { 1281 bufferOffset = 0; 1282 break; 1283 } 1284 } 1285 1286 if (current->link_phy & TD_TERMINATE) 1287 break; 1288 1289 current = (uhci_td *)current->link_log; 1290 } 1291 1292 if (lastDataToggle) 1293 *lastDataToggle = dataToggle; 1294 1295 TRACE(("usb_uhci: read descriptor chain (%d bytes)\n", actualLength)); 1296 return actualLength; 1297 } 1298 1299 1300 size_t 1301 UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle) 1302 { 1303 size_t actualLength = 0; 1304 uhci_td *current = topDescriptor; 1305 uint8 dataToggle = 0; 1306 1307 while (current && (current->status & TD_STATUS_ACTIVE) == 0) { 1308 size_t length = (current->status & TD_STATUS_ACTLEN_MASK) + 1; 1309 if (length == TD_STATUS_ACTLEN_NULL + 1) 1310 length = 0; 1311 1312 actualLength += length; 1313 dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01; 1314 1315 if (current->link_phy & TD_TERMINATE) 1316 break; 1317 1318 current = (uhci_td *)current->link_log; 1319 } 1320 1321 if (lastDataToggle) 1322 *lastDataToggle = dataToggle; 1323 1324 TRACE(("usb_uhci: read actual length (%d bytes)\n", actualLength)); 1325 return actualLength; 1326 } 1327 1328 1329 inline void 1330 UHCI::WriteReg8(uint32 reg, uint8 value) 1331 { 1332 sPCIModule->write_io_8(fRegisterBase + reg, value); 1333 } 1334 1335 1336 inline void 1337 UHCI::WriteReg16(uint32 reg, uint16 value) 1338 { 1339 sPCIModule->write_io_16(fRegisterBase + reg, value); 1340 } 1341 1342 1343 inline void 1344 UHCI::WriteReg32(uint32 reg, uint32 value) 1345 { 1346 sPCIModule->write_io_32(fRegisterBase + reg, value); 1347 } 1348 1349 1350 inline uint8 1351 UHCI::ReadReg8(uint32 reg) 1352 { 1353 return sPCIModule->read_io_8(fRegisterBase + reg); 1354 } 1355 1356 1357 inline uint16 1358 UHCI::ReadReg16(uint32 reg) 1359 { 1360 return sPCIModule->read_io_16(fRegisterBase + reg); 1361 } 1362 1363 1364 inline uint32 1365 UHCI::ReadReg32(uint32 reg) 1366 { 1367 return sPCIModule->read_io_32(fRegisterBase + reg); 1368 } 1369