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