vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / busses / usb / uhci.cpp
blob3a57c73268293455cec7a3e6e735cae22995c301
1 /*
2 * Copyright 2004-2011, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 * Niels S. Reedijk
8 * Salvatore Benedetto <salvatore.benedetto@gmail.com>
9 */
11 #include <module.h>
12 #include <PCI.h>
13 #include <PCI_x86.h>
14 #include <USB3.h>
15 #include <KernelExport.h>
17 #include "uhci.h"
19 #define USB_MODULE_NAME "uhci"
21 pci_module_info *UHCI::sPCIModule = NULL;
22 pci_x86_module_info *UHCI::sPCIx86Module = NULL;
25 static int32
26 uhci_std_ops(int32 op, ...)
28 switch (op) {
29 case B_MODULE_INIT:
30 TRACE_MODULE("init module\n");
31 return B_OK;
32 case B_MODULE_UNINIT:
33 TRACE_MODULE("uninit module\n");
34 break;
35 default:
36 return EINVAL;
39 return B_OK;
43 usb_host_controller_info uhci_module = {
45 "busses/usb/uhci",
47 uhci_std_ops
49 NULL,
50 UHCI::AddTo
54 module_info *modules[] = {
55 (module_info *)&uhci_module,
56 NULL
61 // #pragma mark -
65 #ifdef TRACE_USB
67 void
68 print_descriptor_chain(uhci_td *descriptor)
70 while (descriptor) {
71 dprintf("ph: 0x%08" B_PRIx32 "; lp: 0x%08" B_PRIx32 "; vf: %s; q: %s; "
72 "t: %s; st: 0x%08" B_PRIx32 "; to: 0x%08" B_PRIx32 "\n",
73 descriptor->this_phy & 0xffffffff, descriptor->link_phy & 0xfffffff0,
74 descriptor->link_phy & 0x4 ? "y" : "n",
75 descriptor->link_phy & 0x2 ? "qh" : "td",
76 descriptor->link_phy & 0x1 ? "y" : "n",
77 descriptor->status, descriptor->token);
79 if (descriptor->link_phy & TD_TERMINATE)
80 break;
82 descriptor = (uhci_td *)descriptor->link_log;
86 #endif // TRACE_USB
90 // #pragma mark -
94 Queue::Queue(Stack *stack)
96 fStack = stack;
98 mutex_init(&fLock, "uhci queue lock");
100 phys_addr_t physicalAddress;
101 fStatus = fStack->AllocateChunk((void **)&fQueueHead, &physicalAddress,
102 sizeof(uhci_qh));
103 if (fStatus < B_OK)
104 return;
106 fQueueHead->this_phy = (uint32)physicalAddress;
107 fQueueHead->element_phy = QH_TERMINATE;
109 fStrayDescriptor = NULL;
110 fQueueTop = NULL;
114 Queue::~Queue()
116 Lock();
117 mutex_destroy(&fLock);
119 fStack->FreeChunk(fQueueHead, fQueueHead->this_phy, sizeof(uhci_qh));
121 if (fStrayDescriptor)
122 fStack->FreeChunk(fStrayDescriptor, fStrayDescriptor->this_phy,
123 sizeof(uhci_td));
127 status_t
128 Queue::InitCheck()
130 return fStatus;
134 bool
135 Queue::Lock()
137 return (mutex_lock(&fLock) == B_OK);
141 void
142 Queue::Unlock()
144 mutex_unlock(&fLock);
148 status_t
149 Queue::LinkTo(Queue *other)
151 if (!other)
152 return B_BAD_VALUE;
154 if (!Lock())
155 return B_ERROR;
157 fQueueHead->link_phy = other->fQueueHead->this_phy | QH_NEXT_IS_QH;
158 fQueueHead->link_log = other->fQueueHead;
159 Unlock();
161 return B_OK;
165 status_t
166 Queue::TerminateByStrayDescriptor()
168 // According to the *BSD USB sources, there needs to be a stray transfer
169 // descriptor in order to get some chipset to work nicely (like the PIIX).
170 phys_addr_t physicalAddress;
171 status_t result = fStack->AllocateChunk((void **)&fStrayDescriptor,
172 &physicalAddress, sizeof(uhci_td));
173 if (result < B_OK) {
174 TRACE_ERROR("failed to allocate a stray transfer descriptor\n");
175 return result;
178 fStrayDescriptor->status = 0;
179 fStrayDescriptor->this_phy = (uint32)physicalAddress;
180 fStrayDescriptor->link_phy = TD_TERMINATE;
181 fStrayDescriptor->link_log = NULL;
182 fStrayDescriptor->buffer_phy = 0;
183 fStrayDescriptor->buffer_log = NULL;
184 fStrayDescriptor->buffer_size = 0;
185 fStrayDescriptor->token = TD_TOKEN_NULL_DATA
186 | (0x7f << TD_TOKEN_DEVADDR_SHIFT) | TD_TOKEN_IN;
188 if (!Lock()) {
189 fStack->FreeChunk(fStrayDescriptor, fStrayDescriptor->this_phy,
190 sizeof(uhci_td));
191 return B_ERROR;
194 fQueueHead->link_phy = fStrayDescriptor->this_phy;
195 fQueueHead->link_log = fStrayDescriptor;
196 Unlock();
198 return B_OK;
202 status_t
203 Queue::AppendTransfer(uhci_qh *transfer, bool lock)
205 if (lock && !Lock())
206 return B_ERROR;
208 transfer->link_log = NULL;
209 transfer->link_phy = fQueueHead->link_phy;
211 if (!fQueueTop) {
212 // the list is empty, make this the first element
213 fQueueTop = transfer;
214 fQueueHead->element_phy = transfer->this_phy | QH_NEXT_IS_QH;
215 } else {
216 // append the transfer queue to the list
217 uhci_qh *element = fQueueTop;
218 while (element && element->link_log)
219 element = (uhci_qh *)element->link_log;
221 element->link_log = transfer;
222 element->link_phy = transfer->this_phy | QH_NEXT_IS_QH;
225 if (lock)
226 Unlock();
227 return B_OK;
231 status_t
232 Queue::RemoveTransfer(uhci_qh *transfer, bool lock)
234 if (lock && !Lock())
235 return B_ERROR;
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;
248 if (lock)
249 Unlock();
250 return B_OK;
251 } else {
252 uhci_qh *element = fQueueTop;
253 while (element) {
254 if (element->link_log == transfer) {
255 element->link_log = transfer->link_log;
256 element->link_phy = transfer->link_phy;
257 if (lock)
258 Unlock();
259 return B_OK;
262 element = (uhci_qh *)element->link_log;
266 if (lock)
267 Unlock();
268 return B_BAD_VALUE;
272 uint32
273 Queue::PhysicalAddress()
275 return fQueueHead->this_phy;
279 void
280 Queue::PrintToStream()
282 #ifdef TRACE_USB
283 TRACE("queue:\n");
284 dprintf("link phy: 0x%08" B_PRIx32 "; link type: %s; terminate: %s\n",
285 fQueueHead->link_phy & 0xfff0,
286 fQueueHead->link_phy & 0x0002 ? "QH" : "TD",
287 fQueueHead->link_phy & 0x0001 ? "yes" : "no");
288 dprintf("elem phy: 0x%08" B_PRIx32 "; elem type: %s; terminate: %s\n",
289 fQueueHead->element_phy & 0xfff0,
290 fQueueHead->element_phy & 0x0002 ? "QH" : "TD",
291 fQueueHead->element_phy & 0x0001 ? "yes" : "no");
292 #endif
297 // #pragma mark -
301 UHCI::UHCI(pci_info *info, Stack *stack)
302 : BusManager(stack),
303 fPCIInfo(info),
304 fStack(stack),
305 fEnabledInterrupts(0),
306 fFrameArea(-1),
307 fFrameList(NULL),
308 fFrameBandwidth(NULL),
309 fFirstIsochronousDescriptor(NULL),
310 fLastIsochronousDescriptor(NULL),
311 fQueueCount(0),
312 fQueues(NULL),
313 fFirstTransfer(NULL),
314 fLastTransfer(NULL),
315 fFinishTransfersSem(-1),
316 fFinishThread(-1),
317 fStopThreads(false),
318 fProcessingPipe(NULL),
319 fFreeList(NULL),
320 fCleanupThread(-1),
321 fCleanupSem(-1),
322 fCleanupCount(0),
323 fFirstIsochronousTransfer(NULL),
324 fLastIsochronousTransfer(NULL),
325 fFinishIsochronousTransfersSem(-1),
326 fFinishIsochronousThread(-1),
327 fRootHub(NULL),
328 fRootHubAddress(0),
329 fPortResetChange(0),
330 fIRQ(0),
331 fUseMSI(false)
333 // Create a lock for the isochronous transfer list
334 mutex_init(&fIsochronousLock, "UHCI isochronous lock");
336 if (!fInitOK) {
337 TRACE_ERROR("bus manager failed to init\n");
338 return;
341 TRACE("constructing new UHCI host controller driver\n");
342 fInitOK = false;
344 fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus,
345 fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4);
346 fRegisterBase &= PCI_address_io_mask;
347 TRACE("iospace offset: 0x%08" B_PRIx32 "\n", fRegisterBase);
349 if (fRegisterBase == 0) {
350 fRegisterBase = fPCIInfo->u.h0.base_registers[0];
351 TRACE_ALWAYS("register base: 0x%08" B_PRIx32 "\n", fRegisterBase);
354 // enable pci address access
355 uint16 command = PCI_command_io | PCI_command_master | PCI_command_memory;
356 command |= sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device,
357 fPCIInfo->function, PCI_command, 2);
359 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
360 fPCIInfo->function, PCI_command, 2, command);
362 // disable interrupts
363 WriteReg16(UHCI_USBINTR, 0);
365 // make sure we gain control of the UHCI controller instead of the BIOS
366 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
367 fPCIInfo->function, PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN
368 | PCI_LEGSUP_CLEAR_SMI);
370 // do a global and host reset
371 GlobalReset();
372 if (ControllerReset() < B_OK) {
373 TRACE_ERROR("host failed to reset\n");
374 return;
377 // Setup the frame list
378 phys_addr_t physicalAddress;
379 fFrameArea = fStack->AllocateArea((void **)&fFrameList, &physicalAddress,
380 4096, "USB UHCI framelist");
382 if (fFrameArea < B_OK) {
383 TRACE_ERROR("unable to create an area for the frame pointer list\n");
384 return;
387 // Set base pointer and reset frame number
388 WriteReg32(UHCI_FRBASEADD, (uint32)physicalAddress);
389 WriteReg16(UHCI_FRNUM, 0);
391 // Set the max packet size for bandwidth reclamation to 64 bytes
392 WriteReg16(UHCI_USBCMD, ReadReg16(UHCI_USBCMD) | UHCI_USBCMD_MAXP);
394 // we will create four queues:
395 // 0: interrupt transfers
396 // 1: low speed control transfers
397 // 2: full speed control transfers
398 // 3: bulk transfers
399 // 4: debug queue
400 // TODO: 4: bandwidth reclamation queue
401 fQueueCount = 5;
402 fQueues = new(std::nothrow) Queue *[fQueueCount];
403 if (!fQueues) {
404 delete_area(fFrameArea);
405 return;
408 for (int32 i = 0; i < fQueueCount; i++) {
409 fQueues[i] = new(std::nothrow) Queue(fStack);
410 if (!fQueues[i] || fQueues[i]->InitCheck() < B_OK) {
411 TRACE_ERROR("cannot create queues\n");
412 delete_area(fFrameArea);
413 return;
416 if (i > 0)
417 fQueues[i - 1]->LinkTo(fQueues[i]);
420 // Make sure the last queue terminates
421 fQueues[fQueueCount - 1]->TerminateByStrayDescriptor();
423 // Create the array that will keep bandwidth information
424 fFrameBandwidth = new(std::nothrow) uint16[NUMBER_OF_FRAMES];
426 // Create lists for managing isochronous transfer descriptors
427 fFirstIsochronousDescriptor = new(std::nothrow) uhci_td *[NUMBER_OF_FRAMES];
428 if (!fFirstIsochronousDescriptor) {
429 TRACE_ERROR("faild to allocate memory for first isochronous descriptor\n");
430 return;
433 fLastIsochronousDescriptor = new(std::nothrow) uhci_td *[NUMBER_OF_FRAMES];
434 if (!fLastIsochronousDescriptor) {
435 TRACE_ERROR("failed to allocate memory for last isochronous descriptor\n");
436 delete [] fFirstIsochronousDescriptor;
437 return;
440 for (int32 i = 0; i < NUMBER_OF_FRAMES; i++) {
441 fFrameList[i] = fQueues[UHCI_INTERRUPT_QUEUE]->PhysicalAddress()
442 | FRAMELIST_NEXT_IS_QH;
443 fFrameBandwidth[i] = MAX_AVAILABLE_BANDWIDTH;
444 fFirstIsochronousDescriptor[i] = NULL;
445 fLastIsochronousDescriptor[i] = NULL;
448 // Create semaphore the finisher and cleanup threads will wait for
449 fFinishTransfersSem = create_sem(0, "UHCI Finish Transfers");
450 if (fFinishTransfersSem < B_OK) {
451 TRACE_ERROR("failed to create finisher semaphore\n");
452 return;
455 fCleanupSem = create_sem(0, "UHCI Cleanup");
456 if (fCleanupSem < B_OK) {
457 TRACE_ERROR("failed to create cleanup semaphore\n");
458 return;
461 // Create the finisher service and cleanup threads
462 fFinishThread = spawn_kernel_thread(FinishThread,
463 "uhci finish thread", B_URGENT_DISPLAY_PRIORITY, (void *)this);
464 resume_thread(fFinishThread);
466 fCleanupThread = spawn_kernel_thread(CleanupThread,
467 "uhci cleanup thread", B_NORMAL_PRIORITY, (void *)this);
468 resume_thread(fCleanupThread);
470 // Create semaphore the isochronous finisher thread will wait for
471 fFinishIsochronousTransfersSem = create_sem(0,
472 "UHCI Isochronous Finish Transfers");
473 if (fFinishIsochronousTransfersSem < B_OK) {
474 TRACE_ERROR("failed to create isochronous finisher semaphore\n");
475 return;
478 // Create the isochronous finisher service thread
479 fFinishIsochronousThread = spawn_kernel_thread(FinishIsochronousThread,
480 "uhci isochronous finish thread", B_URGENT_DISPLAY_PRIORITY,
481 (void *)this);
482 resume_thread(fFinishIsochronousThread);
484 // Find the right interrupt vector, using MSIs if available.
485 fIRQ = fPCIInfo->u.h0.interrupt_line;
486 if (sPCIx86Module != NULL && sPCIx86Module->get_msi_count(fPCIInfo->bus,
487 fPCIInfo->device, fPCIInfo->function) >= 1) {
488 uint8 msiVector = 0;
489 if (sPCIx86Module->configure_msi(fPCIInfo->bus, fPCIInfo->device,
490 fPCIInfo->function, 1, &msiVector) == B_OK
491 && sPCIx86Module->enable_msi(fPCIInfo->bus, fPCIInfo->device,
492 fPCIInfo->function) == B_OK) {
493 TRACE_ALWAYS("using message signaled interrupts\n");
494 fIRQ = msiVector;
495 fUseMSI = true;
499 // Install the interrupt handler
500 TRACE("installing interrupt handler\n");
501 install_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this, 0);
503 // Enable interrupts
504 fEnabledInterrupts = UHCI_USBSTS_USBINT | UHCI_USBSTS_ERRINT
505 | UHCI_USBSTS_HOSTERR | UHCI_USBSTS_HCPRERR | UHCI_USBSTS_HCHALT;
506 WriteReg16(UHCI_USBINTR, UHCI_USBINTR_CRC | UHCI_USBINTR_IOC
507 | UHCI_USBINTR_SHORT);
509 TRACE("UHCI host controller driver constructed\n");
510 fInitOK = true;
514 UHCI::~UHCI()
516 int32 result = 0;
517 fStopThreads = true;
518 delete_sem(fFinishTransfersSem);
519 delete_sem(fCleanupSem);
520 delete_sem(fFinishIsochronousTransfersSem);
521 wait_for_thread(fFinishThread, &result);
522 wait_for_thread(fCleanupThread, &result);
523 wait_for_thread(fFinishIsochronousThread, &result);
525 remove_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this);
527 LockIsochronous();
528 isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer;
529 while (isoTransfer) {
530 isochronous_transfer_data *next = isoTransfer->link;
531 delete isoTransfer;
532 isoTransfer = next;
534 mutex_destroy(&fIsochronousLock);
536 Lock();
537 transfer_data *transfer = fFirstTransfer;
538 while (transfer) {
539 transfer->transfer->Finished(B_CANCELED, 0);
540 delete transfer->transfer;
542 transfer_data *next = transfer->link;
543 delete transfer;
544 transfer = next;
547 for (int32 i = 0; i < fQueueCount; i++)
548 delete fQueues[i];
550 delete [] fQueues;
551 delete [] fFrameBandwidth;
552 delete [] fFirstIsochronousDescriptor;
553 delete [] fLastIsochronousDescriptor;
554 delete fRootHub;
555 delete_area(fFrameArea);
557 if (fUseMSI && sPCIx86Module != NULL) {
558 sPCIx86Module->disable_msi(fPCIInfo->bus,
559 fPCIInfo->device, fPCIInfo->function);
560 sPCIx86Module->unconfigure_msi(fPCIInfo->bus,
561 fPCIInfo->device, fPCIInfo->function);
563 put_module(B_PCI_MODULE_NAME);
564 if (sPCIx86Module != NULL) {
565 sPCIx86Module = NULL;
566 put_module(B_PCI_X86_MODULE_NAME);
568 Unlock();
572 status_t
573 UHCI::Start()
575 // Start the host controller, then start the Busmanager
576 TRACE("starting UHCI BusManager\n");
577 TRACE("usbcmd reg 0x%04x, usbsts reg 0x%04x\n",
578 ReadReg16(UHCI_USBCMD), ReadReg16(UHCI_USBSTS));
580 // Set the run bit in the command register
581 WriteReg16(UHCI_USBCMD, ReadReg16(UHCI_USBCMD) | UHCI_USBCMD_RS);
583 bool running = false;
584 for (int32 i = 0; i < 10; i++) {
585 uint16 status = ReadReg16(UHCI_USBSTS);
586 TRACE("current loop %" B_PRId32 ", status 0x%04x\n", i, status);
588 if (status & UHCI_USBSTS_HCHALT)
589 snooze(10000);
590 else {
591 running = true;
592 break;
596 if (!running) {
597 TRACE_ERROR("controller won't start running\n");
598 return B_ERROR;
601 fRootHubAddress = AllocateAddress();
602 fRootHub = new(std::nothrow) UHCIRootHub(RootObject(), fRootHubAddress);
603 if (!fRootHub) {
604 TRACE_ERROR("no memory to allocate root hub\n");
605 return B_NO_MEMORY;
608 if (fRootHub->InitCheck() < B_OK) {
609 TRACE_ERROR("root hub failed init check\n");
610 delete fRootHub;
611 return B_ERROR;
614 SetRootHub(fRootHub);
616 TRACE("controller is started. status: %u curframe: %u\n",
617 ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM));
618 TRACE_ALWAYS("successfully started the controller\n");
619 return BusManager::Start();
623 status_t
624 UHCI::SubmitTransfer(Transfer *transfer)
626 // Short circuit the root hub
627 Pipe *pipe = transfer->TransferPipe();
628 if (pipe->DeviceAddress() == fRootHubAddress)
629 return fRootHub->ProcessTransfer(this, transfer);
631 TRACE("submit transfer called for device %d\n", pipe->DeviceAddress());
632 if (pipe->Type() & USB_OBJECT_CONTROL_PIPE)
633 return SubmitRequest(transfer);
635 // Process isochronous transfers
636 if (pipe->Type() & USB_OBJECT_ISO_PIPE)
637 return SubmitIsochronous(transfer);
639 uhci_td *firstDescriptor = NULL;
640 uhci_qh *transferQueue = NULL;
641 status_t result = CreateFilledTransfer(transfer, &firstDescriptor,
642 &transferQueue);
643 if (result < B_OK)
644 return result;
646 Queue *queue = NULL;
647 if (pipe->Type() & USB_OBJECT_INTERRUPT_PIPE)
648 queue = fQueues[UHCI_INTERRUPT_QUEUE];
649 else
650 queue = fQueues[UHCI_BULK_QUEUE];
652 bool directionIn = (pipe->Direction() == Pipe::In);
653 result = AddPendingTransfer(transfer, queue, transferQueue,
654 firstDescriptor, firstDescriptor, directionIn);
655 if (result < B_OK) {
656 TRACE_ERROR("failed to add pending transfer\n");
657 FreeDescriptorChain(firstDescriptor);
658 FreeTransferQueue(transferQueue);
659 return result;
662 queue->AppendTransfer(transferQueue);
663 return B_OK;
667 status_t
668 UHCI::StartDebugTransfer(Transfer *transfer)
670 if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) != 0)
671 return B_UNSUPPORTED;
673 static transfer_data transferData;
674 transferData.first_descriptor = NULL;
675 transferData.transfer_queue = NULL;
676 status_t result = CreateFilledTransfer(transfer,
677 &transferData.first_descriptor, &transferData.transfer_queue);
678 if (result < B_OK)
679 return result;
681 fQueues[UHCI_DEBUG_QUEUE]->AppendTransfer(transferData.transfer_queue,
682 false);
684 // we abuse the callback cookie to hold our transfer data
685 transfer->SetCallback(NULL, &transferData);
686 return B_OK;
690 status_t
691 UHCI::CheckDebugTransfer(Transfer *transfer)
693 bool transferOK = false;
694 bool transferError = false;
695 transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
696 uhci_td *descriptor = transferData->first_descriptor;
698 while (descriptor) {
699 uint32 status = descriptor->status;
700 if (status & TD_STATUS_ACTIVE)
701 break;
703 if (status & TD_ERROR_MASK) {
704 transferError = true;
705 break;
708 if ((descriptor->link_phy & TD_TERMINATE)
709 || uhci_td_actual_length(descriptor)
710 < uhci_td_maximum_length(descriptor)) {
711 transferOK = true;
712 break;
715 descriptor = (uhci_td *)descriptor->link_log;
718 if (!transferOK && !transferError) {
719 spin(200);
720 return B_DEV_PENDING;
723 if (transferOK) {
724 uint8 lastDataToggle = 0;
725 if (transfer->TransferPipe()->Direction() == Pipe::In) {
726 // data to read out
727 iovec *vector = transfer->Vector();
728 size_t vectorCount = transfer->VectorCount();
730 ReadDescriptorChain(transferData->first_descriptor,
731 vector, vectorCount, &lastDataToggle);
732 } else {
733 // read the actual length that was sent
734 ReadActualLength(transferData->first_descriptor, &lastDataToggle);
737 transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
740 fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transferData->transfer_queue,
741 false);
742 FreeDescriptorChain(transferData->first_descriptor);
743 FreeTransferQueue(transferData->transfer_queue);
744 return transferOK ? B_OK : B_IO_ERROR;
748 void
749 UHCI::CancelDebugTransfer(Transfer *transfer)
751 transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
753 // clear the active bit so the descriptors are canceled
754 uhci_td *descriptor = transferData->first_descriptor;
755 while (descriptor) {
756 descriptor->status &= ~TD_STATUS_ACTIVE;
757 descriptor = (uhci_td *)descriptor->link_log;
760 transfer->Finished(B_CANCELED, 0);
762 // dequeue and free resources
763 fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transferData->transfer_queue,
764 false);
765 FreeDescriptorChain(transferData->first_descriptor);
766 FreeTransferQueue(transferData->transfer_queue);
767 // TODO: [bonefish] The Free*() calls cause "PMA: provided address resulted
768 // in invalid index" to be printed, so apparently something is not right.
769 // Though I have not clue what. This is the same cleanup code as in
770 // CheckDebugTransfer() that should undo the CreateFilledTransfer() from
771 // StartDebugTransfer().
775 status_t
776 UHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
778 if (pipe->Type() & USB_OBJECT_ISO_PIPE)
779 return CancelQueuedIsochronousTransfers(pipe, force);
781 if (!Lock())
782 return B_ERROR;
784 struct transfer_entry {
785 Transfer * transfer;
786 transfer_entry * next;
789 transfer_entry *list = NULL;
790 transfer_data *current = fFirstTransfer;
791 while (current) {
792 if (current->transfer && current->transfer->TransferPipe() == pipe) {
793 // clear the active bit so the descriptors are canceled
794 uhci_td *descriptor = current->first_descriptor;
795 while (descriptor) {
796 descriptor->status &= ~TD_STATUS_ACTIVE;
797 descriptor = (uhci_td *)descriptor->link_log;
800 if (!force) {
801 // if the transfer is canceled by force, the one causing the
802 // cancel is probably not the one who initiated the transfer
803 // and the callback is likely not safe anymore
804 transfer_entry *entry
805 = (transfer_entry *)malloc(sizeof(transfer_entry));
806 if (entry != NULL) {
807 entry->transfer = current->transfer;
808 current->transfer = NULL;
809 entry->next = list;
810 list = entry;
814 current->canceled = true;
816 current = current->link;
819 Unlock();
821 while (list != NULL) {
822 transfer_entry *next = list->next;
823 list->transfer->Finished(B_CANCELED, 0);
824 delete list->transfer;
825 free(list);
826 list = next;
829 // wait for any transfers that might have made it before canceling
830 while (fProcessingPipe == pipe)
831 snooze(1000);
833 // notify the finisher so it can clean up the canceled transfers
834 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
835 return B_OK;
839 status_t
840 UHCI::CancelQueuedIsochronousTransfers(Pipe *pipe, bool force)
842 isochronous_transfer_data *current = fFirstIsochronousTransfer;
844 while (current) {
845 if (current->transfer->TransferPipe() == pipe) {
846 int32 packetCount
847 = current->transfer->IsochronousData()->packet_count;
848 // Set the active bit off on every descriptor in order to prevent
849 // the controller from processing them. Then set off the is_active
850 // field of the transfer in order to make the finisher thread skip
851 // the transfer. The FinishIsochronousThread will do the rest.
852 for (int32 i = 0; i < packetCount; i++)
853 current->descriptors[i]->status &= ~TD_STATUS_ACTIVE;
855 // TODO: Use the force paramater in order to avoid calling
856 // invalid callbacks
857 current->is_active = false;
860 current = current->link;
863 TRACE_ERROR("no isochronous transfer found!\n");
864 return B_ERROR;
868 status_t
869 UHCI::SubmitRequest(Transfer *transfer)
871 Pipe *pipe = transfer->TransferPipe();
872 usb_request_data *requestData = transfer->RequestData();
873 bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
875 uhci_td *setupDescriptor = CreateDescriptor(pipe, TD_TOKEN_SETUP,
876 sizeof(usb_request_data));
878 uhci_td *statusDescriptor = CreateDescriptor(pipe,
879 directionIn ? TD_TOKEN_OUT : TD_TOKEN_IN, 0);
881 if (!setupDescriptor || !statusDescriptor) {
882 TRACE_ERROR("failed to allocate descriptors\n");
883 FreeDescriptor(setupDescriptor);
884 FreeDescriptor(statusDescriptor);
885 return B_NO_MEMORY;
888 iovec vector;
889 vector.iov_base = requestData;
890 vector.iov_len = sizeof(usb_request_data);
891 WriteDescriptorChain(setupDescriptor, &vector, 1);
893 statusDescriptor->status |= TD_CONTROL_IOC;
894 statusDescriptor->token |= TD_TOKEN_DATA1;
895 statusDescriptor->link_phy = TD_TERMINATE;
896 statusDescriptor->link_log = NULL;
898 uhci_td *dataDescriptor = NULL;
899 if (transfer->VectorCount() > 0) {
900 uhci_td *lastDescriptor = NULL;
901 status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
902 &lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
903 transfer->VectorLength());
905 if (result < B_OK) {
906 FreeDescriptor(setupDescriptor);
907 FreeDescriptor(statusDescriptor);
908 return result;
911 if (!directionIn) {
912 WriteDescriptorChain(dataDescriptor, transfer->Vector(),
913 transfer->VectorCount());
916 LinkDescriptors(setupDescriptor, dataDescriptor);
917 LinkDescriptors(lastDescriptor, statusDescriptor);
918 } else {
919 // Link transfer and status descriptors directly
920 LinkDescriptors(setupDescriptor, statusDescriptor);
923 Queue *queue = NULL;
924 if (pipe->Speed() == USB_SPEED_LOWSPEED)
925 queue = fQueues[UHCI_LOW_SPEED_CONTROL_QUEUE];
926 else
927 queue = fQueues[UHCI_FULL_SPEED_CONTROL_QUEUE];
929 uhci_qh *transferQueue = CreateTransferQueue(setupDescriptor);
930 status_t result = AddPendingTransfer(transfer, queue, transferQueue,
931 setupDescriptor, dataDescriptor, directionIn);
932 if (result < B_OK) {
933 TRACE_ERROR("failed to add pending transfer\n");
934 FreeDescriptorChain(setupDescriptor);
935 FreeTransferQueue(transferQueue);
936 return result;
939 queue->AppendTransfer(transferQueue);
940 return B_OK;
944 status_t
945 UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue,
946 uhci_qh *transferQueue, uhci_td *firstDescriptor, uhci_td *dataDescriptor,
947 bool directionIn)
949 if (!transfer || !queue || !transferQueue || !firstDescriptor)
950 return B_BAD_VALUE;
952 transfer_data *data = new(std::nothrow) transfer_data;
953 if (!data)
954 return B_NO_MEMORY;
956 status_t result = transfer->InitKernelAccess();
957 if (result < B_OK) {
958 delete data;
959 return result;
962 data->transfer = transfer;
963 data->queue = queue;
964 data->transfer_queue = transferQueue;
965 data->first_descriptor = firstDescriptor;
966 data->data_descriptor = dataDescriptor;
967 data->incoming = directionIn;
968 data->canceled = false;
969 data->link = NULL;
971 if (!Lock()) {
972 delete data;
973 return B_ERROR;
976 if (fLastTransfer)
977 fLastTransfer->link = data;
978 if (!fFirstTransfer)
979 fFirstTransfer = data;
981 fLastTransfer = data;
982 Unlock();
983 return B_OK;
987 status_t
988 UHCI::AddPendingIsochronousTransfer(Transfer *transfer, uhci_td **isoRequest,
989 bool directionIn)
991 if (!transfer || !isoRequest)
992 return B_BAD_VALUE;
994 isochronous_transfer_data *data
995 = new(std::nothrow) isochronous_transfer_data;
996 if (!data)
997 return B_NO_MEMORY;
999 status_t result = transfer->InitKernelAccess();
1000 if (result < B_OK) {
1001 delete data;
1002 return result;
1005 data->transfer = transfer;
1006 data->descriptors = isoRequest;
1007 data->last_to_process = transfer->IsochronousData()->packet_count - 1;
1008 data->incoming = directionIn;
1009 data->is_active = true;
1010 data->link = NULL;
1012 // Put in the isochronous transfer list
1013 if (!LockIsochronous()) {
1014 delete data;
1015 return B_ERROR;
1018 if (fLastIsochronousTransfer)
1019 fLastIsochronousTransfer->link = data;
1020 if (!fFirstIsochronousTransfer)
1021 fFirstIsochronousTransfer = data;
1023 fLastIsochronousTransfer = data;
1024 UnlockIsochronous();
1025 return B_OK;
1029 status_t
1030 UHCI::SubmitIsochronous(Transfer *transfer)
1032 Pipe *pipe = transfer->TransferPipe();
1033 bool directionIn = (pipe->Direction() == Pipe::In);
1034 usb_isochronous_data *isochronousData = transfer->IsochronousData();
1035 size_t packetSize = transfer->DataLength();
1036 size_t restSize = packetSize % isochronousData->packet_count;
1037 packetSize /= isochronousData->packet_count;
1038 uint16 currentFrame;
1040 if (packetSize > pipe->MaxPacketSize()) {
1041 TRACE_ERROR("isochronous packetSize is bigger than pipe MaxPacketSize\n");
1042 return B_BAD_VALUE;
1045 // Ignore the fact that the last descriptor might need less bandwidth.
1046 // The overhead is not worthy.
1047 uint16 bandwidth = transfer->Bandwidth() / isochronousData->packet_count;
1049 TRACE("isochronous transfer descriptor bandwidth %d\n", bandwidth);
1051 // The following holds the list of transfer descriptor of the
1052 // isochronous request. It is used to quickly remove all the isochronous
1053 // descriptors from the frame list, as descriptors are not link to each
1054 // other in a queue like for every other transfer.
1055 uhci_td **isoRequest
1056 = new(std::nothrow) uhci_td *[isochronousData->packet_count];
1057 if (isoRequest == NULL) {
1058 TRACE("failed to create isoRequest array!\n");
1059 return B_NO_MEMORY;
1062 // Create the list of transfer descriptors
1063 for (uint32 i = 0; i < (isochronousData->packet_count - 1); i++) {
1064 isoRequest[i] = CreateDescriptor(pipe,
1065 directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, packetSize);
1066 // If we ran out of memory, clean up and return
1067 if (isoRequest[i] == NULL) {
1068 for (uint32 j = 0; j < i; j++)
1069 FreeDescriptor(isoRequest[j]);
1070 delete [] isoRequest;
1071 return B_NO_MEMORY;
1073 // Make sure data toggle is set to zero
1074 isoRequest[i]->token &= ~TD_TOKEN_DATA1;
1077 // Create the last transfer descriptor which should be of smaller size
1078 // and set the IOC bit
1079 isoRequest[isochronousData->packet_count - 1] = CreateDescriptor(pipe,
1080 directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
1081 (restSize) ? restSize : packetSize);
1082 // If we are that unlucky...
1083 if (!isoRequest[isochronousData->packet_count - 1]) {
1084 for (uint32 i = 0; i < (isochronousData->packet_count - 2); i++)
1085 FreeDescriptor(isoRequest[i]);
1086 delete [] isoRequest;
1087 return B_NO_MEMORY;
1089 isoRequest[isochronousData->packet_count - 1]->token &= ~TD_TOKEN_DATA1;
1091 // If direction is out set every descriptor data
1092 if (!directionIn) {
1093 iovec *vector = transfer->Vector();
1094 WriteIsochronousDescriptorChain(isoRequest,
1095 isochronousData->packet_count, vector);
1096 } else {
1097 // Initialize the packet descriptors
1098 for (uint32 i = 0; i < isochronousData->packet_count; i++) {
1099 isochronousData->packet_descriptors[i].actual_length = 0;
1100 isochronousData->packet_descriptors[i].status = B_NO_INIT;
1104 TRACE("isochronous submitted size=%ld bytes, TDs=%" B_PRId32 ", "
1105 "packetSize=%ld, restSize=%ld\n", transfer->DataLength(),
1106 isochronousData->packet_count, packetSize, restSize);
1108 // Find the entry where to start inserting the first Isochronous descriptor
1109 if (isochronousData->flags & USB_ISO_ASAP ||
1110 isochronousData->starting_frame_number == NULL) {
1111 // find the first available frame with enough bandwidth.
1112 // This should always be the case, as defining the starting frame
1113 // number in the driver makes no sense for many reason, one of which
1114 // is that frame numbers value are host controller specific, and the
1115 // driver does not know which host controller is running.
1116 currentFrame = ReadReg16(UHCI_FRNUM);
1118 // Make sure that:
1119 // 1. We are at least 5ms ahead the controller
1120 // 2. We stay in the range 0-1023
1121 // 3. There is enough bandwidth in the first entry
1122 currentFrame = (currentFrame + 5) % NUMBER_OF_FRAMES;
1123 } else {
1124 // Find out if the frame number specified has enough bandwidth,
1125 // otherwise find the first next available frame with enough bandwidth
1126 currentFrame = *isochronousData->starting_frame_number;
1129 // Find the first entry with enough bandwidth
1130 // TODO: should we also check the bandwidth of the following packet_count frames?
1131 uint16 startSeekingFromFrame = currentFrame;
1132 while (fFrameBandwidth[currentFrame] < bandwidth) {
1133 currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
1134 if (currentFrame == startSeekingFromFrame) {
1135 TRACE_ERROR("not enough bandwidth to queue the isochronous request");
1136 for (uint32 i = 0; i < isochronousData->packet_count; i++)
1137 FreeDescriptor(isoRequest[i]);
1138 delete [] isoRequest;
1139 return B_ERROR;
1143 if (isochronousData->starting_frame_number)
1144 *isochronousData->starting_frame_number = currentFrame;
1146 // Add transfer to the list
1147 status_t result = AddPendingIsochronousTransfer(transfer, isoRequest,
1148 directionIn);
1149 if (result < B_OK) {
1150 TRACE_ERROR("failed to add pending isochronous transfer\n");
1151 for (uint32 i = 0; i < isochronousData->packet_count; i++)
1152 FreeDescriptor(isoRequest[i]);
1153 delete [] isoRequest;
1154 return result;
1157 TRACE("appended isochronous transfer by starting at frame number %d\n",
1158 currentFrame);
1160 // Insert the Transfer Descriptor by starting at
1161 // the starting_frame_number entry
1162 // TODO: We don't consider bInterval, and assume it's 1!
1163 for (uint32 i = 0; i < isochronousData->packet_count; i++) {
1164 result = LinkIsochronousDescriptor(isoRequest[i], currentFrame);
1165 if (result < B_OK) {
1166 TRACE_ERROR("failed to add pending isochronous transfer\n");
1167 for (uint32 i = 0; i < isochronousData->packet_count; i++)
1168 FreeDescriptor(isoRequest[i]);
1169 delete [] isoRequest;
1170 return result;
1173 fFrameBandwidth[currentFrame] -= bandwidth;
1174 currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
1177 // Wake up the isochronous finisher thread
1178 release_sem_etc(fFinishIsochronousTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1180 return B_OK;
1184 isochronous_transfer_data *
1185 UHCI::FindIsochronousTransfer(uhci_td *descriptor)
1187 // Simply check every last descriptor of the isochronous transfer list
1188 if (LockIsochronous()) {
1189 isochronous_transfer_data *transfer = fFirstIsochronousTransfer;
1190 if (transfer) {
1191 while (transfer->descriptors[transfer->last_to_process]
1192 != descriptor) {
1193 transfer = transfer->link;
1194 if (!transfer)
1195 break;
1198 UnlockIsochronous();
1199 return transfer;
1201 return NULL;
1205 status_t
1206 UHCI::LinkIsochronousDescriptor(uhci_td *descriptor, uint16 frame)
1208 // The transfer descriptor is appended to the last
1209 // existing isochronous transfer descriptor (if any)
1210 // in that frame.
1211 if (LockIsochronous()) {
1212 if (!fFirstIsochronousDescriptor[frame]) {
1213 // Insert the transfer descriptor in the first position
1214 fFrameList[frame] = descriptor->this_phy & ~FRAMELIST_NEXT_IS_QH;
1215 fFirstIsochronousDescriptor[frame] = descriptor;
1216 fLastIsochronousDescriptor[frame] = descriptor;
1217 } else {
1218 // Append to the last transfer descriptor
1219 fLastIsochronousDescriptor[frame]->link_log = descriptor;
1220 fLastIsochronousDescriptor[frame]->link_phy
1221 = descriptor->this_phy & ~TD_NEXT_IS_QH;
1222 fLastIsochronousDescriptor[frame] = descriptor;
1225 descriptor->link_phy
1226 = fQueues[UHCI_INTERRUPT_QUEUE]->PhysicalAddress() | TD_NEXT_IS_QH;
1227 UnlockIsochronous();
1228 return B_OK;
1230 return B_ERROR;
1234 uhci_td *
1235 UHCI::UnlinkIsochronousDescriptor(uint16 frame)
1237 // We always unlink from the top
1238 if (LockIsochronous()) {
1239 uhci_td *descriptor = fFirstIsochronousDescriptor[frame];
1240 if (descriptor) {
1241 // The descriptor will be freed later.
1242 fFrameList[frame] = descriptor->link_phy;
1243 if (descriptor->link_log) {
1244 fFirstIsochronousDescriptor[frame]
1245 = (uhci_td *)descriptor->link_log;
1246 } else {
1247 fFirstIsochronousDescriptor[frame] = NULL;
1248 fLastIsochronousDescriptor[frame] = NULL;
1251 UnlockIsochronous();
1252 return descriptor;
1254 return NULL;
1258 int32
1259 UHCI::FinishThread(void *data)
1261 ((UHCI *)data)->FinishTransfers();
1262 return B_OK;
1266 void
1267 UHCI::FinishTransfers()
1269 while (!fStopThreads) {
1270 if (acquire_sem(fFinishTransfersSem) < B_OK)
1271 continue;
1273 // eat up sems that have been released by multiple interrupts
1274 int32 semCount = 0;
1275 get_sem_count(fFinishTransfersSem, &semCount);
1276 if (semCount > 0)
1277 acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
1279 if (!Lock())
1280 continue;
1282 TRACE("finishing transfers (first transfer: 0x%08lx; last"
1283 " transfer: 0x%08lx)\n", (addr_t)fFirstTransfer,
1284 (addr_t)fLastTransfer);
1285 transfer_data *lastTransfer = NULL;
1286 transfer_data *transfer = fFirstTransfer;
1287 Unlock();
1289 while (transfer) {
1290 bool transferDone = false;
1291 uhci_td *descriptor = transfer->first_descriptor;
1292 status_t callbackStatus = B_OK;
1294 while (descriptor) {
1295 uint32 status = descriptor->status;
1296 if (status & TD_STATUS_ACTIVE) {
1297 // still in progress
1298 TRACE("td (0x%08" B_PRIx32 ") still active\n",
1299 descriptor->this_phy);
1300 break;
1303 if (status & TD_ERROR_MASK) {
1304 // an error occured
1305 TRACE_ERROR("td (0x%08" B_PRIx32 ") error: status: 0x%08"
1306 B_PRIx32 "; token: 0x%08" B_PRIx32 ";\n",
1307 descriptor->this_phy, status, descriptor->token);
1309 uint8 errorCount = status >> TD_ERROR_COUNT_SHIFT;
1310 errorCount &= TD_ERROR_COUNT_MASK;
1311 if (errorCount == 0) {
1312 // the error counter counted down to zero, report why
1313 int32 reasons = 0;
1314 if (status & TD_STATUS_ERROR_BUFFER) {
1315 callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN;
1316 reasons++;
1318 if (status & TD_STATUS_ERROR_TIMEOUT) {
1319 callbackStatus = transfer->incoming ? B_DEV_CRC_ERROR : B_TIMED_OUT;
1320 reasons++;
1322 if (status & TD_STATUS_ERROR_NAK) {
1323 callbackStatus = B_DEV_UNEXPECTED_PID;
1324 reasons++;
1326 if (status & TD_STATUS_ERROR_BITSTUFF) {
1327 callbackStatus = B_DEV_CRC_ERROR;
1328 reasons++;
1331 if (reasons > 1)
1332 callbackStatus = B_DEV_MULTIPLE_ERRORS;
1333 } else if (status & TD_STATUS_ERROR_BABBLE) {
1334 // there is a babble condition
1335 callbackStatus = transfer->incoming ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN;
1336 } else {
1337 // if the error counter didn't count down to zero
1338 // and there was no babble, then this halt was caused
1339 // by a stall handshake
1340 callbackStatus = B_DEV_STALLED;
1343 transferDone = true;
1344 break;
1347 if ((descriptor->link_phy & TD_TERMINATE)
1348 || ((descriptor->status & TD_CONTROL_SPD) != 0
1349 && uhci_td_actual_length(descriptor)
1350 < uhci_td_maximum_length(descriptor))) {
1351 // all descriptors are done, or we have a short packet
1352 TRACE("td (0x%08" B_PRIx32 ") ok\n", descriptor->this_phy);
1353 callbackStatus = B_OK;
1354 transferDone = true;
1355 break;
1358 descriptor = (uhci_td *)descriptor->link_log;
1361 if (!transferDone) {
1362 lastTransfer = transfer;
1363 transfer = transfer->link;
1364 continue;
1367 // remove the transfer from the list first so we are sure
1368 // it doesn't get canceled while we still process it
1369 transfer_data *next = transfer->link;
1370 if (Lock()) {
1371 if (lastTransfer)
1372 lastTransfer->link = transfer->link;
1374 if (transfer == fFirstTransfer)
1375 fFirstTransfer = transfer->link;
1376 if (transfer == fLastTransfer)
1377 fLastTransfer = lastTransfer;
1379 // store the currently processing pipe here so we can wait
1380 // in cancel if we are processing something on the target pipe
1381 if (!transfer->canceled)
1382 fProcessingPipe = transfer->transfer->TransferPipe();
1384 transfer->link = NULL;
1385 Unlock();
1388 // if canceled the callback has already been called
1389 if (!transfer->canceled) {
1390 size_t actualLength = 0;
1391 if (callbackStatus == B_OK) {
1392 uint8 lastDataToggle = 0;
1393 if (transfer->data_descriptor && transfer->incoming) {
1394 // data to read out
1395 iovec *vector = transfer->transfer->Vector();
1396 size_t vectorCount = transfer->transfer->VectorCount();
1398 transfer->transfer->PrepareKernelAccess();
1399 actualLength = ReadDescriptorChain(
1400 transfer->data_descriptor,
1401 vector, vectorCount,
1402 &lastDataToggle);
1403 } else if (transfer->data_descriptor) {
1404 // read the actual length that was sent
1405 actualLength = ReadActualLength(
1406 transfer->data_descriptor, &lastDataToggle);
1409 transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
1411 if (transfer->transfer->IsFragmented()) {
1412 // this transfer may still have data left
1413 TRACE("advancing fragmented transfer\n");
1414 transfer->transfer->AdvanceByFragment(actualLength);
1415 if (transfer->transfer->VectorLength() > 0) {
1416 TRACE("still %ld bytes left on transfer\n",
1417 transfer->transfer->VectorLength());
1419 Transfer *resubmit = transfer->transfer;
1421 // free the used descriptors
1422 transfer->queue->RemoveTransfer(
1423 transfer->transfer_queue);
1424 AddToFreeList(transfer);
1426 // resubmit the advanced transfer so the rest
1427 // of the buffers are transmitted over the bus
1428 resubmit->PrepareKernelAccess();
1429 if (SubmitTransfer(resubmit) != B_OK)
1430 resubmit->Finished(B_ERROR, 0);
1432 transfer = next;
1433 continue;
1436 // the transfer is done, but we already set the
1437 // actualLength with AdvanceByFragment()
1438 actualLength = 0;
1442 transfer->transfer->Finished(callbackStatus, actualLength);
1443 fProcessingPipe = NULL;
1446 // remove and free the hardware queue and its descriptors
1447 transfer->queue->RemoveTransfer(transfer->transfer_queue);
1448 delete transfer->transfer;
1449 AddToFreeList(transfer);
1450 transfer = next;
1456 void
1457 UHCI::AddToFreeList(transfer_data *transfer)
1459 transfer->free_after_frame = ReadReg16(UHCI_FRNUM);
1460 if (!Lock())
1461 return;
1463 transfer->link = fFreeList;
1464 fFreeList = transfer;
1465 Unlock();
1467 if (atomic_add(&fCleanupCount, 1) == 0)
1468 release_sem(fCleanupSem);
1472 int32
1473 UHCI::CleanupThread(void *data)
1475 ((UHCI *)data)->Cleanup();
1476 return B_OK;
1480 void
1481 UHCI::Cleanup()
1483 while (!fStopThreads) {
1484 if (acquire_sem(fCleanupSem) != B_OK)
1485 continue;
1487 bigtime_t nextTime = system_time() + 1000;
1488 while (atomic_get(&fCleanupCount) != 0) {
1489 // wait for the frame to pass
1490 snooze_until(nextTime, B_SYSTEM_TIMEBASE);
1491 nextTime += 1000;
1493 if (!Lock())
1494 continue;
1496 // find the first entry we may free
1497 transfer_data **link = &fFreeList;
1498 transfer_data *transfer = fFreeList;
1499 uint16 frameNumber = ReadReg16(UHCI_FRNUM);
1500 while (transfer) {
1501 if (transfer->free_after_frame != frameNumber) {
1502 *link = NULL;
1503 break;
1506 link = &transfer->link;
1507 transfer = transfer->link;
1510 Unlock();
1512 // the transfers below this one are all freeable
1513 while (transfer) {
1514 transfer_data *next = transfer->link;
1515 FreeDescriptorChain(transfer->first_descriptor);
1516 FreeTransferQueue(transfer->transfer_queue);
1517 delete transfer;
1518 atomic_add(&fCleanupCount, -1);
1519 transfer = next;
1526 int32
1527 UHCI::FinishIsochronousThread(void *data)
1529 ((UHCI *)data)->FinishIsochronousTransfers();
1530 return B_OK;
1534 void
1535 UHCI::FinishIsochronousTransfers()
1537 /* This thread stays one position behind the controller and processes every
1538 * isochronous descriptor. Once it finds the last isochronous descriptor
1539 * of a transfer, it processes the entire transfer.
1542 while (!fStopThreads) {
1543 // Go to sleep if there are not isochronous transfer to process
1544 if (acquire_sem(fFinishIsochronousTransfersSem) < B_OK)
1545 return;
1547 bool transferDone = false;
1548 uint16 currentFrame = ReadReg16(UHCI_FRNUM);
1550 // Process the frame list until one transfer is processed
1551 while (!transferDone) {
1552 // wait 1ms in order to be sure to be one position behind
1553 // the controller
1554 if (currentFrame == ReadReg16(UHCI_FRNUM))
1555 snooze(1000);
1557 // Process the frame till it has isochronous descriptors in it.
1558 while (!(fFrameList[currentFrame] & FRAMELIST_NEXT_IS_QH)) {
1559 uhci_td *current = UnlinkIsochronousDescriptor(currentFrame);
1561 // Process the transfer if we found the last descriptor
1562 isochronous_transfer_data *transfer
1563 = FindIsochronousTransfer(current);
1564 // Process the descriptors only if it is still active and
1565 // belongs to an inbound transfer. If the transfer is not
1566 // active, it means the request has been removed, so simply
1567 // remove the descriptors.
1568 if (transfer && transfer->is_active) {
1569 if (current->token & TD_TOKEN_IN) {
1570 iovec *vector = transfer->transfer->Vector();
1571 transfer->transfer->PrepareKernelAccess();
1572 ReadIsochronousDescriptorChain(transfer, vector);
1575 // Remove the transfer
1576 if (LockIsochronous()) {
1577 if (transfer == fFirstIsochronousTransfer) {
1578 fFirstIsochronousTransfer = transfer->link;
1579 if (transfer == fLastIsochronousTransfer)
1580 fLastIsochronousTransfer = NULL;
1581 } else {
1582 isochronous_transfer_data *temp
1583 = fFirstIsochronousTransfer;
1584 while (transfer != temp->link)
1585 temp = temp->link;
1587 if (transfer == fLastIsochronousTransfer)
1588 fLastIsochronousTransfer = temp;
1589 temp->link = temp->link->link;
1591 UnlockIsochronous();
1594 transfer->transfer->Finished(B_OK, 0);
1596 uint32 packetCount =
1597 transfer->transfer->IsochronousData()->packet_count;
1598 for (uint32 i = 0; i < packetCount; i++)
1599 FreeDescriptor(transfer->descriptors[i]);
1601 delete [] transfer->descriptors;
1602 delete transfer->transfer;
1603 delete transfer;
1604 transferDone = true;
1608 // Make sure to reset the frame bandwidth
1609 fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH;
1610 currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
1616 void
1617 UHCI::GlobalReset()
1619 uint8 sofValue = ReadReg8(UHCI_SOFMOD);
1621 WriteReg16(UHCI_USBCMD, UHCI_USBCMD_GRESET);
1622 snooze(100000);
1623 WriteReg16(UHCI_USBCMD, 0);
1624 snooze(10000);
1626 WriteReg8(UHCI_SOFMOD, sofValue);
1630 status_t
1631 UHCI::ControllerReset()
1633 WriteReg16(UHCI_USBCMD, UHCI_USBCMD_HCRESET);
1635 int32 tries = 5;
1636 while (ReadReg16(UHCI_USBCMD) & UHCI_USBCMD_HCRESET) {
1637 snooze(10000);
1638 if (tries-- < 0)
1639 return B_ERROR;
1642 return B_OK;
1646 status_t
1647 UHCI::GetPortStatus(uint8 index, usb_port_status *status)
1649 if (index > 1)
1650 return B_BAD_INDEX;
1652 status->status = status->change = 0;
1653 uint16 portStatus = ReadReg16(UHCI_PORTSC1 + index * 2);
1655 // build the status
1656 if (portStatus & UHCI_PORTSC_CURSTAT)
1657 status->status |= PORT_STATUS_CONNECTION;
1658 if (portStatus & UHCI_PORTSC_ENABLED)
1659 status->status |= PORT_STATUS_ENABLE;
1660 if (portStatus & UHCI_PORTSC_RESET)
1661 status->status |= PORT_STATUS_RESET;
1662 if (portStatus & UHCI_PORTSC_LOWSPEED)
1663 status->status |= PORT_STATUS_LOW_SPEED;
1665 // build the change
1666 if (portStatus & UHCI_PORTSC_STATCHA)
1667 status->change |= PORT_STATUS_CONNECTION;
1668 if (portStatus & UHCI_PORTSC_ENABCHA)
1669 status->change |= PORT_STATUS_ENABLE;
1671 // ToDo: work out suspended/resume
1673 // there are no bits to indicate reset change
1674 if (fPortResetChange & (1 << index))
1675 status->change |= PORT_STATUS_RESET;
1677 // the port is automagically powered on
1678 status->status |= PORT_STATUS_POWER;
1679 return B_OK;
1683 status_t
1684 UHCI::SetPortFeature(uint8 index, uint16 feature)
1686 if (index > 1)
1687 return B_BAD_INDEX;
1689 switch (feature) {
1690 case PORT_RESET:
1691 return ResetPort(index);
1693 case PORT_POWER:
1694 // the ports are automatically powered
1695 return B_OK;
1698 return B_BAD_VALUE;
1702 status_t
1703 UHCI::ClearPortFeature(uint8 index, uint16 feature)
1705 if (index > 1)
1706 return B_BAD_INDEX;
1708 uint32 portRegister = UHCI_PORTSC1 + index * 2;
1709 uint16 portStatus = ReadReg16(portRegister) & UHCI_PORTSC_DATAMASK;
1711 switch (feature) {
1712 case C_PORT_RESET:
1713 fPortResetChange &= ~(1 << index);
1714 return B_OK;
1716 case C_PORT_CONNECTION:
1717 WriteReg16(portRegister, portStatus | UHCI_PORTSC_STATCHA);
1718 return B_OK;
1720 case C_PORT_ENABLE:
1721 WriteReg16(portRegister, portStatus | UHCI_PORTSC_ENABCHA);
1722 return B_OK;
1725 return B_BAD_VALUE;
1729 status_t
1730 UHCI::ResetPort(uint8 index)
1732 if (index > 1)
1733 return B_BAD_INDEX;
1735 TRACE("reset port %d\n", index);
1737 uint32 port = UHCI_PORTSC1 + index * 2;
1738 uint16 status = ReadReg16(port);
1739 status &= UHCI_PORTSC_DATAMASK;
1740 WriteReg16(port, status | UHCI_PORTSC_RESET);
1741 snooze(250000);
1743 status = ReadReg16(port);
1744 status &= UHCI_PORTSC_DATAMASK;
1745 WriteReg16(port, status & ~UHCI_PORTSC_RESET);
1746 snooze(1000);
1748 for (int32 i = 10; i > 0; i--) {
1749 // try to enable the port
1750 status = ReadReg16(port);
1751 status &= UHCI_PORTSC_DATAMASK;
1752 WriteReg16(port, status | UHCI_PORTSC_ENABLED);
1753 snooze(50000);
1755 status = ReadReg16(port);
1757 if ((status & UHCI_PORTSC_CURSTAT) == 0) {
1758 // no device connected. since we waited long enough we can assume
1759 // that the port was reset and no device is connected.
1760 break;
1763 if (status & (UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA)) {
1764 // port enabled changed or connection status were set.
1765 // acknowledge either / both and wait again.
1766 status &= UHCI_PORTSC_DATAMASK;
1767 WriteReg16(port, status | UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA);
1768 continue;
1771 if (status & UHCI_PORTSC_ENABLED) {
1772 // the port is enabled
1773 break;
1777 fPortResetChange |= (1 << index);
1778 TRACE("port was reset: 0x%04x\n", ReadReg16(port));
1779 return B_OK;
1783 int32
1784 UHCI::InterruptHandler(void *data)
1786 return ((UHCI *)data)->Interrupt();
1790 int32
1791 UHCI::Interrupt()
1793 static spinlock lock = B_SPINLOCK_INITIALIZER;
1794 acquire_spinlock(&lock);
1796 // Check if we really had an interrupt
1797 uint16 status = ReadReg16(UHCI_USBSTS);
1798 if ((status & fEnabledInterrupts) == 0) {
1799 if (status != 0) {
1800 TRACE("discarding not enabled interrupts 0x%08x\n", status);
1801 WriteReg16(UHCI_USBSTS, status);
1804 release_spinlock(&lock);
1805 return B_UNHANDLED_INTERRUPT;
1808 uint16 acknowledge = 0;
1809 bool finishTransfers = false;
1810 int32 result = B_HANDLED_INTERRUPT;
1812 if (status & UHCI_USBSTS_USBINT) {
1813 TRACE_MODULE("transfer finished\n");
1814 acknowledge |= UHCI_USBSTS_USBINT;
1815 result = B_INVOKE_SCHEDULER;
1816 finishTransfers = true;
1819 if (status & UHCI_USBSTS_ERRINT) {
1820 TRACE_MODULE("transfer error\n");
1821 acknowledge |= UHCI_USBSTS_ERRINT;
1822 result = B_INVOKE_SCHEDULER;
1823 finishTransfers = true;
1826 if (status & UHCI_USBSTS_RESDET) {
1827 TRACE_MODULE("resume detected\n");
1828 acknowledge |= UHCI_USBSTS_RESDET;
1831 if (status & UHCI_USBSTS_HOSTERR) {
1832 TRACE_MODULE_ERROR("host system error\n");
1833 acknowledge |= UHCI_USBSTS_HOSTERR;
1836 if (status & UHCI_USBSTS_HCPRERR) {
1837 TRACE_MODULE_ERROR("process error\n");
1838 acknowledge |= UHCI_USBSTS_HCPRERR;
1841 if (status & UHCI_USBSTS_HCHALT) {
1842 TRACE_MODULE_ERROR("host controller halted\n");
1843 // at least disable interrupts so we do not flood the system
1844 WriteReg16(UHCI_USBINTR, 0);
1845 fEnabledInterrupts = 0;
1846 // ToDo: cancel all transfers and reset the host controller
1847 // acknowledge not needed
1850 if (acknowledge)
1851 WriteReg16(UHCI_USBSTS, acknowledge);
1853 release_spinlock(&lock);
1855 if (finishTransfers)
1856 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1858 return result;
1862 status_t
1863 UHCI::AddTo(Stack *stack)
1865 #ifdef TRACE_USB
1866 set_dprintf_enabled(true);
1867 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
1868 load_driver_symbols("uhci");
1869 #endif
1870 #endif
1872 if (!sPCIModule) {
1873 status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule);
1874 if (status < B_OK) {
1875 TRACE_MODULE_ERROR("AddTo(): getting pci module failed! 0x%08"
1876 B_PRIx32 "\n", status);
1877 return status;
1881 TRACE_MODULE("AddTo(): setting up hardware\n");
1883 bool found = false;
1884 pci_info *item = new(std::nothrow) pci_info;
1885 if (!item) {
1886 sPCIModule = NULL;
1887 put_module(B_PCI_MODULE_NAME);
1888 return B_NO_MEMORY;
1891 // Try to get the PCI x86 module as well so we can enable possible MSIs.
1892 if (sPCIx86Module == NULL && get_module(B_PCI_X86_MODULE_NAME,
1893 (module_info **)&sPCIx86Module) != B_OK) {
1894 // If it isn't there, that's not critical though.
1895 TRACE_MODULE_ERROR("failed to get pci x86 module\n");
1896 sPCIx86Module = NULL;
1899 for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) {
1901 if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb
1902 && item->class_api == PCI_usb_uhci) {
1903 if (item->u.h0.interrupt_line == 0
1904 || item->u.h0.interrupt_line == 0xFF) {
1905 TRACE_MODULE_ERROR("AddTo(): found with invalid IRQ - check IRQ assignement\n");
1906 continue;
1909 TRACE_MODULE("AddTo(): found at IRQ %u\n",
1910 item->u.h0.interrupt_line);
1911 UHCI *bus = new(std::nothrow) UHCI(item, stack);
1912 if (!bus) {
1913 delete item;
1914 sPCIModule = NULL;
1915 put_module(B_PCI_MODULE_NAME);
1916 return B_NO_MEMORY;
1919 if (bus->InitCheck() < B_OK) {
1920 TRACE_MODULE_ERROR("AddTo(): InitCheck() failed 0x%08" B_PRIx32
1921 "\n", bus->InitCheck());
1922 delete bus;
1923 continue;
1926 // the bus took it away
1927 item = new(std::nothrow) pci_info;
1929 bus->Start();
1930 stack->AddBusManager(bus);
1931 found = true;
1935 if (!found) {
1936 TRACE_MODULE_ERROR("no devices found\n");
1937 delete item;
1938 sPCIModule = NULL;
1939 put_module(B_PCI_MODULE_NAME);
1940 return ENODEV;
1943 delete item;
1944 return B_OK;
1948 status_t
1949 UHCI::CreateFilledTransfer(Transfer *transfer, uhci_td **_firstDescriptor,
1950 uhci_qh **_transferQueue)
1952 Pipe *pipe = transfer->TransferPipe();
1953 bool directionIn = (pipe->Direction() == Pipe::In);
1955 uhci_td *firstDescriptor = NULL;
1956 uhci_td *lastDescriptor = NULL;
1957 status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
1958 &lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
1959 transfer->VectorLength());
1961 if (result < B_OK)
1962 return result;
1963 if (!firstDescriptor || !lastDescriptor)
1964 return B_NO_MEMORY;
1966 lastDescriptor->status |= TD_CONTROL_IOC;
1967 lastDescriptor->link_phy = TD_TERMINATE;
1968 lastDescriptor->link_log = NULL;
1970 if (!directionIn) {
1971 WriteDescriptorChain(firstDescriptor, transfer->Vector(),
1972 transfer->VectorCount());
1975 uhci_qh *transferQueue = CreateTransferQueue(firstDescriptor);
1976 if (!transferQueue) {
1977 FreeDescriptorChain(firstDescriptor);
1978 return B_NO_MEMORY;
1981 *_firstDescriptor = firstDescriptor;
1982 *_transferQueue = transferQueue;
1983 return B_OK;
1987 uhci_qh *
1988 UHCI::CreateTransferQueue(uhci_td *descriptor)
1990 uhci_qh *queueHead;
1991 phys_addr_t physicalAddress;
1992 if (fStack->AllocateChunk((void **)&queueHead, &physicalAddress,
1993 sizeof(uhci_qh)) < B_OK)
1994 return NULL;
1996 queueHead->this_phy = (uint32)physicalAddress;
1997 queueHead->element_phy = descriptor->this_phy;
1998 return queueHead;
2002 void
2003 UHCI::FreeTransferQueue(uhci_qh *queueHead)
2005 if (!queueHead)
2006 return;
2008 fStack->FreeChunk(queueHead, queueHead->this_phy, sizeof(uhci_qh));
2012 uhci_td *
2013 UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, size_t bufferSize)
2015 uhci_td *result;
2016 phys_addr_t physicalAddress;
2018 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2019 sizeof(uhci_td)) < B_OK) {
2020 TRACE_ERROR("failed to allocate a transfer descriptor\n");
2021 return NULL;
2024 result->this_phy = (uint32)physicalAddress;
2025 result->status = TD_STATUS_ACTIVE;
2026 if (pipe->Type() & USB_OBJECT_ISO_PIPE)
2027 result->status |= TD_CONTROL_ISOCHRONOUS;
2028 else {
2029 result->status |= TD_CONTROL_3_ERRORS;
2030 if (direction == TD_TOKEN_IN)
2031 result->status |= TD_CONTROL_SPD;
2033 if (pipe->Speed() == USB_SPEED_LOWSPEED)
2034 result->status |= TD_CONTROL_LOWSPEED;
2036 result->buffer_size = bufferSize;
2037 if (bufferSize == 0)
2038 result->token = TD_TOKEN_NULL_DATA;
2039 else
2040 result->token = (bufferSize - 1) << TD_TOKEN_MAXLEN_SHIFT;
2042 result->token |= (pipe->EndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT)
2043 | (pipe->DeviceAddress() << 8) | direction;
2045 result->link_phy = 0;
2046 result->link_log = NULL;
2047 if (bufferSize <= 0) {
2048 result->buffer_log = NULL;
2049 result->buffer_phy = 0;
2050 return result;
2053 if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress,
2054 bufferSize) < B_OK) {
2055 TRACE_ERROR("unable to allocate space for the buffer\n");
2056 fStack->FreeChunk(result, result->this_phy, sizeof(uhci_td));
2057 return NULL;
2059 result->buffer_phy = physicalAddress;
2061 return result;
2065 status_t
2066 UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
2067 uhci_td **_lastDescriptor, uint8 direction, size_t bufferSize)
2069 size_t packetSize = pipe->MaxPacketSize();
2070 int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
2071 if (descriptorCount == 0)
2072 descriptorCount = 1;
2074 bool dataToggle = pipe->DataToggle();
2075 uhci_td *firstDescriptor = NULL;
2076 uhci_td *lastDescriptor = *_firstDescriptor;
2077 for (int32 i = 0; i < descriptorCount; i++) {
2078 uhci_td *descriptor = CreateDescriptor(pipe, direction,
2079 min_c(packetSize, bufferSize));
2081 if (!descriptor) {
2082 FreeDescriptorChain(firstDescriptor);
2083 return B_NO_MEMORY;
2086 if (dataToggle)
2087 descriptor->token |= TD_TOKEN_DATA1;
2089 // link to previous
2090 if (lastDescriptor)
2091 LinkDescriptors(lastDescriptor, descriptor);
2093 dataToggle = !dataToggle;
2094 bufferSize -= packetSize;
2095 lastDescriptor = descriptor;
2096 if (!firstDescriptor)
2097 firstDescriptor = descriptor;
2100 *_firstDescriptor = firstDescriptor;
2101 *_lastDescriptor = lastDescriptor;
2102 return B_OK;
2106 void
2107 UHCI::FreeDescriptor(uhci_td *descriptor)
2109 if (!descriptor)
2110 return;
2112 if (descriptor->buffer_log) {
2113 fStack->FreeChunk(descriptor->buffer_log,
2114 descriptor->buffer_phy, descriptor->buffer_size);
2117 fStack->FreeChunk(descriptor, descriptor->this_phy, sizeof(uhci_td));
2121 void
2122 UHCI::FreeDescriptorChain(uhci_td *topDescriptor)
2124 uhci_td *current = topDescriptor;
2125 uhci_td *next = NULL;
2127 while (current) {
2128 next = (uhci_td *)current->link_log;
2129 FreeDescriptor(current);
2130 current = next;
2135 void
2136 UHCI::LinkDescriptors(uhci_td *first, uhci_td *second)
2138 first->link_phy = second->this_phy | TD_DEPTH_FIRST;
2139 first->link_log = second;
2143 size_t
2144 UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector,
2145 size_t vectorCount)
2147 uhci_td *current = topDescriptor;
2148 size_t actualLength = 0;
2149 size_t vectorIndex = 0;
2150 size_t vectorOffset = 0;
2151 size_t bufferOffset = 0;
2153 while (current) {
2154 if (!current->buffer_log)
2155 break;
2157 while (true) {
2158 size_t length = min_c(current->buffer_size - bufferOffset,
2159 vector[vectorIndex].iov_len - vectorOffset);
2161 TRACE("copying %ld bytes to bufferOffset %ld from"
2162 " vectorOffset %ld at index %ld of %ld\n", length, bufferOffset,
2163 vectorOffset, vectorIndex, vectorCount);
2164 memcpy((uint8 *)current->buffer_log + bufferOffset,
2165 (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length);
2167 actualLength += length;
2168 vectorOffset += length;
2169 bufferOffset += length;
2171 if (vectorOffset >= vector[vectorIndex].iov_len) {
2172 if (++vectorIndex >= vectorCount) {
2173 TRACE("wrote descriptor chain (%ld bytes, no more vectors)\n",
2174 actualLength);
2175 return actualLength;
2178 vectorOffset = 0;
2181 if (bufferOffset >= current->buffer_size) {
2182 bufferOffset = 0;
2183 break;
2187 if (current->link_phy & TD_TERMINATE)
2188 break;
2190 current = (uhci_td *)current->link_log;
2193 TRACE("wrote descriptor chain (%ld bytes)\n", actualLength);
2194 return actualLength;
2198 size_t
2199 UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector,
2200 size_t vectorCount, uint8 *lastDataToggle)
2202 uint8 dataToggle = 0;
2203 uhci_td *current = topDescriptor;
2204 size_t actualLength = 0;
2205 size_t vectorIndex = 0;
2206 size_t vectorOffset = 0;
2207 size_t bufferOffset = 0;
2209 while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
2210 if (!current->buffer_log)
2211 break;
2213 dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
2214 size_t bufferSize = uhci_td_actual_length(current);
2216 while (true) {
2217 size_t length = min_c(bufferSize - bufferOffset,
2218 vector[vectorIndex].iov_len - vectorOffset);
2220 TRACE("copying %ld bytes to vectorOffset %ld from"
2221 " bufferOffset %ld at index %ld of %ld\n", length, vectorOffset,
2222 bufferOffset, vectorIndex, vectorCount);
2223 memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
2224 (uint8 *)current->buffer_log + bufferOffset, length);
2226 actualLength += length;
2227 vectorOffset += length;
2228 bufferOffset += length;
2230 if (vectorOffset >= vector[vectorIndex].iov_len) {
2231 if (++vectorIndex >= vectorCount) {
2232 TRACE("read descriptor chain (%ld bytes, no more vectors)\n",
2233 actualLength);
2234 if (lastDataToggle)
2235 *lastDataToggle = dataToggle;
2236 return actualLength;
2239 vectorOffset = 0;
2242 if (bufferOffset >= bufferSize) {
2243 bufferOffset = 0;
2244 break;
2248 if (current->link_phy & TD_TERMINATE)
2249 break;
2251 current = (uhci_td *)current->link_log;
2254 if (lastDataToggle)
2255 *lastDataToggle = dataToggle;
2257 TRACE("read descriptor chain (%ld bytes)\n", actualLength);
2258 return actualLength;
2262 size_t
2263 UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle)
2265 size_t actualLength = 0;
2266 uhci_td *current = topDescriptor;
2267 uint8 dataToggle = 0;
2269 while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
2270 actualLength += uhci_td_actual_length(current);
2271 dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
2273 if (current->link_phy & TD_TERMINATE)
2274 break;
2276 current = (uhci_td *)current->link_log;
2279 if (lastDataToggle)
2280 *lastDataToggle = dataToggle;
2282 TRACE("read actual length (%ld bytes)\n", actualLength);
2283 return actualLength;
2287 void
2288 UHCI::WriteIsochronousDescriptorChain(uhci_td **isoRequest, uint32 packetCount,
2289 iovec *vector)
2291 size_t vectorOffset = 0;
2292 for (uint32 i = 0; i < packetCount; i++) {
2293 size_t bufferSize = isoRequest[i]->buffer_size;
2294 memcpy((uint8 *)isoRequest[i]->buffer_log,
2295 (uint8 *)vector->iov_base + vectorOffset, bufferSize);
2296 vectorOffset += bufferSize;
2301 void
2302 UHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer,
2303 iovec *vector)
2305 size_t vectorOffset = 0;
2306 usb_isochronous_data *isochronousData
2307 = transfer->transfer->IsochronousData();
2309 for (uint32 i = 0; i < isochronousData->packet_count; i++) {
2310 uhci_td *current = transfer->descriptors[i];
2312 size_t bufferSize = current->buffer_size;
2313 size_t actualLength = uhci_td_actual_length(current);
2315 isochronousData->packet_descriptors[i].actual_length = actualLength;
2317 if (actualLength > 0)
2318 isochronousData->packet_descriptors[i].status = B_OK;
2319 else {
2320 isochronousData->packet_descriptors[i].status = B_ERROR;
2321 vectorOffset += bufferSize;
2322 continue;
2324 memcpy((uint8 *)vector->iov_base + vectorOffset,
2325 (uint8 *)current->buffer_log, bufferSize);
2327 vectorOffset += bufferSize;
2332 bool
2333 UHCI::LockIsochronous()
2335 return (mutex_lock(&fIsochronousLock) == B_OK);
2339 void
2340 UHCI::UnlockIsochronous()
2342 mutex_unlock(&fIsochronousLock);
2346 inline void
2347 UHCI::WriteReg8(uint32 reg, uint8 value)
2349 sPCIModule->write_io_8(fRegisterBase + reg, value);
2353 inline void
2354 UHCI::WriteReg16(uint32 reg, uint16 value)
2356 sPCIModule->write_io_16(fRegisterBase + reg, value);
2360 inline void
2361 UHCI::WriteReg32(uint32 reg, uint32 value)
2363 sPCIModule->write_io_32(fRegisterBase + reg, value);
2367 inline uint8
2368 UHCI::ReadReg8(uint32 reg)
2370 return sPCIModule->read_io_8(fRegisterBase + reg);
2374 inline uint16
2375 UHCI::ReadReg16(uint32 reg)
2377 return sPCIModule->read_io_16(fRegisterBase + reg);
2381 inline uint32
2382 UHCI::ReadReg32(uint32 reg)
2384 return sPCIModule->read_io_32(fRegisterBase + reg);