2 * Copyright 2006-2011, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
6 * Michael Lotz <mmlr@mlotz.ch>
7 * Jérôme Duval <korli@users.berlios.de>
11 #include <driver_settings.h>
16 #include <KernelExport.h>
20 #define USB_MODULE_NAME "ehci"
22 pci_module_info
*EHCI::sPCIModule
= NULL
;
23 pci_x86_module_info
*EHCI::sPCIx86Module
= NULL
;
27 ehci_std_ops(int32 op
, ...)
31 TRACE_MODULE("ehci init module\n");
34 TRACE_MODULE("ehci uninit module\n");
42 usb_host_controller_info ehci_module
= {
53 module_info
*modules
[] = {
54 (module_info
*)&ehci_module
,
67 print_descriptor_chain(ehci_qtd
*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
)
82 descriptor
= descriptor
->next_log
;
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
);
113 EHCI::EHCI(pci_info
*info
, Stack
*stack
)
115 fCapabilityRegisters(NULL
),
116 fOperationalRegisters(NULL
),
120 fEnabledInterrupts(0),
122 fPeriodicFrameListArea(-1),
123 fPeriodicFrameList(NULL
),
124 fInterruptEntries(NULL
),
127 fAsyncQueueHead(NULL
),
128 fAsyncAdvanceSem(-1),
129 fFirstTransfer(NULL
),
131 fFinishTransfersSem(-1),
133 fProcessingPipe(NULL
),
138 fNextStartingFrame(-1),
139 fFrameBandwidth(NULL
),
140 fFirstIsochronousTransfer(NULL
),
141 fLastIsochronousTransfer(NULL
),
142 fFinishIsochronousTransfersSem(-1),
143 fFinishIsochronousThread(-1),
148 fPortSuspendChange(0),
149 fInterruptPollThread(-1),
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");
161 TRACE("constructing new EHCI host controller driver\n");
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
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;
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
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
);
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");
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
)))
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",
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"
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)
277 TRACE_ALWAYS("controller is still bios owned, waiting\n");
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
) {
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);
299 "extended capability is not a legacy support register\n");
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");
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");
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");
339 // Create the isochronous finisher service thread
340 fFinishIsochronousThread
= spawn_kernel_thread(FinishIsochronousThread
,
341 "ehci isochronous finish thread", B_URGENT_DISPLAY_PRIORITY
,
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,
356 unload_driver_settings(settings
);
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
);
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) {
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");
381 // install the interrupt handler and enable interrupts
382 install_io_interrupt_handler(fIRQ
, InterruptHandler
,
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
;
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
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");
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
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
),
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
,
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
,
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
;
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");
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
));
559 TRACE("EHCI host controller driver constructed\n");
565 TRACE("tear down EHCI host controller driver\n");
567 WriteOpReg(EHCI_USBCMD
, 0);
568 WriteOpReg(EHCI_CONFIGFLAG
, 0);
569 CancelAllPendingTransfers();
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
);
583 remove_io_interrupt_handler(fIRQ
, InterruptHandler
, (void *)this);
586 isochronous_transfer_data
*isoTransfer
= fFirstIsochronousTransfer
;
587 while (isoTransfer
) {
588 isochronous_transfer_data
*next
= isoTransfer
->link
;
592 mutex_destroy(&fIsochronousLock
);
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
);
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
) {
640 TRACE("frame list size 1024\n");
643 TRACE("frame list size 512\n");
646 TRACE("frame list size 256\n");
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
) {
666 TRACE_ERROR("host controller didn't start\n");
670 // route all ports to us
671 WriteOpReg(EHCI_CONFIGFLAG
, EHCI_CONFIGFLAG_FLAG
);
674 fRootHubAddress
= AllocateAddress();
675 fRootHub
= new(std::nothrow
) EHCIRootHub(RootObject(), fRootHubAddress
);
677 TRACE_ERROR("no memory to allocate root hub\n");
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();
694 EHCI::StartDebugTransfer(Transfer
*transfer
)
696 static transfer_data transferData
;
698 transferData
.queue_head
= CreateQueueHead();
699 if (transferData
.queue_head
== NULL
)
702 Pipe
*pipe
= transfer
->TransferPipe();
703 status_t result
= InitQueueHead(transferData
.queue_head
, pipe
);
704 if (result
!= B_OK
) {
705 FreeQueueHead(transferData
.queue_head
);
709 if ((pipe
->Type() & USB_OBJECT_CONTROL_PIPE
) != 0) {
710 result
= FillQueueWithRequest(transfer
, transferData
.queue_head
,
711 &transferData
.data_descriptor
, &transferData
.incoming
);
713 result
= FillQueueWithData(transfer
, transferData
.queue_head
,
714 &transferData
.data_descriptor
, &transferData
.incoming
);
717 if (result
!= B_OK
) {
718 FreeQueueHead(transferData
.queue_head
);
722 if ((pipe
->Type() & USB_OBJECT_INTERRUPT_PIPE
) != 0)
723 LinkPeriodicDebugQueueHead(transferData
.queue_head
, pipe
);
725 LinkAsyncDebugQueueHead(transferData
.queue_head
);
727 // we abuse the callback cookie to hold our transfer data
728 transfer
->SetCallback(NULL
, &transferData
);
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
;
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
);
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
;
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
;
776 uint32 status
= descriptor
->token
;
777 if ((status
& EHCI_QTD_STATUS_ACTIVE
) != 0) {
782 if ((status
& EHCI_QTD_STATUS_ERRMASK
) != 0) {
783 transferError
= true;
787 if ((descriptor
->next_phy
& EHCI_ITEM_TERMINATE
) != 0) {
788 // we arrived at the last (stray) descriptor, we're done
793 if (((status
>> EHCI_QTD_PID_SHIFT
) & EHCI_QTD_PID_MASK
)
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
;
806 descriptor
= descriptor
->next_log
;
809 if (!transferOK
&& !transferError
) {
811 return B_DEV_PENDING
;
815 bool nextDataToggle
= false;
816 if (transferData
->data_descriptor
!= NULL
&& transferData
->incoming
) {
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
;
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
);
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.
874 FreeQueueHead(queueHead
);
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();
891 TRACE_ERROR("failed to allocate queue head\n");
895 status_t result
= InitQueueHead(queueHead
, pipe
);
896 if (result
!= B_OK
) {
897 TRACE_ERROR("failed to init queue head\n");
898 FreeQueueHead(queueHead
);
903 ehci_qtd
*dataDescriptor
;
904 if ((pipe
->Type() & USB_OBJECT_CONTROL_PIPE
) != 0) {
905 result
= FillQueueWithRequest(transfer
, queueHead
, &dataDescriptor
,
908 result
= FillQueueWithData(transfer
, queueHead
, &dataDescriptor
,
912 if (result
!= B_OK
) {
913 TRACE_ERROR("failed to fill transfer queue with data\n");
914 FreeQueueHead(queueHead
);
918 result
= AddPendingTransfer(transfer
, queueHead
, dataDescriptor
,
920 if (result
!= B_OK
) {
921 TRACE_ERROR("failed to add pending transfer\n");
922 FreeQueueHead(queueHead
);
927 TRACE("linking queue\n");
928 print_queue(queueHead
);
931 if ((pipe
->Type() & USB_OBJECT_INTERRUPT_PIPE
) != 0)
932 result
= LinkInterruptQueueHead(queueHead
, pipe
);
934 result
= LinkQueueHead(queueHead
);
936 if (result
!= B_OK
) {
937 TRACE_ERROR("failed to link queue head\n");
938 FreeQueueHead(queueHead
);
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();
954 size_t restSize
= packetSize
% isochronousData
->packet_count
;
956 packetSize
/= isochronousData
->packet_count
;
959 if (packetSize
> pipe
->MaxPacketSize()) {
961 "isochronous packetSize is bigger than pipe MaxPacketSize\n");
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");
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
,
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
;
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);
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;
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();
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
;
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
;
1038 itd
->buffer_phy
[pg
] = currentPhy
& 0xfffff000;
1039 uint32 offset
= currentPhy
& 0xfff;
1040 TRACE("isochronous created itd, filling it with phy %" B_PRIxPHYSADDR
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
,
1050 dataLength
-= 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;
1058 if (dataLength
<= 0)
1059 itd
->token
[i
] |= EHCI_ITD_IOC
;
1062 currentPhy
+= (offset
& 0xfff) - (currentPhy
& 0xfff);
1065 |= (pipe
->EndpointAddress() << EHCI_ITD_ENDPOINT_SHIFT
)
1066 | (pipe
->DeviceAddress() << EHCI_ITD_ADDRESS_SHIFT
);
1068 |= (pipe
->MaxPacketSize() & EHCI_ITD_MAXPACKETSIZE_MASK
)
1069 | (directionIn
<< EHCI_ITD_DIR_SHIFT
);
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())
1080 LinkITDescriptors(itd
, &fItdEntries
[currentFrame
]);
1081 UnlockIsochronous();
1082 fFrameBandwidth
[currentFrame
] -= bandwidth
;
1083 currentFrame
= (currentFrame
+ 1) & (EHCI_VFRAMELIST_ENTRIES_COUNT
- 1);
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
;
1101 TRACE("appended isochronous transfer by starting at frame number %d\n",
1103 fNextStartingFrame
= currentFrame
+ 1;
1105 // Wake up the isochronous finisher thread
1106 release_sem_etc(fFinishIsochronousTransfersSem
, 1 /*frameCount*/,
1107 B_DO_NOT_RESCHEDULE
);
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
;
1119 while (transfer
->descriptors
[transfer
->last_to_process
]
1121 transfer
= transfer
->link
;
1131 EHCI::NotifyPipeChange(Pipe
*pipe
, usb_change change
)
1133 TRACE("pipe change %d for pipe %p\n", change
, pipe
);
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
1142 case USB_CHANGE_PIPE_POLICY_CHANGED
: {
1143 // ToDo: for isochronous pipes we might need to adapt to new
1144 // pipe policy settings here
1154 EHCI::AddTo(Stack
*stack
)
1157 set_dprintf_enabled(true);
1158 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
1159 load_driver_symbols("ehci");
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
1173 TRACE_MODULE("searching devices\n");
1175 pci_info
*item
= new(std::nothrow
) pci_info
;
1178 put_module(B_PCI_MODULE_NAME
);
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");
1200 TRACE_MODULE("found device at IRQ %u\n", item
->u
.h0
.interrupt_line
);
1201 EHCI
*bus
= new(std::nothrow
) EHCI(item
, stack
);
1205 put_module(B_PCI_MODULE_NAME
);
1206 if (sPCIx86Module
!= NULL
) {
1207 sPCIx86Module
= NULL
;
1208 put_module(B_PCI_X86_MODULE_NAME
);
1213 if (bus
->InitCheck() != B_OK
) {
1214 TRACE_MODULE_ERROR("bus failed init check\n");
1219 // the bus took it away
1220 item
= new(std::nothrow
) pci_info
;
1223 stack
->AddBusManager(bus
);
1229 TRACE_MODULE_ERROR("no devices found\n");
1232 put_module(B_PCI_MODULE_NAME
);
1233 if (sPCIx86Module
!= NULL
) {
1234 sPCIx86Module
= NULL
;
1235 put_module(B_PCI_X86_MODULE_NAME
);
1246 EHCI::GetPortStatus(uint8 index
, usb_port_status
*status
)
1248 if (index
>= fPortCount
)
1251 status
->status
= status
->change
= 0;
1252 uint32 portStatus
= ReadOpReg(EHCI_PORTSC
+ index
* sizeof(uint32
));
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
;
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
;
1291 EHCI::SetPortFeature(uint8 index
, uint16 feature
)
1293 if (index
>= fPortCount
)
1296 uint32 portRegister
= EHCI_PORTSC
+ index
* sizeof(uint32
);
1297 uint32 portStatus
= ReadOpReg(portRegister
) & EHCI_PORTSC_DATAMASK
;
1301 return SuspendPort(index
);
1304 return ResetPort(index
);
1307 WriteOpReg(portRegister
, portStatus
| EHCI_PORTSC_PORTPOWER
);
1316 EHCI::ClearPortFeature(uint8 index
, uint16 feature
)
1318 if (index
>= fPortCount
)
1321 uint32 portRegister
= EHCI_PORTSC
+ index
* sizeof(uint32
);
1322 uint32 portStatus
= ReadOpReg(portRegister
) & EHCI_PORTSC_DATAMASK
;
1326 WriteOpReg(portRegister
, portStatus
& ~EHCI_PORTSC_ENABLE
);
1330 WriteOpReg(portRegister
, portStatus
& ~EHCI_PORTSC_PORTPOWER
);
1333 case C_PORT_CONNECTION
:
1334 WriteOpReg(portRegister
, portStatus
| EHCI_PORTSC_CONNCHANGE
);
1338 WriteOpReg(portRegister
, portStatus
| EHCI_PORTSC_ENABLECHANGE
);
1341 case C_PORT_OVER_CURRENT
:
1342 WriteOpReg(portRegister
, portStatus
| EHCI_PORTSC_OCCHANGE
);
1346 fPortResetChange
&= ~(1 << index
);
1349 case C_PORT_SUSPEND
:
1350 fPortSuspendChange
&= ~(1 << index
);
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
);
1374 // enable reset signaling
1375 WriteOpReg(portRegister
, (portStatus
& ~EHCI_PORTSC_ENABLE
)
1376 | EHCI_PORTSC_PORTRESET
);
1379 // disable reset signaling
1380 portStatus
= ReadOpReg(portRegister
) & EHCI_PORTSC_DATAMASK
;
1381 WriteOpReg(portRegister
, portStatus
& ~EHCI_PORTSC_PORTRESET
);
1384 portStatus
= ReadOpReg(portRegister
) & EHCI_PORTSC_DATAMASK
;
1385 if (portStatus
& EHCI_PORTSC_PORTRESET
) {
1386 TRACE_ERROR("port reset won't complete\n");
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
);
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
);
1414 EHCI::ControllerReset()
1416 // halt the controller first
1417 WriteOpReg(EHCI_USBCMD
, 0);
1421 WriteOpReg(EHCI_USBCMD
, EHCI_USBCMD_HCRESET
);
1424 while (ReadOpReg(EHCI_USBCMD
) & EHCI_USBCMD_HCRESET
) {
1442 EHCI::InterruptHandler(void *data
)
1444 return ((EHCI
*)data
)->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) {
1458 TRACE("discarding not enabled interrupts 0x%08" B_PRIx32
"\n",
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
);
1502 release_sem_etc(fAsyncAdvanceSem
, 1, B_DO_NOT_RESCHEDULE
);
1503 if (finishTransfers
)
1504 release_sem_etc(fFinishTransfersSem
, 1, B_DO_NOT_RESCHEDULE
);
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...
1520 cpu_status status
= disable_interrupts();
1522 restore_interrupts(status
);
1530 EHCI::AddPendingTransfer(Transfer
*transfer
, ehci_qh
*queueHead
,
1531 ehci_qtd
*dataDescriptor
, bool directionIn
)
1533 transfer_data
*data
= new(std::nothrow
) transfer_data
;
1537 status_t result
= transfer
->InitKernelAccess();
1538 if (result
!= B_OK
) {
1543 data
->transfer
= transfer
;
1544 data
->queue_head
= queueHead
;
1545 data
->data_descriptor
= dataDescriptor
;
1546 data
->incoming
= directionIn
;
1547 data
->canceled
= false;
1556 fLastTransfer
->link
= data
;
1558 fFirstTransfer
= data
;
1560 fLastTransfer
= data
;
1568 EHCI::AddPendingIsochronousTransfer(Transfer
*transfer
, ehci_itd
**isoRequest
,
1569 uint32 lastIndex
, bool directionIn
, addr_t bufferPhy
, void* bufferLog
,
1572 if (!transfer
|| !isoRequest
)
1575 isochronous_transfer_data
*data
1576 = new(std::nothrow
) isochronous_transfer_data
;
1580 status_t result
= transfer
->InitKernelAccess();
1581 if (result
!= B_OK
) {
1586 data
->transfer
= transfer
;
1587 data
->descriptors
= isoRequest
;
1588 data
->last_to_process
= lastIndex
;
1589 data
->incoming
= directionIn
;
1590 data
->is_active
= true;
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()) {
1602 if (fLastIsochronousTransfer
)
1603 fLastIsochronousTransfer
->link
= data
;
1604 else if (!fFirstIsochronousTransfer
)
1605 fFirstIsochronousTransfer
= data
;
1607 fLastIsochronousTransfer
= data
;
1608 UnlockIsochronous();
1614 EHCI::CancelQueuedTransfers(Pipe
*pipe
, bool force
)
1616 if ((pipe
->Type() & USB_OBJECT_ISO_PIPE
) != 0)
1617 return CancelQueuedIsochronousTransfers(pipe
, force
);
1622 struct transfer_entry
{
1623 Transfer
* transfer
;
1624 transfer_entry
* next
;
1627 transfer_entry
*list
= NULL
;
1628 transfer_data
*current
= fFirstTransfer
;
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
;
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
;
1652 current
->canceled
= true;
1655 current
= current
->link
;
1660 while (list
!= NULL
) {
1661 transfer_entry
*next
= list
->next
;
1662 list
->transfer
->Finished(B_CANCELED
, 0);
1663 delete list
->transfer
;
1668 // wait for any transfers that might have made it before canceling
1669 while (fProcessingPipe
== pipe
)
1672 // notify the finisher so it can clean up the canceled transfers
1673 release_sem_etc(fFinishTransfersSem
, 1, B_DO_NOT_RESCHEDULE
);
1679 EHCI::CancelQueuedIsochronousTransfers(Pipe
*pipe
, bool force
)
1681 isochronous_transfer_data
*current
= fFirstIsochronousTransfer
;
1684 if (current
->transfer
->TransferPipe() == pipe
) {
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");
1701 EHCI::CancelAllPendingTransfers()
1706 transfer_data
*transfer
= fFirstTransfer
;
1708 transfer
->transfer
->Finished(B_CANCELED
, 0);
1709 delete transfer
->transfer
;
1711 transfer_data
*next
= transfer
->link
;
1716 fFirstTransfer
= NULL
;
1717 fLastTransfer
= NULL
;
1724 EHCI::FinishThread(void *data
)
1726 ((EHCI
*)data
)->FinishTransfers();
1732 EHCI::FinishTransfers()
1734 while (!fStopThreads
) {
1735 if (acquire_sem(fFinishTransfersSem
) != B_OK
)
1738 // eat up sems that have been released by multiple interrupts
1740 get_sem_count(fFinishTransfersSem
, &semCount
);
1742 acquire_sem_etc(fFinishTransfersSem
, semCount
, B_RELATIVE_TIMEOUT
,
1749 TRACE("finishing transfers\n");
1750 transfer_data
*lastTransfer
= NULL
;
1751 transfer_data
*transfer
= fFirstTransfer
;
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
);
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
1778 if (status
& EHCI_QTD_STATUS_BUFFER
) {
1779 callbackStatus
= transfer
->incoming
1780 ? B_DEV_DATA_OVERRUN
: B_DEV_DATA_UNDERRUN
;
1783 if (status
& EHCI_QTD_STATUS_TERROR
) {
1784 callbackStatus
= B_DEV_CRC_ERROR
;
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
;
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
;
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;
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;
1829 if (((status
>> EHCI_QTD_PID_SHIFT
) & EHCI_QTD_PID_MASK
)
1831 && ((status
>> EHCI_QTD_BYTES_SHIFT
) & EHCI_QTD_BYTES_MASK
)
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
;
1840 // no alternate next, transfer is done
1841 callbackStatus
= B_OK
;
1842 transferDone
= true;
1846 descriptor
= descriptor
->next_log
;
1849 if (!transferDone
) {
1850 lastTransfer
= transfer
;
1851 transfer
= transfer
->link
;
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
;
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
;
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
) {
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
,
1891 } else if (transfer
->data_descriptor
) {
1892 // calculate transfered length
1893 actualLength
= ReadActualLength(
1894 transfer
->data_descriptor
, &nextDataToggle
);
1897 transfer
->transfer
->TransferPipe()->SetDataToggle(
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(
1908 transfer
->queue_head
,
1909 &transfer
->data_descriptor
, NULL
);
1911 if (result
== B_OK
&& Lock()) {
1912 // reappend the transfer
1914 fLastTransfer
->link
= transfer
;
1915 if (!fFirstTransfer
)
1916 fFirstTransfer
= transfer
;
1918 fLastTransfer
= transfer
;
1926 // the transfer is done, but we already set the
1927 // actualLength with AdvanceByFragment()
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
;
1941 release_sem(fCleanupSem
);
1948 EHCI::CleanupThread(void *data
)
1950 ((EHCI
*)data
)->Cleanup();
1958 ehci_qh
*lastFreeListHead
= NULL
;
1960 while (!fStopThreads
) {
1961 if (acquire_sem(fCleanupSem
) != B_OK
)
1964 ehci_qh
*freeListHead
= fFreeListHead
;
1965 if (freeListHead
== lastFreeListHead
)
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
)
1973 ehci_qh
*current
= freeListHead
;
1974 while (current
!= lastFreeListHead
) {
1975 ehci_qh
*next
= current
->next_log
;
1976 FreeQueueHead(current
);
1980 lastFreeListHead
= freeListHead
;
1986 EHCI::FinishIsochronousThread(void *data
)
1988 ((EHCI
*)data
)->FinishIsochronousTransfers();
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
)
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);
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
2017 while (currentFrame
== (((ReadOpReg(EHCI_FRINDEX
) / 8)
2018 & (EHCI_VFRAMELIST_ENTRIES_COUNT
- 1)))) {
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())
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
;
2068 isochronous_transfer_data
*temp
2069 = fFirstIsochronousTransfer
;
2070 while (temp
!= NULL
&& transfer
!= 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
);
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
);
2095 transferDone
= true;
2097 TRACE("FinishIsochronousTransfers not end of transfer\n");
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
;
2115 EHCI::CreateQueueHead()
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");
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);
2132 TRACE_ERROR("failed to allocate initial qtd for queue head\n");
2133 fStack
->FreeChunk(result
, physicalAddress
, sizeof(ehci_qh
));
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;
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
;
2160 case USB_SPEED_FULLSPEED
:
2161 queueHead
->endpoint_chars
= EHCI_QH_CHARS_EPS_FULL
;
2163 case USB_SPEED_HIGHSPEED
:
2164 queueHead
->endpoint_chars
= EHCI_QH_CHARS_EPS_HIGH
;
2167 TRACE_ERROR("unknown pipe speed\n");
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
);
2191 EHCI::FreeQueueHead(ehci_qh
*queueHead
)
2196 FreeDescriptorChain(queueHead
->element_log
);
2197 FreeDescriptor(queueHead
->stray_log
);
2198 fStack
->FreeChunk(queueHead
, (phys_addr_t
)queueHead
->this_phy
,
2204 EHCI::LinkQueueHead(ehci_qh
*queueHead
)
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
;
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
);
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
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
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
;
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
;
2271 EHCI::UnlinkQueueHead(ehci_qh
*queueHead
, ehci_qh
**freeListHead
)
2276 ehci_qh
*prevHead
= queueHead
->prev_log
;
2277 ehci_qh
*nextHead
= queueHead
->next_log
;
2279 prevHead
->next_phy
= queueHead
->next_phy
;
2280 prevHead
->next_log
= queueHead
->next_log
;
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
;
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
);
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
);
2339 WriteDescriptorChain(dataDescriptor
, transfer
->Vector(),
2340 transfer
->VectorCount());
2343 LinkDescriptors(setupDescriptor
, dataDescriptor
, strayDescriptor
);
2344 LinkDescriptors(lastDescriptor
, statusDescriptor
, statusDescriptor
);
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
;
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
);
2377 lastDescriptor
->token
|= EHCI_QTD_IOC
;
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
;
2389 *_directionIn
= directionIn
;
2395 EHCI::CreateDescriptor(size_t bufferSize
, uint8 pid
)
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");
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;
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
,
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;
2447 EHCI::CreateDescriptorChain(Pipe
*pipe
, ehci_qtd
**_firstDescriptor
,
2448 ehci_qtd
**_lastDescriptor
, ehci_qtd
*strayDescriptor
, size_t bufferSize
,
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
),
2462 FreeDescriptorChain(firstDescriptor
);
2467 descriptor
->token
|= EHCI_QTD_DATA_TOGGLE
;
2470 LinkDescriptors(lastDescriptor
, descriptor
, strayDescriptor
);
2472 bufferSize
-= packetSize
;
2473 lastDescriptor
= descriptor
;
2474 if (!firstDescriptor
)
2475 firstDescriptor
= descriptor
;
2478 *_firstDescriptor
= firstDescriptor
;
2479 *_lastDescriptor
= lastDescriptor
;
2485 EHCI::FreeDescriptor(ehci_qtd
*descriptor
)
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
,
2501 EHCI::FreeDescriptorChain(ehci_qtd
*topDescriptor
)
2503 ehci_qtd
*current
= topDescriptor
;
2504 ehci_qtd
*next
= NULL
;
2507 next
= current
->next_log
;
2508 FreeDescriptor(current
);
2515 EHCI::CreateItdDescriptor()
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");
2525 memset(result
, 0, sizeof(ehci_itd
));
2526 result
->this_phy
= (addr_t
)physicalAddress
;
2527 result
->next_phy
= EHCI_ITEM_TERMINATE
;
2534 EHCI::CreateSitdDescriptor()
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");
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
;
2553 EHCI::FreeDescriptor(ehci_itd
*descriptor
)
2558 fStack
->FreeChunk(descriptor
, (phys_addr_t
)descriptor
->this_phy
,
2564 EHCI::FreeDescriptor(ehci_sitd
*descriptor
)
2569 fStack
->FreeChunk(descriptor
, (phys_addr_t
)descriptor
->this_phy
,
2575 EHCI::LinkDescriptors(ehci_qtd
*first
, ehci_qtd
*last
, ehci_qtd
*alt
)
2577 first
->next_phy
= last
->this_phy
;
2578 first
->next_log
= last
;
2581 first
->alt_next_phy
= alt
->this_phy
;
2582 first
->alt_next_log
= alt
;
2584 first
->alt_next_phy
= EHCI_ITEM_TERMINATE
;
2585 first
->alt_next_log
= NULL
;
2591 EHCI::LinkITDescriptors(ehci_itd
*itd
, ehci_itd
**_last
)
2593 ehci_itd
*last
= *_last
;
2594 itd
->next_phy
= last
->next_phy
;
2598 last
->next_phy
= itd
->this_phy
;
2604 EHCI::LinkSITDescriptors(ehci_sitd
*sitd
, ehci_sitd
**_last
)
2606 ehci_sitd
*last
= *_last
;
2607 sitd
->next_phy
= last
->next_phy
;
2611 last
->next_phy
= sitd
->this_phy
;
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
;
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
;
2641 EHCI::WriteDescriptorChain(ehci_qtd
*topDescriptor
, iovec
*vector
,
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;
2651 if (!current
->buffer_log
)
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
;
2675 if (bufferOffset
>= current
->buffer_size
) {
2681 if (current
->next_phy
& EHCI_ITEM_TERMINATE
)
2684 current
= current
->next_log
;
2687 TRACE("wrote descriptor chain (%ld bytes)\n", actualLength
);
2688 return actualLength
;
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
)
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
;
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
;
2734 if (bufferOffset
>= bufferSize
) {
2740 if (current
->next_phy
& EHCI_ITEM_TERMINATE
)
2743 current
= current
->next_log
;
2746 TRACE("read descriptor chain (%ld bytes)\n", actualLength
);
2747 *nextDataToggle
= dataToggle
> 0 ? true : false;
2748 return actualLength
;
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
)
2769 current
= current
->next_log
;
2772 TRACE("read actual length (%ld bytes)\n", actualLength
);
2773 *nextDataToggle
= dataToggle
> 0 ? true : false;
2774 return actualLength
;
2779 EHCI::WriteIsochronousDescriptorChain(isochronous_transfer_data
*transfer
,
2780 uint32 packetCount
, iovec
*vector
)
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();
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) {
2814 isochronousData
->packet_descriptors
[packet
].actual_length
2818 isochronousData
->packet_descriptors
[packet
].status
= B_OK
;
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
);
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
);
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
;
2852 if (vectorOffset
>= vector
[vectorIndex
].iov_len
) {
2853 if (++vectorIndex
>= vectorCount
) {
2854 TRACE("read isodescriptor chain (%ld bytes, no more "
2855 "vectors)\n", totalLength
);
2863 bufferOffset
+= packetSize
;
2864 if (bufferOffset
>= transfer
->buffer_size
)
2871 TRACE("ReadIsochronousDescriptorChain packet count %" B_PRId32
"\n",
2879 EHCI::LockIsochronous()
2881 return (mutex_lock(&fIsochronousLock
) == B_OK
);
2886 EHCI::UnlockIsochronous()
2888 mutex_unlock(&fIsochronousLock
);
2893 EHCI::WriteOpReg(uint32 reg
, uint32 value
)
2895 *(volatile uint32
*)(fOperationalRegisters
+ reg
) = value
;
2900 EHCI::ReadOpReg(uint32 reg
)
2902 return *(volatile uint32
*)(fOperationalRegisters
+ reg
);
2907 EHCI::ReadCapReg8(uint32 reg
)
2909 return *(volatile uint8
*)(fCapabilityRegisters
+ reg
);
2914 EHCI::ReadCapReg16(uint32 reg
)
2916 return *(volatile uint16
*)(fCapabilityRegisters
+ reg
);
2921 EHCI::ReadCapReg32(uint32 reg
)
2923 return *(volatile uint32
*)(fCapabilityRegisters
+ reg
);