BPicture: Fix archive constructor.
[haiku.git] / src / add-ons / kernel / busses / usb / ehci.cpp
blobdfa51f8448711b13cdb51d6a6a1ee15ed61ed427
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 < B_OK) {
231 TRACE("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 < B_OK || fAsyncAdvanceSem < B_OK
322 || fCleanupSem < B_OK) {
323 TRACE_ERROR("failed to create semaphores\n");
324 return;
327 // create finisher service thread
328 fFinishThread = spawn_kernel_thread(FinishThread, "ehci finish thread",
329 B_NORMAL_PRIORITY, (void *)this);
330 resume_thread(fFinishThread);
332 // Create semaphore the isochronous finisher thread will wait for
333 fFinishIsochronousTransfersSem = create_sem(0,
334 "EHCI Isochronous Finish Transfers");
335 if (fFinishIsochronousTransfersSem < B_OK) {
336 TRACE_ERROR("failed to create isochronous finisher semaphore\n");
337 return;
340 // Create the isochronous finisher service thread
341 fFinishIsochronousThread = spawn_kernel_thread(FinishIsochronousThread,
342 "ehci isochronous finish thread", B_URGENT_DISPLAY_PRIORITY,
343 (void *)this);
344 resume_thread(fFinishIsochronousThread);
346 // create cleanup service thread
347 fCleanupThread = spawn_kernel_thread(CleanupThread, "ehci cleanup thread",
348 B_NORMAL_PRIORITY, (void *)this);
349 resume_thread(fCleanupThread);
351 // set up interrupts or interrupt polling now that the controller is ready
352 bool polling = false;
353 void *settings = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS);
354 if (settings != NULL) {
355 polling = get_driver_boolean_parameter(settings, "ehci_polling", false,
356 false);
357 unload_driver_settings(settings);
360 if (polling) {
361 // create and run the polling thread
362 TRACE_ALWAYS("enabling ehci polling\n");
363 fInterruptPollThread = spawn_kernel_thread(InterruptPollThread,
364 "ehci interrupt poll thread", B_NORMAL_PRIORITY, (void *)this);
365 resume_thread(fInterruptPollThread);
366 } else {
367 // Find the right interrupt vector, using MSIs if available.
368 fIRQ = fPCIInfo->u.h0.interrupt_line;
369 if (sPCIx86Module != NULL && sPCIx86Module->get_msi_count(
370 fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function) >= 1) {
371 uint8 msiVector = 0;
372 if (sPCIx86Module->configure_msi(fPCIInfo->bus, fPCIInfo->device,
373 fPCIInfo->function, 1, &msiVector) == B_OK
374 && sPCIx86Module->enable_msi(fPCIInfo->bus, fPCIInfo->device,
375 fPCIInfo->function) == B_OK) {
376 TRACE_ALWAYS("using message signaled interrupts\n");
377 fIRQ = msiVector;
378 fUseMSI = true;
382 // install the interrupt handler and enable interrupts
383 install_io_interrupt_handler(fIRQ, InterruptHandler,
384 (void *)this, 0);
387 // ensure that interrupts are en-/disabled on the PCI device
388 command = sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device,
389 fPCIInfo->function, PCI_command, 2);
390 if ((polling || fUseMSI) == ((command & PCI_command_int_disable) == 0)) {
391 if (polling || fUseMSI)
392 command &= ~PCI_command_int_disable;
393 else
394 command |= PCI_command_int_disable;
396 sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
397 fPCIInfo->function, PCI_command, 2, command);
400 fEnabledInterrupts = EHCI_USBINTR_HOSTSYSERR | EHCI_USBINTR_USBERRINT
401 | EHCI_USBINTR_USBINT | EHCI_USBINTR_INTONAA;
402 WriteOpReg(EHCI_USBINTR, fEnabledInterrupts);
404 // structures don't span page boundaries
405 size_t itdListSize = EHCI_VFRAMELIST_ENTRIES_COUNT
406 / (B_PAGE_SIZE / sizeof(itd_entry)) * B_PAGE_SIZE;
407 size_t sitdListSize = EHCI_VFRAMELIST_ENTRIES_COUNT
408 / (B_PAGE_SIZE / sizeof(sitd_entry)) * B_PAGE_SIZE;
409 size_t frameListSize = B_PAGE_SIZE + B_PAGE_SIZE + itdListSize
410 + sitdListSize;
412 // allocate the periodic frame list
413 fPeriodicFrameListArea = fStack->AllocateArea((void **)&fPeriodicFrameList,
414 &physicalAddress, frameListSize, "USB EHCI Periodic Framelist");
415 if (fPeriodicFrameListArea < B_OK) {
416 TRACE_ERROR("unable to allocate periodic framelist\n");
417 return;
420 if ((physicalAddress & 0xfff) != 0) {
421 panic("EHCI_PERIODICLISTBASE not aligned on 4k: 0x%" B_PRIxPHYSADDR
422 "\n", physicalAddress);
425 // set the periodic frame list base on the controller
426 WriteOpReg(EHCI_PERIODICLISTBASE, (uint32)physicalAddress);
428 // create the interrupt entries to support different polling intervals
429 TRACE("creating interrupt entries\n");
430 uint32_t physicalBase = physicalAddress + B_PAGE_SIZE;
431 uint8 *logicalBase = (uint8 *)fPeriodicFrameList + B_PAGE_SIZE;
432 memset(logicalBase, 0, B_PAGE_SIZE);
434 fInterruptEntries = (interrupt_entry *)logicalBase;
435 for (int32 i = 0; i < EHCI_INTERRUPT_ENTRIES_COUNT; i++) {
436 ehci_qh *queueHead = &fInterruptEntries[i].queue_head;
437 queueHead->this_phy = physicalBase | EHCI_ITEM_TYPE_QH;
438 queueHead->current_qtd_phy = EHCI_ITEM_TERMINATE;
439 queueHead->overlay.next_phy = EHCI_ITEM_TERMINATE;
440 queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
441 queueHead->overlay.token = EHCI_QTD_STATUS_HALTED;
443 // set dummy endpoint information
444 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH
445 | (3 << EHCI_QH_CHARS_RL_SHIFT) | (64 << EHCI_QH_CHARS_MPL_SHIFT)
446 | EHCI_QH_CHARS_TOGGLE;
447 queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT)
448 | (0xff << EHCI_QH_CAPS_ISM_SHIFT);
450 physicalBase += sizeof(interrupt_entry);
451 if ((physicalBase & 0x10) != 0) {
452 panic("physical base for interrupt entry %" B_PRId32
453 " not aligned on 32, interrupt entry structure size %lu\n",
454 i, sizeof(interrupt_entry));
458 // create the itd and sitd entries
459 TRACE("build up iso entries\n");
460 uint32_t itdPhysicalBase = physicalAddress + B_PAGE_SIZE + B_PAGE_SIZE;
461 itd_entry* itds = (itd_entry *)((uint8 *)fPeriodicFrameList + B_PAGE_SIZE
462 + B_PAGE_SIZE);
463 memset(itds, 0, itdListSize);
465 uint32_t sitdPhysicalBase = itdPhysicalBase + itdListSize;
466 sitd_entry* sitds = (sitd_entry *)((uint8 *)fPeriodicFrameList + B_PAGE_SIZE
467 + B_PAGE_SIZE + itdListSize);
468 memset(sitds, 0, sitdListSize);
470 fItdEntries = new(std::nothrow) ehci_itd *[EHCI_VFRAMELIST_ENTRIES_COUNT];
471 fSitdEntries = new(std::nothrow) ehci_sitd *[EHCI_VFRAMELIST_ENTRIES_COUNT];
473 dprintf("sitd entry size %lu, itd entry size %lu\n", sizeof(sitd_entry),
474 sizeof(itd_entry));
475 for (int32 i = 0; i < EHCI_VFRAMELIST_ENTRIES_COUNT; i++) {
476 ehci_sitd *sitd = &sitds[i].sitd;
477 sitd->this_phy = sitdPhysicalBase | EHCI_ITEM_TYPE_SITD;
478 sitd->back_phy = EHCI_ITEM_TERMINATE;
479 fSitdEntries[i] = sitd;
480 TRACE("sitd entry %" B_PRId32 " %p 0x%" B_PRIx32 "\n", i, sitd,
481 sitd->this_phy);
483 ehci_itd *itd = &itds[i].itd;
484 itd->this_phy = itdPhysicalBase | EHCI_ITEM_TYPE_ITD;
485 itd->next_phy = sitd->this_phy;
486 fItdEntries[i] = itd;
487 TRACE("itd entry %" B_PRId32 " %p 0x%" B_PRIx32 "\n", i, itd,
488 itd->this_phy);
490 sitdPhysicalBase += sizeof(sitd_entry);
491 itdPhysicalBase += sizeof(itd_entry);
492 if ((sitdPhysicalBase & 0x10) != 0 || (itdPhysicalBase & 0x10) != 0)
493 panic("physical base for entry %" B_PRId32 " not aligned on 32\n",
497 // build flat interrupt tree
498 TRACE("build up interrupt links\n");
499 uint32 interval = EHCI_VFRAMELIST_ENTRIES_COUNT;
500 uint32 intervalIndex = EHCI_INTERRUPT_ENTRIES_COUNT - 1;
501 while (interval > 1) {
502 for (uint32 insertIndex = interval / 2;
503 insertIndex < EHCI_VFRAMELIST_ENTRIES_COUNT;
504 insertIndex += interval) {
505 fSitdEntries[insertIndex]->next_phy
506 = fInterruptEntries[intervalIndex].queue_head.this_phy;
509 intervalIndex--;
510 interval /= 2;
513 // setup the empty slot in the list and linking of all -> first
514 ehci_qh *firstLogical = &fInterruptEntries[0].queue_head;
515 fSitdEntries[0]->next_phy = firstLogical->this_phy;
516 for (int32 i = 1; i < EHCI_INTERRUPT_ENTRIES_COUNT; i++) {
517 fInterruptEntries[i].queue_head.next_phy = firstLogical->this_phy;
518 fInterruptEntries[i].queue_head.next_log = firstLogical;
519 fInterruptEntries[i].queue_head.prev_log = NULL;
522 // terminate the first entry
523 firstLogical->next_phy = EHCI_ITEM_TERMINATE;
524 firstLogical->next_log = NULL;
525 firstLogical->prev_log = NULL;
527 for (int32 i = 0; i < EHCI_FRAMELIST_ENTRIES_COUNT; i++) {
528 fPeriodicFrameList[i]
529 = fItdEntries[i & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1)]->this_phy;
530 TRACE("periodic entry %" B_PRId32 " linked to 0x%" B_PRIx32 "\n", i,
531 fPeriodicFrameList[i]);
534 // Create the array that will keep bandwidth information
535 fFrameBandwidth = new(std::nothrow) uint16[EHCI_VFRAMELIST_ENTRIES_COUNT];
536 for (int32 i = 0; i < EHCI_VFRAMELIST_ENTRIES_COUNT; i++) {
537 fFrameBandwidth[i] = MAX_AVAILABLE_BANDWIDTH;
540 // allocate a queue head that will always stay in the async frame list
541 fAsyncQueueHead = CreateQueueHead();
542 if (!fAsyncQueueHead) {
543 TRACE_ERROR("unable to allocate stray async queue head\n");
544 return;
547 fAsyncQueueHead->next_phy = fAsyncQueueHead->this_phy;
548 fAsyncQueueHead->next_log = fAsyncQueueHead;
549 fAsyncQueueHead->prev_log = fAsyncQueueHead;
550 fAsyncQueueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH
551 | EHCI_QH_CHARS_RECHEAD;
552 fAsyncQueueHead->endpoint_caps = 1 << EHCI_QH_CAPS_MULT_SHIFT;
553 fAsyncQueueHead->current_qtd_phy = EHCI_ITEM_TERMINATE;
554 fAsyncQueueHead->overlay.next_phy = EHCI_ITEM_TERMINATE;
556 WriteOpReg(EHCI_ASYNCLISTADDR, (uint32)fAsyncQueueHead->this_phy);
557 TRACE("set the async list addr to 0x%08" B_PRIx32 "\n",
558 ReadOpReg(EHCI_ASYNCLISTADDR));
560 fInitOK = true;
561 TRACE("EHCI host controller driver constructed\n");
565 EHCI::~EHCI()
567 TRACE("tear down EHCI host controller driver\n");
569 WriteOpReg(EHCI_USBCMD, 0);
570 WriteOpReg(EHCI_CONFIGFLAG, 0);
571 CancelAllPendingTransfers();
573 int32 result = 0;
574 fStopThreads = true;
575 delete_sem(fAsyncAdvanceSem);
576 delete_sem(fFinishTransfersSem);
577 delete_sem(fFinishIsochronousTransfersSem);
578 wait_for_thread(fFinishThread, &result);
579 wait_for_thread(fCleanupThread, &result);
580 wait_for_thread(fFinishIsochronousThread, &result);
582 if (fInterruptPollThread >= 0)
583 wait_for_thread(fInterruptPollThread, &result);
584 else
585 remove_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this);
587 LockIsochronous();
588 isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer;
589 while (isoTransfer) {
590 isochronous_transfer_data *next = isoTransfer->link;
591 delete isoTransfer;
592 isoTransfer = next;
594 mutex_destroy(&fIsochronousLock);
596 delete fRootHub;
597 delete [] fFrameBandwidth;
598 delete [] fItdEntries;
599 delete [] fSitdEntries;
600 delete_area(fPeriodicFrameListArea);
601 delete_area(fRegisterArea);
603 if (fUseMSI && sPCIx86Module != NULL) {
604 sPCIx86Module->disable_msi(fPCIInfo->bus,
605 fPCIInfo->device, fPCIInfo->function);
606 sPCIx86Module->unconfigure_msi(fPCIInfo->bus,
607 fPCIInfo->device, fPCIInfo->function);
609 put_module(B_PCI_MODULE_NAME);
611 if (sPCIx86Module != NULL) {
612 sPCIx86Module = NULL;
613 put_module(B_PCI_X86_MODULE_NAME);
618 status_t
619 EHCI::Start()
621 TRACE("starting EHCI host controller\n");
622 TRACE("usbcmd: 0x%08" B_PRIx32 "; usbsts: 0x%08" B_PRIx32 "\n",
623 ReadOpReg(EHCI_USBCMD), ReadOpReg(EHCI_USBSTS));
625 bool hasPerPortChangeEvent = (ReadCapReg32(EHCI_HCCPARAMS)
626 & EHCI_HCCPARAMS_PPCEC) != 0;
628 uint32 config = ReadOpReg(EHCI_USBCMD);
629 config &= ~((EHCI_USBCMD_ITC_MASK << EHCI_USBCMD_ITC_SHIFT)
630 | EHCI_USBCMD_PPCEE);
631 uint32 frameListSize = (config >> EHCI_USBCMD_FLS_SHIFT)
632 & EHCI_USBCMD_FLS_MASK;
634 WriteOpReg(EHCI_USBCMD, config | EHCI_USBCMD_RUNSTOP
635 | (hasPerPortChangeEvent ? EHCI_USBCMD_PPCEE : 0)
636 | EHCI_USBCMD_ASENABLE | EHCI_USBCMD_PSENABLE
637 | (frameListSize << EHCI_USBCMD_FLS_SHIFT)
638 | (1 << EHCI_USBCMD_ITC_SHIFT));
640 switch (frameListSize) {
641 case 0:
642 TRACE("frame list size 1024\n");
643 break;
644 case 1:
645 TRACE("frame list size 512\n");
646 break;
647 case 2:
648 TRACE("frame list size 256\n");
649 break;
650 default:
651 TRACE_ALWAYS("unknown frame list size\n");
654 bool running = false;
655 for (int32 i = 0; i < 10; i++) {
656 uint32 status = ReadOpReg(EHCI_USBSTS);
657 TRACE("try %" B_PRId32 ": status 0x%08" B_PRIx32 "\n", i, status);
659 if (status & EHCI_USBSTS_HCHALTED) {
660 snooze(10000);
661 } else {
662 running = true;
663 break;
667 if (!running) {
668 TRACE_ERROR("host controller didn't start\n");
669 return B_ERROR;
672 // route all ports to us
673 WriteOpReg(EHCI_CONFIGFLAG, EHCI_CONFIGFLAG_FLAG);
674 snooze(10000);
676 fRootHubAddress = AllocateAddress();
677 fRootHub = new(std::nothrow) EHCIRootHub(RootObject(), fRootHubAddress);
678 if (!fRootHub) {
679 TRACE_ERROR("no memory to allocate root hub\n");
680 return B_NO_MEMORY;
683 if (fRootHub->InitCheck() < B_OK) {
684 TRACE_ERROR("root hub failed init check\n");
685 return fRootHub->InitCheck();
688 SetRootHub(fRootHub);
690 TRACE_ALWAYS("successfully started the controller\n");
691 return BusManager::Start();
695 status_t
696 EHCI::StartDebugTransfer(Transfer *transfer)
698 static transfer_data transferData;
700 transferData.queue_head = CreateQueueHead();
701 if (transferData.queue_head == NULL)
702 return B_NO_MEMORY;
704 Pipe *pipe = transfer->TransferPipe();
705 status_t result = InitQueueHead(transferData.queue_head, pipe);
706 if (result != B_OK) {
707 FreeQueueHead(transferData.queue_head);
708 return result;
711 if ((pipe->Type() & USB_OBJECT_CONTROL_PIPE) != 0) {
712 result = FillQueueWithRequest(transfer, transferData.queue_head,
713 &transferData.data_descriptor, &transferData.incoming);
714 } else {
715 result = FillQueueWithData(transfer, transferData.queue_head,
716 &transferData.data_descriptor, &transferData.incoming);
719 if (result != B_OK) {
720 FreeQueueHead(transferData.queue_head);
721 return result;
724 if ((pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) != 0)
725 LinkPeriodicDebugQueueHead(transferData.queue_head, pipe);
726 else
727 LinkAsyncDebugQueueHead(transferData.queue_head);
729 // we abuse the callback cookie to hold our transfer data
730 transfer->SetCallback(NULL, &transferData);
731 return B_OK;
735 void
736 EHCI::LinkAsyncDebugQueueHead(ehci_qh *queueHead)
738 ehci_qh *prevHead = fAsyncQueueHead->prev_log;
739 queueHead->next_phy = fAsyncQueueHead->this_phy;
740 queueHead->next_log = fAsyncQueueHead;
741 queueHead->prev_log = prevHead;
742 fAsyncQueueHead->prev_log = queueHead;
743 prevHead->next_log = queueHead;
744 prevHead->next_phy = queueHead->this_phy;
748 void
749 EHCI::LinkPeriodicDebugQueueHead(ehci_qh *queueHead, Pipe *pipe)
751 if (pipe->Speed() == USB_SPEED_HIGHSPEED)
752 queueHead->endpoint_caps |= (0xff << EHCI_QH_CAPS_ISM_SHIFT);
753 else {
754 queueHead->endpoint_caps |= (0x01 << EHCI_QH_CAPS_ISM_SHIFT);
755 queueHead->endpoint_caps |= (0x1c << EHCI_QH_CAPS_SCM_SHIFT);
758 ehci_qh *interruptQueue = &fInterruptEntries[0].queue_head;
759 queueHead->next_phy = interruptQueue->next_phy;
760 queueHead->next_log = interruptQueue->next_log;
761 queueHead->prev_log = interruptQueue;
762 if (interruptQueue->next_log)
763 interruptQueue->next_log->prev_log = queueHead;
764 interruptQueue->next_log = queueHead;
765 interruptQueue->next_phy = queueHead->this_phy;
769 status_t
770 EHCI::CheckDebugTransfer(Transfer *transfer)
772 bool transferOK = false;
773 bool transferError = false;
774 transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
775 ehci_qtd *descriptor = transferData->queue_head->element_log;
777 while (descriptor) {
778 uint32 status = descriptor->token;
779 if ((status & EHCI_QTD_STATUS_ACTIVE) != 0) {
780 // still in progress
781 break;
784 if ((status & EHCI_QTD_STATUS_ERRMASK) != 0) {
785 transferError = true;
786 break;
789 if ((descriptor->next_phy & EHCI_ITEM_TERMINATE) != 0) {
790 // we arrived at the last (stray) descriptor, we're done
791 transferOK = true;
792 break;
795 if (((status >> EHCI_QTD_PID_SHIFT) & EHCI_QTD_PID_MASK)
796 == EHCI_QTD_PID_IN
797 && ((status >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK) != 0) {
798 // a short packet condition existed on this descriptor
799 if (descriptor->alt_next_log != NULL) {
800 descriptor = descriptor->alt_next_log;
801 continue;
804 transferOK = true;
805 break;
808 descriptor = descriptor->next_log;
811 if (!transferOK && !transferError) {
812 spin(75);
813 return B_DEV_PENDING;
816 if (transferOK) {
817 bool nextDataToggle = false;
818 if (transferData->data_descriptor != NULL && transferData->incoming) {
819 // data to read out
820 iovec *vector = transfer->Vector();
821 size_t vectorCount = transfer->VectorCount();
823 ReadDescriptorChain(transferData->data_descriptor,
824 vector, vectorCount, &nextDataToggle);
825 } else if (transferData->data_descriptor != NULL)
826 ReadActualLength(transferData->data_descriptor, &nextDataToggle);
828 transfer->TransferPipe()->SetDataToggle(nextDataToggle);
831 CleanupDebugTransfer(transfer);
832 return transferOK ? B_OK : B_IO_ERROR;
836 void
837 EHCI::CancelDebugTransfer(Transfer *transfer)
839 transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
841 // clear the active bit so the descriptors are canceled
842 ehci_qtd *descriptor = transferData->queue_head->element_log;
843 while (descriptor != NULL) {
844 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
845 descriptor = descriptor->next_log;
848 transfer->Finished(B_CANCELED, 0);
849 CleanupDebugTransfer(transfer);
853 void
854 EHCI::CleanupDebugTransfer(Transfer *transfer)
856 transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
857 ehci_qh *queueHead = transferData->queue_head;
858 ehci_qh *prevHead = queueHead->prev_log;
859 if (prevHead != NULL) {
860 prevHead->next_phy = queueHead->next_phy;
861 prevHead->next_log = queueHead->next_log;
864 ehci_qh *nextHead = queueHead->next_log;
865 if (nextHead != NULL)
866 nextHead->prev_log = queueHead->prev_log;
868 queueHead->next_phy = fAsyncQueueHead->this_phy;
869 queueHead->prev_log = NULL;
870 queueHead->next_log = NULL;
872 // wait for async advance to ensure the controller does not access this
873 // queue head anymore.
874 spin(125);
876 FreeQueueHead(queueHead);
880 status_t
881 EHCI::SubmitTransfer(Transfer *transfer)
883 // short circuit the root hub
884 if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
885 return fRootHub->ProcessTransfer(this, transfer);
887 Pipe *pipe = transfer->TransferPipe();
888 if ((pipe->Type() & USB_OBJECT_ISO_PIPE) != 0)
889 return SubmitIsochronous(transfer);
891 ehci_qh *queueHead = CreateQueueHead();
892 if (!queueHead) {
893 TRACE_ERROR("failed to allocate queue head\n");
894 return B_NO_MEMORY;
897 status_t result = InitQueueHead(queueHead, pipe);
898 if (result < B_OK) {
899 TRACE_ERROR("failed to init queue head\n");
900 FreeQueueHead(queueHead);
901 return result;
904 bool directionIn;
905 ehci_qtd *dataDescriptor;
906 if ((pipe->Type() & USB_OBJECT_CONTROL_PIPE) != 0) {
907 result = FillQueueWithRequest(transfer, queueHead, &dataDescriptor,
908 &directionIn);
909 } else {
910 result = FillQueueWithData(transfer, queueHead, &dataDescriptor,
911 &directionIn);
914 if (result < B_OK) {
915 TRACE_ERROR("failed to fill transfer queue with data\n");
916 FreeQueueHead(queueHead);
917 return result;
920 result = AddPendingTransfer(transfer, queueHead, dataDescriptor,
921 directionIn);
922 if (result < B_OK) {
923 TRACE_ERROR("failed to add pending transfer\n");
924 FreeQueueHead(queueHead);
925 return result;
928 #ifdef TRACE_USB
929 TRACE("linking queue\n");
930 print_queue(queueHead);
931 #endif
933 if ((pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) != 0)
934 result = LinkInterruptQueueHead(queueHead, pipe);
935 else
936 result = LinkQueueHead(queueHead);
938 if (result < B_OK) {
939 TRACE_ERROR("failed to link queue head\n");
940 FreeQueueHead(queueHead);
941 return result;
944 return B_OK;
948 status_t
949 EHCI::SubmitIsochronous(Transfer *transfer)
951 Pipe *pipe = transfer->TransferPipe();
952 bool directionIn = (pipe->Direction() == Pipe::In);
953 usb_isochronous_data *isochronousData = transfer->IsochronousData();
954 size_t packetSize = transfer->DataLength();
955 #ifdef TRACE_USB
956 size_t restSize = packetSize % isochronousData->packet_count;
957 #endif
958 packetSize /= isochronousData->packet_count;
959 uint16 currentFrame;
961 if (packetSize > pipe->MaxPacketSize()) {
962 TRACE_ERROR(
963 "isochronous packetSize is bigger than pipe MaxPacketSize\n");
964 return B_BAD_VALUE;
967 // Ignore the fact that the last descriptor might need less bandwidth.
968 // The overhead is not worthy.
969 uint16 bandwidth = transfer->Bandwidth() / isochronousData->packet_count;
971 TRACE("isochronous transfer descriptor bandwidth %d\n", bandwidth);
973 // The following holds the list of transfer descriptor of the
974 // isochronous request. It is used to quickly remove all the isochronous
975 // descriptors from the frame list, as descriptors are not link to each
976 // other in a queue like for every other transfer.
977 ehci_itd **isoRequest
978 = new(std::nothrow) ehci_itd *[isochronousData->packet_count];
979 if (isoRequest == NULL) {
980 TRACE("failed to create isoRequest array!\n");
981 return B_NO_MEMORY;
984 TRACE("isochronous submitted size=%" B_PRIuSIZE " bytes, TDs=%" B_PRIu32
985 ", maxPacketSize=%" B_PRIuSIZE ", packetSize=%" B_PRIuSIZE
986 ", restSize=%" B_PRIuSIZE "\n", transfer->DataLength(),
987 isochronousData->packet_count, pipe->MaxPacketSize(), packetSize,
988 restSize);
990 // Find the entry where to start inserting the first Isochronous descriptor
991 if ((isochronousData->flags & USB_ISO_ASAP) != 0 ||
992 isochronousData->starting_frame_number == NULL) {
994 if (fFirstIsochronousTransfer != NULL && fNextStartingFrame != -1)
995 currentFrame = fNextStartingFrame;
996 else {
997 uint32 threshold = fThreshold;
998 TRACE("threshold: %" B_PRIu32 "\n", threshold);
1000 // find the first available frame with enough bandwidth.
1001 // This should always be the case, as defining the starting frame
1002 // number in the driver makes no sense for many reason, one of which
1003 // is that frame numbers value are host controller specific, and the
1004 // driver does not know which host controller is running.
1005 currentFrame = ((ReadOpReg(EHCI_FRINDEX) + threshold) / 8)
1006 & (EHCI_FRAMELIST_ENTRIES_COUNT - 1);
1009 // Make sure that:
1010 // 1. We are at least 5ms ahead the controller
1011 // 2. We stay in the range 0-127
1012 // 3. There is enough bandwidth in the first entry
1013 currentFrame &= EHCI_VFRAMELIST_ENTRIES_COUNT - 1;
1014 } else {
1015 // Find out if the frame number specified has enough bandwidth,
1016 // otherwise find the first next available frame with enough bandwidth
1017 currentFrame = *isochronousData->starting_frame_number;
1020 TRACE("isochronous starting frame=%d\n", currentFrame);
1022 uint16 itdIndex = 0;
1023 size_t dataLength = transfer->DataLength();
1024 void* bufferLog;
1025 phys_addr_t bufferPhy;
1026 if (fStack->AllocateChunk(&bufferLog, &bufferPhy, dataLength) < B_OK) {
1027 TRACE_ERROR("unable to allocate itd buffer\n");
1028 delete[] isoRequest;
1029 return B_NO_MEMORY;
1032 memset(bufferLog, 0, dataLength);
1034 phys_addr_t currentPhy = bufferPhy;
1035 uint32 frameCount = 0;
1036 while (dataLength > 0) {
1037 ehci_itd* itd = CreateItdDescriptor();
1038 isoRequest[itdIndex++] = itd;
1039 uint16 pg = 0;
1040 itd->buffer_phy[pg] = currentPhy & 0xfffff000;
1041 uint32 offset = currentPhy & 0xfff;
1042 TRACE("isochronous created itd, filling it with phy %" B_PRIxPHYSADDR
1043 "\n", currentPhy);
1044 for (int32 i = 0; i < 8 && dataLength > 0; i++) {
1045 size_t length = min_c(dataLength, packetSize);
1046 itd->token[i] = (EHCI_ITD_STATUS_ACTIVE << EHCI_ITD_STATUS_SHIFT)
1047 | (length << EHCI_ITD_TLENGTH_SHIFT) | (pg << EHCI_ITD_PG_SHIFT)
1048 | (offset << EHCI_ITD_TOFFSET_SHIFT);
1049 itd->last_token = i;
1050 TRACE("isochronous filled slot %" B_PRId32 " 0x%" B_PRIx32 "\n", i,
1051 itd->token[i]);
1052 dataLength -= length;
1053 offset += length;
1054 if (dataLength > 0 && offset > 0xfff) {
1055 offset -= B_PAGE_SIZE;
1056 currentPhy += B_PAGE_SIZE;
1057 itd->buffer_phy[pg + 1] = currentPhy & 0xfffff000;
1058 pg++;
1060 if (dataLength <= 0)
1061 itd->token[i] |= EHCI_ITD_IOC;
1064 currentPhy += (offset & 0xfff) - (currentPhy & 0xfff);
1066 itd->buffer_phy[0]
1067 |= (pipe->EndpointAddress() << EHCI_ITD_ENDPOINT_SHIFT)
1068 | (pipe->DeviceAddress() << EHCI_ITD_ADDRESS_SHIFT);
1069 itd->buffer_phy[1]
1070 |= (pipe->MaxPacketSize() & EHCI_ITD_MAXPACKETSIZE_MASK)
1071 | (directionIn << EHCI_ITD_DIR_SHIFT);
1072 itd->buffer_phy[2]
1073 |= ((((pipe->MaxPacketSize() >> EHCI_ITD_MAXPACKETSIZE_LENGTH) + 1)
1074 & EHCI_ITD_MUL_MASK) << EHCI_ITD_MUL_SHIFT);
1076 TRACE("isochronous filled itd buffer_phy[0,1,2] 0x%" B_PRIx32 ", 0x%"
1077 B_PRIx32 " 0x%" B_PRIx32 "\n",
1078 itd->buffer_phy[0], itd->buffer_phy[1], itd->buffer_phy[2]);
1080 if (!LockIsochronous())
1081 continue;
1082 LinkITDescriptors(itd, &fItdEntries[currentFrame]);
1083 UnlockIsochronous();
1084 fFrameBandwidth[currentFrame] -= bandwidth;
1085 currentFrame = (currentFrame + 1) & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1);
1086 frameCount++;
1089 TRACE("isochronous filled itds count %d\n", itdIndex);
1091 // Add transfer to the list
1092 status_t result = AddPendingIsochronousTransfer(transfer, isoRequest,
1093 itdIndex - 1, directionIn, bufferPhy, bufferLog,
1094 transfer->DataLength());
1095 if (result < B_OK) {
1096 TRACE_ERROR("failed to add pending isochronous transfer\n");
1097 for (uint32 i = 0; i < itdIndex; i++)
1098 FreeDescriptor(isoRequest[i]);
1099 delete[] isoRequest;
1100 return result;
1103 TRACE("appended isochronous transfer by starting at frame number %d\n",
1104 currentFrame);
1105 fNextStartingFrame = currentFrame + 1;
1107 // Wake up the isochronous finisher thread
1108 release_sem_etc(fFinishIsochronousTransfersSem, 1 /*frameCount*/,
1109 B_DO_NOT_RESCHEDULE);
1111 return B_OK;
1115 isochronous_transfer_data *
1116 EHCI::FindIsochronousTransfer(ehci_itd *itd)
1118 // Simply check every last descriptor of the isochronous transfer list
1119 isochronous_transfer_data *transfer = fFirstIsochronousTransfer;
1120 if (transfer) {
1121 while (transfer->descriptors[transfer->last_to_process]
1122 != itd) {
1123 transfer = transfer->link;
1124 if (!transfer)
1125 break;
1128 return transfer;
1132 status_t
1133 EHCI::NotifyPipeChange(Pipe *pipe, usb_change change)
1135 TRACE("pipe change %d for pipe %p\n", change, pipe);
1136 switch (change) {
1137 case USB_CHANGE_CREATED:
1138 case USB_CHANGE_DESTROYED: {
1139 // ToDo: we should create and keep a single queue head
1140 // for all transfers to/from this pipe
1141 break;
1144 case USB_CHANGE_PIPE_POLICY_CHANGED: {
1145 // ToDo: for isochronous pipes we might need to adapt to new
1146 // pipe policy settings here
1147 break;
1151 return B_OK;
1155 status_t
1156 EHCI::AddTo(Stack *stack)
1158 #ifdef TRACE_USB
1159 set_dprintf_enabled(true);
1160 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
1161 load_driver_symbols("ehci");
1162 #endif
1163 #endif
1165 if (!sPCIModule) {
1166 status_t status = get_module(B_PCI_MODULE_NAME,
1167 (module_info **)&sPCIModule);
1168 if (status < B_OK) {
1169 TRACE_MODULE_ERROR("getting pci module failed! 0x%08" B_PRIx32
1170 "\n", status);
1171 return status;
1175 TRACE_MODULE("searching devices\n");
1176 bool found = false;
1177 pci_info *item = new(std::nothrow) pci_info;
1178 if (!item) {
1179 sPCIModule = NULL;
1180 put_module(B_PCI_MODULE_NAME);
1181 return B_NO_MEMORY;
1184 // Try to get the PCI x86 module as well so we can enable possible MSIs.
1185 if (sPCIx86Module == NULL && get_module(B_PCI_X86_MODULE_NAME,
1186 (module_info **)&sPCIx86Module) != B_OK) {
1187 // If it isn't there, that's not critical though.
1188 TRACE_MODULE_ERROR("failed to get pci x86 module\n");
1189 sPCIx86Module = NULL;
1192 for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) {
1193 if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb
1194 && item->class_api == PCI_usb_ehci) {
1195 if (item->u.h0.interrupt_line == 0
1196 || item->u.h0.interrupt_line == 0xFF) {
1197 TRACE_MODULE_ERROR("found device with invalid IRQ - "
1198 "check IRQ assignement\n");
1199 continue;
1202 TRACE_MODULE("found device at IRQ %u\n", item->u.h0.interrupt_line);
1203 EHCI *bus = new(std::nothrow) EHCI(item, stack);
1204 if (!bus) {
1205 delete item;
1206 sPCIModule = NULL;
1207 put_module(B_PCI_MODULE_NAME);
1208 if (sPCIx86Module != NULL) {
1209 sPCIx86Module = NULL;
1210 put_module(B_PCI_X86_MODULE_NAME);
1212 return B_NO_MEMORY;
1215 if (bus->InitCheck() < B_OK) {
1216 TRACE_MODULE_ERROR("bus failed init check\n");
1217 delete bus;
1218 continue;
1221 // the bus took it away
1222 item = new(std::nothrow) pci_info;
1224 bus->Start();
1225 stack->AddBusManager(bus);
1226 found = true;
1230 if (!found) {
1231 TRACE_MODULE_ERROR("no devices found\n");
1232 delete item;
1233 sPCIModule = NULL;
1234 put_module(B_PCI_MODULE_NAME);
1235 if (sPCIx86Module != NULL) {
1236 sPCIx86Module = NULL;
1237 put_module(B_PCI_X86_MODULE_NAME);
1239 return ENODEV;
1242 delete item;
1243 return B_OK;
1247 status_t
1248 EHCI::GetPortStatus(uint8 index, usb_port_status *status)
1250 if (index >= fPortCount)
1251 return B_BAD_INDEX;
1253 status->status = status->change = 0;
1254 uint32 portStatus = ReadOpReg(EHCI_PORTSC + index * sizeof(uint32));
1256 // build the status
1257 if (portStatus & EHCI_PORTSC_CONNSTATUS)
1258 status->status |= PORT_STATUS_CONNECTION;
1259 if (portStatus & EHCI_PORTSC_ENABLE)
1260 status->status |= PORT_STATUS_ENABLE;
1261 if (portStatus & EHCI_PORTSC_ENABLE)
1262 status->status |= PORT_STATUS_HIGH_SPEED;
1263 if (portStatus & EHCI_PORTSC_OCACTIVE)
1264 status->status |= PORT_STATUS_OVER_CURRENT;
1265 if (portStatus & EHCI_PORTSC_PORTRESET)
1266 status->status |= PORT_STATUS_RESET;
1267 if (portStatus & EHCI_PORTSC_PORTPOWER)
1268 status->status |= PORT_STATUS_POWER;
1269 if (portStatus & EHCI_PORTSC_SUSPEND)
1270 status->status |= PORT_STATUS_SUSPEND;
1271 if (portStatus & EHCI_PORTSC_DMINUS)
1272 status->status |= PORT_STATUS_LOW_SPEED;
1274 // build the change
1275 if (portStatus & EHCI_PORTSC_CONNCHANGE)
1276 status->change |= PORT_STATUS_CONNECTION;
1277 if (portStatus & EHCI_PORTSC_ENABLECHANGE)
1278 status->change |= PORT_STATUS_ENABLE;
1279 if (portStatus & EHCI_PORTSC_OCCHANGE)
1280 status->change |= PORT_STATUS_OVER_CURRENT;
1282 // there are no bits to indicate suspend and reset change
1283 if (fPortResetChange & (1 << index))
1284 status->change |= PORT_STATUS_RESET;
1285 if (fPortSuspendChange & (1 << index))
1286 status->change |= PORT_STATUS_SUSPEND;
1288 return B_OK;
1292 status_t
1293 EHCI::SetPortFeature(uint8 index, uint16 feature)
1295 if (index >= fPortCount)
1296 return B_BAD_INDEX;
1298 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
1299 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1301 switch (feature) {
1302 case PORT_SUSPEND:
1303 return SuspendPort(index);
1305 case PORT_RESET:
1306 return ResetPort(index);
1308 case PORT_POWER:
1309 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTPOWER);
1310 return B_OK;
1313 return B_BAD_VALUE;
1317 status_t
1318 EHCI::ClearPortFeature(uint8 index, uint16 feature)
1320 if (index >= fPortCount)
1321 return B_BAD_INDEX;
1323 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
1324 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1326 switch (feature) {
1327 case PORT_ENABLE:
1328 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_ENABLE);
1329 return B_OK;
1331 case PORT_POWER:
1332 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTPOWER);
1333 return B_OK;
1335 case C_PORT_CONNECTION:
1336 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_CONNCHANGE);
1337 return B_OK;
1339 case C_PORT_ENABLE:
1340 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_ENABLECHANGE);
1341 return B_OK;
1343 case C_PORT_OVER_CURRENT:
1344 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_OCCHANGE);
1345 return B_OK;
1347 case C_PORT_RESET:
1348 fPortResetChange &= ~(1 << index);
1349 return B_OK;
1351 case C_PORT_SUSPEND:
1352 fPortSuspendChange &= ~(1 << index);
1353 return B_OK;
1356 return B_BAD_VALUE;
1360 status_t
1361 EHCI::ResetPort(uint8 index)
1363 TRACE("reset port %d\n", index);
1364 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
1365 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1367 if (portStatus & EHCI_PORTSC_DMINUS) {
1368 TRACE_ALWAYS("lowspeed device connected, giving up port ownership\n");
1369 // there is a lowspeed device connected.
1370 // we give the ownership to a companion controller.
1371 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER);
1372 fPortResetChange |= (1 << index);
1373 return B_OK;
1376 // enable reset signaling
1377 WriteOpReg(portRegister, (portStatus & ~EHCI_PORTSC_ENABLE)
1378 | EHCI_PORTSC_PORTRESET);
1379 snooze(50000);
1381 // disable reset signaling
1382 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1383 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTRESET);
1384 snooze(2000);
1386 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1387 if (portStatus & EHCI_PORTSC_PORTRESET) {
1388 TRACE_ERROR("port reset won't complete\n");
1389 return B_ERROR;
1392 if ((portStatus & EHCI_PORTSC_ENABLE) == 0) {
1393 TRACE_ALWAYS("fullspeed device connected, giving up port ownership\n");
1394 // the port was not enabled, this means that no high speed device is
1395 // attached to this port. we give up ownership to a companion controler
1396 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER);
1399 fPortResetChange |= (1 << index);
1400 return B_OK;
1404 status_t
1405 EHCI::SuspendPort(uint8 index)
1407 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
1408 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1409 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_SUSPEND);
1410 fPortSuspendChange |= (1 << index);
1411 return B_OK;
1415 status_t
1416 EHCI::ControllerReset()
1418 // halt the controller first
1419 WriteOpReg(EHCI_USBCMD, 0);
1420 snooze(10000);
1422 // then reset it
1423 WriteOpReg(EHCI_USBCMD, EHCI_USBCMD_HCRESET);
1425 int32 tries = 5;
1426 while (ReadOpReg(EHCI_USBCMD) & EHCI_USBCMD_HCRESET) {
1427 snooze(10000);
1428 if (tries-- < 0)
1429 return B_ERROR;
1432 return B_OK;
1436 status_t
1437 EHCI::LightReset()
1439 return B_ERROR;
1443 int32
1444 EHCI::InterruptHandler(void *data)
1446 return ((EHCI *)data)->Interrupt();
1450 int32
1451 EHCI::Interrupt()
1453 static spinlock lock = B_SPINLOCK_INITIALIZER;
1454 acquire_spinlock(&lock);
1456 // check if any interrupt was generated
1457 uint32 status = ReadOpReg(EHCI_USBSTS) & EHCI_USBSTS_INTMASK;
1458 if ((status & fEnabledInterrupts) == 0) {
1459 if (status != 0) {
1460 TRACE("discarding not enabled interrupts 0x%08" B_PRIx32 "\n",
1461 status);
1462 WriteOpReg(EHCI_USBSTS, status);
1465 release_spinlock(&lock);
1466 return B_UNHANDLED_INTERRUPT;
1469 bool asyncAdvance = false;
1470 bool finishTransfers = false;
1471 int32 result = B_HANDLED_INTERRUPT;
1473 if (status & EHCI_USBSTS_USBINT) {
1474 TRACE("transfer finished\n");
1475 result = B_INVOKE_SCHEDULER;
1476 finishTransfers = true;
1479 if (status & EHCI_USBSTS_USBERRINT) {
1480 TRACE("transfer error\n");
1481 result = B_INVOKE_SCHEDULER;
1482 finishTransfers = true;
1485 if (status & EHCI_USBSTS_FLROLLOVER)
1486 TRACE("frame list rollover\n");
1488 if (status & EHCI_USBSTS_PORTCHANGE)
1489 TRACE("port change detected\n");
1491 if (status & EHCI_USBSTS_INTONAA) {
1492 TRACE("interrupt on async advance\n");
1493 asyncAdvance = true;
1494 result = B_INVOKE_SCHEDULER;
1497 if (status & EHCI_USBSTS_HOSTSYSERR)
1498 TRACE_ERROR("host system error!\n");
1500 WriteOpReg(EHCI_USBSTS, status);
1501 release_spinlock(&lock);
1503 if (asyncAdvance)
1504 release_sem_etc(fAsyncAdvanceSem, 1, B_DO_NOT_RESCHEDULE);
1505 if (finishTransfers)
1506 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1508 return result;
1512 int32
1513 EHCI::InterruptPollThread(void *data)
1515 EHCI *ehci = (EHCI *)data;
1517 while (!ehci->fStopThreads) {
1518 // TODO: this could be handled much better by only polling when there
1519 // are actual transfers going on...
1520 snooze(1000);
1522 cpu_status status = disable_interrupts();
1523 ehci->Interrupt();
1524 restore_interrupts(status);
1527 return 0;
1531 status_t
1532 EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead,
1533 ehci_qtd *dataDescriptor, bool directionIn)
1535 transfer_data *data = new(std::nothrow) transfer_data;
1536 if (!data)
1537 return B_NO_MEMORY;
1539 status_t result = transfer->InitKernelAccess();
1540 if (result < B_OK) {
1541 delete data;
1542 return result;
1545 data->transfer = transfer;
1546 data->queue_head = queueHead;
1547 data->data_descriptor = dataDescriptor;
1548 data->incoming = directionIn;
1549 data->canceled = false;
1550 data->link = NULL;
1552 if (!Lock()) {
1553 delete data;
1554 return B_ERROR;
1557 if (fLastTransfer)
1558 fLastTransfer->link = data;
1559 else
1560 fFirstTransfer = data;
1562 fLastTransfer = data;
1563 Unlock();
1565 return B_OK;
1569 status_t
1570 EHCI::AddPendingIsochronousTransfer(Transfer *transfer, ehci_itd **isoRequest,
1571 uint32 lastIndex, bool directionIn, addr_t bufferPhy, void* bufferLog,
1572 size_t bufferSize)
1574 if (!transfer || !isoRequest)
1575 return B_BAD_VALUE;
1577 isochronous_transfer_data *data
1578 = new(std::nothrow) isochronous_transfer_data;
1579 if (!data)
1580 return B_NO_MEMORY;
1582 status_t result = transfer->InitKernelAccess();
1583 if (result < B_OK) {
1584 delete data;
1585 return result;
1588 data->transfer = transfer;
1589 data->descriptors = isoRequest;
1590 data->last_to_process = lastIndex;
1591 data->incoming = directionIn;
1592 data->is_active = true;
1593 data->link = NULL;
1594 data->buffer_phy = bufferPhy;
1595 data->buffer_log = bufferLog;
1596 data->buffer_size = bufferSize;
1598 // Put in the isochronous transfer list
1599 if (!LockIsochronous()) {
1600 delete data;
1601 return B_ERROR;
1604 if (fLastIsochronousTransfer)
1605 fLastIsochronousTransfer->link = data;
1606 else if (!fFirstIsochronousTransfer)
1607 fFirstIsochronousTransfer = data;
1609 fLastIsochronousTransfer = data;
1610 UnlockIsochronous();
1611 return B_OK;
1615 status_t
1616 EHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
1618 if ((pipe->Type() & USB_OBJECT_ISO_PIPE) != 0)
1619 return CancelQueuedIsochronousTransfers(pipe, force);
1621 if (!Lock())
1622 return B_ERROR;
1624 struct transfer_entry {
1625 Transfer * transfer;
1626 transfer_entry * next;
1629 transfer_entry *list = NULL;
1630 transfer_data *current = fFirstTransfer;
1631 while (current) {
1632 if (current->transfer && current->transfer->TransferPipe() == pipe) {
1633 // clear the active bit so the descriptors are canceled
1634 ehci_qtd *descriptor = current->queue_head->element_log;
1635 while (descriptor) {
1636 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
1637 descriptor = descriptor->next_log;
1640 if (!force) {
1641 // if the transfer is canceled by force, the one causing the
1642 // cancel is probably not the one who initiated the transfer
1643 // and the callback is likely not safe anymore
1644 transfer_entry *entry
1645 = (transfer_entry *)malloc(sizeof(transfer_entry));
1646 if (entry != NULL) {
1647 entry->transfer = current->transfer;
1648 current->transfer = NULL;
1649 entry->next = list;
1650 list = entry;
1654 current->canceled = true;
1657 current = current->link;
1660 Unlock();
1662 while (list != NULL) {
1663 transfer_entry *next = list->next;
1664 list->transfer->Finished(B_CANCELED, 0);
1665 delete list->transfer;
1666 free(list);
1667 list = next;
1670 // wait for any transfers that might have made it before canceling
1671 while (fProcessingPipe == pipe)
1672 snooze(1000);
1674 // notify the finisher so it can clean up the canceled transfers
1675 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1676 return B_OK;
1680 status_t
1681 EHCI::CancelQueuedIsochronousTransfers(Pipe *pipe, bool force)
1683 isochronous_transfer_data *current = fFirstIsochronousTransfer;
1685 while (current) {
1686 if (current->transfer->TransferPipe() == pipe) {
1687 // TODO implement
1689 // TODO: Use the force paramater in order to avoid calling
1690 // invalid callbacks
1691 current->is_active = false;
1694 current = current->link;
1697 TRACE_ERROR("no isochronous transfer found!\n");
1698 return B_ERROR;
1702 status_t
1703 EHCI::CancelAllPendingTransfers()
1705 if (!Lock())
1706 return B_ERROR;
1708 transfer_data *transfer = fFirstTransfer;
1709 while (transfer) {
1710 transfer->transfer->Finished(B_CANCELED, 0);
1711 delete transfer->transfer;
1713 transfer_data *next = transfer->link;
1714 delete transfer;
1715 transfer = next;
1718 fFirstTransfer = NULL;
1719 fLastTransfer = NULL;
1720 Unlock();
1721 return B_OK;
1725 int32
1726 EHCI::FinishThread(void *data)
1728 ((EHCI *)data)->FinishTransfers();
1729 return B_OK;
1733 void
1734 EHCI::FinishTransfers()
1736 while (!fStopThreads) {
1737 if (acquire_sem(fFinishTransfersSem) < B_OK)
1738 continue;
1740 // eat up sems that have been released by multiple interrupts
1741 int32 semCount = 0;
1742 get_sem_count(fFinishTransfersSem, &semCount);
1743 if (semCount > 0) {
1744 acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT,
1748 if (!Lock())
1749 continue;
1751 TRACE("finishing transfers\n");
1752 transfer_data *lastTransfer = NULL;
1753 transfer_data *transfer = fFirstTransfer;
1754 Unlock();
1756 while (transfer) {
1757 bool transferDone = false;
1758 ehci_qtd *descriptor = transfer->queue_head->element_log;
1759 status_t callbackStatus = B_OK;
1761 while (descriptor) {
1762 uint32 status = descriptor->token;
1763 if (status & EHCI_QTD_STATUS_ACTIVE) {
1764 // still in progress
1765 TRACE("qtd (0x%08" B_PRIx32 ") still active\n",
1766 descriptor->this_phy);
1767 break;
1770 if (status & EHCI_QTD_STATUS_ERRMASK) {
1771 // a transfer error occured
1772 TRACE_ERROR("qtd (0x%" B_PRIx32 ") error: 0x%08" B_PRIx32
1773 "\n", descriptor->this_phy, status);
1775 uint8 errorCount = status >> EHCI_QTD_ERRCOUNT_SHIFT;
1776 errorCount &= EHCI_QTD_ERRCOUNT_MASK;
1777 if (errorCount == 0) {
1778 // the error counter counted down to zero, report why
1779 int32 reasons = 0;
1780 if (status & EHCI_QTD_STATUS_BUFFER) {
1781 callbackStatus = transfer->incoming
1782 ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN;
1783 reasons++;
1785 if (status & EHCI_QTD_STATUS_TERROR) {
1786 callbackStatus = B_DEV_CRC_ERROR;
1787 reasons++;
1789 if ((transfer->queue_head->endpoint_chars
1790 & EHCI_QH_CHARS_EPS_HIGH) == 0) {
1791 // For full-/lowspeed endpoints the unused ping
1792 // state bit is used as another error bit, it is
1793 // unspecific however.
1794 if ((status & EHCI_QTD_STATUS_LS_ERR) != 0) {
1795 callbackStatus = B_DEV_STALLED;
1796 reasons++;
1800 if (reasons > 1)
1801 callbackStatus = B_DEV_MULTIPLE_ERRORS;
1802 else if (reasons == 0) {
1803 TRACE_ERROR("error counter counted down to zero "
1804 "but none of the error bits are set\n");
1805 callbackStatus = B_DEV_STALLED;
1807 } else if (status & EHCI_QTD_STATUS_BABBLE) {
1808 // there is a babble condition
1809 callbackStatus = transfer->incoming
1810 ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN;
1811 } else {
1812 // if the error counter didn't count down to zero
1813 // and there was no babble, then this halt was caused
1814 // by a stall handshake
1815 callbackStatus = B_DEV_STALLED;
1818 transferDone = true;
1819 break;
1822 if (descriptor->next_phy & EHCI_ITEM_TERMINATE) {
1823 // we arrived at the last (stray) descriptor, we're done
1824 TRACE("qtd (0x%08" B_PRIx32 ") done\n",
1825 descriptor->this_phy);
1826 callbackStatus = B_OK;
1827 transferDone = true;
1828 break;
1831 if (((status >> EHCI_QTD_PID_SHIFT) & EHCI_QTD_PID_MASK)
1832 == EHCI_QTD_PID_IN
1833 && ((status >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK)
1834 != 0) {
1835 // a short packet condition existed on this descriptor,
1836 // follow the alternate next pointer if set
1837 if (descriptor->alt_next_log != NULL) {
1838 descriptor = descriptor->alt_next_log;
1839 continue;
1842 // no alternate next, transfer is done
1843 callbackStatus = B_OK;
1844 transferDone = true;
1845 break;
1848 descriptor = descriptor->next_log;
1851 if (!transferDone) {
1852 lastTransfer = transfer;
1853 transfer = transfer->link;
1854 continue;
1857 // remove the transfer from the list first so we are sure
1858 // it doesn't get canceled while we still process it
1859 transfer_data *next = transfer->link;
1860 if (Lock()) {
1861 if (lastTransfer)
1862 lastTransfer->link = transfer->link;
1864 if (transfer == fFirstTransfer)
1865 fFirstTransfer = transfer->link;
1866 if (transfer == fLastTransfer)
1867 fLastTransfer = lastTransfer;
1869 // store the currently processing pipe here so we can wait
1870 // in cancel if we are processing something on the target pipe
1871 if (!transfer->canceled)
1872 fProcessingPipe = transfer->transfer->TransferPipe();
1874 transfer->link = NULL;
1875 Unlock();
1878 // if canceled the callback has already been called
1879 if (!transfer->canceled) {
1880 size_t actualLength = 0;
1882 if (callbackStatus == B_OK) {
1883 bool nextDataToggle = false;
1884 if (transfer->data_descriptor && transfer->incoming) {
1885 // data to read out
1886 iovec *vector = transfer->transfer->Vector();
1887 size_t vectorCount = transfer->transfer->VectorCount();
1888 transfer->transfer->PrepareKernelAccess();
1889 actualLength = ReadDescriptorChain(
1890 transfer->data_descriptor,
1891 vector, vectorCount,
1892 &nextDataToggle);
1893 } else if (transfer->data_descriptor) {
1894 // calculate transfered length
1895 actualLength = ReadActualLength(
1896 transfer->data_descriptor, &nextDataToggle);
1899 transfer->transfer->TransferPipe()->SetDataToggle(
1900 nextDataToggle);
1902 if (transfer->transfer->IsFragmented()) {
1903 // this transfer may still have data left
1904 transfer->transfer->AdvanceByFragment(actualLength);
1905 if (transfer->transfer->VectorLength() > 0) {
1906 FreeDescriptorChain(transfer->data_descriptor);
1907 transfer->transfer->PrepareKernelAccess();
1908 status_t result = FillQueueWithData(
1909 transfer->transfer,
1910 transfer->queue_head,
1911 &transfer->data_descriptor, NULL);
1913 if (result == B_OK && Lock()) {
1914 // reappend the transfer
1915 if (fLastTransfer)
1916 fLastTransfer->link = transfer;
1917 if (!fFirstTransfer)
1918 fFirstTransfer = transfer;
1920 fLastTransfer = transfer;
1921 Unlock();
1923 transfer = next;
1924 continue;
1928 // the transfer is done, but we already set the
1929 // actualLength with AdvanceByFragment()
1930 actualLength = 0;
1934 transfer->transfer->Finished(callbackStatus, actualLength);
1935 fProcessingPipe = NULL;
1938 // unlink hardware queue and delete the transfer
1939 UnlinkQueueHead(transfer->queue_head, &fFreeListHead);
1940 delete transfer->transfer;
1941 delete transfer;
1942 transfer = next;
1943 release_sem(fCleanupSem);
1949 int32
1950 EHCI::CleanupThread(void *data)
1952 ((EHCI *)data)->Cleanup();
1953 return B_OK;
1957 void
1958 EHCI::Cleanup()
1960 ehci_qh *lastFreeListHead = NULL;
1962 while (!fStopThreads) {
1963 if (acquire_sem(fCleanupSem) < B_OK)
1964 continue;
1966 ehci_qh *freeListHead = fFreeListHead;
1967 if (freeListHead == lastFreeListHead)
1968 continue;
1970 // set the doorbell and wait for the host controller to notify us
1971 WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD);
1972 if (acquire_sem(fAsyncAdvanceSem) < B_OK)
1973 continue;
1975 ehci_qh *current = freeListHead;
1976 while (current != lastFreeListHead) {
1977 ehci_qh *next = current->next_log;
1978 FreeQueueHead(current);
1979 current = next;
1982 lastFreeListHead = freeListHead;
1987 int32
1988 EHCI::FinishIsochronousThread(void *data)
1990 ((EHCI *)data)->FinishIsochronousTransfers();
1991 return B_OK;
1995 void
1996 EHCI::FinishIsochronousTransfers()
1998 /* This thread stays one position behind the controller and processes every
1999 * isochronous descriptor. Once it finds the last isochronous descriptor
2000 * of a transfer, it processes the entire transfer.
2002 while (!fStopThreads) {
2003 // Go to sleep if there are not isochronous transfer to process
2004 if (acquire_sem(fFinishIsochronousTransfersSem) < B_OK)
2005 return;
2007 bool transferDone = false;
2009 uint32 frame = (ReadOpReg(EHCI_FRINDEX) / 8 )
2010 & (EHCI_FRAMELIST_ENTRIES_COUNT - 1);
2011 uint32 currentFrame = (frame + EHCI_VFRAMELIST_ENTRIES_COUNT - 5)
2012 & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1);
2013 uint32 loop = 0;
2015 // Process the frame list until one transfer is processed
2016 while (!transferDone && loop++ < EHCI_VFRAMELIST_ENTRIES_COUNT) {
2017 // wait 1ms in order to be sure to be one position behind
2018 // the controller
2019 while (currentFrame == (((ReadOpReg(EHCI_FRINDEX) / 8)
2020 & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1)))) {
2021 snooze(1000);
2024 ehci_itd *itd = fItdEntries[currentFrame];
2026 TRACE("FinishIsochronousTransfers itd %p phy 0x%" B_PRIx32
2027 " prev (%p/0x%" B_PRIx32 ") at frame %" B_PRId32 "\n", itd,
2028 itd->this_phy, itd->prev, itd->prev != NULL
2029 ? itd->prev->this_phy : 0, currentFrame);
2031 if (!LockIsochronous())
2032 continue;
2034 // Process the frame till it has isochronous descriptors in it.
2035 while (!(itd->next_phy & EHCI_ITEM_TERMINATE) && itd->prev != NULL) {
2036 TRACE("FinishIsochronousTransfers checking itd %p last_token"
2037 " %" B_PRId32 "\n", itd, itd->last_token);
2038 TRACE("FinishIsochronousTransfers tokens 0x%" B_PRIx32 " 0x%"
2039 B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx32
2040 " 0x%" B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx32 "\n",
2041 itd->token[0], itd->token[1], itd->token[2], itd->token[3],
2042 itd->token[4], itd->token[5], itd->token[6], itd->token[7]);
2043 if (((itd->token[itd->last_token] >> EHCI_ITD_STATUS_SHIFT)
2044 & EHCI_ITD_STATUS_ACTIVE) == EHCI_ITD_STATUS_ACTIVE) {
2045 TRACE("FinishIsochronousTransfers unprocessed active itd\n");
2047 UnlinkITDescriptors(itd, &fItdEntries[currentFrame]);
2049 // Process the transfer if we found the last descriptor
2050 isochronous_transfer_data *transfer
2051 = FindIsochronousTransfer(itd);
2052 // Process the descriptors only if it is still active and
2053 // belongs to an inbound transfer. If the transfer is not
2054 // active, it means the request has been removed, so simply
2055 // remove the descriptors.
2056 if (transfer && transfer->is_active) {
2057 TRACE("FinishIsochronousTransfers active transfer\n");
2058 size_t actualLength = 0;
2059 if (((itd->buffer_phy[1] >> EHCI_ITD_DIR_SHIFT) & 1) != 0) {
2060 transfer->transfer->PrepareKernelAccess();
2061 actualLength = ReadIsochronousDescriptorChain(transfer);
2064 // Remove the transfer
2065 if (transfer == fFirstIsochronousTransfer) {
2066 fFirstIsochronousTransfer = transfer->link;
2067 if (transfer == fLastIsochronousTransfer)
2068 fLastIsochronousTransfer = NULL;
2069 } else {
2070 isochronous_transfer_data *temp
2071 = fFirstIsochronousTransfer;
2072 while (temp != NULL && transfer != temp->link)
2073 temp = temp->link;
2075 if (transfer == fLastIsochronousTransfer)
2076 fLastIsochronousTransfer = temp;
2077 if (temp != NULL && temp->link != NULL)
2078 temp->link = temp->link->link;
2080 transfer->link = NULL;
2082 transfer->transfer->Finished(B_OK, actualLength);
2084 itd = itd->prev;
2086 for (uint32 i = 0; i <= transfer->last_to_process; i++)
2087 FreeDescriptor(transfer->descriptors[i]);
2089 TRACE("FinishIsochronousTransfers descriptors freed\n");
2091 delete [] transfer->descriptors;
2092 delete transfer->transfer;
2093 fStack->FreeChunk(transfer->buffer_log,
2094 (phys_addr_t)transfer->buffer_phy,
2095 transfer->buffer_size);
2096 delete transfer;
2097 transferDone = true;
2098 } else {
2099 TRACE("FinishIsochronousTransfers not end of transfer\n");
2100 itd = itd->prev;
2104 UnlockIsochronous();
2106 TRACE("FinishIsochronousTransfers next frame\n");
2108 // Make sure to reset the frame bandwidth
2109 fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH;
2110 currentFrame = (currentFrame + 1) % EHCI_VFRAMELIST_ENTRIES_COUNT;
2116 ehci_qh *
2117 EHCI::CreateQueueHead()
2119 ehci_qh *result;
2120 phys_addr_t physicalAddress;
2121 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2122 sizeof(ehci_qh)) < B_OK) {
2123 TRACE_ERROR("failed to allocate queue head\n");
2124 return NULL;
2127 result->this_phy = (addr_t)physicalAddress | EHCI_ITEM_TYPE_QH;
2128 result->next_phy = EHCI_ITEM_TERMINATE;
2129 result->next_log = NULL;
2130 result->prev_log = NULL;
2132 ehci_qtd *descriptor = CreateDescriptor(0, 0);
2133 if (!descriptor) {
2134 TRACE_ERROR("failed to allocate initial qtd for queue head\n");
2135 fStack->FreeChunk(result, physicalAddress, sizeof(ehci_qh));
2136 return NULL;
2139 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
2140 result->stray_log = descriptor;
2141 result->element_log = descriptor;
2142 result->current_qtd_phy = EHCI_ITEM_TERMINATE;
2143 result->overlay.next_phy = descriptor->this_phy;
2144 result->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
2145 result->overlay.token = 0;
2146 for (int32 i = 0; i < 5; i++) {
2147 result->overlay.buffer_phy[i] = 0;
2148 result->overlay.ext_buffer_phy[i] = 0;
2151 return result;
2155 status_t
2156 EHCI::InitQueueHead(ehci_qh *queueHead, Pipe *pipe)
2158 switch (pipe->Speed()) {
2159 case USB_SPEED_LOWSPEED:
2160 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_LOW;
2161 break;
2162 case USB_SPEED_FULLSPEED:
2163 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_FULL;
2164 break;
2165 case USB_SPEED_HIGHSPEED:
2166 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH;
2167 break;
2168 default:
2169 TRACE_ERROR("unknown pipe speed\n");
2170 return B_ERROR;
2173 queueHead->endpoint_chars |= (3 << EHCI_QH_CHARS_RL_SHIFT)
2174 | (pipe->MaxPacketSize() << EHCI_QH_CHARS_MPL_SHIFT)
2175 | (pipe->EndpointAddress() << EHCI_QH_CHARS_EPT_SHIFT)
2176 | (pipe->DeviceAddress() << EHCI_QH_CHARS_DEV_SHIFT)
2177 | EHCI_QH_CHARS_TOGGLE;
2179 queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT);
2180 if (pipe->Speed() != USB_SPEED_HIGHSPEED) {
2181 if ((pipe->Type() & USB_OBJECT_CONTROL_PIPE) != 0)
2182 queueHead->endpoint_chars |= EHCI_QH_CHARS_CONTROL;
2184 queueHead->endpoint_caps |= (pipe->HubPort() << EHCI_QH_CAPS_PORT_SHIFT)
2185 | (pipe->HubAddress() << EHCI_QH_CAPS_HUB_SHIFT);
2188 return B_OK;
2192 void
2193 EHCI::FreeQueueHead(ehci_qh *queueHead)
2195 if (!queueHead)
2196 return;
2198 FreeDescriptorChain(queueHead->element_log);
2199 FreeDescriptor(queueHead->stray_log);
2200 fStack->FreeChunk(queueHead, (phys_addr_t)queueHead->this_phy,
2201 sizeof(ehci_qh));
2205 status_t
2206 EHCI::LinkQueueHead(ehci_qh *queueHead)
2208 if (!Lock())
2209 return B_ERROR;
2211 ehci_qh *prevHead = fAsyncQueueHead->prev_log;
2212 queueHead->next_phy = fAsyncQueueHead->this_phy;
2213 queueHead->next_log = fAsyncQueueHead;
2214 queueHead->prev_log = prevHead;
2215 fAsyncQueueHead->prev_log = queueHead;
2216 prevHead->next_log = queueHead;
2217 prevHead->next_phy = queueHead->this_phy;
2219 Unlock();
2220 return B_OK;
2224 status_t
2225 EHCI::LinkInterruptQueueHead(ehci_qh *queueHead, Pipe *pipe)
2227 uint8 interval = pipe->Interval();
2228 if (pipe->Speed() == USB_SPEED_HIGHSPEED) {
2229 // Allow interrupts to be scheduled on each possible micro frame.
2230 queueHead->endpoint_caps |= (0xff << EHCI_QH_CAPS_ISM_SHIFT);
2231 } else {
2232 // As we do not yet support FSTNs to correctly reference low/full
2233 // speed interrupt transfers, we simply put them into the 1 interval
2234 // queue. This way we ensure that we reach them on every micro frame
2235 // and can do the corresponding start/complete split transactions.
2236 // ToDo: use FSTNs to correctly link non high speed interrupt transfers
2237 interval = 1;
2239 // For now we also force start splits to be in micro frame 0 and
2240 // complete splits to be in micro frame 2, 3 and 4.
2241 queueHead->endpoint_caps |= (0x01 << EHCI_QH_CAPS_ISM_SHIFT);
2242 queueHead->endpoint_caps |= (0x1c << EHCI_QH_CAPS_SCM_SHIFT);
2245 // this should not happen
2246 if (interval < 1)
2247 interval = 1;
2249 // this may happen as intervals can go up to 16; we limit the value to
2250 // EHCI_INTERRUPT_ENTRIES_COUNT as you cannot support intervals above
2251 // that with a frame list of just EHCI_VFRAMELIST_ENTRIES_COUNT entries...
2252 if (interval > EHCI_INTERRUPT_ENTRIES_COUNT)
2253 interval = EHCI_INTERRUPT_ENTRIES_COUNT;
2255 if (!Lock())
2256 return B_ERROR;
2258 ehci_qh *interruptQueue = &fInterruptEntries[interval - 1].queue_head;
2259 queueHead->next_phy = interruptQueue->next_phy;
2260 queueHead->next_log = interruptQueue->next_log;
2261 queueHead->prev_log = interruptQueue;
2262 if (interruptQueue->next_log)
2263 interruptQueue->next_log->prev_log = queueHead;
2264 interruptQueue->next_log = queueHead;
2265 interruptQueue->next_phy = queueHead->this_phy;
2267 Unlock();
2268 return B_OK;
2272 status_t
2273 EHCI::UnlinkQueueHead(ehci_qh *queueHead, ehci_qh **freeListHead)
2275 if (!Lock())
2276 return B_ERROR;
2278 ehci_qh *prevHead = queueHead->prev_log;
2279 ehci_qh *nextHead = queueHead->next_log;
2280 if (prevHead) {
2281 prevHead->next_phy = queueHead->next_phy;
2282 prevHead->next_log = queueHead->next_log;
2285 if (nextHead)
2286 nextHead->prev_log = queueHead->prev_log;
2288 queueHead->next_phy = fAsyncQueueHead->this_phy;
2289 queueHead->prev_log = NULL;
2291 queueHead->next_log = *freeListHead;
2292 *freeListHead = queueHead;
2294 Unlock();
2295 return B_OK;
2299 status_t
2300 EHCI::FillQueueWithRequest(Transfer *transfer, ehci_qh *queueHead,
2301 ehci_qtd **_dataDescriptor, bool *_directionIn)
2303 Pipe *pipe = transfer->TransferPipe();
2304 usb_request_data *requestData = transfer->RequestData();
2305 bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
2307 ehci_qtd *setupDescriptor = CreateDescriptor(sizeof(usb_request_data),
2308 EHCI_QTD_PID_SETUP);
2309 ehci_qtd *statusDescriptor = CreateDescriptor(0,
2310 directionIn ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN);
2312 if (!setupDescriptor || !statusDescriptor) {
2313 TRACE_ERROR("failed to allocate descriptors\n");
2314 FreeDescriptor(setupDescriptor);
2315 FreeDescriptor(statusDescriptor);
2316 return B_NO_MEMORY;
2319 iovec vector;
2320 vector.iov_base = requestData;
2321 vector.iov_len = sizeof(usb_request_data);
2322 WriteDescriptorChain(setupDescriptor, &vector, 1);
2324 ehci_qtd *strayDescriptor = queueHead->stray_log;
2325 statusDescriptor->token |= EHCI_QTD_IOC | EHCI_QTD_DATA_TOGGLE;
2327 ehci_qtd *dataDescriptor = NULL;
2328 if (transfer->VectorCount() > 0) {
2329 ehci_qtd *lastDescriptor = NULL;
2330 status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
2331 &lastDescriptor, statusDescriptor, transfer->VectorLength(),
2332 directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
2334 if (result < B_OK) {
2335 FreeDescriptor(setupDescriptor);
2336 FreeDescriptor(statusDescriptor);
2337 return result;
2340 if (!directionIn) {
2341 WriteDescriptorChain(dataDescriptor, transfer->Vector(),
2342 transfer->VectorCount());
2345 LinkDescriptors(setupDescriptor, dataDescriptor, strayDescriptor);
2346 LinkDescriptors(lastDescriptor, statusDescriptor, statusDescriptor);
2347 } else {
2348 // no data: link setup and status descriptors directly
2349 LinkDescriptors(setupDescriptor, statusDescriptor, strayDescriptor);
2352 queueHead->element_log = setupDescriptor;
2353 queueHead->overlay.next_phy = setupDescriptor->this_phy;
2354 queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
2356 *_dataDescriptor = dataDescriptor;
2357 *_directionIn = directionIn;
2358 return B_OK;
2362 status_t
2363 EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead,
2364 ehci_qtd **_dataDescriptor, bool *_directionIn)
2366 Pipe *pipe = transfer->TransferPipe();
2367 bool directionIn = (pipe->Direction() == Pipe::In);
2369 ehci_qtd *firstDescriptor = NULL;
2370 ehci_qtd *lastDescriptor = NULL;
2371 ehci_qtd *strayDescriptor = queueHead->stray_log;
2372 status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
2373 &lastDescriptor, strayDescriptor, transfer->VectorLength(),
2374 directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
2376 if (result < B_OK)
2377 return result;
2379 lastDescriptor->token |= EHCI_QTD_IOC;
2380 if (!directionIn) {
2381 WriteDescriptorChain(firstDescriptor, transfer->Vector(),
2382 transfer->VectorCount());
2385 queueHead->element_log = firstDescriptor;
2386 queueHead->overlay.next_phy = firstDescriptor->this_phy;
2387 queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
2389 *_dataDescriptor = firstDescriptor;
2390 if (_directionIn)
2391 *_directionIn = directionIn;
2392 return B_OK;
2396 ehci_qtd *
2397 EHCI::CreateDescriptor(size_t bufferSize, uint8 pid)
2399 ehci_qtd *result;
2400 phys_addr_t physicalAddress;
2401 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2402 sizeof(ehci_qtd)) < B_OK) {
2403 TRACE_ERROR("failed to allocate a qtd\n");
2404 return NULL;
2407 result->this_phy = (addr_t)physicalAddress;
2408 result->next_phy = EHCI_ITEM_TERMINATE;
2409 result->next_log = NULL;
2410 result->alt_next_phy = EHCI_ITEM_TERMINATE;
2411 result->alt_next_log = NULL;
2412 result->buffer_size = bufferSize;
2413 result->token = bufferSize << EHCI_QTD_BYTES_SHIFT;
2414 result->token |= 3 << EHCI_QTD_ERRCOUNT_SHIFT;
2415 result->token |= pid << EHCI_QTD_PID_SHIFT;
2416 result->token |= EHCI_QTD_STATUS_ACTIVE;
2417 if (bufferSize == 0) {
2418 result->buffer_log = NULL;
2419 for (int32 i = 0; i < 5; i++) {
2420 result->buffer_phy[i] = 0;
2421 result->ext_buffer_phy[i] = 0;
2424 return result;
2427 if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress,
2428 bufferSize) < B_OK) {
2429 TRACE_ERROR("unable to allocate qtd buffer\n");
2430 fStack->FreeChunk(result, (phys_addr_t)result->this_phy,
2431 sizeof(ehci_qtd));
2432 return NULL;
2435 addr_t physicalBase = (addr_t)physicalAddress;
2436 result->buffer_phy[0] = physicalBase;
2437 result->ext_buffer_phy[0] = 0;
2438 for (int32 i = 1; i < 5; i++) {
2439 physicalBase += B_PAGE_SIZE;
2440 result->buffer_phy[i] = physicalBase & EHCI_QTD_PAGE_MASK;
2441 result->ext_buffer_phy[i] = 0;
2444 return result;
2448 status_t
2449 EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor,
2450 ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize,
2451 uint8 pid)
2453 size_t packetSize = B_PAGE_SIZE * 4;
2454 int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
2456 bool dataToggle = pipe->DataToggle();
2457 ehci_qtd *firstDescriptor = NULL;
2458 ehci_qtd *lastDescriptor = *_firstDescriptor;
2459 for (int32 i = 0; i < descriptorCount; i++) {
2460 ehci_qtd *descriptor = CreateDescriptor(min_c(packetSize, bufferSize),
2461 pid);
2463 if (!descriptor) {
2464 FreeDescriptorChain(firstDescriptor);
2465 return B_NO_MEMORY;
2468 if (dataToggle)
2469 descriptor->token |= EHCI_QTD_DATA_TOGGLE;
2471 if (lastDescriptor)
2472 LinkDescriptors(lastDescriptor, descriptor, strayDescriptor);
2474 bufferSize -= packetSize;
2475 lastDescriptor = descriptor;
2476 if (!firstDescriptor)
2477 firstDescriptor = descriptor;
2480 *_firstDescriptor = firstDescriptor;
2481 *_lastDescriptor = lastDescriptor;
2482 return B_OK;
2486 void
2487 EHCI::FreeDescriptor(ehci_qtd *descriptor)
2489 if (!descriptor)
2490 return;
2492 if (descriptor->buffer_log) {
2493 fStack->FreeChunk(descriptor->buffer_log,
2494 (phys_addr_t)descriptor->buffer_phy[0], descriptor->buffer_size);
2497 fStack->FreeChunk(descriptor, (phys_addr_t)descriptor->this_phy,
2498 sizeof(ehci_qtd));
2502 void
2503 EHCI::FreeDescriptorChain(ehci_qtd *topDescriptor)
2505 ehci_qtd *current = topDescriptor;
2506 ehci_qtd *next = NULL;
2508 while (current) {
2509 next = current->next_log;
2510 FreeDescriptor(current);
2511 current = next;
2516 ehci_itd *
2517 EHCI::CreateItdDescriptor()
2519 ehci_itd *result;
2520 phys_addr_t physicalAddress;
2521 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2522 sizeof(ehci_itd)) < B_OK) {
2523 TRACE_ERROR("failed to allocate a itd\n");
2524 return NULL;
2527 memset(result, 0, sizeof(ehci_itd));
2528 result->this_phy = (addr_t)physicalAddress;
2529 result->next_phy = EHCI_ITEM_TERMINATE;
2531 return result;
2535 ehci_sitd *
2536 EHCI::CreateSitdDescriptor()
2538 ehci_sitd *result;
2539 phys_addr_t physicalAddress;
2540 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2541 sizeof(ehci_sitd)) < B_OK) {
2542 TRACE_ERROR("failed to allocate a sitd\n");
2543 return NULL;
2546 memset(result, 0, sizeof(ehci_sitd));
2547 result->this_phy = (addr_t)physicalAddress | EHCI_ITEM_TYPE_SITD;
2548 result->next_phy = EHCI_ITEM_TERMINATE;
2550 return result;
2554 void
2555 EHCI::FreeDescriptor(ehci_itd *descriptor)
2557 if (!descriptor)
2558 return;
2560 fStack->FreeChunk(descriptor, (phys_addr_t)descriptor->this_phy,
2561 sizeof(ehci_itd));
2565 void
2566 EHCI::FreeDescriptor(ehci_sitd *descriptor)
2568 if (!descriptor)
2569 return;
2571 fStack->FreeChunk(descriptor, (phys_addr_t)descriptor->this_phy,
2572 sizeof(ehci_sitd));
2576 void
2577 EHCI::LinkDescriptors(ehci_qtd *first, ehci_qtd *last, ehci_qtd *alt)
2579 first->next_phy = last->this_phy;
2580 first->next_log = last;
2582 if (alt) {
2583 first->alt_next_phy = alt->this_phy;
2584 first->alt_next_log = alt;
2585 } else {
2586 first->alt_next_phy = EHCI_ITEM_TERMINATE;
2587 first->alt_next_log = NULL;
2592 void
2593 EHCI::LinkITDescriptors(ehci_itd *itd, ehci_itd **_last)
2595 ehci_itd *last = *_last;
2596 itd->next_phy = last->next_phy;
2597 itd->next = NULL;
2598 itd->prev = last;
2599 last->next = itd;
2600 last->next_phy = itd->this_phy;
2601 *_last = itd;
2605 void
2606 EHCI::LinkSITDescriptors(ehci_sitd *sitd, ehci_sitd **_last)
2608 ehci_sitd *last = *_last;
2609 sitd->next_phy = last->next_phy;
2610 sitd->next = NULL;
2611 sitd->prev = last;
2612 last->next = sitd;
2613 last->next_phy = sitd->this_phy;
2614 *_last = sitd;
2618 void
2619 EHCI::UnlinkITDescriptors(ehci_itd *itd, ehci_itd **last)
2621 itd->prev->next_phy = itd->next_phy;
2622 itd->prev->next = itd->next;
2623 if (itd->next != NULL)
2624 itd->next->prev = itd->prev;
2625 if (itd == *last)
2626 *last = itd->prev;
2630 void
2631 EHCI::UnlinkSITDescriptors(ehci_sitd *sitd, ehci_sitd **last)
2633 sitd->prev->next_phy = sitd->next_phy;
2634 sitd->prev->next = sitd->next;
2635 if (sitd->next != NULL)
2636 sitd->next->prev = sitd->prev;
2637 if (sitd == *last)
2638 *last = sitd->prev;
2642 size_t
2643 EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
2644 size_t vectorCount)
2646 ehci_qtd *current = topDescriptor;
2647 size_t actualLength = 0;
2648 size_t vectorIndex = 0;
2649 size_t vectorOffset = 0;
2650 size_t bufferOffset = 0;
2652 while (current) {
2653 if (!current->buffer_log)
2654 break;
2656 while (true) {
2657 size_t length = min_c(current->buffer_size - bufferOffset,
2658 vector[vectorIndex].iov_len - vectorOffset);
2660 memcpy((uint8 *)current->buffer_log + bufferOffset,
2661 (uint8 *)vector[vectorIndex].iov_base + vectorOffset, length);
2663 actualLength += length;
2664 vectorOffset += length;
2665 bufferOffset += length;
2667 if (vectorOffset >= vector[vectorIndex].iov_len) {
2668 if (++vectorIndex >= vectorCount) {
2669 TRACE("wrote descriptor chain (%ld bytes, no more vectors)"
2670 "\n", actualLength);
2671 return actualLength;
2674 vectorOffset = 0;
2677 if (bufferOffset >= current->buffer_size) {
2678 bufferOffset = 0;
2679 break;
2683 if (current->next_phy & EHCI_ITEM_TERMINATE)
2684 break;
2686 current = current->next_log;
2689 TRACE("wrote descriptor chain (%ld bytes)\n", actualLength);
2690 return actualLength;
2694 size_t
2695 EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
2696 size_t vectorCount, bool *nextDataToggle)
2698 uint32 dataToggle = 0;
2699 ehci_qtd *current = topDescriptor;
2700 size_t actualLength = 0;
2701 size_t vectorIndex = 0;
2702 size_t vectorOffset = 0;
2703 size_t bufferOffset = 0;
2705 while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) {
2706 if (!current->buffer_log)
2707 break;
2709 dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
2710 size_t bufferSize = current->buffer_size;
2711 bufferSize -= (current->token >> EHCI_QTD_BYTES_SHIFT)
2712 & EHCI_QTD_BYTES_MASK;
2714 while (true) {
2715 size_t length = min_c(bufferSize - bufferOffset,
2716 vector[vectorIndex].iov_len - vectorOffset);
2718 memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
2719 (uint8 *)current->buffer_log + bufferOffset, length);
2721 actualLength += length;
2722 vectorOffset += length;
2723 bufferOffset += length;
2725 if (vectorOffset >= vector[vectorIndex].iov_len) {
2726 if (++vectorIndex >= vectorCount) {
2727 TRACE("read descriptor chain (%ld bytes, no more vectors)"
2728 "\n", actualLength);
2729 *nextDataToggle = dataToggle > 0 ? true : false;
2730 return actualLength;
2733 vectorOffset = 0;
2736 if (bufferOffset >= bufferSize) {
2737 bufferOffset = 0;
2738 break;
2742 if (current->next_phy & EHCI_ITEM_TERMINATE)
2743 break;
2745 current = current->next_log;
2748 TRACE("read descriptor chain (%ld bytes)\n", actualLength);
2749 *nextDataToggle = dataToggle > 0 ? true : false;
2750 return actualLength;
2754 size_t
2755 EHCI::ReadActualLength(ehci_qtd *topDescriptor, bool *nextDataToggle)
2757 size_t actualLength = 0;
2758 ehci_qtd *current = topDescriptor;
2759 uint32 dataToggle = 0;
2761 while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) {
2762 dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
2763 size_t length = current->buffer_size;
2764 length -= (current->token >> EHCI_QTD_BYTES_SHIFT)
2765 & EHCI_QTD_BYTES_MASK;
2766 actualLength += length;
2768 if (current->next_phy & EHCI_ITEM_TERMINATE)
2769 break;
2771 current = current->next_log;
2774 TRACE("read actual length (%ld bytes)\n", actualLength);
2775 *nextDataToggle = dataToggle > 0 ? true : false;
2776 return actualLength;
2780 size_t
2781 EHCI::WriteIsochronousDescriptorChain(isochronous_transfer_data *transfer,
2782 uint32 packetCount, iovec *vector)
2784 // TODO implement
2785 return 0;
2789 size_t
2790 EHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer)
2792 iovec *vector = transfer->transfer->Vector();
2793 size_t vectorCount = transfer->transfer->VectorCount();
2794 size_t vectorOffset = 0;
2795 size_t vectorIndex = 0;
2796 usb_isochronous_data *isochronousData
2797 = transfer->transfer->IsochronousData();
2798 uint32 packet = 0;
2799 size_t totalLength = 0;
2800 size_t bufferOffset = 0;
2802 size_t packetSize = transfer->transfer->DataLength();
2803 packetSize /= isochronousData->packet_count;
2805 for (uint32 i = 0; i <= transfer->last_to_process; i++) {
2806 ehci_itd *itd = transfer->descriptors[i];
2807 for (uint32 j = 0; j <= itd->last_token
2808 && packet < isochronousData->packet_count; j++) {
2810 size_t bufferSize = (itd->token[j] >> EHCI_ITD_TLENGTH_SHIFT)
2811 & EHCI_ITD_TLENGTH_MASK;
2812 if (((itd->token[j] >> EHCI_ITD_STATUS_SHIFT)
2813 & EHCI_ITD_STATUS_MASK) != 0) {
2814 bufferSize = 0;
2816 isochronousData->packet_descriptors[packet].actual_length
2817 = bufferSize;
2819 if (bufferSize > 0)
2820 isochronousData->packet_descriptors[packet].status = B_OK;
2821 else
2822 isochronousData->packet_descriptors[packet].status = B_ERROR;
2824 totalLength += bufferSize;
2826 size_t offset = bufferOffset;
2827 size_t skipSize = packetSize - bufferSize;
2828 while (bufferSize > 0) {
2829 size_t length = min_c(bufferSize,
2830 vector[vectorIndex].iov_len - vectorOffset);
2831 memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
2832 (uint8 *)transfer->buffer_log + bufferOffset, length);
2833 offset += length;
2834 vectorOffset += length;
2835 bufferSize -= length;
2837 if (vectorOffset >= vector[vectorIndex].iov_len) {
2838 if (++vectorIndex >= vectorCount) {
2839 TRACE("read isodescriptor chain (%ld bytes, no more "
2840 "vectors)\n", totalLength);
2841 return totalLength;
2844 vectorOffset = 0;
2848 // skip to next packet offset
2849 while (skipSize > 0) {
2850 size_t length = min_c(skipSize,
2851 vector[vectorIndex].iov_len - vectorOffset);
2852 vectorOffset += length;
2853 skipSize -= length;
2854 if (vectorOffset >= vector[vectorIndex].iov_len) {
2855 if (++vectorIndex >= vectorCount) {
2856 TRACE("read isodescriptor chain (%ld bytes, no more "
2857 "vectors)\n", totalLength);
2858 return totalLength;
2861 vectorOffset = 0;
2865 bufferOffset += packetSize;
2866 if (bufferOffset >= transfer->buffer_size)
2867 return totalLength;
2869 packet++;
2873 TRACE("ReadIsochronousDescriptorChain packet count %" B_PRId32 "\n",
2874 packet);
2876 return totalLength;
2880 bool
2881 EHCI::LockIsochronous()
2883 return (mutex_lock(&fIsochronousLock) == B_OK);
2887 void
2888 EHCI::UnlockIsochronous()
2890 mutex_unlock(&fIsochronousLock);
2894 inline void
2895 EHCI::WriteOpReg(uint32 reg, uint32 value)
2897 *(volatile uint32 *)(fOperationalRegisters + reg) = value;
2901 inline uint32
2902 EHCI::ReadOpReg(uint32 reg)
2904 return *(volatile uint32 *)(fOperationalRegisters + reg);
2908 inline uint8
2909 EHCI::ReadCapReg8(uint32 reg)
2911 return *(volatile uint8 *)(fCapabilityRegisters + reg);
2915 inline uint16
2916 EHCI::ReadCapReg16(uint32 reg)
2918 return *(volatile uint16 *)(fCapabilityRegisters + reg);
2922 inline uint32
2923 EHCI::ReadCapReg32(uint32 reg)
2925 return *(volatile uint32 *)(fCapabilityRegisters + reg);