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 0, 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%08lx; lp: 0x%08lx; vf: %s; q: %s; t: %s; st: 0x%08lx; to: 0x%08lx\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, 103 sizeof(uhci_qh)); 104 if (fStatus < B_OK) 105 return; 106 107 fQueueHead->this_phy = (addr_t)physicalAddress; 108 fQueueHead->element_phy = QH_TERMINATE; 109 110 fStrayDescriptor = NULL; 111 fQueueTop = NULL; 112 } 113 114 115 Queue::~Queue() 116 { 117 Lock(); 118 benaphore_destroy(&fLock); 119 120 fStack->FreeChunk(fQueueHead, (void *)fQueueHead->this_phy, sizeof(uhci_qh)); 121 122 if (fStrayDescriptor) 123 fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy, 124 sizeof(uhci_td)); 125 } 126 127 128 status_t 129 Queue::InitCheck() 130 { 131 return fStatus; 132 } 133 134 135 bool 136 Queue::Lock() 137 { 138 return (benaphore_lock(&fLock) == B_OK); 139 } 140 141 142 void 143 Queue::Unlock() 144 { 145 benaphore_unlock(&fLock); 146 } 147 148 149 status_t 150 Queue::LinkTo(Queue *other) 151 { 152 if (!other) 153 return B_BAD_VALUE; 154 155 if (!Lock()) 156 return B_ERROR; 157 158 fQueueHead->link_phy = other->fQueueHead->this_phy | QH_NEXT_IS_QH; 159 fQueueHead->link_log = other->fQueueHead; 160 Unlock(); 161 162 return B_OK; 163 } 164 165 166 status_t 167 Queue::TerminateByStrayDescriptor() 168 { 169 // According to the *BSD USB sources, there needs to be a stray transfer 170 // descriptor in order to get some chipset to work nicely (like the PIIX). 171 void *physicalAddress; 172 status_t result = fStack->AllocateChunk((void **)&fStrayDescriptor, 173 &physicalAddress, sizeof(uhci_td)); 174 if (result < B_OK) { 175 TRACE_ERROR(("usb_uhci: failed to allocate a stray transfer descriptor\n")); 176 return result; 177 } 178 179 fStrayDescriptor->status = 0; 180 fStrayDescriptor->this_phy = (addr_t)physicalAddress; 181 fStrayDescriptor->link_phy = TD_TERMINATE; 182 fStrayDescriptor->link_log = 0; 183 fStrayDescriptor->buffer_phy = 0; 184 fStrayDescriptor->buffer_log = 0; 185 fStrayDescriptor->buffer_size = 0; 186 fStrayDescriptor->token = TD_TOKEN_NULL_DATA 187 | (0x7f << TD_TOKEN_DEVADDR_SHIFT) | TD_TOKEN_IN; 188 189 if (!Lock()) { 190 fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy, 191 sizeof(uhci_td)); 192 return B_ERROR; 193 } 194 195 fQueueHead->link_phy = fStrayDescriptor->this_phy; 196 fQueueHead->link_log = fStrayDescriptor; 197 fQueueHead->element_phy = QH_TERMINATE; 198 Unlock(); 199 200 return B_OK; 201 } 202 203 204 status_t 205 Queue::AppendDescriptorChain(uhci_td *descriptor) 206 { 207 TRACE(("usb_uhci: appending descriptor chain\n")); 208 209 if (!Lock()) 210 return B_ERROR; 211 212 #ifdef TRACE_USB 213 print_descriptor_chain(descriptor); 214 #endif 215 216 if (fQueueTop == NULL) { 217 // the queue is empty, make this the first element 218 fQueueTop = descriptor; 219 fQueueHead->element_phy = descriptor->this_phy; 220 TRACE(("usb_uhci: first transfer in queue\n")); 221 } else { 222 // there are transfers linked, append to the queue 223 uhci_td *element = fQueueTop; 224 while ((element->link_phy & TD_TERMINATE) == 0) 225 element = (uhci_td *)element->link_log; 226 227 element->link_log = descriptor; 228 element->link_phy = descriptor->this_phy | TD_DEPTH_FIRST; 229 TRACE(("usb_uhci: appended transfer to queue\n")); 230 } 231 232 Unlock(); 233 return B_OK; 234 } 235 236 237 status_t 238 Queue::RemoveDescriptorChain(uhci_td *firstDescriptor, uhci_td *lastDescriptor) 239 { 240 TRACE(("usb_uhci: removing descriptor chain\n")); 241 242 if (!Lock()) 243 return B_ERROR; 244 245 if (fQueueTop == firstDescriptor) { 246 // it is the first chain in this queue 247 if ((lastDescriptor->link_phy & TD_TERMINATE) > 0) { 248 // it is the only chain in this queue 249 fQueueTop = NULL; 250 fQueueHead->element_phy = QH_TERMINATE; 251 } else { 252 // there are still linked transfers 253 fQueueTop = (uhci_td *)lastDescriptor->link_log; 254 fQueueHead->element_phy = fQueueTop->this_phy & TD_LINK_MASK; 255 } 256 } else { 257 // unlink the chain 258 uhci_td *element = fQueueTop; 259 while (element) { 260 if (element->link_log == firstDescriptor) { 261 element->link_log = lastDescriptor->link_log; 262 element->link_phy = lastDescriptor->link_phy; 263 break; 264 } 265 266 element = (uhci_td *)element->link_log; 267 } 268 269 element = firstDescriptor; 270 while (element && element != lastDescriptor) { 271 if ((fQueueHead->element_phy & TD_LINK_MASK) == element->this_phy) { 272 fQueueHead->element_phy = lastDescriptor->link_phy; 273 break; 274 } 275 276 element = (uhci_td *)element->link_log; 277 } 278 } 279 280 lastDescriptor->link_log = NULL; 281 lastDescriptor->link_phy = TD_TERMINATE; 282 283 #ifdef TRACE_USB 284 print_descriptor_chain(firstDescriptor); 285 #endif 286 287 Unlock(); 288 return B_OK; 289 } 290 291 292 addr_t 293 Queue::PhysicalAddress() 294 { 295 return fQueueHead->this_phy; 296 } 297 298 299 void 300 Queue::PrintToStream() 301 { 302 #ifdef TRACE_USB 303 dprintf("USB UHCI Queue:\n"); 304 dprintf("link phy: 0x%08lx; link type: %s; terminate: %s\n", fQueueHead->link_phy & 0xfff0, fQueueHead->link_phy & 0x0002 ? "QH" : "TD", fQueueHead->link_phy & 0x0001 ? "yes" : "no"); 305 dprintf("elem phy: 0x%08lx; elem type: %s; terminate: %s\n", fQueueHead->element_phy & 0xfff0, fQueueHead->element_phy & 0x0002 ? "QH" : "TD", fQueueHead->element_phy & 0x0001 ? "yes" : "no"); 306 dprintf("elements:\n"); 307 print_descriptor_chain(fQueueTop); 308 #endif 309 } 310 311 312 // 313 // #pragma mark - 314 // 315 316 317 UHCI::UHCI(pci_info *info, Stack *stack) 318 : BusManager(stack), 319 fPCIInfo(info), 320 fStack(stack), 321 fFrameArea(-1), 322 fFrameList(NULL), 323 fQueueCount(0), 324 fQueues(NULL), 325 fFirstTransfer(NULL), 326 fLastTransfer(NULL), 327 fFinishThread(-1), 328 fStopFinishThread(false), 329 fRootHub(NULL), 330 fRootHubAddress(0), 331 fPortResetChange(0) 332 { 333 if (!fInitOK) { 334 TRACE_ERROR(("usb_uhci: bus manager failed to init\n")); 335 return; 336 } 337 338 TRACE(("usb_uhci: constructing new UHCI Host Controller Driver\n")); 339 fInitOK = false; 340 341 fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus, 342 fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4); 343 fRegisterBase &= PCI_address_io_mask; 344 TRACE_ERROR(("usb_uhci: iospace offset: 0x%08lx\n", fRegisterBase)); 345 346 if (fRegisterBase == 0) { 347 fRegisterBase = fPCIInfo->u.h0.base_registers[0]; 348 TRACE_ERROR(("usb_uhci: register base: 0x%08lx\n", fRegisterBase)); 349 } 350 351 // enable pci address access 352 uint16 command = PCI_command_io | PCI_command_master | PCI_command_memory; 353 command |= sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device, 354 fPCIInfo->function, PCI_command, 2); 355 356 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 357 fPCIInfo->function, PCI_command, 2, command); 358 359 // make sure we gain controll of the UHCI controller instead of the BIOS 360 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 2, 361 PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN); 362 363 // disable interrupts 364 WriteReg16(UHCI_USBINTR, 0); 365 366 // do a global and host reset 367 GlobalReset(); 368 if (ControllerReset() < B_OK) { 369 TRACE_ERROR(("usb_uhci: host failed to reset\n")); 370 return; 371 } 372 373 // Setup the frame list 374 void *physicalAddress; 375 fFrameArea = fStack->AllocateArea((void **)&fFrameList, 376 (void **)&physicalAddress, 4096, "USB UHCI framelist"); 377 378 if (fFrameArea < B_OK) { 379 TRACE_ERROR(("usb_uhci: unable to create an area for the frame pointer list\n")); 380 return; 381 } 382 383 // Set base pointer and reset frame number 384 WriteReg32(UHCI_FRBASEADD, (uint32)physicalAddress); 385 WriteReg16(UHCI_FRNUM, 0); 386 387 fQueueCount = 4; 388 fQueues = new(std::nothrow) Queue *[fQueueCount]; 389 if (!fQueues) { 390 delete_area(fFrameArea); 391 return; 392 } 393 394 for (int32 i = 0; i < fQueueCount; i++) { 395 fQueues[i] = new(std::nothrow) Queue(fStack); 396 if (!fQueues[i] || fQueues[i]->InitCheck() < B_OK) { 397 TRACE_ERROR(("usb_uhci: cannot create queues\n")); 398 delete_area(fFrameArea); 399 return; 400 } 401 402 if (i > 0) 403 fQueues[i - 1]->LinkTo(fQueues[i]); 404 } 405 406 // Make sure the last queue terminates 407 fQueues[fQueueCount - 1]->TerminateByStrayDescriptor(); 408 409 for (int32 i = 0; i < 1024; i++) 410 fFrameList[i] = fQueues[0]->PhysicalAddress() | FRAMELIST_NEXT_IS_QH; 411 412 // create semaphore the finisher thread will wait for 413 fFinishTransfersSem = create_sem(0, "UHCI Finish Transfers"); 414 if (fFinishTransfersSem < B_OK) { 415 TRACE_ERROR(("usb_uhci: failed to create semaphore\n")); 416 return; 417 } 418 419 // Create the finisher service thread 420 fFinishThread = spawn_kernel_thread(FinishThread, 421 "uhci finish thread", B_NORMAL_PRIORITY, (void *)this); 422 resume_thread(fFinishThread); 423 424 // Install the interrupt handler 425 TRACE(("usb_uhci: installing interrupt handler\n")); 426 install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line, 427 InterruptHandler, (void *)this, 0); 428 429 // Enable interrupts 430 WriteReg16(UHCI_USBINTR, UHCI_USBINTR_CRC | UHCI_USBINTR_RESUME 431 | UHCI_USBINTR_IOC | UHCI_USBINTR_SHORT); 432 433 TRACE(("usb_uhci: UHCI Host Controller Driver constructed\n")); 434 fInitOK = true; 435 } 436 437 438 UHCI::~UHCI() 439 { 440 int32 result = 0; 441 fStopFinishThread = true; 442 delete_sem(fFinishTransfersSem); 443 wait_for_thread(fFinishThread, &result); 444 445 Lock(); 446 transfer_data *transfer = fFirstTransfer; 447 while (transfer) { 448 transfer_data *next = transfer->link; 449 delete transfer; 450 transfer = next; 451 } 452 453 for (int32 i = 0; i < fQueueCount; i++) 454 delete fQueues[i]; 455 456 delete [] fQueues; 457 delete fRootHub; 458 delete_area(fFrameArea); 459 460 put_module(B_PCI_MODULE_NAME); 461 Unlock(); 462 } 463 464 465 status_t 466 UHCI::Start() 467 { 468 // Start the host controller, then start the Busmanager 469 TRACE(("usb_uhci: starting UHCI BusManager\n")); 470 TRACE(("usb_uhci: usbcmd reg 0x%04x, usbsts reg 0x%04x\n", 471 ReadReg16(UHCI_USBCMD), ReadReg16(UHCI_USBSTS))); 472 473 // Set the run bit in the command register 474 WriteReg16(UHCI_USBCMD, ReadReg16(UHCI_USBCMD) | UHCI_USBCMD_RS); 475 476 bool running = false; 477 for (int32 i = 0; i < 10; i++) { 478 uint16 status = ReadReg16(UHCI_USBSTS); 479 TRACE(("usb_uhci: current loop %ld, status 0x%04x\n", i, status)); 480 481 if (status & UHCI_USBSTS_HCHALT) 482 snooze(10000); 483 else { 484 running = true; 485 break; 486 } 487 } 488 489 if (!running) { 490 TRACE_ERROR(("usb_uhci: controller won't start running\n")); 491 return B_ERROR; 492 } 493 494 fRootHubAddress = AllocateAddress(); 495 fRootHub = new(std::nothrow) UHCIRootHub(RootObject(), fRootHubAddress); 496 if (!fRootHub) { 497 TRACE_ERROR(("usb_uhci: no memory to allocate root hub\n")); 498 return B_NO_MEMORY; 499 } 500 501 if (fRootHub->InitCheck() < B_OK) { 502 TRACE_ERROR(("usb_uhci: root hub failed init check\n")); 503 delete fRootHub; 504 return B_ERROR; 505 } 506 507 SetRootHub(fRootHub); 508 509 TRACE(("usb_uhci: controller is started. status: %u curframe: %u\n", 510 ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM))); 511 return BusManager::Start(); 512 } 513 514 515 status_t 516 UHCI::SubmitTransfer(Transfer *transfer) 517 { 518 // Short circuit the root hub 519 if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress) 520 return fRootHub->ProcessTransfer(this, transfer); 521 522 TRACE(("usb_uhci: submit transfer called for device %d\n", transfer->TransferPipe()->DeviceAddress())); 523 if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) 524 return SubmitRequest(transfer); 525 526 if (transfer->VectorCount() == 0) 527 return B_BAD_VALUE; 528 529 Pipe *pipe = transfer->TransferPipe(); 530 bool directionIn = (pipe->Direction() == Pipe::In); 531 532 uhci_td *firstDescriptor = NULL; 533 uhci_td *lastDescriptor = NULL; 534 status_t result = CreateDescriptorChain(pipe, &firstDescriptor, 535 &lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, 536 transfer->VectorLength()); 537 538 if (result < B_OK) 539 return result; 540 if (!firstDescriptor || !lastDescriptor) 541 return B_NO_MEMORY; 542 543 lastDescriptor->status |= TD_CONTROL_IOC; 544 lastDescriptor->link_phy = TD_TERMINATE; 545 lastDescriptor->link_log = 0; 546 547 if (!directionIn) { 548 WriteDescriptorChain(firstDescriptor, transfer->Vector(), 549 transfer->VectorCount()); 550 } 551 552 Queue *queue = fQueues[3]; 553 if (pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) 554 queue = fQueues[2]; 555 556 result = AddPendingTransfer(transfer, queue, firstDescriptor, 557 firstDescriptor, lastDescriptor, directionIn); 558 if (result < B_OK) { 559 TRACE_ERROR(("usb_uhci: failed to add pending transfer\n")); 560 FreeDescriptorChain(firstDescriptor); 561 return result; 562 } 563 564 result = queue->AppendDescriptorChain(firstDescriptor); 565 if (result < B_OK) { 566 TRACE_ERROR(("usb_uhci: failed to append descriptor chain\n")); 567 FreeDescriptorChain(firstDescriptor); 568 return result; 569 } 570 571 return B_OK; 572 } 573 574 575 status_t 576 UHCI::SubmitRequest(Transfer *transfer) 577 { 578 Pipe *pipe = transfer->TransferPipe(); 579 usb_request_data *requestData = transfer->RequestData(); 580 bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0; 581 582 uhci_td *setupDescriptor = CreateDescriptor(pipe, TD_TOKEN_SETUP, 583 sizeof(usb_request_data)); 584 585 uhci_td *statusDescriptor = CreateDescriptor(pipe, 586 directionIn ? TD_TOKEN_OUT : TD_TOKEN_IN, 0); 587 588 if (!setupDescriptor || !statusDescriptor) { 589 TRACE_ERROR(("usb_uhci: failed to allocate descriptors\n")); 590 FreeDescriptor(setupDescriptor); 591 FreeDescriptor(statusDescriptor); 592 return B_NO_MEMORY; 593 } 594 595 iovec vector; 596 vector.iov_base = requestData; 597 vector.iov_len = sizeof(usb_request_data); 598 WriteDescriptorChain(setupDescriptor, &vector, 1); 599 600 statusDescriptor->status |= TD_CONTROL_IOC; 601 statusDescriptor->token |= TD_TOKEN_DATA1; 602 statusDescriptor->link_phy = TD_TERMINATE; 603 statusDescriptor->link_log = NULL; 604 605 uhci_td *dataDescriptor = NULL; 606 if (transfer->VectorCount() > 0) { 607 uhci_td *lastDescriptor = NULL; 608 status_t result = CreateDescriptorChain(pipe, &dataDescriptor, 609 &lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, 610 transfer->VectorLength()); 611 612 if (result < B_OK) { 613 FreeDescriptor(setupDescriptor); 614 FreeDescriptor(statusDescriptor); 615 return result; 616 } 617 618 if (!directionIn) { 619 WriteDescriptorChain(dataDescriptor, transfer->Vector(), 620 transfer->VectorCount()); 621 } 622 623 LinkDescriptors(setupDescriptor, dataDescriptor); 624 LinkDescriptors(lastDescriptor, statusDescriptor); 625 } else { 626 // Link transfer and status descriptors directly 627 LinkDescriptors(setupDescriptor, statusDescriptor); 628 } 629 630 status_t result = AddPendingTransfer(transfer, fQueues[1], setupDescriptor, 631 dataDescriptor, statusDescriptor, directionIn); 632 if (result < B_OK) { 633 TRACE_ERROR(("usb_uhci: failed to add pending transfer\n")); 634 FreeDescriptorChain(setupDescriptor); 635 return result; 636 } 637 638 result = fQueues[1]->AppendDescriptorChain(setupDescriptor); 639 if (result < B_OK) { 640 TRACE_ERROR(("usb_uhci: failed to append descriptor chain\n")); 641 FreeDescriptorChain(setupDescriptor); 642 return result; 643 } 644 645 return B_OK; 646 } 647 648 649 status_t 650 UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue, 651 uhci_td *firstDescriptor, uhci_td *dataDescriptor, uhci_td *lastDescriptor, 652 bool directionIn) 653 { 654 transfer_data *data = new(std::nothrow) transfer_data(); 655 if (!data) 656 return B_NO_MEMORY; 657 658 data->transfer = transfer; 659 data->queue = queue; 660 data->first_descriptor = firstDescriptor; 661 data->data_descriptor = dataDescriptor; 662 data->last_descriptor = lastDescriptor; 663 data->user_area = -1; 664 data->incoming = directionIn; 665 data->link = NULL; 666 667 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 668 if (directionIn) { 669 // we might need to access a buffer in userspace. this will not 670 // be possible in the kernel space finisher thread unless we 671 // get the proper area id for the space we need and then clone it 672 // before writing to it. this is of course terribly inefficient... 673 iovec *vector = transfer->Vector(); 674 size_t vectorCount = transfer->VectorCount(); 675 for (size_t i = 0; i < vectorCount; i++) { 676 if (IS_USER_ADDRESS(vector[i].iov_base)) { 677 data->user_area = area_for(vector[i].iov_base); 678 if (data->user_area < B_OK) { 679 TRACE_ERROR(("usb_uhci: failed to get area of userspace buffer\n")); 680 delete data; 681 return B_BAD_ADDRESS; 682 } 683 684 break; 685 } 686 } 687 688 if (data->user_area >= B_OK) { 689 area_info areaInfo; 690 if (get_area_info(data->user_area, &areaInfo) < B_OK) { 691 TRACE_ERROR(("usb_uhci: failed to get info about user area\n")); 692 delete data; 693 return B_BAD_ADDRESS; 694 } 695 696 for (size_t i = 0; i < vectorCount; i++) { 697 (uint8 *)vector[i].iov_base -= (uint8 *)areaInfo.address; 698 699 if ((size_t)vector[i].iov_base > areaInfo.size 700 || (size_t)vector[i].iov_base + vector[i].iov_len > areaInfo.size) { 701 TRACE_ERROR(("usb_uhci: output data buffer spans across multiple areas!\n")); 702 delete data; 703 return B_BAD_ADDRESS; 704 } 705 } 706 } 707 } 708 #endif // !HAIKU_TARGET_PLATFORM_HAIKU 709 710 if (!Lock()) { 711 delete data; 712 return B_ERROR; 713 } 714 715 if (fLastTransfer) 716 fLastTransfer->link = data; 717 else 718 fFirstTransfer = data; 719 720 fLastTransfer = data; 721 Unlock(); 722 723 return B_OK; 724 } 725 726 727 int32 728 UHCI::FinishThread(void *data) 729 { 730 ((UHCI *)data)->FinishTransfers(); 731 return B_OK; 732 } 733 734 735 void 736 UHCI::FinishTransfers() 737 { 738 while (!fStopFinishThread) { 739 if (acquire_sem(fFinishTransfersSem) < B_OK) 740 continue; 741 742 // eat up sems that have been released by multiple interrupts 743 int32 semCount = 0; 744 get_sem_count(fFinishTransfersSem, &semCount); 745 if (semCount > 0) 746 acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0); 747 748 if (!Lock()) 749 continue; 750 751 TRACE(("usb_uhci: finishing transfers (first transfer: 0x%08lx; last transfer: 0x%08lx)\n", (uint32)fFirstTransfer, (uint32)fLastTransfer)); 752 transfer_data *lastTransfer = NULL; 753 transfer_data *transfer = fFirstTransfer; 754 Unlock(); 755 756 while (transfer) { 757 bool transferDone = false; 758 uhci_td *descriptor = transfer->first_descriptor; 759 760 while (descriptor) { 761 uint32 status = descriptor->status; 762 if (status & TD_STATUS_ACTIVE) { 763 TRACE(("usb_uhci: td (0x%08lx) still active\n", descriptor->this_phy)); 764 // still in progress 765 break; 766 } 767 768 if (status & TD_ERROR_MASK) { 769 TRACE_ERROR(("usb_uhci: td (0x%08lx) error: 0x%08lx\n", descriptor->this_phy, status)); 770 // an error occured. we have to remove the 771 // transfer from the queue and clean up 772 773 status_t callbackStatus = B_ERROR; 774 uint8 errorCount = status >> TD_ERROR_COUNT_SHIFT; 775 errorCount &= TD_ERROR_COUNT_MASK; 776 if (errorCount == 0) { 777 // the error counter counted down to zero, report why 778 int32 reasons = 0; 779 if (status & TD_STATUS_ERROR_BUFFER) { 780 callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN; 781 reasons++; 782 } 783 if (status & TD_STATUS_ERROR_TIMEOUT) { 784 callbackStatus = transfer->incoming ? B_DEV_CRC_ERROR : B_TIMED_OUT; 785 reasons++; 786 } 787 if (status & TD_STATUS_ERROR_NAK) { 788 callbackStatus = B_DEV_UNEXPECTED_PID; 789 reasons++; 790 } 791 if (status & TD_STATUS_ERROR_BITSTUFF) { 792 callbackStatus = B_DEV_CRC_ERROR; 793 reasons++; 794 } 795 796 if (reasons > 1) 797 callbackStatus = B_DEV_MULTIPLE_ERRORS; 798 } else if (status & TD_STATUS_ERROR_BABBLE) { 799 // there is a babble condition 800 callbackStatus = transfer->incoming ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN; 801 } else { 802 // if the error counter didn't count down to zero 803 // and there was no babble, then this halt was caused 804 // by a stall handshake 805 callbackStatus = B_DEV_STALLED; 806 } 807 808 transfer->queue->RemoveDescriptorChain( 809 transfer->first_descriptor, 810 transfer->last_descriptor); 811 812 FreeDescriptorChain(transfer->first_descriptor); 813 transfer->transfer->Finished(callbackStatus, 0); 814 transferDone = true; 815 break; 816 } 817 818 // either all descriptors are done, or we have a short packet 819 if (descriptor == transfer->last_descriptor 820 || (descriptor->status & TD_STATUS_ACTLEN_MASK) 821 < (descriptor->token >> TD_TOKEN_MAXLEN_SHIFT)) { 822 TRACE(("usb_uhci: td (0x%08lx) ok\n", descriptor->this_phy)); 823 // we got through without errors so we are finished 824 transfer->queue->RemoveDescriptorChain( 825 transfer->first_descriptor, 826 transfer->last_descriptor); 827 828 size_t actualLength = 0; 829 uint8 lastDataToggle = 0; 830 if (transfer->data_descriptor && transfer->incoming) { 831 // data to read out 832 iovec *vector = transfer->transfer->Vector(); 833 size_t vectorCount = transfer->transfer->VectorCount(); 834 835 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 836 area_id clonedArea = -1; 837 if (transfer->user_area >= B_OK) { 838 // we got a userspace output buffer, need to clone 839 // the area for that space first and map the iovecs 840 // to this cloned area. 841 void *clonedMemory = NULL; 842 clonedArea = clone_area("userspace accessor", 843 &clonedMemory, B_ANY_ADDRESS, 844 B_WRITE_AREA | B_KERNEL_WRITE_AREA, 845 transfer->user_area); 846 847 for (size_t i = 0; i < vectorCount; i++) 848 (uint8 *)vector[i].iov_base += (addr_t)clonedMemory; 849 } 850 #endif // !HAIKU_TARGET_PLATFORM_HAIKU 851 852 actualLength = ReadDescriptorChain( 853 transfer->data_descriptor, 854 vector, vectorCount, 855 &lastDataToggle); 856 857 #ifndef HAIKU_TARGET_PLATFORM_HAIKU 858 if (clonedArea >= B_OK) 859 delete_area(clonedArea); 860 #endif // !HAIKU_TARGET_PLATFORM_HAIKU 861 } else { 862 // read the actual length that was sent 863 actualLength = ReadActualLength( 864 transfer->first_descriptor, &lastDataToggle); 865 } 866 867 FreeDescriptorChain(transfer->first_descriptor); 868 transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0); 869 transfer->transfer->Finished(B_OK, actualLength); 870 transferDone = true; 871 break; 872 } 873 874 descriptor = (uhci_td *)descriptor->link_log; 875 } 876 877 if (transferDone) { 878 if (Lock()) { 879 if (lastTransfer) 880 lastTransfer->link = transfer->link; 881 882 if (transfer == fFirstTransfer) 883 fFirstTransfer = transfer->link; 884 if (transfer == fLastTransfer) 885 fLastTransfer = lastTransfer; 886 887 transfer_data *next = transfer->link; 888 delete transfer->transfer; 889 delete transfer; 890 transfer = next; 891 892 Unlock(); 893 } 894 } else { 895 lastTransfer = transfer; 896 transfer = transfer->link; 897 } 898 } 899 } 900 } 901 902 903 void 904 UHCI::GlobalReset() 905 { 906 uint8 sofValue = ReadReg8(UHCI_SOFMOD); 907 908 WriteReg16(UHCI_USBCMD, UHCI_USBCMD_GRESET); 909 snooze(100000); 910 WriteReg16(UHCI_USBCMD, 0); 911 snooze(10000); 912 913 WriteReg8(UHCI_SOFMOD, sofValue); 914 } 915 916 917 status_t 918 UHCI::ControllerReset() 919 { 920 WriteReg16(UHCI_USBCMD, UHCI_USBCMD_HCRESET); 921 922 int32 tries = 5; 923 while (ReadReg16(UHCI_USBCMD) & UHCI_USBCMD_HCRESET) { 924 snooze(10000); 925 if (tries-- < 0) 926 return B_ERROR; 927 } 928 929 return B_OK; 930 } 931 932 933 status_t 934 UHCI::GetPortStatus(uint8 index, usb_port_status *status) 935 { 936 if (index > 1) 937 return B_BAD_INDEX; 938 939 status->status = status->change = 0; 940 uint16 portStatus = ReadReg16(UHCI_PORTSC1 + index * 2); 941 942 // build the status 943 if (portStatus & UHCI_PORTSC_CURSTAT) 944 status->status |= PORT_STATUS_CONNECTION; 945 if (portStatus & UHCI_PORTSC_ENABLED) 946 status->status |= PORT_STATUS_ENABLE; 947 if (portStatus & UHCI_PORTSC_RESET) 948 status->status |= PORT_STATUS_RESET; 949 if (portStatus & UHCI_PORTSC_LOWSPEED) 950 status->status |= PORT_STATUS_LOW_SPEED; 951 952 // build the change 953 if (portStatus & UHCI_PORTSC_STATCHA) 954 status->change |= PORT_STATUS_CONNECTION; 955 if (portStatus & UHCI_PORTSC_ENABCHA) 956 status->change |= PORT_STATUS_ENABLE; 957 958 // ToDo: work out suspended/resume 959 960 // there are no bits to indicate reset change 961 if (fPortResetChange & (1 << index)) 962 status->change |= PORT_STATUS_RESET; 963 964 // the port is automagically powered on 965 status->status |= PORT_STATUS_POWER; 966 return B_OK; 967 } 968 969 970 status_t 971 UHCI::SetPortFeature(uint8 index, uint16 feature) 972 { 973 if (index > 1) 974 return B_BAD_INDEX; 975 976 switch (feature) { 977 case PORT_RESET: 978 return ResetPort(index); 979 980 case PORT_POWER: 981 // the ports are automatically powered 982 return B_OK; 983 } 984 985 return B_BAD_VALUE; 986 } 987 988 989 status_t 990 UHCI::ClearPortFeature(uint8 index, uint16 feature) 991 { 992 if (index > 1) 993 return B_BAD_INDEX; 994 995 uint32 portRegister = UHCI_PORTSC1 + index * 2; 996 uint16 portStatus = ReadReg16(portRegister) & UHCI_PORTSC_DATAMASK; 997 998 switch (feature) { 999 case C_PORT_RESET: 1000 fPortResetChange &= ~(1 << index); 1001 return B_OK; 1002 1003 case C_PORT_CONNECTION: 1004 WriteReg16(portRegister, portStatus | UHCI_PORTSC_STATCHA); 1005 return B_OK; 1006 } 1007 1008 return B_BAD_VALUE; 1009 } 1010 1011 1012 status_t 1013 UHCI::ResetPort(uint8 index) 1014 { 1015 if (index > 1) 1016 return B_BAD_INDEX; 1017 1018 TRACE(("usb_uhci: reset port %d\n", index)); 1019 1020 uint32 port = UHCI_PORTSC1 + index * 2; 1021 uint16 status = ReadReg16(port); 1022 status &= UHCI_PORTSC_DATAMASK; 1023 WriteReg16(port, status | UHCI_PORTSC_RESET); 1024 snooze(250000); 1025 1026 status = ReadReg16(port); 1027 status &= UHCI_PORTSC_DATAMASK; 1028 WriteReg16(port, status & ~UHCI_PORTSC_RESET); 1029 snooze(1000); 1030 1031 for (int32 i = 10; i > 0; i--) { 1032 // try to enable the port 1033 status = ReadReg16(port); 1034 status &= UHCI_PORTSC_DATAMASK; 1035 WriteReg16(port, status | UHCI_PORTSC_ENABLED); 1036 snooze(50000); 1037 1038 status = ReadReg16(port); 1039 1040 if ((status & UHCI_PORTSC_CURSTAT) == 0) { 1041 // no device connected. since we waited long enough we can assume 1042 // that the port was reset and no device is connected. 1043 break; 1044 } 1045 1046 if (status & (UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA)) { 1047 // port enabled changed or connection status were set. 1048 // acknowledge either / both and wait again. 1049 status &= UHCI_PORTSC_DATAMASK; 1050 WriteReg16(port, status | UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA); 1051 continue; 1052 } 1053 1054 if (status & UHCI_PORTSC_ENABLED) { 1055 // the port is enabled 1056 break; 1057 } 1058 } 1059 1060 fPortResetChange |= (1 << index); 1061 TRACE(("usb_uhci: port was reset: 0x%04x\n", ReadReg16(port))); 1062 return B_OK; 1063 } 1064 1065 1066 int32 1067 UHCI::InterruptHandler(void *data) 1068 { 1069 return ((UHCI *)data)->Interrupt(); 1070 } 1071 1072 1073 int32 1074 UHCI::Interrupt() 1075 { 1076 spinlock lock = 0; 1077 acquire_spinlock(&lock); 1078 1079 // Check if we really had an interrupt 1080 uint16 status = ReadReg16(UHCI_USBSTS); 1081 if ((status & UHCI_INTERRUPT_MASK) == 0) { 1082 release_spinlock(&lock); 1083 return B_UNHANDLED_INTERRUPT; 1084 } 1085 1086 uint16 acknowledge = 0; 1087 bool finishTransfers = false; 1088 int32 result = B_HANDLED_INTERRUPT; 1089 1090 if (status & UHCI_USBSTS_USBINT) { 1091 TRACE(("usb_uhci: transfer finished\n")); 1092 acknowledge |= UHCI_USBSTS_USBINT; 1093 result = B_INVOKE_SCHEDULER; 1094 finishTransfers = true; 1095 } 1096 1097 if (status & UHCI_USBSTS_ERRINT) { 1098 TRACE(("usb_uhci: transfer error\n")); 1099 acknowledge |= UHCI_USBSTS_ERRINT; 1100 result = B_INVOKE_SCHEDULER; 1101 finishTransfers = true; 1102 } 1103 1104 if (status & UHCI_USBSTS_RESDET) { 1105 TRACE(("usb_uhci: resume detected\n")); 1106 acknowledge |= UHCI_USBSTS_RESDET; 1107 } 1108 1109 if (status & UHCI_USBSTS_HOSTERR) { 1110 TRACE(("usb_uhci: host system error\n")); 1111 acknowledge |= UHCI_USBSTS_HOSTERR; 1112 } 1113 1114 if (status & UHCI_USBSTS_HCPRERR) { 1115 TRACE(("usb_uhci: process error\n")); 1116 acknowledge |= UHCI_USBSTS_HCPRERR; 1117 } 1118 1119 if (status & UHCI_USBSTS_HCHALT) { 1120 TRACE(("usb_uhci: host controller halted\n")); 1121 // ToDo: cancel all transfers and reset the host controller 1122 // acknowledge not needed 1123 } 1124 1125 if (acknowledge) 1126 WriteReg16(UHCI_USBSTS, acknowledge); 1127 1128 release_spinlock(&lock); 1129 1130 if (finishTransfers) 1131 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE); 1132 1133 return result; 1134 } 1135 1136 1137 status_t 1138 UHCI::AddTo(Stack *stack) 1139 { 1140 #ifdef TRACE_USB 1141 set_dprintf_enabled(true); 1142 load_driver_symbols("uhci"); 1143 #endif 1144 1145 if (!sPCIModule) { 1146 status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule); 1147 if (status < B_OK) { 1148 TRACE_ERROR(("usb_uhci: AddTo(): getting pci module failed! 0x%08lx\n", 1149 status)); 1150 return status; 1151 } 1152 } 1153 1154 TRACE(("usb_uhci: AddTo(): setting up hardware\n")); 1155 1156 bool found = false; 1157 pci_info *item = new(std::nothrow) pci_info; 1158 if (!item) { 1159 sPCIModule = NULL; 1160 put_module(B_PCI_MODULE_NAME); 1161 return B_NO_MEMORY; 1162 } 1163 1164 for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) { 1165 1166 if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb 1167 && item->class_api == PCI_usb_uhci) { 1168 if (item->u.h0.interrupt_line == 0 1169 || item->u.h0.interrupt_line == 0xFF) { 1170 TRACE_ERROR(("usb_uhci: AddTo(): found with invalid IRQ - check IRQ assignement\n")); 1171 continue; 1172 } 1173 1174 TRACE(("usb_uhci: AddTo(): found at IRQ %u\n", item->u.h0.interrupt_line)); 1175 UHCI *bus = new(std::nothrow) UHCI(item, stack); 1176 if (!bus) { 1177 delete item; 1178 sPCIModule = NULL; 1179 put_module(B_PCI_MODULE_NAME); 1180 return B_NO_MEMORY; 1181 } 1182 1183 if (bus->InitCheck() < B_OK) { 1184 TRACE_ERROR(("usb_uhci: AddTo(): InitCheck() failed 0x%08lx\n", bus->InitCheck())); 1185 delete bus; 1186 continue; 1187 } 1188 1189 // the bus took it away 1190 item = new(std::nothrow) pci_info; 1191 1192 bus->Start(); 1193 stack->AddBusManager(bus); 1194 found = true; 1195 } 1196 } 1197 1198 if (!found) { 1199 TRACE_ERROR(("usb_uhci: no devices found\n")); 1200 delete item; 1201 sPCIModule = NULL; 1202 put_module(B_PCI_MODULE_NAME); 1203 return ENODEV; 1204 } 1205 1206 delete item; 1207 return B_OK; 1208 } 1209 1210 1211 uhci_td * 1212 UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, size_t bufferSize) 1213 { 1214 uhci_td *result; 1215 void *physicalAddress; 1216 1217 if (fStack->AllocateChunk((void **)&result, &physicalAddress, 1218 sizeof(uhci_td)) < B_OK) { 1219 TRACE_ERROR(("usb_uhci: failed to allocate a transfer descriptor\n")); 1220 return NULL; 1221 } 1222 1223 result->this_phy = (addr_t)physicalAddress; 1224 result->status = TD_STATUS_ACTIVE | TD_CONTROL_3_ERRORS | TD_CONTROL_SPD; 1225 if (pipe->Speed() == USB_SPEED_LOWSPEED) 1226 result->status |= TD_CONTROL_LOWSPEED; 1227 1228 result->buffer_size = bufferSize; 1229 if (bufferSize == 0) 1230 result->token = TD_TOKEN_NULL_DATA; 1231 else 1232 result->token = (bufferSize - 1) << TD_TOKEN_MAXLEN_SHIFT; 1233 1234 result->token |= (pipe->EndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT) 1235 | (pipe->DeviceAddress() << 8) | direction; 1236 1237 result->link_phy = 0; 1238 result->link_log = NULL; 1239 if (bufferSize <= 0) { 1240 result->buffer_log = NULL; 1241 result->buffer_phy = NULL; 1242 return result; 1243 } 1244 1245 if (fStack->AllocateChunk(&result->buffer_log, &result->buffer_phy, 1246 bufferSize) < B_OK) { 1247 TRACE_ERROR(("usb_uhci: unable to allocate space for the buffer\n")); 1248 fStack->FreeChunk(result, (void *)result->this_phy, sizeof(uhci_td)); 1249 return NULL; 1250 } 1251 1252 return result; 1253 } 1254 1255 1256 status_t 1257 UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor, 1258 uhci_td **_lastDescriptor, uint8 direction, size_t bufferSize) 1259 { 1260 size_t packetSize = pipe->MaxPacketSize(); 1261 int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize; 1262 1263 bool dataToggle = pipe->DataToggle(); 1264 uhci_td *firstDescriptor = NULL; 1265 uhci_td *lastDescriptor = *_firstDescriptor; 1266 for (int32 i = 0; i < descriptorCount; i++) { 1267 uhci_td *descriptor = CreateDescriptor(pipe, direction, 1268 min_c(packetSize, bufferSize)); 1269 1270 if (!descriptor) { 1271 FreeDescriptorChain(firstDescriptor); 1272 return B_NO_MEMORY; 1273 } 1274 1275 if (dataToggle) 1276 descriptor->token |= TD_TOKEN_DATA1; 1277 1278 // link to previous 1279 if (lastDescriptor) 1280 LinkDescriptors(lastDescriptor, descriptor); 1281 1282 dataToggle = !dataToggle; 1283 bufferSize -= packetSize; 1284 lastDescriptor = descriptor; 1285 if (!firstDescriptor) 1286 firstDescriptor = descriptor; 1287 } 1288 1289 *_firstDescriptor = firstDescriptor; 1290 *_lastDescriptor = lastDescriptor; 1291 return B_OK; 1292 } 1293 1294 1295 void 1296 UHCI::FreeDescriptor(uhci_td *descriptor) 1297 { 1298 if (!descriptor) 1299 return; 1300 1301 if (descriptor->buffer_log) { 1302 fStack->FreeChunk(descriptor->buffer_log, 1303 (void *)descriptor->buffer_phy, descriptor->buffer_size); 1304 } 1305 1306 fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(uhci_td)); 1307 } 1308 1309 1310 void 1311 UHCI::FreeDescriptorChain(uhci_td *topDescriptor) 1312 { 1313 uhci_td *current = topDescriptor; 1314 uhci_td *next = NULL; 1315 1316 while (current) { 1317 next = (uhci_td *)current->link_log; 1318 FreeDescriptor(current); 1319 current = next; 1320 } 1321 } 1322 1323 1324 void 1325 UHCI::LinkDescriptors(uhci_td *first, uhci_td *second) 1326 { 1327 first->link_phy = second->this_phy | TD_DEPTH_FIRST; 1328 first->link_log = second; 1329 } 1330 1331 1332 size_t 1333 UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector, 1334 size_t vectorCount) 1335 { 1336 uhci_td *current = topDescriptor; 1337 size_t actualLength = 0; 1338 size_t vectorIndex = 0; 1339 size_t vectorOffset = 0; 1340 size_t bufferOffset = 0; 1341 1342 while (current) { 1343 if (!current->buffer_log) 1344 break; 1345 1346 while (true) { 1347 size_t length = min_c(current->buffer_size - bufferOffset, 1348 vector[vectorIndex].iov_len - vectorOffset); 1349 1350 TRACE(("usb_uhci: copying %ld bytes to bufferOffset %ld from vectorOffset %ld at index %ld of %ld\n", length, bufferOffset, vectorOffset, vectorIndex, vectorCount)); 1351 memcpy((uint8 *)current->buffer_log + bufferOffset, 1352 (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length); 1353 1354 actualLength += length; 1355 vectorOffset += length; 1356 bufferOffset += length; 1357 1358 if (vectorOffset >= vector[vectorIndex].iov_len) { 1359 if (++vectorIndex >= vectorCount) { 1360 TRACE(("usb_uhci: wrote descriptor chain (%ld bytes, no more vectors)\n", actualLength)); 1361 return actualLength; 1362 } 1363 1364 vectorOffset = 0; 1365 } 1366 1367 if (bufferOffset >= current->buffer_size) { 1368 bufferOffset = 0; 1369 break; 1370 } 1371 } 1372 1373 if (current->link_phy & TD_TERMINATE) 1374 break; 1375 1376 current = (uhci_td *)current->link_log; 1377 } 1378 1379 TRACE(("usb_uhci: wrote descriptor chain (%ld bytes)\n", actualLength)); 1380 return actualLength; 1381 } 1382 1383 1384 size_t 1385 UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector, 1386 size_t vectorCount, uint8 *lastDataToggle) 1387 { 1388 uint8 dataToggle = 0; 1389 uhci_td *current = topDescriptor; 1390 size_t actualLength = 0; 1391 size_t vectorIndex = 0; 1392 size_t vectorOffset = 0; 1393 size_t bufferOffset = 0; 1394 1395 while (current && (current->status & TD_STATUS_ACTIVE) == 0) { 1396 if (!current->buffer_log) 1397 break; 1398 1399 dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01; 1400 size_t bufferSize = (current->status & TD_STATUS_ACTLEN_MASK) + 1; 1401 if (bufferSize == TD_STATUS_ACTLEN_NULL + 1) 1402 bufferSize = 0; 1403 1404 while (true) { 1405 size_t length = min_c(bufferSize - bufferOffset, 1406 vector[vectorIndex].iov_len - vectorOffset); 1407 1408 TRACE(("usb_uhci: copying %ld bytes to vectorOffset %ld from bufferOffset %ld at index %ld of %ld\n", length, vectorOffset, bufferOffset, vectorIndex, vectorCount)); 1409 memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset, 1410 (uint8 *)current->buffer_log + bufferOffset, length); 1411 1412 actualLength += length; 1413 vectorOffset += length; 1414 bufferOffset += length; 1415 1416 if (vectorOffset >= vector[vectorIndex].iov_len) { 1417 if (++vectorIndex >= vectorCount) { 1418 TRACE(("usb_uhci: read descriptor chain (%ld bytes, no more vectors)\n", actualLength)); 1419 if (lastDataToggle) 1420 *lastDataToggle = dataToggle; 1421 return actualLength; 1422 } 1423 1424 vectorOffset = 0; 1425 } 1426 1427 if (bufferOffset >= bufferSize) { 1428 bufferOffset = 0; 1429 break; 1430 } 1431 } 1432 1433 if (current->link_phy & TD_TERMINATE) 1434 break; 1435 1436 current = (uhci_td *)current->link_log; 1437 } 1438 1439 if (lastDataToggle) 1440 *lastDataToggle = dataToggle; 1441 1442 TRACE(("usb_uhci: read descriptor chain (%ld bytes)\n", actualLength)); 1443 return actualLength; 1444 } 1445 1446 1447 size_t 1448 UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle) 1449 { 1450 size_t actualLength = 0; 1451 uhci_td *current = topDescriptor; 1452 uint8 dataToggle = 0; 1453 1454 while (current && (current->status & TD_STATUS_ACTIVE) == 0) { 1455 size_t length = (current->status & TD_STATUS_ACTLEN_MASK) + 1; 1456 if (length == TD_STATUS_ACTLEN_NULL + 1) 1457 length = 0; 1458 1459 actualLength += length; 1460 dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01; 1461 1462 if (current->link_phy & TD_TERMINATE) 1463 break; 1464 1465 current = (uhci_td *)current->link_log; 1466 } 1467 1468 if (lastDataToggle) 1469 *lastDataToggle = dataToggle; 1470 1471 TRACE(("usb_uhci: read actual length (%ld bytes)\n", actualLength)); 1472 return actualLength; 1473 } 1474 1475 1476 inline void 1477 UHCI::WriteReg8(uint32 reg, uint8 value) 1478 { 1479 sPCIModule->write_io_8(fRegisterBase + reg, value); 1480 } 1481 1482 1483 inline void 1484 UHCI::WriteReg16(uint32 reg, uint16 value) 1485 { 1486 sPCIModule->write_io_16(fRegisterBase + reg, value); 1487 } 1488 1489 1490 inline void 1491 UHCI::WriteReg32(uint32 reg, uint32 value) 1492 { 1493 sPCIModule->write_io_32(fRegisterBase + reg, value); 1494 } 1495 1496 1497 inline uint8 1498 UHCI::ReadReg8(uint32 reg) 1499 { 1500 return sPCIModule->read_io_8(fRegisterBase + reg); 1501 } 1502 1503 1504 inline uint16 1505 UHCI::ReadReg16(uint32 reg) 1506 { 1507 return sPCIModule->read_io_16(fRegisterBase + reg); 1508 } 1509 1510 1511 inline uint32 1512 UHCI::ReadReg32(uint32 reg) 1513 { 1514 return sPCIModule->read_io_32(fRegisterBase + reg); 1515 } 1516