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
< B_OK
) {
231 TRACE("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
< B_OK
|| fAsyncAdvanceSem
< B_OK
322 || fCleanupSem
< B_OK
) {
323 TRACE_ERROR("failed to create semaphores\n");
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");
340 // Create the isochronous finisher service thread
341 fFinishIsochronousThread
= spawn_kernel_thread(FinishIsochronousThread
,
342 "ehci isochronous finish thread", B_URGENT_DISPLAY_PRIORITY
,
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,
357 unload_driver_settings(settings
);
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
);
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) {
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");
382 // install the interrupt handler and enable interrupts
383 install_io_interrupt_handler(fIRQ
, InterruptHandler
,
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
;
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
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");
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
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
),
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
,
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
,
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
;
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");
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
));
561 TRACE("EHCI host controller driver constructed\n");
567 TRACE("tear down EHCI host controller driver\n");
569 WriteOpReg(EHCI_USBCMD
, 0);
570 WriteOpReg(EHCI_CONFIGFLAG
, 0);
571 CancelAllPendingTransfers();
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
);
585 remove_io_interrupt_handler(fIRQ
, InterruptHandler
, (void *)this);
588 isochronous_transfer_data
*isoTransfer
= fFirstIsochronousTransfer
;
589 while (isoTransfer
) {
590 isochronous_transfer_data
*next
= isoTransfer
->link
;
594 mutex_destroy(&fIsochronousLock
);
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
);
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
) {
642 TRACE("frame list size 1024\n");
645 TRACE("frame list size 512\n");
648 TRACE("frame list size 256\n");
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
) {
668 TRACE_ERROR("host controller didn't start\n");
672 // route all ports to us
673 WriteOpReg(EHCI_CONFIGFLAG
, EHCI_CONFIGFLAG_FLAG
);
676 fRootHubAddress
= AllocateAddress();
677 fRootHub
= new(std::nothrow
) EHCIRootHub(RootObject(), fRootHubAddress
);
679 TRACE_ERROR("no memory to allocate root hub\n");
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();
696 EHCI::StartDebugTransfer(Transfer
*transfer
)
698 static transfer_data transferData
;
700 transferData
.queue_head
= CreateQueueHead();
701 if (transferData
.queue_head
== NULL
)
704 Pipe
*pipe
= transfer
->TransferPipe();
705 status_t result
= InitQueueHead(transferData
.queue_head
, pipe
);
706 if (result
!= B_OK
) {
707 FreeQueueHead(transferData
.queue_head
);
711 if ((pipe
->Type() & USB_OBJECT_CONTROL_PIPE
) != 0) {
712 result
= FillQueueWithRequest(transfer
, transferData
.queue_head
,
713 &transferData
.data_descriptor
, &transferData
.incoming
);
715 result
= FillQueueWithData(transfer
, transferData
.queue_head
,
716 &transferData
.data_descriptor
, &transferData
.incoming
);
719 if (result
!= B_OK
) {
720 FreeQueueHead(transferData
.queue_head
);
724 if ((pipe
->Type() & USB_OBJECT_INTERRUPT_PIPE
) != 0)
725 LinkPeriodicDebugQueueHead(transferData
.queue_head
, pipe
);
727 LinkAsyncDebugQueueHead(transferData
.queue_head
);
729 // we abuse the callback cookie to hold our transfer data
730 transfer
->SetCallback(NULL
, &transferData
);
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
;
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
);
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
;
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
;
778 uint32 status
= descriptor
->token
;
779 if ((status
& EHCI_QTD_STATUS_ACTIVE
) != 0) {
784 if ((status
& EHCI_QTD_STATUS_ERRMASK
) != 0) {
785 transferError
= true;
789 if ((descriptor
->next_phy
& EHCI_ITEM_TERMINATE
) != 0) {
790 // we arrived at the last (stray) descriptor, we're done
795 if (((status
>> EHCI_QTD_PID_SHIFT
) & EHCI_QTD_PID_MASK
)
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
;
808 descriptor
= descriptor
->next_log
;
811 if (!transferOK
&& !transferError
) {
813 return B_DEV_PENDING
;
817 bool nextDataToggle
= false;
818 if (transferData
->data_descriptor
!= NULL
&& transferData
->incoming
) {
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
;
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
);
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.
876 FreeQueueHead(queueHead
);
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();
893 TRACE_ERROR("failed to allocate queue head\n");
897 status_t result
= InitQueueHead(queueHead
, pipe
);
899 TRACE_ERROR("failed to init queue head\n");
900 FreeQueueHead(queueHead
);
905 ehci_qtd
*dataDescriptor
;
906 if ((pipe
->Type() & USB_OBJECT_CONTROL_PIPE
) != 0) {
907 result
= FillQueueWithRequest(transfer
, queueHead
, &dataDescriptor
,
910 result
= FillQueueWithData(transfer
, queueHead
, &dataDescriptor
,
915 TRACE_ERROR("failed to fill transfer queue with data\n");
916 FreeQueueHead(queueHead
);
920 result
= AddPendingTransfer(transfer
, queueHead
, dataDescriptor
,
923 TRACE_ERROR("failed to add pending transfer\n");
924 FreeQueueHead(queueHead
);
929 TRACE("linking queue\n");
930 print_queue(queueHead
);
933 if ((pipe
->Type() & USB_OBJECT_INTERRUPT_PIPE
) != 0)
934 result
= LinkInterruptQueueHead(queueHead
, pipe
);
936 result
= LinkQueueHead(queueHead
);
939 TRACE_ERROR("failed to link queue head\n");
940 FreeQueueHead(queueHead
);
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();
956 size_t restSize
= packetSize
% isochronousData
->packet_count
;
958 packetSize
/= isochronousData
->packet_count
;
961 if (packetSize
> pipe
->MaxPacketSize()) {
963 "isochronous packetSize is bigger than pipe MaxPacketSize\n");
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");
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
,
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
;
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);
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;
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();
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
;
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
;
1040 itd
->buffer_phy
[pg
] = currentPhy
& 0xfffff000;
1041 uint32 offset
= currentPhy
& 0xfff;
1042 TRACE("isochronous created itd, filling it with phy %" B_PRIxPHYSADDR
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
,
1052 dataLength
-= 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;
1060 if (dataLength
<= 0)
1061 itd
->token
[i
] |= EHCI_ITD_IOC
;
1064 currentPhy
+= (offset
& 0xfff) - (currentPhy
& 0xfff);
1067 |= (pipe
->EndpointAddress() << EHCI_ITD_ENDPOINT_SHIFT
)
1068 | (pipe
->DeviceAddress() << EHCI_ITD_ADDRESS_SHIFT
);
1070 |= (pipe
->MaxPacketSize() & EHCI_ITD_MAXPACKETSIZE_MASK
)
1071 | (directionIn
<< EHCI_ITD_DIR_SHIFT
);
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())
1082 LinkITDescriptors(itd
, &fItdEntries
[currentFrame
]);
1083 UnlockIsochronous();
1084 fFrameBandwidth
[currentFrame
] -= bandwidth
;
1085 currentFrame
= (currentFrame
+ 1) & (EHCI_VFRAMELIST_ENTRIES_COUNT
- 1);
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
;
1103 TRACE("appended isochronous transfer by starting at frame number %d\n",
1105 fNextStartingFrame
= currentFrame
+ 1;
1107 // Wake up the isochronous finisher thread
1108 release_sem_etc(fFinishIsochronousTransfersSem
, 1 /*frameCount*/,
1109 B_DO_NOT_RESCHEDULE
);
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
;
1121 while (transfer
->descriptors
[transfer
->last_to_process
]
1123 transfer
= transfer
->link
;
1133 EHCI::NotifyPipeChange(Pipe
*pipe
, usb_change change
)
1135 TRACE("pipe change %d for pipe %p\n", change
, pipe
);
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
1144 case USB_CHANGE_PIPE_POLICY_CHANGED
: {
1145 // ToDo: for isochronous pipes we might need to adapt to new
1146 // pipe policy settings here
1156 EHCI::AddTo(Stack
*stack
)
1159 set_dprintf_enabled(true);
1160 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
1161 load_driver_symbols("ehci");
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
1175 TRACE_MODULE("searching devices\n");
1177 pci_info
*item
= new(std::nothrow
) pci_info
;
1180 put_module(B_PCI_MODULE_NAME
);
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");
1202 TRACE_MODULE("found device at IRQ %u\n", item
->u
.h0
.interrupt_line
);
1203 EHCI
*bus
= new(std::nothrow
) EHCI(item
, stack
);
1207 put_module(B_PCI_MODULE_NAME
);
1208 if (sPCIx86Module
!= NULL
) {
1209 sPCIx86Module
= NULL
;
1210 put_module(B_PCI_X86_MODULE_NAME
);
1215 if (bus
->InitCheck() < B_OK
) {
1216 TRACE_MODULE_ERROR("bus failed init check\n");
1221 // the bus took it away
1222 item
= new(std::nothrow
) pci_info
;
1225 stack
->AddBusManager(bus
);
1231 TRACE_MODULE_ERROR("no devices found\n");
1234 put_module(B_PCI_MODULE_NAME
);
1235 if (sPCIx86Module
!= NULL
) {
1236 sPCIx86Module
= NULL
;
1237 put_module(B_PCI_X86_MODULE_NAME
);
1248 EHCI::GetPortStatus(uint8 index
, usb_port_status
*status
)
1250 if (index
>= fPortCount
)
1253 status
->status
= status
->change
= 0;
1254 uint32 portStatus
= ReadOpReg(EHCI_PORTSC
+ index
* sizeof(uint32
));
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
;
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
;
1293 EHCI::SetPortFeature(uint8 index
, uint16 feature
)
1295 if (index
>= fPortCount
)
1298 uint32 portRegister
= EHCI_PORTSC
+ index
* sizeof(uint32
);
1299 uint32 portStatus
= ReadOpReg(portRegister
) & EHCI_PORTSC_DATAMASK
;
1303 return SuspendPort(index
);
1306 return ResetPort(index
);
1309 WriteOpReg(portRegister
, portStatus
| EHCI_PORTSC_PORTPOWER
);
1318 EHCI::ClearPortFeature(uint8 index
, uint16 feature
)
1320 if (index
>= fPortCount
)
1323 uint32 portRegister
= EHCI_PORTSC
+ index
* sizeof(uint32
);
1324 uint32 portStatus
= ReadOpReg(portRegister
) & EHCI_PORTSC_DATAMASK
;
1328 WriteOpReg(portRegister
, portStatus
& ~EHCI_PORTSC_ENABLE
);
1332 WriteOpReg(portRegister
, portStatus
& ~EHCI_PORTSC_PORTPOWER
);
1335 case C_PORT_CONNECTION
:
1336 WriteOpReg(portRegister
, portStatus
| EHCI_PORTSC_CONNCHANGE
);
1340 WriteOpReg(portRegister
, portStatus
| EHCI_PORTSC_ENABLECHANGE
);
1343 case C_PORT_OVER_CURRENT
:
1344 WriteOpReg(portRegister
, portStatus
| EHCI_PORTSC_OCCHANGE
);
1348 fPortResetChange
&= ~(1 << index
);
1351 case C_PORT_SUSPEND
:
1352 fPortSuspendChange
&= ~(1 << index
);
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
);
1376 // enable reset signaling
1377 WriteOpReg(portRegister
, (portStatus
& ~EHCI_PORTSC_ENABLE
)
1378 | EHCI_PORTSC_PORTRESET
);
1381 // disable reset signaling
1382 portStatus
= ReadOpReg(portRegister
) & EHCI_PORTSC_DATAMASK
;
1383 WriteOpReg(portRegister
, portStatus
& ~EHCI_PORTSC_PORTRESET
);
1386 portStatus
= ReadOpReg(portRegister
) & EHCI_PORTSC_DATAMASK
;
1387 if (portStatus
& EHCI_PORTSC_PORTRESET
) {
1388 TRACE_ERROR("port reset won't complete\n");
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
);
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
);
1416 EHCI::ControllerReset()
1418 // halt the controller first
1419 WriteOpReg(EHCI_USBCMD
, 0);
1423 WriteOpReg(EHCI_USBCMD
, EHCI_USBCMD_HCRESET
);
1426 while (ReadOpReg(EHCI_USBCMD
) & EHCI_USBCMD_HCRESET
) {
1444 EHCI::InterruptHandler(void *data
)
1446 return ((EHCI
*)data
)->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) {
1460 TRACE("discarding not enabled interrupts 0x%08" B_PRIx32
"\n",
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
);
1504 release_sem_etc(fAsyncAdvanceSem
, 1, B_DO_NOT_RESCHEDULE
);
1505 if (finishTransfers
)
1506 release_sem_etc(fFinishTransfersSem
, 1, B_DO_NOT_RESCHEDULE
);
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...
1522 cpu_status status
= disable_interrupts();
1524 restore_interrupts(status
);
1532 EHCI::AddPendingTransfer(Transfer
*transfer
, ehci_qh
*queueHead
,
1533 ehci_qtd
*dataDescriptor
, bool directionIn
)
1535 transfer_data
*data
= new(std::nothrow
) transfer_data
;
1539 status_t result
= transfer
->InitKernelAccess();
1540 if (result
< B_OK
) {
1545 data
->transfer
= transfer
;
1546 data
->queue_head
= queueHead
;
1547 data
->data_descriptor
= dataDescriptor
;
1548 data
->incoming
= directionIn
;
1549 data
->canceled
= false;
1558 fLastTransfer
->link
= data
;
1560 fFirstTransfer
= data
;
1562 fLastTransfer
= data
;
1570 EHCI::AddPendingIsochronousTransfer(Transfer
*transfer
, ehci_itd
**isoRequest
,
1571 uint32 lastIndex
, bool directionIn
, addr_t bufferPhy
, void* bufferLog
,
1574 if (!transfer
|| !isoRequest
)
1577 isochronous_transfer_data
*data
1578 = new(std::nothrow
) isochronous_transfer_data
;
1582 status_t result
= transfer
->InitKernelAccess();
1583 if (result
< B_OK
) {
1588 data
->transfer
= transfer
;
1589 data
->descriptors
= isoRequest
;
1590 data
->last_to_process
= lastIndex
;
1591 data
->incoming
= directionIn
;
1592 data
->is_active
= true;
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()) {
1604 if (fLastIsochronousTransfer
)
1605 fLastIsochronousTransfer
->link
= data
;
1606 else if (!fFirstIsochronousTransfer
)
1607 fFirstIsochronousTransfer
= data
;
1609 fLastIsochronousTransfer
= data
;
1610 UnlockIsochronous();
1616 EHCI::CancelQueuedTransfers(Pipe
*pipe
, bool force
)
1618 if ((pipe
->Type() & USB_OBJECT_ISO_PIPE
) != 0)
1619 return CancelQueuedIsochronousTransfers(pipe
, force
);
1624 struct transfer_entry
{
1625 Transfer
* transfer
;
1626 transfer_entry
* next
;
1629 transfer_entry
*list
= NULL
;
1630 transfer_data
*current
= fFirstTransfer
;
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
;
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
;
1654 current
->canceled
= true;
1657 current
= current
->link
;
1662 while (list
!= NULL
) {
1663 transfer_entry
*next
= list
->next
;
1664 list
->transfer
->Finished(B_CANCELED
, 0);
1665 delete list
->transfer
;
1670 // wait for any transfers that might have made it before canceling
1671 while (fProcessingPipe
== pipe
)
1674 // notify the finisher so it can clean up the canceled transfers
1675 release_sem_etc(fFinishTransfersSem
, 1, B_DO_NOT_RESCHEDULE
);
1681 EHCI::CancelQueuedIsochronousTransfers(Pipe
*pipe
, bool force
)
1683 isochronous_transfer_data
*current
= fFirstIsochronousTransfer
;
1686 if (current
->transfer
->TransferPipe() == pipe
) {
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");
1703 EHCI::CancelAllPendingTransfers()
1708 transfer_data
*transfer
= fFirstTransfer
;
1710 transfer
->transfer
->Finished(B_CANCELED
, 0);
1711 delete transfer
->transfer
;
1713 transfer_data
*next
= transfer
->link
;
1718 fFirstTransfer
= NULL
;
1719 fLastTransfer
= NULL
;
1726 EHCI::FinishThread(void *data
)
1728 ((EHCI
*)data
)->FinishTransfers();
1734 EHCI::FinishTransfers()
1736 while (!fStopThreads
) {
1737 if (acquire_sem(fFinishTransfersSem
) < B_OK
)
1740 // eat up sems that have been released by multiple interrupts
1742 get_sem_count(fFinishTransfersSem
, &semCount
);
1744 acquire_sem_etc(fFinishTransfersSem
, semCount
, B_RELATIVE_TIMEOUT
,
1751 TRACE("finishing transfers\n");
1752 transfer_data
*lastTransfer
= NULL
;
1753 transfer_data
*transfer
= fFirstTransfer
;
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
);
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
1780 if (status
& EHCI_QTD_STATUS_BUFFER
) {
1781 callbackStatus
= transfer
->incoming
1782 ? B_DEV_DATA_OVERRUN
: B_DEV_DATA_UNDERRUN
;
1785 if (status
& EHCI_QTD_STATUS_TERROR
) {
1786 callbackStatus
= B_DEV_CRC_ERROR
;
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
;
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
;
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;
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;
1831 if (((status
>> EHCI_QTD_PID_SHIFT
) & EHCI_QTD_PID_MASK
)
1833 && ((status
>> EHCI_QTD_BYTES_SHIFT
) & EHCI_QTD_BYTES_MASK
)
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
;
1842 // no alternate next, transfer is done
1843 callbackStatus
= B_OK
;
1844 transferDone
= true;
1848 descriptor
= descriptor
->next_log
;
1851 if (!transferDone
) {
1852 lastTransfer
= transfer
;
1853 transfer
= transfer
->link
;
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
;
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
;
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
) {
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
,
1893 } else if (transfer
->data_descriptor
) {
1894 // calculate transfered length
1895 actualLength
= ReadActualLength(
1896 transfer
->data_descriptor
, &nextDataToggle
);
1899 transfer
->transfer
->TransferPipe()->SetDataToggle(
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(
1910 transfer
->queue_head
,
1911 &transfer
->data_descriptor
, NULL
);
1913 if (result
== B_OK
&& Lock()) {
1914 // reappend the transfer
1916 fLastTransfer
->link
= transfer
;
1917 if (!fFirstTransfer
)
1918 fFirstTransfer
= transfer
;
1920 fLastTransfer
= transfer
;
1928 // the transfer is done, but we already set the
1929 // actualLength with AdvanceByFragment()
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
;
1943 release_sem(fCleanupSem
);
1950 EHCI::CleanupThread(void *data
)
1952 ((EHCI
*)data
)->Cleanup();
1960 ehci_qh
*lastFreeListHead
= NULL
;
1962 while (!fStopThreads
) {
1963 if (acquire_sem(fCleanupSem
) < B_OK
)
1966 ehci_qh
*freeListHead
= fFreeListHead
;
1967 if (freeListHead
== lastFreeListHead
)
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
)
1975 ehci_qh
*current
= freeListHead
;
1976 while (current
!= lastFreeListHead
) {
1977 ehci_qh
*next
= current
->next_log
;
1978 FreeQueueHead(current
);
1982 lastFreeListHead
= freeListHead
;
1988 EHCI::FinishIsochronousThread(void *data
)
1990 ((EHCI
*)data
)->FinishIsochronousTransfers();
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
)
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);
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
2019 while (currentFrame
== (((ReadOpReg(EHCI_FRINDEX
) / 8)
2020 & (EHCI_VFRAMELIST_ENTRIES_COUNT
- 1)))) {
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())
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
;
2070 isochronous_transfer_data
*temp
2071 = fFirstIsochronousTransfer
;
2072 while (temp
!= NULL
&& transfer
!= 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
);
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
);
2097 transferDone
= true;
2099 TRACE("FinishIsochronousTransfers not end of transfer\n");
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
;
2117 EHCI::CreateQueueHead()
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");
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);
2134 TRACE_ERROR("failed to allocate initial qtd for queue head\n");
2135 fStack
->FreeChunk(result
, physicalAddress
, sizeof(ehci_qh
));
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;
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
;
2162 case USB_SPEED_FULLSPEED
:
2163 queueHead
->endpoint_chars
= EHCI_QH_CHARS_EPS_FULL
;
2165 case USB_SPEED_HIGHSPEED
:
2166 queueHead
->endpoint_chars
= EHCI_QH_CHARS_EPS_HIGH
;
2169 TRACE_ERROR("unknown pipe speed\n");
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
);
2193 EHCI::FreeQueueHead(ehci_qh
*queueHead
)
2198 FreeDescriptorChain(queueHead
->element_log
);
2199 FreeDescriptor(queueHead
->stray_log
);
2200 fStack
->FreeChunk(queueHead
, (phys_addr_t
)queueHead
->this_phy
,
2206 EHCI::LinkQueueHead(ehci_qh
*queueHead
)
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
;
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
);
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
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
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
;
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
;
2273 EHCI::UnlinkQueueHead(ehci_qh
*queueHead
, ehci_qh
**freeListHead
)
2278 ehci_qh
*prevHead
= queueHead
->prev_log
;
2279 ehci_qh
*nextHead
= queueHead
->next_log
;
2281 prevHead
->next_phy
= queueHead
->next_phy
;
2282 prevHead
->next_log
= queueHead
->next_log
;
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
;
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
);
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
);
2341 WriteDescriptorChain(dataDescriptor
, transfer
->Vector(),
2342 transfer
->VectorCount());
2345 LinkDescriptors(setupDescriptor
, dataDescriptor
, strayDescriptor
);
2346 LinkDescriptors(lastDescriptor
, statusDescriptor
, statusDescriptor
);
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
;
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
);
2379 lastDescriptor
->token
|= EHCI_QTD_IOC
;
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
;
2391 *_directionIn
= directionIn
;
2397 EHCI::CreateDescriptor(size_t bufferSize
, uint8 pid
)
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");
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;
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
,
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;
2449 EHCI::CreateDescriptorChain(Pipe
*pipe
, ehci_qtd
**_firstDescriptor
,
2450 ehci_qtd
**_lastDescriptor
, ehci_qtd
*strayDescriptor
, size_t bufferSize
,
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
),
2464 FreeDescriptorChain(firstDescriptor
);
2469 descriptor
->token
|= EHCI_QTD_DATA_TOGGLE
;
2472 LinkDescriptors(lastDescriptor
, descriptor
, strayDescriptor
);
2474 bufferSize
-= packetSize
;
2475 lastDescriptor
= descriptor
;
2476 if (!firstDescriptor
)
2477 firstDescriptor
= descriptor
;
2480 *_firstDescriptor
= firstDescriptor
;
2481 *_lastDescriptor
= lastDescriptor
;
2487 EHCI::FreeDescriptor(ehci_qtd
*descriptor
)
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
,
2503 EHCI::FreeDescriptorChain(ehci_qtd
*topDescriptor
)
2505 ehci_qtd
*current
= topDescriptor
;
2506 ehci_qtd
*next
= NULL
;
2509 next
= current
->next_log
;
2510 FreeDescriptor(current
);
2517 EHCI::CreateItdDescriptor()
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");
2527 memset(result
, 0, sizeof(ehci_itd
));
2528 result
->this_phy
= (addr_t
)physicalAddress
;
2529 result
->next_phy
= EHCI_ITEM_TERMINATE
;
2536 EHCI::CreateSitdDescriptor()
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");
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
;
2555 EHCI::FreeDescriptor(ehci_itd
*descriptor
)
2560 fStack
->FreeChunk(descriptor
, (phys_addr_t
)descriptor
->this_phy
,
2566 EHCI::FreeDescriptor(ehci_sitd
*descriptor
)
2571 fStack
->FreeChunk(descriptor
, (phys_addr_t
)descriptor
->this_phy
,
2577 EHCI::LinkDescriptors(ehci_qtd
*first
, ehci_qtd
*last
, ehci_qtd
*alt
)
2579 first
->next_phy
= last
->this_phy
;
2580 first
->next_log
= last
;
2583 first
->alt_next_phy
= alt
->this_phy
;
2584 first
->alt_next_log
= alt
;
2586 first
->alt_next_phy
= EHCI_ITEM_TERMINATE
;
2587 first
->alt_next_log
= NULL
;
2593 EHCI::LinkITDescriptors(ehci_itd
*itd
, ehci_itd
**_last
)
2595 ehci_itd
*last
= *_last
;
2596 itd
->next_phy
= last
->next_phy
;
2600 last
->next_phy
= itd
->this_phy
;
2606 EHCI::LinkSITDescriptors(ehci_sitd
*sitd
, ehci_sitd
**_last
)
2608 ehci_sitd
*last
= *_last
;
2609 sitd
->next_phy
= last
->next_phy
;
2613 last
->next_phy
= sitd
->this_phy
;
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
;
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
;
2643 EHCI::WriteDescriptorChain(ehci_qtd
*topDescriptor
, iovec
*vector
,
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;
2653 if (!current
->buffer_log
)
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
;
2677 if (bufferOffset
>= current
->buffer_size
) {
2683 if (current
->next_phy
& EHCI_ITEM_TERMINATE
)
2686 current
= current
->next_log
;
2689 TRACE("wrote descriptor chain (%ld bytes)\n", actualLength
);
2690 return actualLength
;
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
)
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
;
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
;
2736 if (bufferOffset
>= bufferSize
) {
2742 if (current
->next_phy
& EHCI_ITEM_TERMINATE
)
2745 current
= current
->next_log
;
2748 TRACE("read descriptor chain (%ld bytes)\n", actualLength
);
2749 *nextDataToggle
= dataToggle
> 0 ? true : false;
2750 return actualLength
;
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
)
2771 current
= current
->next_log
;
2774 TRACE("read actual length (%ld bytes)\n", actualLength
);
2775 *nextDataToggle
= dataToggle
> 0 ? true : false;
2776 return actualLength
;
2781 EHCI::WriteIsochronousDescriptorChain(isochronous_transfer_data
*transfer
,
2782 uint32 packetCount
, iovec
*vector
)
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();
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) {
2816 isochronousData
->packet_descriptors
[packet
].actual_length
2820 isochronousData
->packet_descriptors
[packet
].status
= B_OK
;
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
);
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
);
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
;
2854 if (vectorOffset
>= vector
[vectorIndex
].iov_len
) {
2855 if (++vectorIndex
>= vectorCount
) {
2856 TRACE("read isodescriptor chain (%ld bytes, no more "
2857 "vectors)\n", totalLength
);
2865 bufferOffset
+= packetSize
;
2866 if (bufferOffset
>= transfer
->buffer_size
)
2873 TRACE("ReadIsochronousDescriptorChain packet count %" B_PRId32
"\n",
2881 EHCI::LockIsochronous()
2883 return (mutex_lock(&fIsochronousLock
) == B_OK
);
2888 EHCI::UnlockIsochronous()
2890 mutex_unlock(&fIsochronousLock
);
2895 EHCI::WriteOpReg(uint32 reg
, uint32 value
)
2897 *(volatile uint32
*)(fOperationalRegisters
+ reg
) = value
;
2902 EHCI::ReadOpReg(uint32 reg
)
2904 return *(volatile uint32
*)(fOperationalRegisters
+ reg
);
2909 EHCI::ReadCapReg8(uint32 reg
)
2911 return *(volatile uint8
*)(fCapabilityRegisters
+ reg
);
2916 EHCI::ReadCapReg16(uint32 reg
)
2918 return *(volatile uint16
*)(fCapabilityRegisters
+ reg
);
2923 EHCI::ReadCapReg32(uint32 reg
)
2925 return *(volatile uint32
*)(fCapabilityRegisters
+ reg
);