vfs: check userland buffers before reading them.
[haiku.git] / src / add-ons / kernel / busses / usb / ehci.cpp
blob977951a0a0841cee2a2721af92fd1902270f9afe
1 /*
2 * Copyright 2006-2011, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 * Jérôme Duval <korli@users.berlios.de>
8 */
11 #include <driver_settings.h>
12 #include <module.h>
13 #include <PCI.h>
14 #include <PCI_x86.h>
15 #include <USB3.h>
16 #include <KernelExport.h>
18 #include "ehci.h"
20 #define USB_MODULE_NAME "ehci"
22 pci_module_info *EHCI::sPCIModule = NULL;
23 pci_x86_module_info *EHCI::sPCIx86Module = NULL;
26 static int32
27 ehci_std_ops(int32 op, ...)
29 switch (op) {
30 case B_MODULE_INIT:
31 TRACE_MODULE("ehci init module\n");
32 return B_OK;
33 case B_MODULE_UNINIT:
34 TRACE_MODULE("ehci uninit module\n");
35 return B_OK;
38 return EINVAL;
42 usb_host_controller_info ehci_module = {
44 "busses/usb/ehci",
46 ehci_std_ops
48 NULL,
49 EHCI::AddTo
53 module_info *modules[] = {
54 (module_info *)&ehci_module,
55 NULL
60 // #pragma mark -
64 #ifdef TRACE_USB
66 void
67 print_descriptor_chain(ehci_qtd *descriptor)
69 while (descriptor) {
70 dprintf(" %08" B_PRIx32 " n%08" B_PRIx32 " a%08" B_PRIx32 " t%08"
71 B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32 " %08"
72 B_PRIx32 " %08" B_PRIx32 " s%" B_PRIuSIZE "\n",
73 descriptor->this_phy, descriptor->next_phy,
74 descriptor->alt_next_phy, descriptor->token,
75 descriptor->buffer_phy[0], descriptor->buffer_phy[1],
76 descriptor->buffer_phy[2], descriptor->buffer_phy[3],
77 descriptor->buffer_phy[4], descriptor->buffer_size);
79 if (descriptor->next_phy & EHCI_ITEM_TERMINATE)
80 break;
82 descriptor = descriptor->next_log;
87 void
88 print_queue(ehci_qh *queueHead)
90 dprintf("queue: t%08" B_PRIx32 " n%08" B_PRIx32 " ch%08" B_PRIx32
91 " ca%08" B_PRIx32 " cu%08" B_PRIx32 "\n",
92 queueHead->this_phy, queueHead->next_phy, queueHead->endpoint_chars,
93 queueHead->endpoint_caps, queueHead->current_qtd_phy);
94 dprintf("overlay: n%08" B_PRIx32 " a%08" B_PRIx32 " t%08" B_PRIx32
95 " %08" B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32
96 " %08" B_PRIx32 "\n", queueHead->overlay.next_phy,
97 queueHead->overlay.alt_next_phy, queueHead->overlay.token,
98 queueHead->overlay.buffer_phy[0], queueHead->overlay.buffer_phy[1],
99 queueHead->overlay.buffer_phy[2], queueHead->overlay.buffer_phy[3],
100 queueHead->overlay.buffer_phy[4]);
101 print_descriptor_chain(queueHead->element_log);
105 #endif // TRACE_USB
109 // #pragma mark -
113 EHCI::EHCI(pci_info *info, Stack *stack)
114 : BusManager(stack),
115 fCapabilityRegisters(NULL),
116 fOperationalRegisters(NULL),
117 fRegisterArea(-1),
118 fPCIInfo(info),
119 fStack(stack),
120 fEnabledInterrupts(0),
121 fThreshold(0),
122 fPeriodicFrameListArea(-1),
123 fPeriodicFrameList(NULL),
124 fInterruptEntries(NULL),
125 fItdEntries(NULL),
126 fSitdEntries(NULL),
127 fAsyncQueueHead(NULL),
128 fAsyncAdvanceSem(-1),
129 fFirstTransfer(NULL),
130 fLastTransfer(NULL),
131 fFinishTransfersSem(-1),
132 fFinishThread(-1),
133 fProcessingPipe(NULL),
134 fFreeListHead(NULL),
135 fCleanupSem(-1),
136 fCleanupThread(-1),
137 fStopThreads(false),
138 fNextStartingFrame(-1),
139 fFrameBandwidth(NULL),
140 fFirstIsochronousTransfer(NULL),
141 fLastIsochronousTransfer(NULL),
142 fFinishIsochronousTransfersSem(-1),
143 fFinishIsochronousThread(-1),
144 fRootHub(NULL),
145 fRootHubAddress(0),
146 fPortCount(0),
147 fPortResetChange(0),
148 fPortSuspendChange(0),
149 fInterruptPollThread(-1),
150 fIRQ(0),
151 fUseMSI(false)
153 // Create a lock for the isochronous transfer list
154 mutex_init(&fIsochronousLock, "EHCI isochronous lock");
156 if (BusManager::InitCheck() != B_OK) {
157 TRACE_ERROR("bus manager failed to init\n");
158 return;
161 TRACE("constructing new EHCI host controller driver\n");
162 fInitOK = false;
164 // ATI/AMD SB600/SB700 periodic list cache workaround
165 // Logic kindly borrowed from NetBSD PR 40056
166 if (fPCIInfo->vendor_id == AMD_SBX00_VENDOR) {
167 bool applyWorkaround = false;
169 if (fPCIInfo->device_id == AMD_SB600_EHCI_CONTROLLER) {
170 // always apply on SB600
171 applyWorkaround = true;
172 } else if (fPCIInfo->device_id == AMD_SB700_SB800_EHCI_CONTROLLER) {
173 // only apply on certain chipsets, determined by SMBus revision
174 pci_info smbus;
175 int32 index = 0;
176 while (sPCIModule->get_nth_pci_info(index++, &smbus) == B_OK) {
177 if (smbus.vendor_id == AMD_SBX00_VENDOR
178 && smbus.device_id == AMD_SBX00_SMBUS_CONTROLLER) {
180 // Only applies to chipsets < SB710 (rev A14)
181 if (smbus.revision == 0x3a || smbus.revision == 0x3b)
182 applyWorkaround = true;
184 break;
189 if (applyWorkaround) {
190 // According to AMD errata of SB700 and SB600 register documentation
191 // this disables the Periodic List Cache on SB600 and the Advanced
192 // Periodic List Cache on early SB700. Both the BSDs and Linux use
193 // this workaround.
195 TRACE_ALWAYS("disabling SB600/SB700 periodic list cache\n");
196 uint32 workaround = sPCIModule->read_pci_config(fPCIInfo->bus,
197 fPCIInfo->device, fPCIInfo->function,
198 AMD_SBX00_EHCI_MISC_REGISTER, 4);
200 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
201 fPCIInfo->function, AMD_SBX00_EHCI_MISC_REGISTER, 4,
202 workaround | AMD_SBX00_EHCI_MISC_DISABLE_PERIODIC_LIST_CACHE);
206 // enable busmaster and memory mapped access
207 uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus,
208 fPCIInfo->device, fPCIInfo->function, PCI_command, 2);
209 command &= ~PCI_command_io;
210 command |= PCI_command_master | PCI_command_memory;
212 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
213 fPCIInfo->function, PCI_command, 2, command);
215 // map the registers
216 uint32 offset = fPCIInfo->u.h0.base_registers[0] & (B_PAGE_SIZE - 1);
217 phys_addr_t physicalAddress = fPCIInfo->u.h0.base_registers[0] - offset;
218 size_t mapSize = (fPCIInfo->u.h0.base_register_sizes[0] + offset
219 + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
221 TRACE("map physical memory 0x%08" B_PRIx32 " (base: 0x%08" B_PRIxPHYSADDR
222 "; offset: %" B_PRIx32 "); size: %" B_PRIu32 "\n",
223 fPCIInfo->u.h0.base_registers[0], physicalAddress, offset,
224 fPCIInfo->u.h0.base_register_sizes[0]);
226 fRegisterArea = map_physical_memory("EHCI memory mapped registers",
227 physicalAddress, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS,
228 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA,
229 (void **)&fCapabilityRegisters);
230 if (fRegisterArea < 0) {
231 TRACE_ERROR("failed to map register memory\n");
232 return;
235 fCapabilityRegisters += offset;
236 fOperationalRegisters = fCapabilityRegisters + ReadCapReg8(EHCI_CAPLENGTH);
237 TRACE("mapped capability registers: 0x%p\n", fCapabilityRegisters);
238 TRACE("mapped operational registers: 0x%p\n", fOperationalRegisters);
240 TRACE("structural parameters: 0x%08" B_PRIx32 "\n",
241 ReadCapReg32(EHCI_HCSPARAMS));
242 TRACE("capability parameters: 0x%08" B_PRIx32 "\n",
243 ReadCapReg32(EHCI_HCCPARAMS));
245 if (EHCI_HCCPARAMS_FRAME_CACHE(ReadCapReg32(EHCI_HCCPARAMS)))
246 fThreshold = 2 + 8;
247 else
248 fThreshold = 2 + EHCI_HCCPARAMS_IPT(ReadCapReg32(EHCI_HCCPARAMS));
250 // read port count from capability register
251 fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f;
253 uint32 extendedCapPointer = ReadCapReg32(EHCI_HCCPARAMS) >> EHCI_ECP_SHIFT;
254 extendedCapPointer &= EHCI_ECP_MASK;
255 if (extendedCapPointer > 0) {
256 TRACE("extended capabilities register at %" B_PRIu32 "\n",
257 extendedCapPointer);
259 uint32 legacySupport = sPCIModule->read_pci_config(fPCIInfo->bus,
260 fPCIInfo->device, fPCIInfo->function, extendedCapPointer, 4);
261 if ((legacySupport & EHCI_LEGSUP_CAPID_MASK) == EHCI_LEGSUP_CAPID) {
262 if ((legacySupport & EHCI_LEGSUP_BIOSOWNED) != 0) {
263 TRACE_ALWAYS("the host controller is bios owned, claiming"
264 " ownership\n");
266 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
267 fPCIInfo->function, extendedCapPointer + 3, 1, 1);
269 for (int32 i = 0; i < 20; i++) {
270 legacySupport = sPCIModule->read_pci_config(fPCIInfo->bus,
271 fPCIInfo->device, fPCIInfo->function,
272 extendedCapPointer, 4);
274 if ((legacySupport & EHCI_LEGSUP_BIOSOWNED) == 0)
275 break;
277 TRACE_ALWAYS("controller is still bios owned, waiting\n");
278 snooze(50000);
282 if (legacySupport & EHCI_LEGSUP_BIOSOWNED) {
283 TRACE_ERROR("bios won't give up control over the host "
284 "controller (ignoring)\n");
285 } else if (legacySupport & EHCI_LEGSUP_OSOWNED) {
286 TRACE_ALWAYS(
287 "successfully took ownership of the host controller\n");
290 // Force off the BIOS owned flag, and clear all SMIs. Some BIOSes
291 // do indicate a successful handover but do not remove their SMIs
292 // and then freeze the system when interrupts are generated.
293 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
294 fPCIInfo->function, extendedCapPointer + 2, 1, 0);
295 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
296 fPCIInfo->function, extendedCapPointer + 4, 4, 0);
297 } else {
298 TRACE_ALWAYS(
299 "extended capability is not a legacy support register\n");
301 } else {
302 TRACE_ALWAYS("no extended capabilities register\n");
305 // disable interrupts
306 WriteOpReg(EHCI_USBINTR, 0);
308 // reset the host controller
309 if (ControllerReset() != B_OK) {
310 TRACE_ERROR("host controller failed to reset\n");
311 return;
314 // reset the segment register
315 WriteOpReg(EHCI_CTRDSSEGMENT, 0);
317 // create semaphores the finisher thread will wait for
318 fAsyncAdvanceSem = create_sem(0, "EHCI Async Advance");
319 fFinishTransfersSem = create_sem(0, "EHCI Finish Transfers");
320 fCleanupSem = create_sem(0, "EHCI Cleanup");
321 if (fFinishTransfersSem < 0 || fAsyncAdvanceSem < 0 || fCleanupSem < 0) {
322 TRACE_ERROR("failed to create semaphores\n");
323 return;
326 // create finisher service thread
327 fFinishThread = spawn_kernel_thread(FinishThread, "ehci finish thread",
328 B_NORMAL_PRIORITY, (void *)this);
329 resume_thread(fFinishThread);
331 // Create semaphore the isochronous finisher thread will wait for
332 fFinishIsochronousTransfersSem = create_sem(0,
333 "EHCI Isochronous Finish Transfers");
334 if (fFinishIsochronousTransfersSem < 0) {
335 TRACE_ERROR("failed to create isochronous finisher semaphore\n");
336 return;
339 // Create the isochronous finisher service thread
340 fFinishIsochronousThread = spawn_kernel_thread(FinishIsochronousThread,
341 "ehci isochronous finish thread", B_URGENT_DISPLAY_PRIORITY,
342 (void *)this);
343 resume_thread(fFinishIsochronousThread);
345 // create cleanup service thread
346 fCleanupThread = spawn_kernel_thread(CleanupThread, "ehci cleanup thread",
347 B_NORMAL_PRIORITY, (void *)this);
348 resume_thread(fCleanupThread);
350 // set up interrupts or interrupt polling now that the controller is ready
351 bool polling = false;
352 void *settings = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS);
353 if (settings != NULL) {
354 polling = get_driver_boolean_parameter(settings, "ehci_polling", false,
355 false);
356 unload_driver_settings(settings);
359 if (polling) {
360 // create and run the polling thread
361 TRACE_ALWAYS("enabling ehci polling\n");
362 fInterruptPollThread = spawn_kernel_thread(InterruptPollThread,
363 "ehci interrupt poll thread", B_NORMAL_PRIORITY, (void *)this);
364 resume_thread(fInterruptPollThread);
365 } else {
366 // Find the right interrupt vector, using MSIs if available.
367 fIRQ = fPCIInfo->u.h0.interrupt_line;
368 if (sPCIx86Module != NULL && sPCIx86Module->get_msi_count(
369 fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function) >= 1) {
370 uint8 msiVector = 0;
371 if (sPCIx86Module->configure_msi(fPCIInfo->bus, fPCIInfo->device,
372 fPCIInfo->function, 1, &msiVector) == B_OK
373 && sPCIx86Module->enable_msi(fPCIInfo->bus, fPCIInfo->device,
374 fPCIInfo->function) == B_OK) {
375 TRACE_ALWAYS("using message signaled interrupts\n");
376 fIRQ = msiVector;
377 fUseMSI = true;
381 // install the interrupt handler and enable interrupts
382 install_io_interrupt_handler(fIRQ, InterruptHandler,
383 (void *)this, 0);
386 // ensure that interrupts are en-/disabled on the PCI device
387 command = sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device,
388 fPCIInfo->function, PCI_command, 2);
389 if ((polling || fUseMSI) == ((command & PCI_command_int_disable) == 0)) {
390 if (polling || fUseMSI)
391 command &= ~PCI_command_int_disable;
392 else
393 command |= PCI_command_int_disable;
395 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
396 fPCIInfo->function, PCI_command, 2, command);
399 fEnabledInterrupts = EHCI_USBINTR_HOSTSYSERR | EHCI_USBINTR_USBERRINT
400 | EHCI_USBINTR_USBINT | EHCI_USBINTR_INTONAA;
401 WriteOpReg(EHCI_USBINTR, fEnabledInterrupts);
403 // structures don't span page boundaries
404 size_t itdListSize = EHCI_VFRAMELIST_ENTRIES_COUNT
405 / (B_PAGE_SIZE / sizeof(itd_entry)) * B_PAGE_SIZE;
406 size_t sitdListSize = EHCI_VFRAMELIST_ENTRIES_COUNT
407 / (B_PAGE_SIZE / sizeof(sitd_entry)) * B_PAGE_SIZE;
408 size_t frameListSize = B_PAGE_SIZE + B_PAGE_SIZE + itdListSize
409 + sitdListSize;
411 // allocate the periodic frame list
412 fPeriodicFrameListArea = fStack->AllocateArea((void **)&fPeriodicFrameList,
413 &physicalAddress, frameListSize, "USB EHCI Periodic Framelist");
414 if (fPeriodicFrameListArea < 0) {
415 TRACE_ERROR("unable to allocate periodic framelist\n");
416 return;
419 if ((physicalAddress & 0xfff) != 0) {
420 panic("EHCI_PERIODICLISTBASE not aligned on 4k: 0x%" B_PRIxPHYSADDR
421 "\n", physicalAddress);
424 // set the periodic frame list base on the controller
425 WriteOpReg(EHCI_PERIODICLISTBASE, (uint32)physicalAddress);
427 // create the interrupt entries to support different polling intervals
428 TRACE("creating interrupt entries\n");
429 uint32_t physicalBase = physicalAddress + B_PAGE_SIZE;
430 uint8 *logicalBase = (uint8 *)fPeriodicFrameList + B_PAGE_SIZE;
431 memset(logicalBase, 0, B_PAGE_SIZE);
433 fInterruptEntries = (interrupt_entry *)logicalBase;
434 for (int32 i = 0; i < EHCI_INTERRUPT_ENTRIES_COUNT; i++) {
435 ehci_qh *queueHead = &fInterruptEntries[i].queue_head;
436 queueHead->this_phy = physicalBase | EHCI_ITEM_TYPE_QH;
437 queueHead->current_qtd_phy = 0;
438 queueHead->overlay.next_phy = EHCI_ITEM_TERMINATE;
439 queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
440 queueHead->overlay.token = EHCI_QTD_STATUS_HALTED;
442 // set dummy endpoint information
443 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH
444 | (3 << EHCI_QH_CHARS_RL_SHIFT) | (64 << EHCI_QH_CHARS_MPL_SHIFT)
445 | EHCI_QH_CHARS_TOGGLE;
446 queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT)
447 | (0xff << EHCI_QH_CAPS_ISM_SHIFT);
449 physicalBase += sizeof(interrupt_entry);
450 if ((physicalBase & 0x1f) != 0) {
451 panic("physical base for interrupt entry %" B_PRId32
452 " not aligned on 32, interrupt entry structure size %lu\n",
453 i, sizeof(interrupt_entry));
457 // create the itd and sitd entries
458 TRACE("build up iso entries\n");
459 uint32_t itdPhysicalBase = physicalAddress + B_PAGE_SIZE + B_PAGE_SIZE;
460 itd_entry* itds = (itd_entry *)((uint8 *)fPeriodicFrameList + B_PAGE_SIZE
461 + B_PAGE_SIZE);
462 memset(itds, 0, itdListSize);
464 uint32_t sitdPhysicalBase = itdPhysicalBase + itdListSize;
465 sitd_entry* sitds = (sitd_entry *)((uint8 *)fPeriodicFrameList + B_PAGE_SIZE
466 + B_PAGE_SIZE + itdListSize);
467 memset(sitds, 0, sitdListSize);
469 fItdEntries = new(std::nothrow) ehci_itd *[EHCI_VFRAMELIST_ENTRIES_COUNT];
470 fSitdEntries = new(std::nothrow) ehci_sitd *[EHCI_VFRAMELIST_ENTRIES_COUNT];
472 dprintf("sitd entry size %lu, itd entry size %lu\n", sizeof(sitd_entry),
473 sizeof(itd_entry));
474 for (int32 i = 0; i < EHCI_VFRAMELIST_ENTRIES_COUNT; i++) {
475 ehci_sitd *sitd = &sitds[i].sitd;
476 sitd->this_phy = sitdPhysicalBase | EHCI_ITEM_TYPE_SITD;
477 sitd->back_phy = EHCI_ITEM_TERMINATE;
478 fSitdEntries[i] = sitd;
479 TRACE("sitd entry %" B_PRId32 " %p 0x%" B_PRIx32 "\n", i, sitd,
480 sitd->this_phy);
482 ehci_itd *itd = &itds[i].itd;
483 itd->this_phy = itdPhysicalBase | EHCI_ITEM_TYPE_ITD;
484 itd->next_phy = sitd->this_phy;
485 fItdEntries[i] = itd;
486 TRACE("itd entry %" B_PRId32 " %p 0x%" B_PRIx32 "\n", i, itd,
487 itd->this_phy);
489 sitdPhysicalBase += sizeof(sitd_entry);
490 itdPhysicalBase += sizeof(itd_entry);
491 if ((sitdPhysicalBase & 0x10) != 0 || (itdPhysicalBase & 0x10) != 0)
492 panic("physical base for entry %" B_PRId32 " not aligned on 32\n",
496 // build flat interrupt tree
497 TRACE("build up interrupt links\n");
498 uint32 interval = EHCI_VFRAMELIST_ENTRIES_COUNT;
499 uint32 intervalIndex = EHCI_INTERRUPT_ENTRIES_COUNT - 1;
500 while (interval > 1) {
501 for (uint32 insertIndex = interval / 2;
502 insertIndex < EHCI_VFRAMELIST_ENTRIES_COUNT;
503 insertIndex += interval) {
504 fSitdEntries[insertIndex]->next_phy
505 = fInterruptEntries[intervalIndex].queue_head.this_phy;
508 intervalIndex--;
509 interval /= 2;
512 // setup the empty slot in the list and linking of all -> first
513 ehci_qh *firstLogical = &fInterruptEntries[0].queue_head;
514 fSitdEntries[0]->next_phy = firstLogical->this_phy;
515 for (int32 i = 1; i < EHCI_INTERRUPT_ENTRIES_COUNT; i++) {
516 fInterruptEntries[i].queue_head.next_phy = firstLogical->this_phy;
517 fInterruptEntries[i].queue_head.next_log = firstLogical;
518 fInterruptEntries[i].queue_head.prev_log = NULL;
521 // terminate the first entry
522 firstLogical->next_phy = EHCI_ITEM_TERMINATE;
523 firstLogical->next_log = NULL;
524 firstLogical->prev_log = NULL;
526 for (int32 i = 0; i < EHCI_FRAMELIST_ENTRIES_COUNT; i++) {
527 fPeriodicFrameList[i]
528 = fItdEntries[i & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1)]->this_phy;
529 TRACE("periodic entry %" B_PRId32 " linked to 0x%" B_PRIx32 "\n", i,
530 fPeriodicFrameList[i]);
533 // Create the array that will keep bandwidth information
534 fFrameBandwidth = new(std::nothrow) uint16[EHCI_VFRAMELIST_ENTRIES_COUNT];
535 for (int32 i = 0; i < EHCI_VFRAMELIST_ENTRIES_COUNT; i++) {
536 fFrameBandwidth[i] = MAX_AVAILABLE_BANDWIDTH;
539 // allocate a queue head that will always stay in the async frame list
540 fAsyncQueueHead = CreateQueueHead();
541 if (!fAsyncQueueHead) {
542 TRACE_ERROR("unable to allocate stray async queue head\n");
543 return;
546 fAsyncQueueHead->next_phy = fAsyncQueueHead->this_phy;
547 fAsyncQueueHead->next_log = fAsyncQueueHead;
548 fAsyncQueueHead->prev_log = fAsyncQueueHead;
549 fAsyncQueueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH
550 | EHCI_QH_CHARS_RECHEAD;
551 fAsyncQueueHead->endpoint_caps = 1 << EHCI_QH_CAPS_MULT_SHIFT;
552 fAsyncQueueHead->overlay.next_phy = EHCI_ITEM_TERMINATE;
554 WriteOpReg(EHCI_ASYNCLISTADDR, (uint32)fAsyncQueueHead->this_phy);
555 TRACE("set the async list addr to 0x%08" B_PRIx32 "\n",
556 ReadOpReg(EHCI_ASYNCLISTADDR));
558 fInitOK = true;
559 TRACE("EHCI host controller driver constructed\n");
563 EHCI::~EHCI()
565 TRACE("tear down EHCI host controller driver\n");
567 WriteOpReg(EHCI_USBCMD, 0);
568 WriteOpReg(EHCI_CONFIGFLAG, 0);
569 CancelAllPendingTransfers();
571 int32 result = 0;
572 fStopThreads = true;
573 delete_sem(fAsyncAdvanceSem);
574 delete_sem(fFinishTransfersSem);
575 delete_sem(fFinishIsochronousTransfersSem);
576 wait_for_thread(fFinishThread, &result);
577 wait_for_thread(fCleanupThread, &result);
578 wait_for_thread(fFinishIsochronousThread, &result);
580 if (fInterruptPollThread >= 0)
581 wait_for_thread(fInterruptPollThread, &result);
582 else
583 remove_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this);
585 LockIsochronous();
586 isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer;
587 while (isoTransfer) {
588 isochronous_transfer_data *next = isoTransfer->link;
589 delete isoTransfer;
590 isoTransfer = next;
592 mutex_destroy(&fIsochronousLock);
594 delete fRootHub;
595 delete [] fFrameBandwidth;
596 delete [] fItdEntries;
597 delete [] fSitdEntries;
598 delete_area(fPeriodicFrameListArea);
599 delete_area(fRegisterArea);
601 if (fUseMSI && sPCIx86Module != NULL) {
602 sPCIx86Module->disable_msi(fPCIInfo->bus,
603 fPCIInfo->device, fPCIInfo->function);
604 sPCIx86Module->unconfigure_msi(fPCIInfo->bus,
605 fPCIInfo->device, fPCIInfo->function);
607 put_module(B_PCI_MODULE_NAME);
609 if (sPCIx86Module != NULL) {
610 sPCIx86Module = NULL;
611 put_module(B_PCI_X86_MODULE_NAME);
616 status_t
617 EHCI::Start()
619 TRACE("starting EHCI host controller\n");
620 TRACE("usbcmd: 0x%08" B_PRIx32 "; usbsts: 0x%08" B_PRIx32 "\n",
621 ReadOpReg(EHCI_USBCMD), ReadOpReg(EHCI_USBSTS));
623 bool hasPerPortChangeEvent = (ReadCapReg32(EHCI_HCCPARAMS)
624 & EHCI_HCCPARAMS_PPCEC) != 0;
626 uint32 config = ReadOpReg(EHCI_USBCMD);
627 config &= ~((EHCI_USBCMD_ITC_MASK << EHCI_USBCMD_ITC_SHIFT)
628 | EHCI_USBCMD_PPCEE);
629 uint32 frameListSize = (config >> EHCI_USBCMD_FLS_SHIFT)
630 & EHCI_USBCMD_FLS_MASK;
632 WriteOpReg(EHCI_USBCMD, config | EHCI_USBCMD_RUNSTOP
633 | (hasPerPortChangeEvent ? EHCI_USBCMD_PPCEE : 0)
634 | EHCI_USBCMD_ASENABLE | EHCI_USBCMD_PSENABLE
635 | (frameListSize << EHCI_USBCMD_FLS_SHIFT)
636 | (1 << EHCI_USBCMD_ITC_SHIFT));
638 switch (frameListSize) {
639 case 0:
640 TRACE("frame list size 1024\n");
641 break;
642 case 1:
643 TRACE("frame list size 512\n");
644 break;
645 case 2:
646 TRACE("frame list size 256\n");
647 break;
648 default:
649 TRACE_ALWAYS("unknown frame list size\n");
652 bool running = false;
653 for (int32 i = 0; i < 10; i++) {
654 uint32 status = ReadOpReg(EHCI_USBSTS);
655 TRACE("try %" B_PRId32 ": status 0x%08" B_PRIx32 "\n", i, status);
657 if (status & EHCI_USBSTS_HCHALTED) {
658 snooze(10000);
659 } else {
660 running = true;
661 break;
665 if (!running) {
666 TRACE_ERROR("host controller didn't start\n");
667 return B_ERROR;
670 // route all ports to us
671 WriteOpReg(EHCI_CONFIGFLAG, EHCI_CONFIGFLAG_FLAG);
672 snooze(10000);
674 fRootHubAddress = AllocateAddress();
675 fRootHub = new(std::nothrow) EHCIRootHub(RootObject(), fRootHubAddress);
676 if (!fRootHub) {
677 TRACE_ERROR("no memory to allocate root hub\n");
678 return B_NO_MEMORY;
681 if (fRootHub->InitCheck() != B_OK) {
682 TRACE_ERROR("root hub failed init check\n");
683 return fRootHub->InitCheck();
686 SetRootHub(fRootHub);
688 TRACE_ALWAYS("successfully started the controller\n");
689 return BusManager::Start();
693 status_t
694 EHCI::StartDebugTransfer(Transfer *transfer)
696 static transfer_data transferData;
698 transferData.queue_head = CreateQueueHead();
699 if (transferData.queue_head == NULL)
700 return B_NO_MEMORY;
702 Pipe *pipe = transfer->TransferPipe();
703 status_t result = InitQueueHead(transferData.queue_head, pipe);
704 if (result != B_OK) {
705 FreeQueueHead(transferData.queue_head);
706 return result;
709 if ((pipe->Type() & USB_OBJECT_CONTROL_PIPE) != 0) {
710 result = FillQueueWithRequest(transfer, transferData.queue_head,
711 &transferData.data_descriptor, &transferData.incoming);
712 } else {
713 result = FillQueueWithData(transfer, transferData.queue_head,
714 &transferData.data_descriptor, &transferData.incoming);
717 if (result != B_OK) {
718 FreeQueueHead(transferData.queue_head);
719 return result;
722 if ((pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) != 0)
723 LinkPeriodicDebugQueueHead(transferData.queue_head, pipe);
724 else
725 LinkAsyncDebugQueueHead(transferData.queue_head);
727 // we abuse the callback cookie to hold our transfer data
728 transfer->SetCallback(NULL, &transferData);
729 return B_OK;
733 void
734 EHCI::LinkAsyncDebugQueueHead(ehci_qh *queueHead)
736 ehci_qh *prevHead = fAsyncQueueHead->prev_log;
737 queueHead->next_phy = fAsyncQueueHead->this_phy;
738 queueHead->next_log = fAsyncQueueHead;
739 queueHead->prev_log = prevHead;
740 fAsyncQueueHead->prev_log = queueHead;
741 prevHead->next_log = queueHead;
742 prevHead->next_phy = queueHead->this_phy;
746 void
747 EHCI::LinkPeriodicDebugQueueHead(ehci_qh *queueHead, Pipe *pipe)
749 if (pipe->Speed() == USB_SPEED_HIGHSPEED)
750 queueHead->endpoint_caps |= (0xff << EHCI_QH_CAPS_ISM_SHIFT);
751 else {
752 queueHead->endpoint_caps |= (0x01 << EHCI_QH_CAPS_ISM_SHIFT);
753 queueHead->endpoint_caps |= (0x1c << EHCI_QH_CAPS_SCM_SHIFT);
756 ehci_qh *interruptQueue = &fInterruptEntries[0].queue_head;
757 queueHead->next_phy = interruptQueue->next_phy;
758 queueHead->next_log = interruptQueue->next_log;
759 queueHead->prev_log = interruptQueue;
760 if (interruptQueue->next_log)
761 interruptQueue->next_log->prev_log = queueHead;
762 interruptQueue->next_log = queueHead;
763 interruptQueue->next_phy = queueHead->this_phy;
767 status_t
768 EHCI::CheckDebugTransfer(Transfer *transfer)
770 bool transferOK = false;
771 bool transferError = false;
772 transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
773 ehci_qtd *descriptor = transferData->queue_head->element_log;
775 while (descriptor) {
776 uint32 status = descriptor->token;
777 if ((status & EHCI_QTD_STATUS_ACTIVE) != 0) {
778 // still in progress
779 break;
782 if ((status & EHCI_QTD_STATUS_ERRMASK) != 0) {
783 transferError = true;
784 break;
787 if ((descriptor->next_phy & EHCI_ITEM_TERMINATE) != 0) {
788 // we arrived at the last (stray) descriptor, we're done
789 transferOK = true;
790 break;
793 if (((status >> EHCI_QTD_PID_SHIFT) & EHCI_QTD_PID_MASK)
794 == EHCI_QTD_PID_IN
795 && ((status >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK) != 0) {
796 // a short packet condition existed on this descriptor
797 if (descriptor->alt_next_log != NULL) {
798 descriptor = descriptor->alt_next_log;
799 continue;
802 transferOK = true;
803 break;
806 descriptor = descriptor->next_log;
809 if (!transferOK && !transferError) {
810 spin(75);
811 return B_DEV_PENDING;
814 if (transferOK) {
815 bool nextDataToggle = false;
816 if (transferData->data_descriptor != NULL && transferData->incoming) {
817 // data to read out
818 iovec *vector = transfer->Vector();
819 size_t vectorCount = transfer->VectorCount();
821 ReadDescriptorChain(transferData->data_descriptor,
822 vector, vectorCount, &nextDataToggle);
823 } else if (transferData->data_descriptor != NULL)
824 ReadActualLength(transferData->data_descriptor, &nextDataToggle);
826 transfer->TransferPipe()->SetDataToggle(nextDataToggle);
829 CleanupDebugTransfer(transfer);
830 return transferOK ? B_OK : B_IO_ERROR;
834 void
835 EHCI::CancelDebugTransfer(Transfer *transfer)
837 transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
839 // clear the active bit so the descriptors are canceled
840 ehci_qtd *descriptor = transferData->queue_head->element_log;
841 while (descriptor != NULL) {
842 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
843 descriptor = descriptor->next_log;
846 transfer->Finished(B_CANCELED, 0);
847 CleanupDebugTransfer(transfer);
851 void
852 EHCI::CleanupDebugTransfer(Transfer *transfer)
854 transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
855 ehci_qh *queueHead = transferData->queue_head;
856 ehci_qh *prevHead = queueHead->prev_log;
857 if (prevHead != NULL) {
858 prevHead->next_phy = queueHead->next_phy;
859 prevHead->next_log = queueHead->next_log;
862 ehci_qh *nextHead = queueHead->next_log;
863 if (nextHead != NULL)
864 nextHead->prev_log = queueHead->prev_log;
866 queueHead->next_phy = fAsyncQueueHead->this_phy;
867 queueHead->prev_log = NULL;
868 queueHead->next_log = NULL;
870 // wait for async advance to ensure the controller does not access this
871 // queue head anymore.
872 spin(125);
874 FreeQueueHead(queueHead);
878 status_t
879 EHCI::SubmitTransfer(Transfer *transfer)
881 // short circuit the root hub
882 if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
883 return fRootHub->ProcessTransfer(this, transfer);
885 Pipe *pipe = transfer->TransferPipe();
886 if ((pipe->Type() & USB_OBJECT_ISO_PIPE) != 0)
887 return SubmitIsochronous(transfer);
889 ehci_qh *queueHead = CreateQueueHead();
890 if (!queueHead) {
891 TRACE_ERROR("failed to allocate queue head\n");
892 return B_NO_MEMORY;
895 status_t result = InitQueueHead(queueHead, pipe);
896 if (result != B_OK) {
897 TRACE_ERROR("failed to init queue head\n");
898 FreeQueueHead(queueHead);
899 return result;
902 bool directionIn;
903 ehci_qtd *dataDescriptor;
904 if ((pipe->Type() & USB_OBJECT_CONTROL_PIPE) != 0) {
905 result = FillQueueWithRequest(transfer, queueHead, &dataDescriptor,
906 &directionIn);
907 } else {
908 result = FillQueueWithData(transfer, queueHead, &dataDescriptor,
909 &directionIn);
912 if (result != B_OK) {
913 TRACE_ERROR("failed to fill transfer queue with data\n");
914 FreeQueueHead(queueHead);
915 return result;
918 result = AddPendingTransfer(transfer, queueHead, dataDescriptor,
919 directionIn);
920 if (result != B_OK) {
921 TRACE_ERROR("failed to add pending transfer\n");
922 FreeQueueHead(queueHead);
923 return result;
926 #ifdef TRACE_USB
927 TRACE("linking queue\n");
928 print_queue(queueHead);
929 #endif
931 if ((pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) != 0)
932 result = LinkInterruptQueueHead(queueHead, pipe);
933 else
934 result = LinkQueueHead(queueHead);
936 if (result != B_OK) {
937 TRACE_ERROR("failed to link queue head\n");
938 FreeQueueHead(queueHead);
939 return result;
942 return B_OK;
946 status_t
947 EHCI::SubmitIsochronous(Transfer *transfer)
949 Pipe *pipe = transfer->TransferPipe();
950 bool directionIn = (pipe->Direction() == Pipe::In);
951 usb_isochronous_data *isochronousData = transfer->IsochronousData();
952 size_t packetSize = transfer->DataLength();
953 #ifdef TRACE_USB
954 size_t restSize = packetSize % isochronousData->packet_count;
955 #endif
956 packetSize /= isochronousData->packet_count;
957 uint16 currentFrame;
959 if (packetSize > pipe->MaxPacketSize()) {
960 TRACE_ERROR(
961 "isochronous packetSize is bigger than pipe MaxPacketSize\n");
962 return B_BAD_VALUE;
965 // Ignore the fact that the last descriptor might need less bandwidth.
966 // The overhead is not worthy.
967 uint16 bandwidth = transfer->Bandwidth() / isochronousData->packet_count;
969 TRACE("isochronous transfer descriptor bandwidth %d\n", bandwidth);
971 // The following holds the list of transfer descriptor of the
972 // isochronous request. It is used to quickly remove all the isochronous
973 // descriptors from the frame list, as descriptors are not link to each
974 // other in a queue like for every other transfer.
975 ehci_itd **isoRequest
976 = new(std::nothrow) ehci_itd *[isochronousData->packet_count];
977 if (isoRequest == NULL) {
978 TRACE("failed to create isoRequest array!\n");
979 return B_NO_MEMORY;
982 TRACE("isochronous submitted size=%" B_PRIuSIZE " bytes, TDs=%" B_PRIu32
983 ", maxPacketSize=%" B_PRIuSIZE ", packetSize=%" B_PRIuSIZE
984 ", restSize=%" B_PRIuSIZE "\n", transfer->DataLength(),
985 isochronousData->packet_count, pipe->MaxPacketSize(), packetSize,
986 restSize);
988 // Find the entry where to start inserting the first Isochronous descriptor
989 if ((isochronousData->flags & USB_ISO_ASAP) != 0 ||
990 isochronousData->starting_frame_number == NULL) {
992 if (fFirstIsochronousTransfer != NULL && fNextStartingFrame != -1)
993 currentFrame = fNextStartingFrame;
994 else {
995 uint32 threshold = fThreshold;
996 TRACE("threshold: %" B_PRIu32 "\n", threshold);
998 // find the first available frame with enough bandwidth.
999 // This should always be the case, as defining the starting frame
1000 // number in the driver makes no sense for many reason, one of which
1001 // is that frame numbers value are host controller specific, and the
1002 // driver does not know which host controller is running.
1003 currentFrame = ((ReadOpReg(EHCI_FRINDEX) + threshold) / 8)
1004 & (EHCI_FRAMELIST_ENTRIES_COUNT - 1);
1007 // Make sure that:
1008 // 1. We are at least 5ms ahead the controller
1009 // 2. We stay in the range 0-127
1010 // 3. There is enough bandwidth in the first entry
1011 currentFrame &= EHCI_VFRAMELIST_ENTRIES_COUNT - 1;
1012 } else {
1013 // Find out if the frame number specified has enough bandwidth,
1014 // otherwise find the first next available frame with enough bandwidth
1015 currentFrame = *isochronousData->starting_frame_number;
1018 TRACE("isochronous starting frame=%d\n", currentFrame);
1020 uint16 itdIndex = 0;
1021 size_t dataLength = transfer->DataLength();
1022 void* bufferLog;
1023 phys_addr_t bufferPhy;
1024 if (fStack->AllocateChunk(&bufferLog, &bufferPhy, dataLength) != B_OK) {
1025 TRACE_ERROR("unable to allocate itd buffer\n");
1026 delete[] isoRequest;
1027 return B_NO_MEMORY;
1030 memset(bufferLog, 0, dataLength);
1032 phys_addr_t currentPhy = bufferPhy;
1033 uint32 frameCount = 0;
1034 while (dataLength > 0) {
1035 ehci_itd* itd = CreateItdDescriptor();
1036 isoRequest[itdIndex++] = itd;
1037 uint16 pg = 0;
1038 itd->buffer_phy[pg] = currentPhy & 0xfffff000;
1039 uint32 offset = currentPhy & 0xfff;
1040 TRACE("isochronous created itd, filling it with phy %" B_PRIxPHYSADDR
1041 "\n", currentPhy);
1042 for (int32 i = 0; i < 8 && dataLength > 0; i++) {
1043 size_t length = min_c(dataLength, packetSize);
1044 itd->token[i] = (EHCI_ITD_STATUS_ACTIVE << EHCI_ITD_STATUS_SHIFT)
1045 | (length << EHCI_ITD_TLENGTH_SHIFT) | (pg << EHCI_ITD_PG_SHIFT)
1046 | (offset << EHCI_ITD_TOFFSET_SHIFT);
1047 itd->last_token = i;
1048 TRACE("isochronous filled slot %" B_PRId32 " 0x%" B_PRIx32 "\n", i,
1049 itd->token[i]);
1050 dataLength -= length;
1051 offset += length;
1052 if (dataLength > 0 && offset > 0xfff) {
1053 offset -= B_PAGE_SIZE;
1054 currentPhy += B_PAGE_SIZE;
1055 itd->buffer_phy[pg + 1] = currentPhy & 0xfffff000;
1056 pg++;
1058 if (dataLength <= 0)
1059 itd->token[i] |= EHCI_ITD_IOC;
1062 currentPhy += (offset & 0xfff) - (currentPhy & 0xfff);
1064 itd->buffer_phy[0]
1065 |= (pipe->EndpointAddress() << EHCI_ITD_ENDPOINT_SHIFT)
1066 | (pipe->DeviceAddress() << EHCI_ITD_ADDRESS_SHIFT);
1067 itd->buffer_phy[1]
1068 |= (pipe->MaxPacketSize() & EHCI_ITD_MAXPACKETSIZE_MASK)
1069 | (directionIn << EHCI_ITD_DIR_SHIFT);
1070 itd->buffer_phy[2]
1071 |= ((((pipe->MaxPacketSize() >> EHCI_ITD_MAXPACKETSIZE_LENGTH) + 1)
1072 & EHCI_ITD_MUL_MASK) << EHCI_ITD_MUL_SHIFT);
1074 TRACE("isochronous filled itd buffer_phy[0,1,2] 0x%" B_PRIx32 ", 0x%"
1075 B_PRIx32 " 0x%" B_PRIx32 "\n",
1076 itd->buffer_phy[0], itd->buffer_phy[1], itd->buffer_phy[2]);
1078 if (!LockIsochronous())
1079 continue;
1080 LinkITDescriptors(itd, &fItdEntries[currentFrame]);
1081 UnlockIsochronous();
1082 fFrameBandwidth[currentFrame] -= bandwidth;
1083 currentFrame = (currentFrame + 1) & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1);
1084 frameCount++;
1087 TRACE("isochronous filled itds count %d\n", itdIndex);
1089 // Add transfer to the list
1090 status_t result = AddPendingIsochronousTransfer(transfer, isoRequest,
1091 itdIndex - 1, directionIn, bufferPhy, bufferLog,
1092 transfer->DataLength());
1093 if (result != B_OK) {
1094 TRACE_ERROR("failed to add pending isochronous transfer\n");
1095 for (uint32 i = 0; i < itdIndex; i++)
1096 FreeDescriptor(isoRequest[i]);
1097 delete[] isoRequest;
1098 return result;
1101 TRACE("appended isochronous transfer by starting at frame number %d\n",
1102 currentFrame);
1103 fNextStartingFrame = currentFrame + 1;
1105 // Wake up the isochronous finisher thread
1106 release_sem_etc(fFinishIsochronousTransfersSem, 1 /*frameCount*/,
1107 B_DO_NOT_RESCHEDULE);
1109 return B_OK;
1113 isochronous_transfer_data *
1114 EHCI::FindIsochronousTransfer(ehci_itd *itd)
1116 // Simply check every last descriptor of the isochronous transfer list
1117 isochronous_transfer_data *transfer = fFirstIsochronousTransfer;
1118 if (transfer) {
1119 while (transfer->descriptors[transfer->last_to_process]
1120 != itd) {
1121 transfer = transfer->link;
1122 if (!transfer)
1123 break;
1126 return transfer;
1130 status_t
1131 EHCI::NotifyPipeChange(Pipe *pipe, usb_change change)
1133 TRACE("pipe change %d for pipe %p\n", change, pipe);
1134 switch (change) {
1135 case USB_CHANGE_CREATED:
1136 case USB_CHANGE_DESTROYED: {
1137 // ToDo: we should create and keep a single queue head
1138 // for all transfers to/from this pipe
1139 break;
1142 case USB_CHANGE_PIPE_POLICY_CHANGED: {
1143 // ToDo: for isochronous pipes we might need to adapt to new
1144 // pipe policy settings here
1145 break;
1149 return B_OK;
1153 status_t
1154 EHCI::AddTo(Stack *stack)
1156 #ifdef TRACE_USB
1157 set_dprintf_enabled(true);
1158 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
1159 load_driver_symbols("ehci");
1160 #endif
1161 #endif
1163 if (!sPCIModule) {
1164 status_t status = get_module(B_PCI_MODULE_NAME,
1165 (module_info **)&sPCIModule);
1166 if (status != B_OK) {
1167 TRACE_MODULE_ERROR("getting pci module failed! 0x%08" B_PRIx32
1168 "\n", status);
1169 return status;
1173 TRACE_MODULE("searching devices\n");
1174 bool found = false;
1175 pci_info *item = new(std::nothrow) pci_info;
1176 if (!item) {
1177 sPCIModule = NULL;
1178 put_module(B_PCI_MODULE_NAME);
1179 return B_NO_MEMORY;
1182 // Try to get the PCI x86 module as well so we can enable possible MSIs.
1183 if (sPCIx86Module == NULL && get_module(B_PCI_X86_MODULE_NAME,
1184 (module_info **)&sPCIx86Module) != B_OK) {
1185 // If it isn't there, that's not critical though.
1186 TRACE_MODULE_ERROR("failed to get pci x86 module\n");
1187 sPCIx86Module = NULL;
1190 for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) {
1191 if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb
1192 && item->class_api == PCI_usb_ehci) {
1193 if (item->u.h0.interrupt_line == 0
1194 || item->u.h0.interrupt_line == 0xFF) {
1195 TRACE_MODULE_ERROR("found device with invalid IRQ - "
1196 "check IRQ assignement\n");
1197 continue;
1200 TRACE_MODULE("found device at IRQ %u\n", item->u.h0.interrupt_line);
1201 EHCI *bus = new(std::nothrow) EHCI(item, stack);
1202 if (!bus) {
1203 delete item;
1204 sPCIModule = NULL;
1205 put_module(B_PCI_MODULE_NAME);
1206 if (sPCIx86Module != NULL) {
1207 sPCIx86Module = NULL;
1208 put_module(B_PCI_X86_MODULE_NAME);
1210 return B_NO_MEMORY;
1213 if (bus->InitCheck() != B_OK) {
1214 TRACE_MODULE_ERROR("bus failed init check\n");
1215 delete bus;
1216 continue;
1219 // the bus took it away
1220 item = new(std::nothrow) pci_info;
1222 bus->Start();
1223 stack->AddBusManager(bus);
1224 found = true;
1228 if (!found) {
1229 TRACE_MODULE_ERROR("no devices found\n");
1230 delete item;
1231 sPCIModule = NULL;
1232 put_module(B_PCI_MODULE_NAME);
1233 if (sPCIx86Module != NULL) {
1234 sPCIx86Module = NULL;
1235 put_module(B_PCI_X86_MODULE_NAME);
1237 return ENODEV;
1240 delete item;
1241 return B_OK;
1245 status_t
1246 EHCI::GetPortStatus(uint8 index, usb_port_status *status)
1248 if (index >= fPortCount)
1249 return B_BAD_INDEX;
1251 status->status = status->change = 0;
1252 uint32 portStatus = ReadOpReg(EHCI_PORTSC + index * sizeof(uint32));
1254 // build the status
1255 if (portStatus & EHCI_PORTSC_CONNSTATUS)
1256 status->status |= PORT_STATUS_CONNECTION;
1257 if (portStatus & EHCI_PORTSC_ENABLE)
1258 status->status |= PORT_STATUS_ENABLE;
1259 if (portStatus & EHCI_PORTSC_ENABLE)
1260 status->status |= PORT_STATUS_HIGH_SPEED;
1261 if (portStatus & EHCI_PORTSC_OCACTIVE)
1262 status->status |= PORT_STATUS_OVER_CURRENT;
1263 if (portStatus & EHCI_PORTSC_PORTRESET)
1264 status->status |= PORT_STATUS_RESET;
1265 if (portStatus & EHCI_PORTSC_PORTPOWER)
1266 status->status |= PORT_STATUS_POWER;
1267 if (portStatus & EHCI_PORTSC_SUSPEND)
1268 status->status |= PORT_STATUS_SUSPEND;
1269 if (portStatus & EHCI_PORTSC_DMINUS)
1270 status->status |= PORT_STATUS_LOW_SPEED;
1272 // build the change
1273 if (portStatus & EHCI_PORTSC_CONNCHANGE)
1274 status->change |= PORT_STATUS_CONNECTION;
1275 if (portStatus & EHCI_PORTSC_ENABLECHANGE)
1276 status->change |= PORT_STATUS_ENABLE;
1277 if (portStatus & EHCI_PORTSC_OCCHANGE)
1278 status->change |= PORT_STATUS_OVER_CURRENT;
1280 // there are no bits to indicate suspend and reset change
1281 if (fPortResetChange & (1 << index))
1282 status->change |= PORT_STATUS_RESET;
1283 if (fPortSuspendChange & (1 << index))
1284 status->change |= PORT_STATUS_SUSPEND;
1286 return B_OK;
1290 status_t
1291 EHCI::SetPortFeature(uint8 index, uint16 feature)
1293 if (index >= fPortCount)
1294 return B_BAD_INDEX;
1296 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
1297 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1299 switch (feature) {
1300 case PORT_SUSPEND:
1301 return SuspendPort(index);
1303 case PORT_RESET:
1304 return ResetPort(index);
1306 case PORT_POWER:
1307 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTPOWER);
1308 return B_OK;
1311 return B_BAD_VALUE;
1315 status_t
1316 EHCI::ClearPortFeature(uint8 index, uint16 feature)
1318 if (index >= fPortCount)
1319 return B_BAD_INDEX;
1321 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
1322 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1324 switch (feature) {
1325 case PORT_ENABLE:
1326 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_ENABLE);
1327 return B_OK;
1329 case PORT_POWER:
1330 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTPOWER);
1331 return B_OK;
1333 case C_PORT_CONNECTION:
1334 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_CONNCHANGE);
1335 return B_OK;
1337 case C_PORT_ENABLE:
1338 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_ENABLECHANGE);
1339 return B_OK;
1341 case C_PORT_OVER_CURRENT:
1342 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_OCCHANGE);
1343 return B_OK;
1345 case C_PORT_RESET:
1346 fPortResetChange &= ~(1 << index);
1347 return B_OK;
1349 case C_PORT_SUSPEND:
1350 fPortSuspendChange &= ~(1 << index);
1351 return B_OK;
1354 return B_BAD_VALUE;
1358 status_t
1359 EHCI::ResetPort(uint8 index)
1361 TRACE("reset port %d\n", index);
1362 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
1363 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1365 if (portStatus & EHCI_PORTSC_DMINUS) {
1366 TRACE_ALWAYS("lowspeed device connected, giving up port ownership\n");
1367 // there is a lowspeed device connected.
1368 // we give the ownership to a companion controller.
1369 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER);
1370 fPortResetChange |= (1 << index);
1371 return B_OK;
1374 // enable reset signaling
1375 WriteOpReg(portRegister, (portStatus & ~EHCI_PORTSC_ENABLE)
1376 | EHCI_PORTSC_PORTRESET);
1377 snooze(50000);
1379 // disable reset signaling
1380 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1381 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTRESET);
1382 snooze(2000);
1384 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1385 if (portStatus & EHCI_PORTSC_PORTRESET) {
1386 TRACE_ERROR("port reset won't complete\n");
1387 return B_ERROR;
1390 if ((portStatus & EHCI_PORTSC_ENABLE) == 0) {
1391 TRACE_ALWAYS("fullspeed device connected, giving up port ownership\n");
1392 // the port was not enabled, this means that no high speed device is
1393 // attached to this port. we give up ownership to a companion controler
1394 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER);
1397 fPortResetChange |= (1 << index);
1398 return B_OK;
1402 status_t
1403 EHCI::SuspendPort(uint8 index)
1405 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
1406 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1407 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_SUSPEND);
1408 fPortSuspendChange |= (1 << index);
1409 return B_OK;
1413 status_t
1414 EHCI::ControllerReset()
1416 // halt the controller first
1417 WriteOpReg(EHCI_USBCMD, 0);
1418 snooze(10000);
1420 // then reset it
1421 WriteOpReg(EHCI_USBCMD, EHCI_USBCMD_HCRESET);
1423 int32 tries = 5;
1424 while (ReadOpReg(EHCI_USBCMD) & EHCI_USBCMD_HCRESET) {
1425 snooze(10000);
1426 if (tries-- < 0)
1427 return B_ERROR;
1430 return B_OK;
1434 status_t
1435 EHCI::LightReset()
1437 return B_ERROR;
1441 int32
1442 EHCI::InterruptHandler(void *data)
1444 return ((EHCI *)data)->Interrupt();
1448 int32
1449 EHCI::Interrupt()
1451 static spinlock lock = B_SPINLOCK_INITIALIZER;
1452 acquire_spinlock(&lock);
1454 // check if any interrupt was generated
1455 uint32 status = ReadOpReg(EHCI_USBSTS) & EHCI_USBSTS_INTMASK;
1456 if ((status & fEnabledInterrupts) == 0) {
1457 if (status != 0) {
1458 TRACE("discarding not enabled interrupts 0x%08" B_PRIx32 "\n",
1459 status);
1460 WriteOpReg(EHCI_USBSTS, status);
1463 release_spinlock(&lock);
1464 return B_UNHANDLED_INTERRUPT;
1467 bool asyncAdvance = false;
1468 bool finishTransfers = false;
1469 int32 result = B_HANDLED_INTERRUPT;
1471 if (status & EHCI_USBSTS_USBINT) {
1472 TRACE("transfer finished\n");
1473 result = B_INVOKE_SCHEDULER;
1474 finishTransfers = true;
1477 if (status & EHCI_USBSTS_USBERRINT) {
1478 TRACE("transfer error\n");
1479 result = B_INVOKE_SCHEDULER;
1480 finishTransfers = true;
1483 if (status & EHCI_USBSTS_FLROLLOVER)
1484 TRACE("frame list rollover\n");
1486 if (status & EHCI_USBSTS_PORTCHANGE)
1487 TRACE("port change detected\n");
1489 if (status & EHCI_USBSTS_INTONAA) {
1490 TRACE("interrupt on async advance\n");
1491 asyncAdvance = true;
1492 result = B_INVOKE_SCHEDULER;
1495 if (status & EHCI_USBSTS_HOSTSYSERR)
1496 TRACE_ERROR("host system error!\n");
1498 WriteOpReg(EHCI_USBSTS, status);
1499 release_spinlock(&lock);
1501 if (asyncAdvance)
1502 release_sem_etc(fAsyncAdvanceSem, 1, B_DO_NOT_RESCHEDULE);
1503 if (finishTransfers)
1504 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1506 return result;
1510 int32
1511 EHCI::InterruptPollThread(void *data)
1513 EHCI *ehci = (EHCI *)data;
1515 while (!ehci->fStopThreads) {
1516 // TODO: this could be handled much better by only polling when there
1517 // are actual transfers going on...
1518 snooze(1000);
1520 cpu_status status = disable_interrupts();
1521 ehci->Interrupt();
1522 restore_interrupts(status);
1525 return 0;
1529 status_t
1530 EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead,
1531 ehci_qtd *dataDescriptor, bool directionIn)
1533 transfer_data *data = new(std::nothrow) transfer_data;
1534 if (!data)
1535 return B_NO_MEMORY;
1537 status_t result = transfer->InitKernelAccess();
1538 if (result != B_OK) {
1539 delete data;
1540 return result;
1543 data->transfer = transfer;
1544 data->queue_head = queueHead;
1545 data->data_descriptor = dataDescriptor;
1546 data->incoming = directionIn;
1547 data->canceled = false;
1548 data->link = NULL;
1550 if (!Lock()) {
1551 delete data;
1552 return B_ERROR;
1555 if (fLastTransfer)
1556 fLastTransfer->link = data;
1557 else
1558 fFirstTransfer = data;
1560 fLastTransfer = data;
1561 Unlock();
1563 return B_OK;
1567 status_t
1568 EHCI::AddPendingIsochronousTransfer(Transfer *transfer, ehci_itd **isoRequest,
1569 uint32 lastIndex, bool directionIn, addr_t bufferPhy, void* bufferLog,
1570 size_t bufferSize)
1572 if (!transfer || !isoRequest)
1573 return B_BAD_VALUE;
1575 isochronous_transfer_data *data
1576 = new(std::nothrow) isochronous_transfer_data;
1577 if (!data)
1578 return B_NO_MEMORY;
1580 status_t result = transfer->InitKernelAccess();
1581 if (result != B_OK) {
1582 delete data;
1583 return result;
1586 data->transfer = transfer;
1587 data->descriptors = isoRequest;
1588 data->last_to_process = lastIndex;
1589 data->incoming = directionIn;
1590 data->is_active = true;
1591 data->link = NULL;
1592 data->buffer_phy = bufferPhy;
1593 data->buffer_log = bufferLog;
1594 data->buffer_size = bufferSize;
1596 // Put in the isochronous transfer list
1597 if (!LockIsochronous()) {
1598 delete data;
1599 return B_ERROR;
1602 if (fLastIsochronousTransfer)
1603 fLastIsochronousTransfer->link = data;
1604 else if (!fFirstIsochronousTransfer)
1605 fFirstIsochronousTransfer = data;
1607 fLastIsochronousTransfer = data;
1608 UnlockIsochronous();
1609 return B_OK;
1613 status_t
1614 EHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
1616 if ((pipe->Type() & USB_OBJECT_ISO_PIPE) != 0)
1617 return CancelQueuedIsochronousTransfers(pipe, force);
1619 if (!Lock())
1620 return B_ERROR;
1622 struct transfer_entry {
1623 Transfer * transfer;
1624 transfer_entry * next;
1627 transfer_entry *list = NULL;
1628 transfer_data *current = fFirstTransfer;
1629 while (current) {
1630 if (current->transfer && current->transfer->TransferPipe() == pipe) {
1631 // clear the active bit so the descriptors are canceled
1632 ehci_qtd *descriptor = current->queue_head->element_log;
1633 while (descriptor) {
1634 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
1635 descriptor = descriptor->next_log;
1638 if (!force) {
1639 // if the transfer is canceled by force, the one causing the
1640 // cancel is probably not the one who initiated the transfer
1641 // and the callback is likely not safe anymore
1642 transfer_entry *entry
1643 = (transfer_entry *)malloc(sizeof(transfer_entry));
1644 if (entry != NULL) {
1645 entry->transfer = current->transfer;
1646 current->transfer = NULL;
1647 entry->next = list;
1648 list = entry;
1652 current->canceled = true;
1655 current = current->link;
1658 Unlock();
1660 while (list != NULL) {
1661 transfer_entry *next = list->next;
1662 list->transfer->Finished(B_CANCELED, 0);
1663 delete list->transfer;
1664 free(list);
1665 list = next;
1668 // wait for any transfers that might have made it before canceling
1669 while (fProcessingPipe == pipe)
1670 snooze(1000);
1672 // notify the finisher so it can clean up the canceled transfers
1673 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1674 return B_OK;
1678 status_t
1679 EHCI::CancelQueuedIsochronousTransfers(Pipe *pipe, bool force)
1681 isochronous_transfer_data *current = fFirstIsochronousTransfer;
1683 while (current) {
1684 if (current->transfer->TransferPipe() == pipe) {
1685 // TODO implement
1687 // TODO: Use the force paramater in order to avoid calling
1688 // invalid callbacks
1689 current->is_active = false;
1692 current = current->link;
1695 TRACE_ERROR("no isochronous transfer found!\n");
1696 return B_ERROR;
1700 status_t
1701 EHCI::CancelAllPendingTransfers()
1703 if (!Lock())
1704 return B_ERROR;
1706 transfer_data *transfer = fFirstTransfer;
1707 while (transfer) {
1708 transfer->transfer->Finished(B_CANCELED, 0);
1709 delete transfer->transfer;
1711 transfer_data *next = transfer->link;
1712 delete transfer;
1713 transfer = next;
1716 fFirstTransfer = NULL;
1717 fLastTransfer = NULL;
1718 Unlock();
1719 return B_OK;
1723 int32
1724 EHCI::FinishThread(void *data)
1726 ((EHCI *)data)->FinishTransfers();
1727 return B_OK;
1731 void
1732 EHCI::FinishTransfers()
1734 while (!fStopThreads) {
1735 if (acquire_sem(fFinishTransfersSem) != B_OK)
1736 continue;
1738 // eat up sems that have been released by multiple interrupts
1739 int32 semCount = 0;
1740 get_sem_count(fFinishTransfersSem, &semCount);
1741 if (semCount > 0) {
1742 acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT,
1746 if (!Lock())
1747 continue;
1749 TRACE("finishing transfers\n");
1750 transfer_data *lastTransfer = NULL;
1751 transfer_data *transfer = fFirstTransfer;
1752 Unlock();
1754 while (transfer) {
1755 bool transferDone = false;
1756 ehci_qtd *descriptor = transfer->queue_head->element_log;
1757 status_t callbackStatus = B_OK;
1759 while (descriptor) {
1760 uint32 status = descriptor->token;
1761 if (status & EHCI_QTD_STATUS_ACTIVE) {
1762 // still in progress
1763 TRACE("qtd (0x%08" B_PRIx32 ") still active\n",
1764 descriptor->this_phy);
1765 break;
1768 if (status & EHCI_QTD_STATUS_ERRMASK) {
1769 // a transfer error occured
1770 TRACE_ERROR("qtd (0x%" B_PRIx32 ") error: 0x%08" B_PRIx32
1771 "\n", descriptor->this_phy, status);
1773 uint8 errorCount = status >> EHCI_QTD_ERRCOUNT_SHIFT;
1774 errorCount &= EHCI_QTD_ERRCOUNT_MASK;
1775 if (errorCount == 0) {
1776 // the error counter counted down to zero, report why
1777 int32 reasons = 0;
1778 if (status & EHCI_QTD_STATUS_BUFFER) {
1779 callbackStatus = transfer->incoming
1780 ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN;
1781 reasons++;
1783 if (status & EHCI_QTD_STATUS_TERROR) {
1784 callbackStatus = B_DEV_CRC_ERROR;
1785 reasons++;
1787 if ((transfer->queue_head->endpoint_chars
1788 & EHCI_QH_CHARS_EPS_HIGH) == 0) {
1789 // For full-/lowspeed endpoints the unused ping
1790 // state bit is used as another error bit, it is
1791 // unspecific however.
1792 if ((status & EHCI_QTD_STATUS_LS_ERR) != 0) {
1793 callbackStatus = B_DEV_STALLED;
1794 reasons++;
1798 if (reasons > 1)
1799 callbackStatus = B_DEV_MULTIPLE_ERRORS;
1800 else if (reasons == 0) {
1801 TRACE_ERROR("error counter counted down to zero "
1802 "but none of the error bits are set\n");
1803 callbackStatus = B_DEV_STALLED;
1805 } else if (status & EHCI_QTD_STATUS_BABBLE) {
1806 // there is a babble condition
1807 callbackStatus = transfer->incoming
1808 ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN;
1809 } else {
1810 // if the error counter didn't count down to zero
1811 // and there was no babble, then this halt was caused
1812 // by a stall handshake
1813 callbackStatus = B_DEV_STALLED;
1816 transferDone = true;
1817 break;
1820 if (descriptor->next_phy & EHCI_ITEM_TERMINATE) {
1821 // we arrived at the last (stray) descriptor, we're done
1822 TRACE("qtd (0x%08" B_PRIx32 ") done\n",
1823 descriptor->this_phy);
1824 callbackStatus = B_OK;
1825 transferDone = true;
1826 break;
1829 if (((status >> EHCI_QTD_PID_SHIFT) & EHCI_QTD_PID_MASK)
1830 == EHCI_QTD_PID_IN
1831 && ((status >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK)
1832 != 0) {
1833 // a short packet condition existed on this descriptor,
1834 // follow the alternate next pointer if set
1835 if (descriptor->alt_next_log != NULL) {
1836 descriptor = descriptor->alt_next_log;
1837 continue;
1840 // no alternate next, transfer is done
1841 callbackStatus = B_OK;
1842 transferDone = true;
1843 break;
1846 descriptor = descriptor->next_log;
1849 if (!transferDone) {
1850 lastTransfer = transfer;
1851 transfer = transfer->link;
1852 continue;
1855 // remove the transfer from the list first so we are sure
1856 // it doesn't get canceled while we still process it
1857 transfer_data *next = transfer->link;
1858 if (Lock()) {
1859 if (lastTransfer)
1860 lastTransfer->link = transfer->link;
1862 if (transfer == fFirstTransfer)
1863 fFirstTransfer = transfer->link;
1864 if (transfer == fLastTransfer)
1865 fLastTransfer = lastTransfer;
1867 // store the currently processing pipe here so we can wait
1868 // in cancel if we are processing something on the target pipe
1869 if (!transfer->canceled)
1870 fProcessingPipe = transfer->transfer->TransferPipe();
1872 transfer->link = NULL;
1873 Unlock();
1876 // if canceled the callback has already been called
1877 if (!transfer->canceled) {
1878 size_t actualLength = 0;
1880 if (callbackStatus == B_OK) {
1881 bool nextDataToggle = false;
1882 if (transfer->data_descriptor && transfer->incoming) {
1883 // data to read out
1884 iovec *vector = transfer->transfer->Vector();
1885 size_t vectorCount = transfer->transfer->VectorCount();
1886 transfer->transfer->PrepareKernelAccess();
1887 actualLength = ReadDescriptorChain(
1888 transfer->data_descriptor,
1889 vector, vectorCount,
1890 &nextDataToggle);
1891 } else if (transfer->data_descriptor) {
1892 // calculate transfered length
1893 actualLength = ReadActualLength(
1894 transfer->data_descriptor, &nextDataToggle);
1897 transfer->transfer->TransferPipe()->SetDataToggle(
1898 nextDataToggle);
1900 if (transfer->transfer->IsFragmented()) {
1901 // this transfer may still have data left
1902 transfer->transfer->AdvanceByFragment(actualLength);
1903 if (transfer->transfer->VectorLength() > 0) {
1904 FreeDescriptorChain(transfer->data_descriptor);
1905 transfer->transfer->PrepareKernelAccess();
1906 status_t result = FillQueueWithData(
1907 transfer->transfer,
1908 transfer->queue_head,
1909 &transfer->data_descriptor, NULL);
1911 if (result == B_OK && Lock()) {
1912 // reappend the transfer
1913 if (fLastTransfer)
1914 fLastTransfer->link = transfer;
1915 if (!fFirstTransfer)
1916 fFirstTransfer = transfer;
1918 fLastTransfer = transfer;
1919 Unlock();
1921 transfer = next;
1922 continue;
1926 // the transfer is done, but we already set the
1927 // actualLength with AdvanceByFragment()
1928 actualLength = 0;
1932 transfer->transfer->Finished(callbackStatus, actualLength);
1933 fProcessingPipe = NULL;
1936 // unlink hardware queue and delete the transfer
1937 UnlinkQueueHead(transfer->queue_head, &fFreeListHead);
1938 delete transfer->transfer;
1939 delete transfer;
1940 transfer = next;
1941 release_sem(fCleanupSem);
1947 int32
1948 EHCI::CleanupThread(void *data)
1950 ((EHCI *)data)->Cleanup();
1951 return B_OK;
1955 void
1956 EHCI::Cleanup()
1958 ehci_qh *lastFreeListHead = NULL;
1960 while (!fStopThreads) {
1961 if (acquire_sem(fCleanupSem) != B_OK)
1962 continue;
1964 ehci_qh *freeListHead = fFreeListHead;
1965 if (freeListHead == lastFreeListHead)
1966 continue;
1968 // set the doorbell and wait for the host controller to notify us
1969 WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD);
1970 if (acquire_sem(fAsyncAdvanceSem) != B_OK)
1971 continue;
1973 ehci_qh *current = freeListHead;
1974 while (current != lastFreeListHead) {
1975 ehci_qh *next = current->next_log;
1976 FreeQueueHead(current);
1977 current = next;
1980 lastFreeListHead = freeListHead;
1985 int32
1986 EHCI::FinishIsochronousThread(void *data)
1988 ((EHCI *)data)->FinishIsochronousTransfers();
1989 return B_OK;
1993 void
1994 EHCI::FinishIsochronousTransfers()
1996 /* This thread stays one position behind the controller and processes every
1997 * isochronous descriptor. Once it finds the last isochronous descriptor
1998 * of a transfer, it processes the entire transfer.
2000 while (!fStopThreads) {
2001 // Go to sleep if there are no isochronous transfers to process
2002 if (acquire_sem(fFinishIsochronousTransfersSem) != B_OK)
2003 return;
2005 bool transferDone = false;
2007 uint32 frame = (ReadOpReg(EHCI_FRINDEX) / 8 )
2008 & (EHCI_FRAMELIST_ENTRIES_COUNT - 1);
2009 uint32 currentFrame = (frame + EHCI_VFRAMELIST_ENTRIES_COUNT - 5)
2010 & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1);
2011 uint32 loop = 0;
2013 // Process the frame list until one transfer is processed
2014 while (!transferDone && loop++ < EHCI_VFRAMELIST_ENTRIES_COUNT) {
2015 // wait 1ms in order to be sure to be one position behind
2016 // the controller
2017 while (currentFrame == (((ReadOpReg(EHCI_FRINDEX) / 8)
2018 & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1)))) {
2019 snooze(1000);
2022 ehci_itd *itd = fItdEntries[currentFrame];
2024 TRACE("FinishIsochronousTransfers itd %p phy 0x%" B_PRIx32
2025 " prev (%p/0x%" B_PRIx32 ") at frame %" B_PRId32 "\n", itd,
2026 itd->this_phy, itd->prev, itd->prev != NULL
2027 ? itd->prev->this_phy : 0, currentFrame);
2029 if (!LockIsochronous())
2030 continue;
2032 // Process the frame till it has isochronous descriptors in it.
2033 while (!(itd->next_phy & EHCI_ITEM_TERMINATE) && itd->prev != NULL) {
2034 TRACE("FinishIsochronousTransfers checking itd %p last_token"
2035 " %" B_PRId32 "\n", itd, itd->last_token);
2036 TRACE("FinishIsochronousTransfers tokens 0x%" B_PRIx32 " 0x%"
2037 B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx32
2038 " 0x%" B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx32 "\n",
2039 itd->token[0], itd->token[1], itd->token[2], itd->token[3],
2040 itd->token[4], itd->token[5], itd->token[6], itd->token[7]);
2041 if (((itd->token[itd->last_token] >> EHCI_ITD_STATUS_SHIFT)
2042 & EHCI_ITD_STATUS_ACTIVE) == EHCI_ITD_STATUS_ACTIVE) {
2043 TRACE("FinishIsochronousTransfers unprocessed active itd\n");
2045 UnlinkITDescriptors(itd, &fItdEntries[currentFrame]);
2047 // Process the transfer if we found the last descriptor
2048 isochronous_transfer_data *transfer
2049 = FindIsochronousTransfer(itd);
2050 // Process the descriptors only if it is still active and
2051 // belongs to an inbound transfer. If the transfer is not
2052 // active, it means the request has been removed, so simply
2053 // remove the descriptors.
2054 if (transfer && transfer->is_active) {
2055 TRACE("FinishIsochronousTransfers active transfer\n");
2056 size_t actualLength = 0;
2057 if (((itd->buffer_phy[1] >> EHCI_ITD_DIR_SHIFT) & 1) != 0) {
2058 transfer->transfer->PrepareKernelAccess();
2059 actualLength = ReadIsochronousDescriptorChain(transfer);
2062 // Remove the transfer
2063 if (transfer == fFirstIsochronousTransfer) {
2064 fFirstIsochronousTransfer = transfer->link;
2065 if (transfer == fLastIsochronousTransfer)
2066 fLastIsochronousTransfer = NULL;
2067 } else {
2068 isochronous_transfer_data *temp
2069 = fFirstIsochronousTransfer;
2070 while (temp != NULL && transfer != temp->link)
2071 temp = temp->link;
2073 if (transfer == fLastIsochronousTransfer)
2074 fLastIsochronousTransfer = temp;
2075 if (temp != NULL && temp->link != NULL)
2076 temp->link = temp->link->link;
2078 transfer->link = NULL;
2080 transfer->transfer->Finished(B_OK, actualLength);
2082 itd = itd->prev;
2084 for (uint32 i = 0; i <= transfer->last_to_process; i++)
2085 FreeDescriptor(transfer->descriptors[i]);
2087 TRACE("FinishIsochronousTransfers descriptors freed\n");
2089 delete [] transfer->descriptors;
2090 delete transfer->transfer;
2091 fStack->FreeChunk(transfer->buffer_log,
2092 (phys_addr_t)transfer->buffer_phy,
2093 transfer->buffer_size);
2094 delete transfer;
2095 transferDone = true;
2096 } else {
2097 TRACE("FinishIsochronousTransfers not end of transfer\n");
2098 itd = itd->prev;
2102 UnlockIsochronous();
2104 TRACE("FinishIsochronousTransfers next frame\n");
2106 // Make sure to reset the frame bandwidth
2107 fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH;
2108 currentFrame = (currentFrame + 1) % EHCI_VFRAMELIST_ENTRIES_COUNT;
2114 ehci_qh *
2115 EHCI::CreateQueueHead()
2117 ehci_qh *result;
2118 phys_addr_t physicalAddress;
2119 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2120 sizeof(ehci_qh)) != B_OK) {
2121 TRACE_ERROR("failed to allocate queue head\n");
2122 return NULL;
2125 result->this_phy = (addr_t)physicalAddress | EHCI_ITEM_TYPE_QH;
2126 result->next_phy = EHCI_ITEM_TERMINATE;
2127 result->next_log = NULL;
2128 result->prev_log = NULL;
2130 ehci_qtd *descriptor = CreateDescriptor(0, 0);
2131 if (!descriptor) {
2132 TRACE_ERROR("failed to allocate initial qtd for queue head\n");
2133 fStack->FreeChunk(result, physicalAddress, sizeof(ehci_qh));
2134 return NULL;
2137 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
2138 result->stray_log = descriptor;
2139 result->element_log = descriptor;
2140 result->current_qtd_phy = 0;
2141 result->overlay.next_phy = descriptor->this_phy;
2142 result->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
2143 result->overlay.token = 0;
2144 for (int32 i = 0; i < 5; i++) {
2145 result->overlay.buffer_phy[i] = 0;
2146 result->overlay.ext_buffer_phy[i] = 0;
2149 return result;
2153 status_t
2154 EHCI::InitQueueHead(ehci_qh *queueHead, Pipe *pipe)
2156 switch (pipe->Speed()) {
2157 case USB_SPEED_LOWSPEED:
2158 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_LOW;
2159 break;
2160 case USB_SPEED_FULLSPEED:
2161 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_FULL;
2162 break;
2163 case USB_SPEED_HIGHSPEED:
2164 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH;
2165 break;
2166 default:
2167 TRACE_ERROR("unknown pipe speed\n");
2168 return B_ERROR;
2171 queueHead->endpoint_chars |= (3 << EHCI_QH_CHARS_RL_SHIFT)
2172 | (pipe->MaxPacketSize() << EHCI_QH_CHARS_MPL_SHIFT)
2173 | (pipe->EndpointAddress() << EHCI_QH_CHARS_EPT_SHIFT)
2174 | (pipe->DeviceAddress() << EHCI_QH_CHARS_DEV_SHIFT)
2175 | EHCI_QH_CHARS_TOGGLE;
2177 queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT);
2178 if (pipe->Speed() != USB_SPEED_HIGHSPEED) {
2179 if ((pipe->Type() & USB_OBJECT_CONTROL_PIPE) != 0)
2180 queueHead->endpoint_chars |= EHCI_QH_CHARS_CONTROL;
2182 queueHead->endpoint_caps |= (pipe->HubPort() << EHCI_QH_CAPS_PORT_SHIFT)
2183 | (pipe->HubAddress() << EHCI_QH_CAPS_HUB_SHIFT);
2186 return B_OK;
2190 void
2191 EHCI::FreeQueueHead(ehci_qh *queueHead)
2193 if (!queueHead)
2194 return;
2196 FreeDescriptorChain(queueHead->element_log);
2197 FreeDescriptor(queueHead->stray_log);
2198 fStack->FreeChunk(queueHead, (phys_addr_t)queueHead->this_phy,
2199 sizeof(ehci_qh));
2203 status_t
2204 EHCI::LinkQueueHead(ehci_qh *queueHead)
2206 if (!Lock())
2207 return B_ERROR;
2209 ehci_qh *prevHead = fAsyncQueueHead->prev_log;
2210 queueHead->next_phy = fAsyncQueueHead->this_phy;
2211 queueHead->next_log = fAsyncQueueHead;
2212 queueHead->prev_log = prevHead;
2213 fAsyncQueueHead->prev_log = queueHead;
2214 prevHead->next_log = queueHead;
2215 prevHead->next_phy = queueHead->this_phy;
2217 Unlock();
2218 return B_OK;
2222 status_t
2223 EHCI::LinkInterruptQueueHead(ehci_qh *queueHead, Pipe *pipe)
2225 uint8 interval = pipe->Interval();
2226 if (pipe->Speed() == USB_SPEED_HIGHSPEED) {
2227 // Allow interrupts to be scheduled on each possible micro frame.
2228 queueHead->endpoint_caps |= (0xff << EHCI_QH_CAPS_ISM_SHIFT);
2229 } else {
2230 // As we do not yet support FSTNs to correctly reference low/full
2231 // speed interrupt transfers, we simply put them into the 1 interval
2232 // queue. This way we ensure that we reach them on every micro frame
2233 // and can do the corresponding start/complete split transactions.
2234 // ToDo: use FSTNs to correctly link non high speed interrupt transfers
2235 interval = 1;
2237 // For now we also force start splits to be in micro frame 0 and
2238 // complete splits to be in micro frame 2, 3 and 4.
2239 queueHead->endpoint_caps |= (0x01 << EHCI_QH_CAPS_ISM_SHIFT);
2240 queueHead->endpoint_caps |= (0x1c << EHCI_QH_CAPS_SCM_SHIFT);
2243 // this should not happen
2244 if (interval < 1)
2245 interval = 1;
2247 // this may happen as intervals can go up to 16; we limit the value to
2248 // EHCI_INTERRUPT_ENTRIES_COUNT as you cannot support intervals above
2249 // that with a frame list of just EHCI_VFRAMELIST_ENTRIES_COUNT entries...
2250 if (interval > EHCI_INTERRUPT_ENTRIES_COUNT)
2251 interval = EHCI_INTERRUPT_ENTRIES_COUNT;
2253 if (!Lock())
2254 return B_ERROR;
2256 ehci_qh *interruptQueue = &fInterruptEntries[interval - 1].queue_head;
2257 queueHead->next_phy = interruptQueue->next_phy;
2258 queueHead->next_log = interruptQueue->next_log;
2259 queueHead->prev_log = interruptQueue;
2260 if (interruptQueue->next_log)
2261 interruptQueue->next_log->prev_log = queueHead;
2262 interruptQueue->next_log = queueHead;
2263 interruptQueue->next_phy = queueHead->this_phy;
2265 Unlock();
2266 return B_OK;
2270 status_t
2271 EHCI::UnlinkQueueHead(ehci_qh *queueHead, ehci_qh **freeListHead)
2273 if (!Lock())
2274 return B_ERROR;
2276 ehci_qh *prevHead = queueHead->prev_log;
2277 ehci_qh *nextHead = queueHead->next_log;
2278 if (prevHead) {
2279 prevHead->next_phy = queueHead->next_phy;
2280 prevHead->next_log = queueHead->next_log;
2283 if (nextHead)
2284 nextHead->prev_log = queueHead->prev_log;
2286 queueHead->next_phy = fAsyncQueueHead->this_phy;
2287 queueHead->prev_log = NULL;
2289 queueHead->next_log = *freeListHead;
2290 *freeListHead = queueHead;
2292 Unlock();
2293 return B_OK;
2297 status_t
2298 EHCI::FillQueueWithRequest(Transfer *transfer, ehci_qh *queueHead,
2299 ehci_qtd **_dataDescriptor, bool *_directionIn)
2301 Pipe *pipe = transfer->TransferPipe();
2302 usb_request_data *requestData = transfer->RequestData();
2303 bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
2305 ehci_qtd *setupDescriptor = CreateDescriptor(sizeof(usb_request_data),
2306 EHCI_QTD_PID_SETUP);
2307 ehci_qtd *statusDescriptor = CreateDescriptor(0,
2308 directionIn ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN);
2310 if (!setupDescriptor || !statusDescriptor) {
2311 TRACE_ERROR("failed to allocate descriptors\n");
2312 FreeDescriptor(setupDescriptor);
2313 FreeDescriptor(statusDescriptor);
2314 return B_NO_MEMORY;
2317 iovec vector;
2318 vector.iov_base = requestData;
2319 vector.iov_len = sizeof(usb_request_data);
2320 WriteDescriptorChain(setupDescriptor, &vector, 1);
2322 ehci_qtd *strayDescriptor = queueHead->stray_log;
2323 statusDescriptor->token |= EHCI_QTD_IOC | EHCI_QTD_DATA_TOGGLE;
2325 ehci_qtd *dataDescriptor = NULL;
2326 if (transfer->VectorCount() > 0) {
2327 ehci_qtd *lastDescriptor = NULL;
2328 status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
2329 &lastDescriptor, statusDescriptor, transfer->VectorLength(),
2330 directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
2332 if (result != B_OK) {
2333 FreeDescriptor(setupDescriptor);
2334 FreeDescriptor(statusDescriptor);
2335 return result;
2338 if (!directionIn) {
2339 WriteDescriptorChain(dataDescriptor, transfer->Vector(),
2340 transfer->VectorCount());
2343 LinkDescriptors(setupDescriptor, dataDescriptor, strayDescriptor);
2344 LinkDescriptors(lastDescriptor, statusDescriptor, statusDescriptor);
2345 } else {
2346 // no data: link setup and status descriptors directly
2347 LinkDescriptors(setupDescriptor, statusDescriptor, strayDescriptor);
2350 queueHead->element_log = setupDescriptor;
2351 queueHead->overlay.next_phy = setupDescriptor->this_phy;
2352 queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
2354 *_dataDescriptor = dataDescriptor;
2355 *_directionIn = directionIn;
2356 return B_OK;
2360 status_t
2361 EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead,
2362 ehci_qtd **_dataDescriptor, bool *_directionIn)
2364 Pipe *pipe = transfer->TransferPipe();
2365 bool directionIn = (pipe->Direction() == Pipe::In);
2367 ehci_qtd *firstDescriptor = NULL;
2368 ehci_qtd *lastDescriptor = NULL;
2369 ehci_qtd *strayDescriptor = queueHead->stray_log;
2370 status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
2371 &lastDescriptor, strayDescriptor, transfer->VectorLength(),
2372 directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
2374 if (result != B_OK)
2375 return result;
2377 lastDescriptor->token |= EHCI_QTD_IOC;
2378 if (!directionIn) {
2379 WriteDescriptorChain(firstDescriptor, transfer->Vector(),
2380 transfer->VectorCount());
2383 queueHead->element_log = firstDescriptor;
2384 queueHead->overlay.next_phy = firstDescriptor->this_phy;
2385 queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
2387 *_dataDescriptor = firstDescriptor;
2388 if (_directionIn)
2389 *_directionIn = directionIn;
2390 return B_OK;
2394 ehci_qtd *
2395 EHCI::CreateDescriptor(size_t bufferSize, uint8 pid)
2397 ehci_qtd *result;
2398 phys_addr_t physicalAddress;
2399 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2400 sizeof(ehci_qtd)) != B_OK) {
2401 TRACE_ERROR("failed to allocate a qtd\n");
2402 return NULL;
2405 result->this_phy = (addr_t)physicalAddress;
2406 result->next_phy = EHCI_ITEM_TERMINATE;
2407 result->next_log = NULL;
2408 result->alt_next_phy = EHCI_ITEM_TERMINATE;
2409 result->alt_next_log = NULL;
2410 result->buffer_size = bufferSize;
2411 result->token = bufferSize << EHCI_QTD_BYTES_SHIFT;
2412 result->token |= 3 << EHCI_QTD_ERRCOUNT_SHIFT;
2413 result->token |= pid << EHCI_QTD_PID_SHIFT;
2414 result->token |= EHCI_QTD_STATUS_ACTIVE;
2415 if (bufferSize == 0) {
2416 result->buffer_log = NULL;
2417 for (int32 i = 0; i < 5; i++) {
2418 result->buffer_phy[i] = 0;
2419 result->ext_buffer_phy[i] = 0;
2422 return result;
2425 if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress,
2426 bufferSize) != B_OK) {
2427 TRACE_ERROR("unable to allocate qtd buffer\n");
2428 fStack->FreeChunk(result, (phys_addr_t)result->this_phy,
2429 sizeof(ehci_qtd));
2430 return NULL;
2433 addr_t physicalBase = (addr_t)physicalAddress;
2434 result->buffer_phy[0] = physicalBase;
2435 result->ext_buffer_phy[0] = 0;
2436 for (int32 i = 1; i < 5; i++) {
2437 physicalBase += B_PAGE_SIZE;
2438 result->buffer_phy[i] = physicalBase & EHCI_QTD_PAGE_MASK;
2439 result->ext_buffer_phy[i] = 0;
2442 return result;
2446 status_t
2447 EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor,
2448 ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize,
2449 uint8 pid)
2451 size_t packetSize = B_PAGE_SIZE * 4;
2452 int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
2454 bool dataToggle = pipe->DataToggle();
2455 ehci_qtd *firstDescriptor = NULL;
2456 ehci_qtd *lastDescriptor = *_firstDescriptor;
2457 for (int32 i = 0; i < descriptorCount; i++) {
2458 ehci_qtd *descriptor = CreateDescriptor(min_c(packetSize, bufferSize),
2459 pid);
2461 if (!descriptor) {
2462 FreeDescriptorChain(firstDescriptor);
2463 return B_NO_MEMORY;
2466 if (dataToggle)
2467 descriptor->token |= EHCI_QTD_DATA_TOGGLE;
2469 if (lastDescriptor)
2470 LinkDescriptors(lastDescriptor, descriptor, strayDescriptor);
2472 bufferSize -= packetSize;
2473 lastDescriptor = descriptor;
2474 if (!firstDescriptor)
2475 firstDescriptor = descriptor;
2478 *_firstDescriptor = firstDescriptor;
2479 *_lastDescriptor = lastDescriptor;
2480 return B_OK;
2484 void
2485 EHCI::FreeDescriptor(ehci_qtd *descriptor)
2487 if (!descriptor)
2488 return;
2490 if (descriptor->buffer_log) {
2491 fStack->FreeChunk(descriptor->buffer_log,
2492 (phys_addr_t)descriptor->buffer_phy[0], descriptor->buffer_size);
2495 fStack->FreeChunk(descriptor, (phys_addr_t)descriptor->this_phy,
2496 sizeof(ehci_qtd));
2500 void
2501 EHCI::FreeDescriptorChain(ehci_qtd *topDescriptor)
2503 ehci_qtd *current = topDescriptor;
2504 ehci_qtd *next = NULL;
2506 while (current) {
2507 next = current->next_log;
2508 FreeDescriptor(current);
2509 current = next;
2514 ehci_itd *
2515 EHCI::CreateItdDescriptor()
2517 ehci_itd *result;
2518 phys_addr_t physicalAddress;
2519 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2520 sizeof(ehci_itd)) != B_OK) {
2521 TRACE_ERROR("failed to allocate a itd\n");
2522 return NULL;
2525 memset(result, 0, sizeof(ehci_itd));
2526 result->this_phy = (addr_t)physicalAddress;
2527 result->next_phy = EHCI_ITEM_TERMINATE;
2529 return result;
2533 ehci_sitd *
2534 EHCI::CreateSitdDescriptor()
2536 ehci_sitd *result;
2537 phys_addr_t physicalAddress;
2538 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2539 sizeof(ehci_sitd)) != B_OK) {
2540 TRACE_ERROR("failed to allocate a sitd\n");
2541 return NULL;
2544 memset(result, 0, sizeof(ehci_sitd));
2545 result->this_phy = (addr_t)physicalAddress | EHCI_ITEM_TYPE_SITD;
2546 result->next_phy = EHCI_ITEM_TERMINATE;
2548 return result;
2552 void
2553 EHCI::FreeDescriptor(ehci_itd *descriptor)
2555 if (!descriptor)
2556 return;
2558 fStack->FreeChunk(descriptor, (phys_addr_t)descriptor->this_phy,
2559 sizeof(ehci_itd));
2563 void
2564 EHCI::FreeDescriptor(ehci_sitd *descriptor)
2566 if (!descriptor)
2567 return;
2569 fStack->FreeChunk(descriptor, (phys_addr_t)descriptor->this_phy,
2570 sizeof(ehci_sitd));
2574 void
2575 EHCI::LinkDescriptors(ehci_qtd *first, ehci_qtd *last, ehci_qtd *alt)
2577 first->next_phy = last->this_phy;
2578 first->next_log = last;
2580 if (alt) {
2581 first->alt_next_phy = alt->this_phy;
2582 first->alt_next_log = alt;
2583 } else {
2584 first->alt_next_phy = EHCI_ITEM_TERMINATE;
2585 first->alt_next_log = NULL;
2590 void
2591 EHCI::LinkITDescriptors(ehci_itd *itd, ehci_itd **_last)
2593 ehci_itd *last = *_last;
2594 itd->next_phy = last->next_phy;
2595 itd->next = NULL;
2596 itd->prev = last;
2597 last->next = itd;
2598 last->next_phy = itd->this_phy;
2599 *_last = itd;
2603 void
2604 EHCI::LinkSITDescriptors(ehci_sitd *sitd, ehci_sitd **_last)
2606 ehci_sitd *last = *_last;
2607 sitd->next_phy = last->next_phy;
2608 sitd->next = NULL;
2609 sitd->prev = last;
2610 last->next = sitd;
2611 last->next_phy = sitd->this_phy;
2612 *_last = sitd;
2616 void
2617 EHCI::UnlinkITDescriptors(ehci_itd *itd, ehci_itd **last)
2619 itd->prev->next_phy = itd->next_phy;
2620 itd->prev->next = itd->next;
2621 if (itd->next != NULL)
2622 itd->next->prev = itd->prev;
2623 if (itd == *last)
2624 *last = itd->prev;
2628 void
2629 EHCI::UnlinkSITDescriptors(ehci_sitd *sitd, ehci_sitd **last)
2631 sitd->prev->next_phy = sitd->next_phy;
2632 sitd->prev->next = sitd->next;
2633 if (sitd->next != NULL)
2634 sitd->next->prev = sitd->prev;
2635 if (sitd == *last)
2636 *last = sitd->prev;
2640 size_t
2641 EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
2642 size_t vectorCount)
2644 ehci_qtd *current = topDescriptor;
2645 size_t actualLength = 0;
2646 size_t vectorIndex = 0;
2647 size_t vectorOffset = 0;
2648 size_t bufferOffset = 0;
2650 while (current) {
2651 if (!current->buffer_log)
2652 break;
2654 while (true) {
2655 size_t length = min_c(current->buffer_size - bufferOffset,
2656 vector[vectorIndex].iov_len - vectorOffset);
2658 memcpy((uint8 *)current->buffer_log + bufferOffset,
2659 (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length);
2661 actualLength += length;
2662 vectorOffset += length;
2663 bufferOffset += length;
2665 if (vectorOffset >= vector[vectorIndex].iov_len) {
2666 if (++vectorIndex >= vectorCount) {
2667 TRACE("wrote descriptor chain (%ld bytes, no more vectors)"
2668 "\n", actualLength);
2669 return actualLength;
2672 vectorOffset = 0;
2675 if (bufferOffset >= current->buffer_size) {
2676 bufferOffset = 0;
2677 break;
2681 if (current->next_phy & EHCI_ITEM_TERMINATE)
2682 break;
2684 current = current->next_log;
2687 TRACE("wrote descriptor chain (%ld bytes)\n", actualLength);
2688 return actualLength;
2692 size_t
2693 EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
2694 size_t vectorCount, bool *nextDataToggle)
2696 uint32 dataToggle = 0;
2697 ehci_qtd *current = topDescriptor;
2698 size_t actualLength = 0;
2699 size_t vectorIndex = 0;
2700 size_t vectorOffset = 0;
2701 size_t bufferOffset = 0;
2703 while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) {
2704 if (!current->buffer_log)
2705 break;
2707 dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
2708 size_t bufferSize = current->buffer_size;
2709 bufferSize -= (current->token >> EHCI_QTD_BYTES_SHIFT)
2710 & EHCI_QTD_BYTES_MASK;
2712 while (true) {
2713 size_t length = min_c(bufferSize - bufferOffset,
2714 vector[vectorIndex].iov_len - vectorOffset);
2716 memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
2717 (uint8 *)current->buffer_log + bufferOffset, length);
2719 actualLength += length;
2720 vectorOffset += length;
2721 bufferOffset += length;
2723 if (vectorOffset >= vector[vectorIndex].iov_len) {
2724 if (++vectorIndex >= vectorCount) {
2725 TRACE("read descriptor chain (%ld bytes, no more vectors)"
2726 "\n", actualLength);
2727 *nextDataToggle = dataToggle > 0 ? true : false;
2728 return actualLength;
2731 vectorOffset = 0;
2734 if (bufferOffset >= bufferSize) {
2735 bufferOffset = 0;
2736 break;
2740 if (current->next_phy & EHCI_ITEM_TERMINATE)
2741 break;
2743 current = current->next_log;
2746 TRACE("read descriptor chain (%ld bytes)\n", actualLength);
2747 *nextDataToggle = dataToggle > 0 ? true : false;
2748 return actualLength;
2752 size_t
2753 EHCI::ReadActualLength(ehci_qtd *topDescriptor, bool *nextDataToggle)
2755 size_t actualLength = 0;
2756 ehci_qtd *current = topDescriptor;
2757 uint32 dataToggle = 0;
2759 while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) {
2760 dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
2761 size_t length = current->buffer_size;
2762 length -= (current->token >> EHCI_QTD_BYTES_SHIFT)
2763 & EHCI_QTD_BYTES_MASK;
2764 actualLength += length;
2766 if (current->next_phy & EHCI_ITEM_TERMINATE)
2767 break;
2769 current = current->next_log;
2772 TRACE("read actual length (%ld bytes)\n", actualLength);
2773 *nextDataToggle = dataToggle > 0 ? true : false;
2774 return actualLength;
2778 size_t
2779 EHCI::WriteIsochronousDescriptorChain(isochronous_transfer_data *transfer,
2780 uint32 packetCount, iovec *vector)
2782 // TODO implement
2783 return 0;
2787 size_t
2788 EHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer)
2790 iovec *vector = transfer->transfer->Vector();
2791 size_t vectorCount = transfer->transfer->VectorCount();
2792 size_t vectorOffset = 0;
2793 size_t vectorIndex = 0;
2794 usb_isochronous_data *isochronousData
2795 = transfer->transfer->IsochronousData();
2796 uint32 packet = 0;
2797 size_t totalLength = 0;
2798 size_t bufferOffset = 0;
2800 size_t packetSize = transfer->transfer->DataLength();
2801 packetSize /= isochronousData->packet_count;
2803 for (uint32 i = 0; i <= transfer->last_to_process; i++) {
2804 ehci_itd *itd = transfer->descriptors[i];
2805 for (uint32 j = 0; j <= itd->last_token
2806 && packet < isochronousData->packet_count; j++) {
2808 size_t bufferSize = (itd->token[j] >> EHCI_ITD_TLENGTH_SHIFT)
2809 & EHCI_ITD_TLENGTH_MASK;
2810 if (((itd->token[j] >> EHCI_ITD_STATUS_SHIFT)
2811 & EHCI_ITD_STATUS_MASK) != 0) {
2812 bufferSize = 0;
2814 isochronousData->packet_descriptors[packet].actual_length
2815 = bufferSize;
2817 if (bufferSize > 0)
2818 isochronousData->packet_descriptors[packet].status = B_OK;
2819 else
2820 isochronousData->packet_descriptors[packet].status = B_ERROR;
2822 totalLength += bufferSize;
2824 size_t offset = bufferOffset;
2825 size_t skipSize = packetSize - bufferSize;
2826 while (bufferSize > 0) {
2827 size_t length = min_c(bufferSize,
2828 vector[vectorIndex].iov_len - vectorOffset);
2829 memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
2830 (uint8 *)transfer->buffer_log + bufferOffset, length);
2831 offset += length;
2832 vectorOffset += length;
2833 bufferSize -= length;
2835 if (vectorOffset >= vector[vectorIndex].iov_len) {
2836 if (++vectorIndex >= vectorCount) {
2837 TRACE("read isodescriptor chain (%ld bytes, no more "
2838 "vectors)\n", totalLength);
2839 return totalLength;
2842 vectorOffset = 0;
2846 // skip to next packet offset
2847 while (skipSize > 0) {
2848 size_t length = min_c(skipSize,
2849 vector[vectorIndex].iov_len - vectorOffset);
2850 vectorOffset += length;
2851 skipSize -= length;
2852 if (vectorOffset >= vector[vectorIndex].iov_len) {
2853 if (++vectorIndex >= vectorCount) {
2854 TRACE("read isodescriptor chain (%ld bytes, no more "
2855 "vectors)\n", totalLength);
2856 return totalLength;
2859 vectorOffset = 0;
2863 bufferOffset += packetSize;
2864 if (bufferOffset >= transfer->buffer_size)
2865 return totalLength;
2867 packet++;
2871 TRACE("ReadIsochronousDescriptorChain packet count %" B_PRId32 "\n",
2872 packet);
2874 return totalLength;
2878 bool
2879 EHCI::LockIsochronous()
2881 return (mutex_lock(&fIsochronousLock) == B_OK);
2885 void
2886 EHCI::UnlockIsochronous()
2888 mutex_unlock(&fIsochronousLock);
2892 inline void
2893 EHCI::WriteOpReg(uint32 reg, uint32 value)
2895 *(volatile uint32 *)(fOperationalRegisters + reg) = value;
2899 inline uint32
2900 EHCI::ReadOpReg(uint32 reg)
2902 return *(volatile uint32 *)(fOperationalRegisters + reg);
2906 inline uint8
2907 EHCI::ReadCapReg8(uint32 reg)
2909 return *(volatile uint8 *)(fCapabilityRegisters + reg);
2913 inline uint16
2914 EHCI::ReadCapReg16(uint32 reg)
2916 return *(volatile uint16 *)(fCapabilityRegisters + reg);
2920 inline uint32
2921 EHCI::ReadCapReg32(uint32 reg)
2923 return *(volatile uint32 *)(fCapabilityRegisters + reg);