1 /*
2 * Copyright 2006-2011, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 *
5 * Authors:
6 * Michael Lotz <mmlr@mlotz.ch>
7 * Jérôme Duval <korli@users.berlios.de>
8 */
9
10
11 #include <stdio.h>
12
13 #include <driver_settings.h>
14 #include <bus/PCI.h>
15 #include <USB3.h>
16 #include <KernelExport.h>
17
18 #include "ehci.h"
19
20
21 #define CALLED(x...) TRACE_MODULE("CALLED %s\n", __PRETTY_FUNCTION__)
22
23 #define USB_MODULE_NAME "ehci"
24
25
26 device_manager_info* gDeviceManager;
27 static usb_for_controller_interface* gUSB;
28
29
30 #define EHCI_PCI_DEVICE_MODULE_NAME "busses/usb/ehci/pci/driver_v1"
31 #define EHCI_PCI_USB_BUS_MODULE_NAME "busses/usb/ehci/device_v1"
32
33
34 typedef struct {
35 EHCI* ehci;
36 pci_device_module_info* pci;
37 pci_device* device;
38
39 pci_info pciinfo;
40
41 device_node* node;
42 device_node* driver_node;
43 } ehci_pci_sim_info;
44
45
46 // #pragma mark -
47
48
49 static status_t
init_bus(device_node * node,void ** bus_cookie)50 init_bus(device_node* node, void** bus_cookie)
51 {
52 CALLED();
53
54 driver_module_info* driver;
55 ehci_pci_sim_info* bus;
56 device_node* parent = gDeviceManager->get_parent_node(node);
57 gDeviceManager->get_driver(parent, &driver, (void**)&bus);
58 gDeviceManager->put_node(parent);
59
60 Stack *stack;
61 if (gUSB->get_stack((void**)&stack) != B_OK)
62 return B_ERROR;
63
64 EHCI *ehci = new(std::nothrow) EHCI(&bus->pciinfo, bus->pci, bus->device, stack, node);
65 if (ehci == NULL) {
66 return B_NO_MEMORY;
67 }
68
69 if (ehci->InitCheck() < B_OK) {
70 TRACE_MODULE_ERROR("bus failed init check\n");
71 delete ehci;
72 return B_ERROR;
73 }
74
75 if (ehci->Start() != B_OK) {
76 delete ehci;
77 return B_ERROR;
78 }
79
80 *bus_cookie = ehci;
81
82 return B_OK;
83 }
84
85
86 static void
uninit_bus(void * bus_cookie)87 uninit_bus(void* bus_cookie)
88 {
89 CALLED();
90 EHCI* ehci = (EHCI*)bus_cookie;
91 delete ehci;
92 }
93
94
95 static status_t
register_child_devices(void * cookie)96 register_child_devices(void* cookie)
97 {
98 CALLED();
99 ehci_pci_sim_info* bus = (ehci_pci_sim_info*)cookie;
100 device_node* node = bus->driver_node;
101
102 char prettyName[25];
103 sprintf(prettyName, "EHCI Controller %" B_PRIu16, 0);
104
105 device_attr attrs[] = {
106 // properties of this controller for the usb bus manager
107 { B_DEVICE_PRETTY_NAME, B_STRING_TYPE,
108 { .string = prettyName }},
109 { B_DEVICE_FIXED_CHILD, B_STRING_TYPE,
110 { .string = USB_FOR_CONTROLLER_MODULE_NAME }},
111
112 // private data to identify the device
113 { NULL }
114 };
115
116 return gDeviceManager->register_node(node, EHCI_PCI_USB_BUS_MODULE_NAME,
117 attrs, NULL, NULL);
118 }
119
120
121 static status_t
init_device(device_node * node,void ** device_cookie)122 init_device(device_node* node, void** device_cookie)
123 {
124 CALLED();
125 ehci_pci_sim_info* bus = (ehci_pci_sim_info*)calloc(1,
126 sizeof(ehci_pci_sim_info));
127 if (bus == NULL)
128 return B_NO_MEMORY;
129
130 pci_device_module_info* pci;
131 pci_device* device;
132 {
133 device_node* pciParent = gDeviceManager->get_parent_node(node);
134 gDeviceManager->get_driver(pciParent, (driver_module_info**)&pci,
135 (void**)&device);
136 gDeviceManager->put_node(pciParent);
137 }
138
139 bus->pci = pci;
140 bus->device = device;
141 bus->driver_node = node;
142
143 pci_info *pciInfo = &bus->pciinfo;
144 pci->get_pci_info(device, pciInfo);
145
146 *device_cookie = bus;
147 return B_OK;
148 }
149
150
151 static void
uninit_device(void * device_cookie)152 uninit_device(void* device_cookie)
153 {
154 CALLED();
155 ehci_pci_sim_info* bus = (ehci_pci_sim_info*)device_cookie;
156 free(bus);
157
158 }
159
160
161 static status_t
register_device(device_node * parent)162 register_device(device_node* parent)
163 {
164 CALLED();
165 device_attr attrs[] = {
166 {B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {.string = "EHCI PCI"}},
167 {}
168 };
169
170 return gDeviceManager->register_node(parent,
171 EHCI_PCI_DEVICE_MODULE_NAME, attrs, NULL, NULL);
172 }
173
174
175 static float
supports_device(device_node * parent)176 supports_device(device_node* parent)
177 {
178 CALLED();
179 const char* bus;
180 uint16 type, subType, api;
181
182 // make sure parent is a EHCI PCI device node
183 if (gDeviceManager->get_attr_string(parent, B_DEVICE_BUS, &bus, false)
184 < B_OK) {
185 return -1;
186 }
187
188 if (strcmp(bus, "pci") != 0)
189 return 0.0f;
190
191 if (gDeviceManager->get_attr_uint16(parent, B_DEVICE_SUB_TYPE, &subType,
192 false) < B_OK
193 || gDeviceManager->get_attr_uint16(parent, B_DEVICE_TYPE, &type,
194 false) < B_OK
195 || gDeviceManager->get_attr_uint16(parent, B_DEVICE_INTERFACE, &api,
196 false) < B_OK) {
197 TRACE_MODULE("Could not find type/subtype/interface attributes\n");
198 return -1;
199 }
200
201 if (type == PCI_serial_bus && subType == PCI_usb && api == PCI_usb_ehci) {
202 pci_device_module_info* pci;
203 pci_device* device;
204 gDeviceManager->get_driver(parent, (driver_module_info**)&pci,
205 (void**)&device);
206 TRACE_MODULE("EHCI Device found!\n");
207
208 return 0.8f;
209 }
210
211 return 0.0f;
212 }
213
214
215 module_dependency module_dependencies[] = {
216 { USB_FOR_CONTROLLER_MODULE_NAME, (module_info**)&gUSB },
217 { B_DEVICE_MANAGER_MODULE_NAME, (module_info**)&gDeviceManager },
218 {}
219 };
220
221
222 static usb_bus_interface gEHCIPCIDeviceModule = {
223 {
224 {
225 EHCI_PCI_USB_BUS_MODULE_NAME,
226 0,
227 NULL
228 },
229 NULL, // supports device
230 NULL, // register device
231 init_bus,
232 uninit_bus,
233 NULL, // register child devices
234 NULL, // rescan
235 NULL, // device removed
236 },
237 };
238
239 // Root device that binds to the PCI bus. It will register an usb_bus_interface
240 // node for each device.
241 static driver_module_info sEHCIDevice = {
242 {
243 EHCI_PCI_DEVICE_MODULE_NAME,
244 0,
245 NULL
246 },
247 supports_device,
248 register_device,
249 init_device,
250 uninit_device,
251 register_child_devices,
252 NULL, // rescan
253 NULL, // device removed
254 };
255
256 module_info* modules[] = {
257 (module_info* )&sEHCIDevice,
258 (module_info* )&gEHCIPCIDeviceModule,
259 NULL
260 };
261
262
263 //
264 // #pragma mark -
265 //
266
267
268 #ifdef TRACE_USB
269
270 void
print_descriptor_chain(ehci_qtd * descriptor)271 print_descriptor_chain(ehci_qtd *descriptor)
272 {
273 while (descriptor) {
274 dprintf(" %08" B_PRIx32 " n%08" B_PRIx32 " a%08" B_PRIx32 " t%08"
275 B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32 " %08"
276 B_PRIx32 " %08" B_PRIx32 " s%" B_PRIuSIZE "\n",
277 descriptor->this_phy, descriptor->next_phy,
278 descriptor->alt_next_phy, descriptor->token,
279 descriptor->buffer_phy[0], descriptor->buffer_phy[1],
280 descriptor->buffer_phy[2], descriptor->buffer_phy[3],
281 descriptor->buffer_phy[4], descriptor->buffer_size);
282
283 if (descriptor->next_phy & EHCI_ITEM_TERMINATE)
284 break;
285
286 descriptor = descriptor->next_log;
287 }
288 }
289
290
291 void
print_queue(ehci_qh * queueHead)292 print_queue(ehci_qh *queueHead)
293 {
294 dprintf("queue: t%08" B_PRIx32 " n%08" B_PRIx32 " ch%08" B_PRIx32
295 " ca%08" B_PRIx32 " cu%08" B_PRIx32 "\n",
296 queueHead->this_phy, queueHead->next_phy, queueHead->endpoint_chars,
297 queueHead->endpoint_caps, queueHead->current_qtd_phy);
298 dprintf("overlay: n%08" B_PRIx32 " a%08" B_PRIx32 " t%08" B_PRIx32
299 " %08" B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32 " %08" B_PRIx32
300 " %08" B_PRIx32 "\n", queueHead->overlay.next_phy,
301 queueHead->overlay.alt_next_phy, queueHead->overlay.token,
302 queueHead->overlay.buffer_phy[0], queueHead->overlay.buffer_phy[1],
303 queueHead->overlay.buffer_phy[2], queueHead->overlay.buffer_phy[3],
304 queueHead->overlay.buffer_phy[4]);
305 print_descriptor_chain(queueHead->element_log);
306 }
307
308
309 #endif // TRACE_USB
310
311
312 //
313 // #pragma mark -
314 //
315
316
EHCI(pci_info * info,pci_device_module_info * pci,pci_device * device,Stack * stack,device_node * node)317 EHCI::EHCI(pci_info *info, pci_device_module_info* pci, pci_device* device, Stack *stack,
318 device_node* node)
319 : BusManager(stack, node),
320 fCapabilityRegisters(NULL),
321 fOperationalRegisters(NULL),
322 fRegisterArea(-1),
323 fPCIInfo(info),
324 fPci(pci),
325 fDevice(device),
326 fStack(stack),
327 fEnabledInterrupts(0),
328 fThreshold(0),
329 fPeriodicFrameListArea(-1),
330 fPeriodicFrameList(NULL),
331 fInterruptEntries(NULL),
332 fItdEntries(NULL),
333 fSitdEntries(NULL),
334 fAsyncQueueHead(NULL),
335 fAsyncAdvanceSem(-1),
336 fFirstTransfer(NULL),
337 fLastTransfer(NULL),
338 fFinishTransfersSem(-1),
339 fFinishThread(-1),
340 fProcessingPipe(NULL),
341 fFreeListHead(NULL),
342 fCleanupSem(-1),
343 fCleanupThread(-1),
344 fStopThreads(false),
345 fNextStartingFrame(-1),
346 fFrameBandwidth(NULL),
347 fFirstIsochronousTransfer(NULL),
348 fLastIsochronousTransfer(NULL),
349 fFinishIsochronousTransfersSem(-1),
350 fFinishIsochronousThread(-1),
351 fRootHub(NULL),
352 fRootHubAddress(0),
353 fPortCount(0),
354 fPortResetChange(0),
355 fPortSuspendChange(0),
356 fInterruptPollThread(-1),
357 fIRQ(0),
358 fUseMSI(false)
359 {
360 // Create a lock for the isochronous transfer list
361 mutex_init(&fIsochronousLock, "EHCI isochronous lock");
362
363 if (BusManager::InitCheck() != B_OK) {
364 TRACE_ERROR("bus manager failed to init\n");
365 return;
366 }
367
368 TRACE("constructing new EHCI host controller driver\n");
369 fInitOK = false;
370
371 // ATI/AMD SB600/SB700 periodic list cache workaround
372 // Logic kindly borrowed from NetBSD PR 40056
373 if (fPCIInfo->vendor_id == AMD_SBX00_VENDOR) {
374 bool applyWorkaround = false;
375
376 if (fPCIInfo->device_id == AMD_SB600_EHCI_CONTROLLER) {
377 // always apply on SB600
378 applyWorkaround = true;
379 } else if (fPCIInfo->device_id == AMD_SB700_SB800_EHCI_CONTROLLER) {
380 // only apply on certain chipsets, determined by SMBus revision
381 device_node *pciNode = NULL;
382 device_node* deviceRoot = gDeviceManager->get_root_node();
383 device_attr acpiAttrs[] = {
384 { B_DEVICE_BUS, B_STRING_TYPE, { .string = "pci" }},
385 { B_DEVICE_VENDOR_ID, B_UINT16_TYPE, { .ui16 = AMD_SBX00_VENDOR }},
386 { B_DEVICE_ID, B_UINT16_TYPE, { .ui16 = AMD_SBX00_SMBUS_CONTROLLER }},
387 { NULL }
388 };
389 if (gDeviceManager->find_child_node(deviceRoot, acpiAttrs,
390 &pciNode) == B_OK) {
391 pci_device_module_info *pci;
392 pci_device *pciDevice;
393 if (gDeviceManager->get_driver(pciNode, (driver_module_info **)&pci,
394 (void **)&pciDevice) == B_OK) {
395
396 pci_info smbus;
397 pci->get_pci_info(pciDevice, &smbus);
398 // Only applies to chipsets < SB710 (rev A14)
399 if (smbus.revision == 0x3a || smbus.revision == 0x3b)
400 applyWorkaround = true;
401 }
402 }
403 }
404
405 if (applyWorkaround) {
406 // According to AMD errata of SB700 and SB600 register documentation
407 // this disables the Periodic List Cache on SB600 and the Advanced
408 // Periodic List Cache on early SB700. Both the BSDs and Linux use
409 // this workaround.
410
411 TRACE_ALWAYS("disabling SB600/SB700 periodic list cache\n");
412 uint32 workaround = fPci->read_pci_config(fDevice,
413 AMD_SBX00_EHCI_MISC_REGISTER, 4);
414
415 fPci->write_pci_config(fDevice, AMD_SBX00_EHCI_MISC_REGISTER, 4,
416 workaround | AMD_SBX00_EHCI_MISC_DISABLE_PERIODIC_LIST_CACHE);
417 }
418 }
419
420 // enable busmaster and memory mapped access
421 uint16 command = fPci->read_pci_config(fDevice, PCI_command, 2);
422 command &= ~PCI_command_io;
423 command |= PCI_command_master | PCI_command_memory;
424
425 fPci->write_pci_config(fDevice, PCI_command, 2, command);
426
427 // map the registers
428 uint32 offset = fPCIInfo->u.h0.base_registers[0] & (B_PAGE_SIZE - 1);
429 phys_addr_t physicalAddress = fPCIInfo->u.h0.base_registers[0] - offset;
430 size_t mapSize = (fPCIInfo->u.h0.base_register_sizes[0] + offset
431 + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
432
433 TRACE("map physical memory 0x%08" B_PRIx32 " (base: 0x%08" B_PRIxPHYSADDR
434 "; offset: %" B_PRIx32 "); size: %" B_PRIu32 "\n",
435 fPCIInfo->u.h0.base_registers[0], physicalAddress, offset,
436 fPCIInfo->u.h0.base_register_sizes[0]);
437
438 fRegisterArea = map_physical_memory("EHCI memory mapped registers",
439 physicalAddress, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS,
440 B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA,
441 (void **)&fCapabilityRegisters);
442 if (fRegisterArea < 0) {
443 TRACE_ERROR("failed to map register memory\n");
444 return;
445 }
446
447 fCapabilityRegisters += offset;
448 fOperationalRegisters = fCapabilityRegisters + ReadCapReg8(EHCI_CAPLENGTH);
449 TRACE("mapped capability registers: 0x%p\n", fCapabilityRegisters);
450 TRACE("mapped operational registers: 0x%p\n", fOperationalRegisters);
451
452 TRACE("structural parameters: 0x%08" B_PRIx32 "\n",
453 ReadCapReg32(EHCI_HCSPARAMS));
454 TRACE("capability parameters: 0x%08" B_PRIx32 "\n",
455 ReadCapReg32(EHCI_HCCPARAMS));
456
457 if (EHCI_HCCPARAMS_FRAME_CACHE(ReadCapReg32(EHCI_HCCPARAMS)))
458 fThreshold = 2 + 8;
459 else
460 fThreshold = 2 + EHCI_HCCPARAMS_IPT(ReadCapReg32(EHCI_HCCPARAMS));
461
462 // read port count from capability register
463 fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f;
464
465 uint32 extendedCapPointer = ReadCapReg32(EHCI_HCCPARAMS) >> EHCI_ECP_SHIFT;
466 extendedCapPointer &= EHCI_ECP_MASK;
467 if (extendedCapPointer > 0) {
468 TRACE("extended capabilities register at %" B_PRIu32 "\n",
469 extendedCapPointer);
470
471 uint32 legacySupport = fPci->read_pci_config(fDevice, extendedCapPointer, 4);
472 if ((legacySupport & EHCI_LEGSUP_CAPID_MASK) == EHCI_LEGSUP_CAPID) {
473 if ((legacySupport & EHCI_LEGSUP_BIOSOWNED) != 0) {
474 TRACE_ALWAYS("the host controller is bios owned, claiming"
475 " ownership\n");
476
477 fPci->write_pci_config(fDevice, extendedCapPointer + 3, 1, 1);
478
479 for (int32 i = 0; i < 20; i++) {
480 legacySupport = fPci->read_pci_config(fDevice,
481 extendedCapPointer, 4);
482
483 if ((legacySupport & EHCI_LEGSUP_BIOSOWNED) == 0)
484 break;
485
486 TRACE_ALWAYS("controller is still bios owned, waiting\n");
487 snooze(50000);
488 }
489 }
490
491 if (legacySupport & EHCI_LEGSUP_BIOSOWNED) {
492 TRACE_ERROR("bios won't give up control over the host "
493 "controller (ignoring)\n");
494 } else if (legacySupport & EHCI_LEGSUP_OSOWNED) {
495 TRACE_ALWAYS(
496 "successfully took ownership of the host controller\n");
497 }
498
499 // Force off the BIOS owned flag, and clear all SMIs. Some BIOSes
500 // do indicate a successful handover but do not remove their SMIs
501 // and then freeze the system when interrupts are generated.
502 fPci->write_pci_config(fDevice, extendedCapPointer + 2, 1, 0);
503 fPci->write_pci_config(fDevice, extendedCapPointer + 4, 4, 0);
504 } else {
505 TRACE_ALWAYS(
506 "extended capability is not a legacy support register\n");
507 }
508 } else {
509 TRACE_ALWAYS("no extended capabilities register\n");
510 }
511
512 // disable interrupts
513 WriteOpReg(EHCI_USBINTR, 0);
514
515 // reset the host controller
516 if (ControllerReset() != B_OK) {
517 TRACE_ERROR("host controller failed to reset\n");
518 return;
519 }
520
521 // reset the segment register
522 WriteOpReg(EHCI_CTRDSSEGMENT, 0);
523
524 // create semaphores the finisher thread will wait for
525 fAsyncAdvanceSem = create_sem(0, "EHCI Async Advance");
526 fFinishTransfersSem = create_sem(0, "EHCI Finish Transfers");
527 fCleanupSem = create_sem(0, "EHCI Cleanup");
528 if (fFinishTransfersSem < 0 || fAsyncAdvanceSem < 0 || fCleanupSem < 0) {
529 TRACE_ERROR("failed to create semaphores\n");
530 return;
531 }
532
533 // create finisher service thread
534 fFinishThread = spawn_kernel_thread(FinishThread, "ehci finish thread",
535 B_NORMAL_PRIORITY, (void *)this);
536 resume_thread(fFinishThread);
537
538 // Create semaphore the isochronous finisher thread will wait for
539 fFinishIsochronousTransfersSem = create_sem(0,
540 "EHCI Isochronous Finish Transfers");
541 if (fFinishIsochronousTransfersSem < 0) {
542 TRACE_ERROR("failed to create isochronous finisher semaphore\n");
543 return;
544 }
545
546 // Create the isochronous finisher service thread
547 fFinishIsochronousThread = spawn_kernel_thread(FinishIsochronousThread,
548 "ehci isochronous finish thread", B_URGENT_DISPLAY_PRIORITY,
549 (void *)this);
550 resume_thread(fFinishIsochronousThread);
551
552 // create cleanup service thread
553 fCleanupThread = spawn_kernel_thread(CleanupThread, "ehci cleanup thread",
554 B_NORMAL_PRIORITY, (void *)this);
555 resume_thread(fCleanupThread);
556
557 // set up interrupts or interrupt polling now that the controller is ready
558 bool polling = false;
559 void *settings = load_driver_settings(B_SAFEMODE_DRIVER_SETTINGS);
560 if (settings != NULL) {
561 polling = get_driver_boolean_parameter(settings, "ehci_polling", false,
562 false);
563 unload_driver_settings(settings);
564 }
565
566 if (polling) {
567 // create and run the polling thread
568 TRACE_ALWAYS("enabling ehci polling\n");
569 fInterruptPollThread = spawn_kernel_thread(InterruptPollThread,
570 "ehci interrupt poll thread", B_NORMAL_PRIORITY, (void *)this);
571 resume_thread(fInterruptPollThread);
572 } else {
573 // Find the right interrupt vector, using MSIs if available.
574 fIRQ = fPCIInfo->u.h0.interrupt_line;
575 if (fIRQ == 0xFF)
576 fIRQ = 0;
577
578 if (fPci->get_msi_count(fDevice) >= 1) {
579 uint32 msiVector = 0;
580 if (fPci->configure_msi(fDevice, 1, &msiVector) == B_OK
581 && fPci->enable_msi(fDevice) == B_OK) {
582 TRACE_ALWAYS("using message signaled interrupts\n");
583 fIRQ = msiVector;
584 fUseMSI = true;
585 }
586 }
587
588 if (fIRQ == 0) {
589 TRACE_MODULE_ERROR("device PCI:%d:%d:%d was assigned an invalid IRQ\n",
590 fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function);
591 return;
592 }
593
594 // install the interrupt handler and enable interrupts
595 install_io_interrupt_handler(fIRQ, InterruptHandler,
596 (void *)this, 0);
597 }
598
599 // ensure that interrupts are en-/disabled on the PCI device
600 command = fPci->read_pci_config(fDevice, PCI_command, 2);
601 if ((polling || fUseMSI) == ((command & PCI_command_int_disable) == 0)) {
602 if (polling || fUseMSI)
603 command &= ~PCI_command_int_disable;
604 else
605 command |= PCI_command_int_disable;
606
607 fPci->write_pci_config(fDevice, PCI_command, 2, command);
608 }
609
610 fEnabledInterrupts = EHCI_USBINTR_HOSTSYSERR | EHCI_USBINTR_USBERRINT
611 | EHCI_USBINTR_USBINT | EHCI_USBINTR_INTONAA;
612 WriteOpReg(EHCI_USBINTR, fEnabledInterrupts);
613
614 // structures don't span page boundaries
615 size_t itdListSize = EHCI_VFRAMELIST_ENTRIES_COUNT
616 / (B_PAGE_SIZE / sizeof(itd_entry)) * B_PAGE_SIZE;
617 size_t sitdListSize = EHCI_VFRAMELIST_ENTRIES_COUNT
618 / (B_PAGE_SIZE / sizeof(sitd_entry)) * B_PAGE_SIZE;
619 size_t frameListSize = B_PAGE_SIZE + B_PAGE_SIZE + itdListSize
620 + sitdListSize;
621
622 // allocate the periodic frame list
623 fPeriodicFrameListArea = fStack->AllocateArea((void **)&fPeriodicFrameList,
624 &physicalAddress, frameListSize, "USB EHCI Periodic Framelist");
625 if (fPeriodicFrameListArea < 0) {
626 TRACE_ERROR("unable to allocate periodic framelist\n");
627 return;
628 }
629
630 if ((physicalAddress & 0xfff) != 0) {
631 panic("EHCI_PERIODICLISTBASE not aligned on 4k: 0x%" B_PRIxPHYSADDR
632 "\n", physicalAddress);
633 }
634
635 // set the periodic frame list base on the controller
636 WriteOpReg(EHCI_PERIODICLISTBASE, (uint32)physicalAddress);
637
638 // create the interrupt entries to support different polling intervals
639 TRACE("creating interrupt entries\n");
640 uint32_t physicalBase = physicalAddress + B_PAGE_SIZE;
641 uint8 *logicalBase = (uint8 *)fPeriodicFrameList + B_PAGE_SIZE;
642 memset(logicalBase, 0, B_PAGE_SIZE);
643
644 fInterruptEntries = (interrupt_entry *)logicalBase;
645 for (int32 i = 0; i < EHCI_INTERRUPT_ENTRIES_COUNT; i++) {
646 ehci_qh *queueHead = &fInterruptEntries[i].queue_head;
647 queueHead->this_phy = physicalBase | EHCI_ITEM_TYPE_QH;
648 queueHead->current_qtd_phy = 0;
649 queueHead->overlay.next_phy = EHCI_ITEM_TERMINATE;
650 queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
651 queueHead->overlay.token = EHCI_QTD_STATUS_HALTED;
652
653 // set dummy endpoint information
654 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH
655 | (3 << EHCI_QH_CHARS_RL_SHIFT) | (64 << EHCI_QH_CHARS_MPL_SHIFT)
656 | EHCI_QH_CHARS_TOGGLE;
657 queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT)
658 | (0xff << EHCI_QH_CAPS_ISM_SHIFT);
659
660 physicalBase += sizeof(interrupt_entry);
661 if ((physicalBase & 0x1f) != 0) {
662 panic("physical base for interrupt entry %" B_PRId32
663 " not aligned on 32, interrupt entry structure size %lu\n",
664 i, sizeof(interrupt_entry));
665 }
666 }
667
668 // create the itd and sitd entries
669 TRACE("build up iso entries\n");
670 uint32_t itdPhysicalBase = physicalAddress + B_PAGE_SIZE + B_PAGE_SIZE;
671 itd_entry* itds = (itd_entry *)((uint8 *)fPeriodicFrameList + B_PAGE_SIZE
672 + B_PAGE_SIZE);
673 memset(itds, 0, itdListSize);
674
675 uint32_t sitdPhysicalBase = itdPhysicalBase + itdListSize;
676 sitd_entry* sitds = (sitd_entry *)((uint8 *)fPeriodicFrameList + B_PAGE_SIZE
677 + B_PAGE_SIZE + itdListSize);
678 memset(sitds, 0, sitdListSize);
679
680 fItdEntries = new(std::nothrow) ehci_itd *[EHCI_VFRAMELIST_ENTRIES_COUNT];
681 fSitdEntries = new(std::nothrow) ehci_sitd *[EHCI_VFRAMELIST_ENTRIES_COUNT];
682
683 dprintf("sitd entry size %lu, itd entry size %lu\n", sizeof(sitd_entry),
684 sizeof(itd_entry));
685 for (int32 i = 0; i < EHCI_VFRAMELIST_ENTRIES_COUNT; i++) {
686 ehci_sitd *sitd = &sitds[i].sitd;
687 sitd->this_phy = sitdPhysicalBase | EHCI_ITEM_TYPE_SITD;
688 sitd->back_phy = EHCI_ITEM_TERMINATE;
689 fSitdEntries[i] = sitd;
690 TRACE("sitd entry %" B_PRId32 " %p 0x%" B_PRIx32 "\n", i, sitd,
691 sitd->this_phy);
692
693 ehci_itd *itd = &itds[i].itd;
694 itd->this_phy = itdPhysicalBase | EHCI_ITEM_TYPE_ITD;
695 itd->next_phy = sitd->this_phy;
696 fItdEntries[i] = itd;
697 TRACE("itd entry %" B_PRId32 " %p 0x%" B_PRIx32 "\n", i, itd,
698 itd->this_phy);
699
700 sitdPhysicalBase += sizeof(sitd_entry);
701 itdPhysicalBase += sizeof(itd_entry);
702 if ((sitdPhysicalBase & 0x10) != 0 || (itdPhysicalBase & 0x10) != 0)
703 panic("physical base for entry %" B_PRId32 " not aligned on 32\n",
704 i);
705 }
706
707 // build flat interrupt tree
708 TRACE("build up interrupt links\n");
709 uint32 interval = EHCI_VFRAMELIST_ENTRIES_COUNT;
710 uint32 intervalIndex = EHCI_INTERRUPT_ENTRIES_COUNT - 1;
711 while (interval > 1) {
712 for (uint32 insertIndex = interval / 2;
713 insertIndex < EHCI_VFRAMELIST_ENTRIES_COUNT;
714 insertIndex += interval) {
715 fSitdEntries[insertIndex]->next_phy
716 = fInterruptEntries[intervalIndex].queue_head.this_phy;
717 }
718
719 intervalIndex--;
720 interval /= 2;
721 }
722
723 // setup the empty slot in the list and linking of all -> first
724 ehci_qh *firstLogical = &fInterruptEntries[0].queue_head;
725 fSitdEntries[0]->next_phy = firstLogical->this_phy;
726 for (int32 i = 1; i < EHCI_INTERRUPT_ENTRIES_COUNT; i++) {
727 fInterruptEntries[i].queue_head.next_phy = firstLogical->this_phy;
728 fInterruptEntries[i].queue_head.next_log = firstLogical;
729 fInterruptEntries[i].queue_head.prev_log = NULL;
730 }
731
732 // terminate the first entry
733 firstLogical->next_phy = EHCI_ITEM_TERMINATE;
734 firstLogical->next_log = NULL;
735 firstLogical->prev_log = NULL;
736
737 for (int32 i = 0; i < EHCI_FRAMELIST_ENTRIES_COUNT; i++) {
738 fPeriodicFrameList[i]
739 = fItdEntries[i & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1)]->this_phy;
740 TRACE("periodic entry %" B_PRId32 " linked to 0x%" B_PRIx32 "\n", i,
741 fPeriodicFrameList[i]);
742 }
743
744 // Create the array that will keep bandwidth information
745 fFrameBandwidth = new(std::nothrow) uint16[EHCI_VFRAMELIST_ENTRIES_COUNT];
746 for (int32 i = 0; i < EHCI_VFRAMELIST_ENTRIES_COUNT; i++) {
747 fFrameBandwidth[i] = MAX_AVAILABLE_BANDWIDTH;
748 }
749
750 // allocate a queue head that will always stay in the async frame list
751 fAsyncQueueHead = CreateQueueHead();
752 if (!fAsyncQueueHead) {
753 TRACE_ERROR("unable to allocate stray async queue head\n");
754 return;
755 }
756
757 fAsyncQueueHead->next_phy = fAsyncQueueHead->this_phy;
758 fAsyncQueueHead->next_log = fAsyncQueueHead;
759 fAsyncQueueHead->prev_log = fAsyncQueueHead;
760 fAsyncQueueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH
761 | EHCI_QH_CHARS_RECHEAD;
762 fAsyncQueueHead->endpoint_caps = 1 << EHCI_QH_CAPS_MULT_SHIFT;
763 fAsyncQueueHead->overlay.next_phy = EHCI_ITEM_TERMINATE;
764
765 WriteOpReg(EHCI_ASYNCLISTADDR, (uint32)fAsyncQueueHead->this_phy);
766 TRACE("set the async list addr to 0x%08" B_PRIx32 "\n",
767 ReadOpReg(EHCI_ASYNCLISTADDR));
768
769 fInitOK = true;
770 TRACE("EHCI host controller driver constructed\n");
771 }
772
773
~EHCI()774 EHCI::~EHCI()
775 {
776 TRACE("tear down EHCI host controller driver\n");
777
778 WriteOpReg(EHCI_USBCMD, 0);
779 WriteOpReg(EHCI_CONFIGFLAG, 0);
780 CancelAllPendingTransfers();
781
782 int32 result = 0;
783 fStopThreads = true;
784 delete_sem(fAsyncAdvanceSem);
785 delete_sem(fFinishTransfersSem);
786 delete_sem(fFinishIsochronousTransfersSem);
787 delete_sem(fCleanupSem);
788 wait_for_thread(fFinishThread, &result);
789 wait_for_thread(fCleanupThread, &result);
790 wait_for_thread(fFinishIsochronousThread, &result);
791
792 if (fInterruptPollThread >= 0)
793 wait_for_thread(fInterruptPollThread, &result);
794 else
795 remove_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this);
796
797 LockIsochronous();
798 isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer;
799 while (isoTransfer) {
800 isochronous_transfer_data *next = isoTransfer->link;
801 delete isoTransfer;
802 isoTransfer = next;
803 }
804 mutex_destroy(&fIsochronousLock);
805
806 delete fRootHub;
807 delete [] fFrameBandwidth;
808 delete [] fItdEntries;
809 delete [] fSitdEntries;
810 delete_area(fPeriodicFrameListArea);
811 delete_area(fRegisterArea);
812
813 if (fUseMSI) {
814 fPci->disable_msi(fDevice);
815 fPci->unconfigure_msi(fDevice);
816 }
817
818 }
819
820
821 status_t
Start()822 EHCI::Start()
823 {
824 TRACE("starting EHCI host controller\n");
825 TRACE("usbcmd: 0x%08" B_PRIx32 "; usbsts: 0x%08" B_PRIx32 "\n",
826 ReadOpReg(EHCI_USBCMD), ReadOpReg(EHCI_USBSTS));
827
828 bool hasPerPortChangeEvent = (ReadCapReg32(EHCI_HCCPARAMS)
829 & EHCI_HCCPARAMS_PPCEC) != 0;
830
831 uint32 config = ReadOpReg(EHCI_USBCMD);
832 config &= ~((EHCI_USBCMD_ITC_MASK << EHCI_USBCMD_ITC_SHIFT)
833 | EHCI_USBCMD_PPCEE);
834 uint32 frameListSize = (config >> EHCI_USBCMD_FLS_SHIFT)
835 & EHCI_USBCMD_FLS_MASK;
836
837 WriteOpReg(EHCI_USBCMD, config | EHCI_USBCMD_RUNSTOP
838 | (hasPerPortChangeEvent ? EHCI_USBCMD_PPCEE : 0)
839 | EHCI_USBCMD_ASENABLE | EHCI_USBCMD_PSENABLE
840 | (frameListSize << EHCI_USBCMD_FLS_SHIFT)
841 | (1 << EHCI_USBCMD_ITC_SHIFT));
842
843 switch (frameListSize) {
844 case 0:
845 TRACE("frame list size 1024\n");
846 break;
847 case 1:
848 TRACE("frame list size 512\n");
849 break;
850 case 2:
851 TRACE("frame list size 256\n");
852 break;
853 default:
854 TRACE_ALWAYS("unknown frame list size\n");
855 }
856
857 bool running = false;
858 for (int32 i = 0; i < 10; i++) {
859 uint32 status = ReadOpReg(EHCI_USBSTS);
860 TRACE("try %" B_PRId32 ": status 0x%08" B_PRIx32 "\n", i, status);
861
862 if (status & EHCI_USBSTS_HCHALTED) {
863 snooze(10000);
864 } else {
865 running = true;
866 break;
867 }
868 }
869
870 if (!running) {
871 TRACE_ERROR("host controller didn't start\n");
872 return B_ERROR;
873 }
874
875 // route all ports to us
876 WriteOpReg(EHCI_CONFIGFLAG, EHCI_CONFIGFLAG_FLAG);
877 snooze(10000);
878
879 fRootHubAddress = AllocateAddress();
880 fRootHub = new(std::nothrow) EHCIRootHub(RootObject(), fRootHubAddress);
881 if (!fRootHub) {
882 TRACE_ERROR("no memory to allocate root hub\n");
883 return B_NO_MEMORY;
884 }
885
886 if (fRootHub->InitCheck() != B_OK) {
887 TRACE_ERROR("root hub failed init check\n");
888 return fRootHub->InitCheck();
889 }
890
891 SetRootHub(fRootHub);
892
893 fRootHub->RegisterNode(Node());
894
895 TRACE_ALWAYS("successfully started the controller\n");
896 return BusManager::Start();
897 }
898
899
900 status_t
StartDebugTransfer(Transfer * transfer)901 EHCI::StartDebugTransfer(Transfer *transfer)
902 {
903 static transfer_data transferData;
904
905 transferData.queue_head = CreateQueueHead();
906 if (transferData.queue_head == NULL)
907 return B_NO_MEMORY;
908
909 Pipe *pipe = transfer->TransferPipe();
910 status_t result = InitQueueHead(transferData.queue_head, pipe);
911 if (result != B_OK) {
912 FreeQueueHead(transferData.queue_head);
913 return result;
914 }
915
916 if ((pipe->Type() & USB_OBJECT_CONTROL_PIPE) != 0) {
917 result = FillQueueWithRequest(transfer, transferData.queue_head,
918 &transferData.data_descriptor, &transferData.incoming, false);
919 } else {
920 result = FillQueueWithData(transfer, transferData.queue_head,
921 &transferData.data_descriptor, &transferData.incoming, false);
922 }
923
924 if (result != B_OK) {
925 FreeQueueHead(transferData.queue_head);
926 return result;
927 }
928
929 if ((pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) != 0)
930 LinkPeriodicDebugQueueHead(transferData.queue_head, pipe);
931 else
932 LinkAsyncDebugQueueHead(transferData.queue_head);
933
934 // we abuse the callback cookie to hold our transfer data
935 transfer->SetCallback(NULL, &transferData);
936 return B_OK;
937 }
938
939
940 void
LinkAsyncDebugQueueHead(ehci_qh * queueHead)941 EHCI::LinkAsyncDebugQueueHead(ehci_qh *queueHead)
942 {
943 ehci_qh *prevHead = fAsyncQueueHead->prev_log;
944 queueHead->next_phy = fAsyncQueueHead->this_phy;
945 queueHead->next_log = fAsyncQueueHead;
946 queueHead->prev_log = prevHead;
947 fAsyncQueueHead->prev_log = queueHead;
948 prevHead->next_log = queueHead;
949 prevHead->next_phy = queueHead->this_phy;
950 }
951
952
953 void
LinkPeriodicDebugQueueHead(ehci_qh * queueHead,Pipe * pipe)954 EHCI::LinkPeriodicDebugQueueHead(ehci_qh *queueHead, Pipe *pipe)
955 {
956 if (pipe->Speed() == USB_SPEED_HIGHSPEED)
957 queueHead->endpoint_caps |= (0xff << EHCI_QH_CAPS_ISM_SHIFT);
958 else {
959 queueHead->endpoint_caps |= (0x01 << EHCI_QH_CAPS_ISM_SHIFT);
960 queueHead->endpoint_caps |= (0x1c << EHCI_QH_CAPS_SCM_SHIFT);
961 }
962
963 ehci_qh *interruptQueue = &fInterruptEntries[0].queue_head;
964 queueHead->next_phy = interruptQueue->next_phy;
965 queueHead->next_log = interruptQueue->next_log;
966 queueHead->prev_log = interruptQueue;
967 if (interruptQueue->next_log)
968 interruptQueue->next_log->prev_log = queueHead;
969 interruptQueue->next_log = queueHead;
970 interruptQueue->next_phy = queueHead->this_phy;
971 }
972
973
974 status_t
CheckDebugTransfer(Transfer * transfer)975 EHCI::CheckDebugTransfer(Transfer *transfer)
976 {
977 bool transferOK = false;
978 bool transferError = false;
979 transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
980 ehci_qtd *descriptor = transferData->queue_head->element_log;
981
982 while (descriptor) {
983 uint32 status = descriptor->token;
984 if ((status & EHCI_QTD_STATUS_ACTIVE) != 0) {
985 // still in progress
986 break;
987 }
988
989 if ((status & EHCI_QTD_STATUS_ERRMASK) != 0) {
990 transferError = true;
991 break;
992 }
993
994 if ((descriptor->next_phy & EHCI_ITEM_TERMINATE) != 0) {
995 // we arrived at the last (stray) descriptor, we're done
996 transferOK = true;
997 break;
998 }
999
1000 if (((status >> EHCI_QTD_PID_SHIFT) & EHCI_QTD_PID_MASK)
1001 == EHCI_QTD_PID_IN
1002 && ((status >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK) != 0) {
1003 // a short packet condition existed on this descriptor
1004 if (descriptor->alt_next_log != NULL) {
1005 descriptor = descriptor->alt_next_log;
1006 continue;
1007 }
1008
1009 transferOK = true;
1010 break;
1011 }
1012
1013 descriptor = descriptor->next_log;
1014 }
1015
1016 if (!transferOK && !transferError) {
1017 spin(75);
1018 return B_DEV_PENDING;
1019 }
1020
1021 if (transferOK) {
1022 bool nextDataToggle = false;
1023 if (transferData->data_descriptor != NULL && transferData->incoming) {
1024 // data to read out
1025 generic_io_vec *vector = transfer->Vector();
1026 size_t vectorCount = transfer->VectorCount();
1027
1028 ReadDescriptorChain(transferData->data_descriptor,
1029 vector, vectorCount, transfer->IsPhysical(), &nextDataToggle);
1030 } else if (transferData->data_descriptor != NULL)
1031 ReadActualLength(transferData->data_descriptor, &nextDataToggle);
1032
1033 transfer->TransferPipe()->SetDataToggle(nextDataToggle);
1034 }
1035
1036 CleanupDebugTransfer(transfer);
1037 return transferOK ? B_OK : B_IO_ERROR;
1038 }
1039
1040
1041 void
CancelDebugTransfer(Transfer * transfer)1042 EHCI::CancelDebugTransfer(Transfer *transfer)
1043 {
1044 transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
1045
1046 // clear the active bit so the descriptors are canceled
1047 ehci_qtd *descriptor = transferData->queue_head->element_log;
1048 while (descriptor != NULL) {
1049 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
1050 descriptor = descriptor->next_log;
1051 }
1052
1053 transfer->Finished(B_CANCELED, 0);
1054 CleanupDebugTransfer(transfer);
1055 }
1056
1057
1058 void
CleanupDebugTransfer(Transfer * transfer)1059 EHCI::CleanupDebugTransfer(Transfer *transfer)
1060 {
1061 transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
1062 ehci_qh *queueHead = transferData->queue_head;
1063 ehci_qh *prevHead = queueHead->prev_log;
1064 if (prevHead != NULL) {
1065 prevHead->next_phy = queueHead->next_phy;
1066 prevHead->next_log = queueHead->next_log;
1067 }
1068
1069 ehci_qh *nextHead = queueHead->next_log;
1070 if (nextHead != NULL)
1071 nextHead->prev_log = queueHead->prev_log;
1072
1073 queueHead->next_phy = fAsyncQueueHead->this_phy;
1074 queueHead->prev_log = NULL;
1075 queueHead->next_log = NULL;
1076
1077 // wait for async advance to ensure the controller does not access this
1078 // queue head anymore.
1079 spin(125);
1080
1081 FreeQueueHead(queueHead);
1082 }
1083
1084
1085 status_t
SubmitTransfer(Transfer * transfer)1086 EHCI::SubmitTransfer(Transfer *transfer)
1087 {
1088 // short circuit the root hub
1089 if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
1090 return fRootHub->ProcessTransfer(this, transfer);
1091
1092 Pipe *pipe = transfer->TransferPipe();
1093 if ((pipe->Type() & USB_OBJECT_ISO_PIPE) != 0)
1094 return SubmitIsochronous(transfer);
1095
1096 status_t result = transfer->InitKernelAccess();
1097 if (result != B_OK)
1098 return result;
1099
1100 ehci_qh *queueHead = CreateQueueHead();
1101 if (!queueHead) {
1102 TRACE_ERROR("failed to allocate queue head\n");
1103 return B_NO_MEMORY;
1104 }
1105
1106 result = InitQueueHead(queueHead, pipe);
1107 if (result != B_OK) {
1108 TRACE_ERROR("failed to init queue head\n");
1109 FreeQueueHead(queueHead);
1110 return result;
1111 }
1112
1113 bool directionIn;
1114 ehci_qtd *dataDescriptor;
1115 if ((pipe->Type() & USB_OBJECT_CONTROL_PIPE) != 0) {
1116 result = FillQueueWithRequest(transfer, queueHead, &dataDescriptor,
1117 &directionIn, true);
1118 } else {
1119 result = FillQueueWithData(transfer, queueHead, &dataDescriptor,
1120 &directionIn, true);
1121 }
1122
1123 if (result != B_OK) {
1124 TRACE_ERROR("failed to fill transfer queue with data\n");
1125 FreeQueueHead(queueHead);
1126 return result;
1127 }
1128
1129 result = AddPendingTransfer(transfer, queueHead, dataDescriptor,
1130 directionIn);
1131 if (result != B_OK) {
1132 TRACE_ERROR("failed to add pending transfer\n");
1133 FreeQueueHead(queueHead);
1134 return result;
1135 }
1136
1137 #ifdef TRACE_USB
1138 TRACE("linking queue\n");
1139 print_queue(queueHead);
1140 #endif
1141
1142 if ((pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) != 0)
1143 result = LinkInterruptQueueHead(queueHead, pipe);
1144 else
1145 result = LinkQueueHead(queueHead);
1146
1147 if (result != B_OK) {
1148 TRACE_ERROR("failed to link queue head\n");
1149 FreeQueueHead(queueHead);
1150 return result;
1151 }
1152
1153 return B_OK;
1154 }
1155
1156
1157 status_t
SubmitIsochronous(Transfer * transfer)1158 EHCI::SubmitIsochronous(Transfer *transfer)
1159 {
1160 Pipe *pipe = transfer->TransferPipe();
1161 bool directionIn = (pipe->Direction() == Pipe::In);
1162 usb_isochronous_data *isochronousData = transfer->IsochronousData();
1163 size_t packetSize = transfer->DataLength();
1164 #ifdef TRACE_USB
1165 size_t restSize = packetSize % isochronousData->packet_count;
1166 #endif
1167 packetSize /= isochronousData->packet_count;
1168 uint16 currentFrame;
1169
1170 if (packetSize > pipe->MaxPacketSize()) {
1171 TRACE_ERROR(
1172 "isochronous packetSize is bigger than pipe MaxPacketSize\n");
1173 return B_BAD_VALUE;
1174 }
1175
1176 status_t result = transfer->InitKernelAccess();
1177 if (result != B_OK)
1178 return result;
1179
1180 // Ignore the fact that the last descriptor might need less bandwidth.
1181 // The overhead is not worthy.
1182 uint16 bandwidth = transfer->Bandwidth() / isochronousData->packet_count;
1183
1184 TRACE("isochronous transfer descriptor bandwidth %d\n", bandwidth);
1185
1186 // The following holds the list of transfer descriptor of the
1187 // isochronous request. It is used to quickly remove all the isochronous
1188 // descriptors from the frame list, as descriptors are not link to each
1189 // other in a queue like for every other transfer.
1190 ehci_itd **isoRequest
1191 = new(std::nothrow) ehci_itd *[isochronousData->packet_count];
1192 if (isoRequest == NULL) {
1193 TRACE("failed to create isoRequest array!\n");
1194 return B_NO_MEMORY;
1195 }
1196
1197 TRACE("isochronous submitted size=%" B_PRIuSIZE " bytes, TDs=%" B_PRIu32
1198 ", maxPacketSize=%" B_PRIuSIZE ", packetSize=%" B_PRIuSIZE
1199 ", restSize=%" B_PRIuSIZE "\n", transfer->DataLength(),
1200 isochronousData->packet_count, pipe->MaxPacketSize(), packetSize,
1201 restSize);
1202
1203 // Find the entry where to start inserting the first Isochronous descriptor
1204 if ((isochronousData->flags & USB_ISO_ASAP) != 0 ||
1205 isochronousData->starting_frame_number == NULL) {
1206
1207 if (fFirstIsochronousTransfer != NULL && fNextStartingFrame != -1)
1208 currentFrame = fNextStartingFrame;
1209 else {
1210 uint32 threshold = fThreshold;
1211 TRACE("threshold: %" B_PRIu32 "\n", threshold);
1212
1213 // find the first available frame with enough bandwidth.
1214 // This should always be the case, as defining the starting frame
1215 // number in the driver makes no sense for many reason, one of which
1216 // is that frame numbers value are host controller specific, and the
1217 // driver does not know which host controller is running.
1218 currentFrame = ((ReadOpReg(EHCI_FRINDEX) + threshold) / 8)
1219 & (EHCI_FRAMELIST_ENTRIES_COUNT - 1);
1220 }
1221
1222 // Make sure that:
1223 // 1. We are at least 5ms ahead the controller
1224 // 2. We stay in the range 0-127
1225 // 3. There is enough bandwidth in the first entry
1226 currentFrame &= EHCI_VFRAMELIST_ENTRIES_COUNT - 1;
1227 } else {
1228 // Find out if the frame number specified has enough bandwidth,
1229 // otherwise find the first next available frame with enough bandwidth
1230 currentFrame = *isochronousData->starting_frame_number;
1231 }
1232
1233 TRACE("isochronous starting frame=%d\n", currentFrame);
1234
1235 uint16 itdIndex = 0;
1236 size_t dataLength = transfer->DataLength();
1237 void* bufferLog;
1238 phys_addr_t bufferPhy;
1239 if (fStack->AllocateChunk(&bufferLog, &bufferPhy, dataLength) != B_OK) {
1240 TRACE_ERROR("unable to allocate itd buffer\n");
1241 delete[] isoRequest;
1242 return B_NO_MEMORY;
1243 }
1244
1245 memset(bufferLog, 0, dataLength);
1246
1247 phys_addr_t currentPhy = bufferPhy;
1248 uint32 frameCount = 0;
1249 while (dataLength > 0) {
1250 ehci_itd* itd = CreateItdDescriptor();
1251 isoRequest[itdIndex++] = itd;
1252 uint16 pg = 0;
1253 itd->buffer_phy[pg] = currentPhy & 0xfffff000;
1254 uint32 offset = currentPhy & 0xfff;
1255 TRACE("isochronous created itd, filling it with phy %" B_PRIxPHYSADDR
1256 "\n", currentPhy);
1257 for (int32 i = 0; i < 8 && dataLength > 0; i++) {
1258 size_t length = min_c(dataLength, packetSize);
1259 itd->token[i] = (EHCI_ITD_STATUS_ACTIVE << EHCI_ITD_STATUS_SHIFT)
1260 | (length << EHCI_ITD_TLENGTH_SHIFT) | (pg << EHCI_ITD_PG_SHIFT)
1261 | (offset << EHCI_ITD_TOFFSET_SHIFT);
1262 itd->last_token = i;
1263 TRACE("isochronous filled slot %" B_PRId32 " 0x%" B_PRIx32 "\n", i,
1264 itd->token[i]);
1265 dataLength -= length;
1266 offset += length;
1267 if (dataLength > 0 && offset > 0xfff) {
1268 offset -= B_PAGE_SIZE;
1269 currentPhy += B_PAGE_SIZE;
1270 itd->buffer_phy[pg + 1] = currentPhy & 0xfffff000;
1271 pg++;
1272 }
1273 if (dataLength <= 0)
1274 itd->token[i] |= EHCI_ITD_IOC;
1275 }
1276
1277 currentPhy += (offset & 0xfff) - (currentPhy & 0xfff);
1278
1279 itd->buffer_phy[0]
1280 |= (pipe->EndpointAddress() << EHCI_ITD_ENDPOINT_SHIFT)
1281 | (pipe->DeviceAddress() << EHCI_ITD_ADDRESS_SHIFT);
1282 itd->buffer_phy[1]
1283 |= (pipe->MaxPacketSize() & EHCI_ITD_MAXPACKETSIZE_MASK)
1284 | (directionIn << EHCI_ITD_DIR_SHIFT);
1285 itd->buffer_phy[2]
1286 |= ((((pipe->MaxPacketSize() >> EHCI_ITD_MAXPACKETSIZE_LENGTH) + 1)
1287 & EHCI_ITD_MUL_MASK) << EHCI_ITD_MUL_SHIFT);
1288
1289 TRACE("isochronous filled itd buffer_phy[0,1,2] 0x%" B_PRIx32 ", 0x%"
1290 B_PRIx32 " 0x%" B_PRIx32 "\n",
1291 itd->buffer_phy[0], itd->buffer_phy[1], itd->buffer_phy[2]);
1292
1293 if (!LockIsochronous())
1294 continue;
1295 LinkITDescriptors(itd, &fItdEntries[currentFrame]);
1296 UnlockIsochronous();
1297 fFrameBandwidth[currentFrame] -= bandwidth;
1298 currentFrame = (currentFrame + 1) & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1);
1299 frameCount++;
1300 }
1301
1302 TRACE("isochronous filled itds count %d\n", itdIndex);
1303
1304 // Add transfer to the list
1305 result = AddPendingIsochronousTransfer(transfer, isoRequest,
1306 itdIndex - 1, directionIn, bufferPhy, bufferLog,
1307 transfer->DataLength());
1308 if (result != B_OK) {
1309 TRACE_ERROR("failed to add pending isochronous transfer\n");
1310 for (uint32 i = 0; i < itdIndex; i++)
1311 FreeDescriptor(isoRequest[i]);
1312 delete[] isoRequest;
1313 return result;
1314 }
1315
1316 TRACE("appended isochronous transfer by starting at frame number %d\n",
1317 currentFrame);
1318 fNextStartingFrame = currentFrame + 1;
1319
1320 // Wake up the isochronous finisher thread
1321 release_sem_etc(fFinishIsochronousTransfersSem, 1 /*frameCount*/,
1322 B_DO_NOT_RESCHEDULE);
1323
1324 return B_OK;
1325 }
1326
1327
1328 isochronous_transfer_data *
FindIsochronousTransfer(ehci_itd * itd)1329 EHCI::FindIsochronousTransfer(ehci_itd *itd)
1330 {
1331 // Simply check every last descriptor of the isochronous transfer list
1332 isochronous_transfer_data *transfer = fFirstIsochronousTransfer;
1333 if (transfer) {
1334 while (transfer->descriptors[transfer->last_to_process]
1335 != itd) {
1336 transfer = transfer->link;
1337 if (!transfer)
1338 break;
1339 }
1340 }
1341 return transfer;
1342 }
1343
1344
1345 status_t
NotifyPipeChange(Pipe * pipe,usb_change change)1346 EHCI::NotifyPipeChange(Pipe *pipe, usb_change change)
1347 {
1348 TRACE("pipe change %d for pipe %p\n", change, pipe);
1349 switch (change) {
1350 case USB_CHANGE_CREATED:
1351 case USB_CHANGE_DESTROYED: {
1352 // ToDo: we should create and keep a single queue head
1353 // for all transfers to/from this pipe
1354 break;
1355 }
1356
1357 case USB_CHANGE_PIPE_POLICY_CHANGED: {
1358 // ToDo: for isochronous pipes we might need to adapt to new
1359 // pipe policy settings here
1360 break;
1361 }
1362 }
1363
1364 return B_OK;
1365 }
1366
1367
1368 status_t
GetPortStatus(uint8 index,usb_port_status * status)1369 EHCI::GetPortStatus(uint8 index, usb_port_status *status)
1370 {
1371 if (index >= fPortCount)
1372 return B_BAD_INDEX;
1373
1374 status->status = status->change = 0;
1375 uint32 portStatus = ReadOpReg(EHCI_PORTSC + index * sizeof(uint32));
1376
1377 // build the status
1378 if (portStatus & EHCI_PORTSC_CONNSTATUS)
1379 status->status |= PORT_STATUS_CONNECTION;
1380 if (portStatus & EHCI_PORTSC_ENABLE)
1381 status->status |= PORT_STATUS_ENABLE;
1382 if (portStatus & EHCI_PORTSC_ENABLE)
1383 status->status |= PORT_STATUS_HIGH_SPEED;
1384 if (portStatus & EHCI_PORTSC_OCACTIVE)
1385 status->status |= PORT_STATUS_OVER_CURRENT;
1386 if (portStatus & EHCI_PORTSC_PORTRESET)
1387 status->status |= PORT_STATUS_RESET;
1388 if (portStatus & EHCI_PORTSC_PORTPOWER)
1389 status->status |= PORT_STATUS_POWER;
1390 if (portStatus & EHCI_PORTSC_SUSPEND)
1391 status->status |= PORT_STATUS_SUSPEND;
1392 if (portStatus & EHCI_PORTSC_DMINUS)
1393 status->status |= PORT_STATUS_LOW_SPEED;
1394
1395 // build the change
1396 if (portStatus & EHCI_PORTSC_CONNCHANGE)
1397 status->change |= PORT_STATUS_CONNECTION;
1398 if (portStatus & EHCI_PORTSC_ENABLECHANGE)
1399 status->change |= PORT_STATUS_ENABLE;
1400 if (portStatus & EHCI_PORTSC_OCCHANGE)
1401 status->change |= PORT_STATUS_OVER_CURRENT;
1402
1403 // there are no bits to indicate suspend and reset change
1404 if (fPortResetChange & (1 << index))
1405 status->change |= PORT_STATUS_RESET;
1406 if (fPortSuspendChange & (1 << index))
1407 status->change |= PORT_STATUS_SUSPEND;
1408
1409 return B_OK;
1410 }
1411
1412
1413 status_t
SetPortFeature(uint8 index,uint16 feature)1414 EHCI::SetPortFeature(uint8 index, uint16 feature)
1415 {
1416 if (index >= fPortCount)
1417 return B_BAD_INDEX;
1418
1419 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
1420 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1421
1422 switch (feature) {
1423 case PORT_SUSPEND:
1424 return SuspendPort(index);
1425
1426 case PORT_RESET:
1427 return ResetPort(index);
1428
1429 case PORT_POWER:
1430 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTPOWER);
1431 return B_OK;
1432 }
1433
1434 return B_BAD_VALUE;
1435 }
1436
1437
1438 status_t
ClearPortFeature(uint8 index,uint16 feature)1439 EHCI::ClearPortFeature(uint8 index, uint16 feature)
1440 {
1441 if (index >= fPortCount)
1442 return B_BAD_INDEX;
1443
1444 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
1445 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1446
1447 switch (feature) {
1448 case PORT_ENABLE:
1449 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_ENABLE);
1450 return B_OK;
1451
1452 case PORT_POWER:
1453 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTPOWER);
1454 return B_OK;
1455
1456 case C_PORT_CONNECTION:
1457 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_CONNCHANGE);
1458 return B_OK;
1459
1460 case C_PORT_ENABLE:
1461 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_ENABLECHANGE);
1462 return B_OK;
1463
1464 case C_PORT_OVER_CURRENT:
1465 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_OCCHANGE);
1466 return B_OK;
1467
1468 case C_PORT_RESET:
1469 fPortResetChange &= ~(1 << index);
1470 return B_OK;
1471
1472 case C_PORT_SUSPEND:
1473 fPortSuspendChange &= ~(1 << index);
1474 return B_OK;
1475 }
1476
1477 return B_BAD_VALUE;
1478 }
1479
1480
1481 status_t
ResetPort(uint8 index)1482 EHCI::ResetPort(uint8 index)
1483 {
1484 TRACE("reset port %d\n", index);
1485 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
1486 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1487
1488 if (portStatus & EHCI_PORTSC_DMINUS) {
1489 TRACE_ALWAYS("lowspeed device connected, giving up port ownership\n");
1490 // there is a lowspeed device connected.
1491 // we give the ownership to a companion controller.
1492 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER);
1493 fPortResetChange |= (1 << index);
1494 return B_OK;
1495 }
1496
1497 // enable reset signaling
1498 WriteOpReg(portRegister, (portStatus & ~EHCI_PORTSC_ENABLE)
1499 | EHCI_PORTSC_PORTRESET);
1500 snooze(50000);
1501
1502 // disable reset signaling
1503 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1504 WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTRESET);
1505 snooze(2000);
1506
1507 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1508 if (portStatus & EHCI_PORTSC_PORTRESET) {
1509 TRACE_ERROR("port reset won't complete\n");
1510 return B_ERROR;
1511 }
1512
1513 if ((portStatus & EHCI_PORTSC_ENABLE) == 0) {
1514 TRACE_ALWAYS("fullspeed device connected, giving up port ownership\n");
1515 // the port was not enabled, this means that no high speed device is
1516 // attached to this port. we give up ownership to a companion controler
1517 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER);
1518 }
1519
1520 fPortResetChange |= (1 << index);
1521 return B_OK;
1522 }
1523
1524
1525 status_t
SuspendPort(uint8 index)1526 EHCI::SuspendPort(uint8 index)
1527 {
1528 uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
1529 uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
1530 WriteOpReg(portRegister, portStatus | EHCI_PORTSC_SUSPEND);
1531 fPortSuspendChange |= (1 << index);
1532 return B_OK;
1533 }
1534
1535
1536 status_t
ControllerReset()1537 EHCI::ControllerReset()
1538 {
1539 // halt the controller first
1540 WriteOpReg(EHCI_USBCMD, 0);
1541 snooze(10000);
1542
1543 // then reset it
1544 WriteOpReg(EHCI_USBCMD, EHCI_USBCMD_HCRESET);
1545
1546 int32 tries = 5;
1547 while (ReadOpReg(EHCI_USBCMD) & EHCI_USBCMD_HCRESET) {
1548 snooze(10000);
1549 if (tries-- < 0)
1550 return B_ERROR;
1551 }
1552
1553 return B_OK;
1554 }
1555
1556
1557 status_t
LightReset()1558 EHCI::LightReset()
1559 {
1560 return B_ERROR;
1561 }
1562
1563
1564 int32
InterruptHandler(void * data)1565 EHCI::InterruptHandler(void *data)
1566 {
1567 return ((EHCI *)data)->Interrupt();
1568 }
1569
1570
1571 int32
Interrupt()1572 EHCI::Interrupt()
1573 {
1574 static spinlock lock = B_SPINLOCK_INITIALIZER;
1575 acquire_spinlock(&lock);
1576
1577 // check if any interrupt was generated
1578 uint32 status = ReadOpReg(EHCI_USBSTS) & EHCI_USBSTS_INTMASK;
1579 if ((status & fEnabledInterrupts) == 0) {
1580 if (status != 0) {
1581 TRACE("discarding not enabled interrupts 0x%08" B_PRIx32 "\n",
1582 status);
1583 WriteOpReg(EHCI_USBSTS, status);
1584 }
1585
1586 release_spinlock(&lock);
1587 return B_UNHANDLED_INTERRUPT;
1588 }
1589
1590 bool asyncAdvance = false;
1591 bool finishTransfers = false;
1592 int32 result = B_HANDLED_INTERRUPT;
1593
1594 if (status & EHCI_USBSTS_USBINT) {
1595 TRACE("transfer finished\n");
1596 result = B_INVOKE_SCHEDULER;
1597 finishTransfers = true;
1598 }
1599
1600 if (status & EHCI_USBSTS_USBERRINT) {
1601 TRACE("transfer error\n");
1602 result = B_INVOKE_SCHEDULER;
1603 finishTransfers = true;
1604 }
1605
1606 if (status & EHCI_USBSTS_FLROLLOVER)
1607 TRACE("frame list rollover\n");
1608
1609 if (status & EHCI_USBSTS_PORTCHANGE)
1610 TRACE("port change detected\n");
1611
1612 if (status & EHCI_USBSTS_INTONAA) {
1613 TRACE("interrupt on async advance\n");
1614 asyncAdvance = true;
1615 result = B_INVOKE_SCHEDULER;
1616 }
1617
1618 if (status & EHCI_USBSTS_HOSTSYSERR)
1619 TRACE_ERROR("host system error!\n");
1620
1621 WriteOpReg(EHCI_USBSTS, status);
1622 release_spinlock(&lock);
1623
1624 if (asyncAdvance)
1625 release_sem_etc(fAsyncAdvanceSem, 1, B_DO_NOT_RESCHEDULE);
1626 if (finishTransfers)
1627 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1628
1629 return result;
1630 }
1631
1632
1633 int32
InterruptPollThread(void * data)1634 EHCI::InterruptPollThread(void *data)
1635 {
1636 EHCI *ehci = (EHCI *)data;
1637
1638 while (!ehci->fStopThreads) {
1639 // TODO: this could be handled much better by only polling when there
1640 // are actual transfers going on...
1641 snooze(1000);
1642
1643 cpu_status status = disable_interrupts();
1644 ehci->Interrupt();
1645 restore_interrupts(status);
1646 }
1647
1648 return 0;
1649 }
1650
1651
1652 status_t
AddPendingTransfer(Transfer * transfer,ehci_qh * queueHead,ehci_qtd * dataDescriptor,bool directionIn)1653 EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead,
1654 ehci_qtd *dataDescriptor, bool directionIn)
1655 {
1656 transfer_data *data = new(std::nothrow) transfer_data;
1657 if (!data)
1658 return B_NO_MEMORY;
1659
1660 data->transfer = transfer;
1661 data->queue_head = queueHead;
1662 data->data_descriptor = dataDescriptor;
1663 data->incoming = directionIn;
1664 data->canceled = false;
1665 data->link = NULL;
1666
1667 if (!Lock()) {
1668 delete data;
1669 return B_ERROR;
1670 }
1671
1672 // We do not support queuing other transfers in tandem with a fragmented one.
1673 transfer_data *it = fFirstTransfer;
1674 while (it) {
1675 if (it->transfer && it->transfer->TransferPipe() == transfer->TransferPipe()
1676 && it->transfer->IsFragmented()) {
1677 TRACE_ERROR("cannot submit transfer: a fragmented transfer is queued\n");
1678
1679 Unlock();
1680 delete data;
1681 return B_DEV_RESOURCE_CONFLICT;
1682 }
1683
1684 it = it->link;
1685 }
1686
1687 if (fLastTransfer)
1688 fLastTransfer->link = data;
1689 else
1690 fFirstTransfer = data;
1691
1692 fLastTransfer = data;
1693 Unlock();
1694
1695 return B_OK;
1696 }
1697
1698
1699 status_t
AddPendingIsochronousTransfer(Transfer * transfer,ehci_itd ** isoRequest,uint32 lastIndex,bool directionIn,addr_t bufferPhy,void * bufferLog,size_t bufferSize)1700 EHCI::AddPendingIsochronousTransfer(Transfer *transfer, ehci_itd **isoRequest,
1701 uint32 lastIndex, bool directionIn, addr_t bufferPhy, void* bufferLog,
1702 size_t bufferSize)
1703 {
1704 if (!transfer || !isoRequest)
1705 return B_BAD_VALUE;
1706
1707 isochronous_transfer_data *data
1708 = new(std::nothrow) isochronous_transfer_data;
1709 if (!data)
1710 return B_NO_MEMORY;
1711
1712 data->transfer = transfer;
1713 data->descriptors = isoRequest;
1714 data->last_to_process = lastIndex;
1715 data->incoming = directionIn;
1716 data->is_active = true;
1717 data->link = NULL;
1718 data->buffer_phy = bufferPhy;
1719 data->buffer_log = bufferLog;
1720 data->buffer_size = bufferSize;
1721
1722 // Put in the isochronous transfer list
1723 if (!LockIsochronous()) {
1724 delete data;
1725 return B_ERROR;
1726 }
1727
1728 if (fLastIsochronousTransfer)
1729 fLastIsochronousTransfer->link = data;
1730 else if (!fFirstIsochronousTransfer)
1731 fFirstIsochronousTransfer = data;
1732
1733 fLastIsochronousTransfer = data;
1734 UnlockIsochronous();
1735 return B_OK;
1736 }
1737
1738
1739 status_t
CancelQueuedTransfers(Pipe * pipe,bool force)1740 EHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
1741 {
1742 if ((pipe->Type() & USB_OBJECT_ISO_PIPE) != 0)
1743 return CancelQueuedIsochronousTransfers(pipe, force);
1744
1745 if (!Lock())
1746 return B_ERROR;
1747
1748 struct transfer_entry {
1749 Transfer * transfer;
1750 transfer_entry * next;
1751 };
1752
1753 transfer_entry *list = NULL;
1754 transfer_data *current = fFirstTransfer;
1755 while (current) {
1756 if (current->transfer && current->transfer->TransferPipe() == pipe) {
1757 // clear the active bit so the descriptors are canceled
1758 ehci_qtd *descriptor = current->queue_head->element_log;
1759 while (descriptor) {
1760 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
1761 descriptor = descriptor->next_log;
1762 }
1763
1764 transfer_entry *entry
1765 = (transfer_entry *)malloc(sizeof(transfer_entry));
1766 if (entry != NULL) {
1767 entry->transfer = current->transfer;
1768 current->transfer = NULL;
1769 entry->next = list;
1770 list = entry;
1771 }
1772
1773 current->canceled = true;
1774 }
1775
1776 current = current->link;
1777 }
1778
1779 Unlock();
1780
1781 while (list != NULL) {
1782 transfer_entry *next = list->next;
1783
1784 // if the transfer is canceled by force, the one causing the
1785 // cancel is possibly not the one who initiated the transfer
1786 // and the callback is likely not safe anymore
1787 if (!force)
1788 list->transfer->Finished(B_CANCELED, 0);
1789
1790 delete list->transfer;
1791 free(list);
1792 list = next;
1793 }
1794
1795 // wait for any transfers that might have made it before canceling
1796 while (fProcessingPipe == pipe)
1797 snooze(1000);
1798
1799 // notify the finisher so it can clean up the canceled transfers
1800 release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1801 return B_OK;
1802 }
1803
1804
1805 status_t
CancelQueuedIsochronousTransfers(Pipe * pipe,bool force)1806 EHCI::CancelQueuedIsochronousTransfers(Pipe *pipe, bool force)
1807 {
1808 isochronous_transfer_data *current = fFirstIsochronousTransfer;
1809
1810 while (current) {
1811 if (current->transfer->TransferPipe() == pipe) {
1812 // TODO implement
1813
1814 // TODO: Use the force paramater in order to avoid calling
1815 // invalid callbacks
1816 current->is_active = false;
1817 }
1818
1819 current = current->link;
1820 }
1821
1822 TRACE_ERROR("no isochronous transfer found!\n");
1823 return B_ERROR;
1824 }
1825
1826
1827 status_t
CancelAllPendingTransfers()1828 EHCI::CancelAllPendingTransfers()
1829 {
1830 if (!Lock())
1831 return B_ERROR;
1832
1833 transfer_data *transfer = fFirstTransfer;
1834 while (transfer) {
1835 transfer->transfer->Finished(B_CANCELED, 0);
1836 delete transfer->transfer;
1837
1838 transfer_data *next = transfer->link;
1839 delete transfer;
1840 transfer = next;
1841 }
1842
1843 fFirstTransfer = NULL;
1844 fLastTransfer = NULL;
1845 Unlock();
1846 return B_OK;
1847 }
1848
1849
1850 int32
FinishThread(void * data)1851 EHCI::FinishThread(void *data)
1852 {
1853 ((EHCI *)data)->FinishTransfers();
1854 return B_OK;
1855 }
1856
1857
1858 void
FinishTransfers()1859 EHCI::FinishTransfers()
1860 {
1861 while (!fStopThreads) {
1862 if (acquire_sem(fFinishTransfersSem) != B_OK)
1863 continue;
1864
1865 // eat up sems that have been released by multiple interrupts
1866 int32 semCount = 0;
1867 get_sem_count(fFinishTransfersSem, &semCount);
1868 if (semCount > 0) {
1869 acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT,
1870 0);
1871 }
1872
1873 if (!Lock())
1874 continue;
1875
1876 TRACE("finishing transfers\n");
1877 transfer_data *lastTransfer = NULL;
1878 transfer_data *transfer = fFirstTransfer;
1879 Unlock();
1880
1881 while (transfer) {
1882 bool transferDone = false;
1883 ehci_qtd *descriptor = transfer->queue_head->element_log;
1884 status_t callbackStatus = B_OK;
1885
1886 while (descriptor) {
1887 uint32 status = descriptor->token;
1888 if (status & EHCI_QTD_STATUS_ACTIVE) {
1889 // still in progress
1890 TRACE("qtd (0x%08" B_PRIx32 ") still active\n",
1891 descriptor->this_phy);
1892 break;
1893 }
1894
1895 if (status & EHCI_QTD_STATUS_ERRMASK) {
1896 // a transfer error occured
1897 TRACE_ERROR("qtd (0x%" B_PRIx32 ") error: 0x%08" B_PRIx32
1898 "\n", descriptor->this_phy, status);
1899
1900 uint8 errorCount = status >> EHCI_QTD_ERRCOUNT_SHIFT;
1901 errorCount &= EHCI_QTD_ERRCOUNT_MASK;
1902 if (errorCount == 0) {
1903 // the error counter counted down to zero, report why
1904 int32 reasons = 0;
1905 if (status & EHCI_QTD_STATUS_BUFFER) {
1906 callbackStatus = transfer->incoming
1907 ? B_DEV_WRITE_ERROR : B_DEV_READ_ERROR;
1908 reasons++;
1909 }
1910 if (status & EHCI_QTD_STATUS_TERROR) {
1911 callbackStatus = B_DEV_CRC_ERROR;
1912 reasons++;
1913 }
1914 if ((transfer->queue_head->endpoint_chars
1915 & EHCI_QH_CHARS_EPS_HIGH) == 0) {
1916 // For full-/lowspeed endpoints the unused ping
1917 // state bit is used as another error bit, it is
1918 // unspecific however.
1919 if ((status & EHCI_QTD_STATUS_LS_ERR) != 0) {
1920 callbackStatus = B_DEV_STALLED;
1921 reasons++;
1922 }
1923 }
1924
1925 if (reasons > 1)
1926 callbackStatus = B_DEV_MULTIPLE_ERRORS;
1927 else if (reasons == 0) {
1928 TRACE_ERROR("error counter counted down to zero "
1929 "but none of the error bits are set\n");
1930 callbackStatus = B_DEV_STALLED;
1931 }
1932 } else if (status & EHCI_QTD_STATUS_BABBLE) {
1933 // there is a babble condition
1934 callbackStatus = transfer->incoming
1935 ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN;
1936 } else {
1937 // if the error counter didn't count down to zero
1938 // and there was no babble, then this halt was caused
1939 // by a stall handshake
1940 callbackStatus = B_DEV_STALLED;
1941 }
1942
1943 transferDone = true;
1944 break;
1945 }
1946
1947 if (descriptor->next_phy & EHCI_ITEM_TERMINATE) {
1948 // we arrived at the last (stray) descriptor, we're done
1949 TRACE("qtd (0x%08" B_PRIx32 ") done\n",
1950 descriptor->this_phy);
1951 callbackStatus = B_OK;
1952 transferDone = true;
1953 break;
1954 }
1955
1956 if (((status >> EHCI_QTD_PID_SHIFT) & EHCI_QTD_PID_MASK)
1957 == EHCI_QTD_PID_IN
1958 && ((status >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK)
1959 != 0) {
1960 // a short packet condition existed on this descriptor,
1961 // follow the alternate next pointer if set
1962 if (descriptor->alt_next_log != NULL) {
1963 descriptor = descriptor->alt_next_log;
1964 continue;
1965 }
1966
1967 // no alternate next, transfer is done
1968 callbackStatus = B_OK;
1969 transferDone = true;
1970 break;
1971 }
1972
1973 descriptor = descriptor->next_log;
1974 }
1975
1976 if (!transferDone) {
1977 lastTransfer = transfer;
1978 transfer = transfer->link;
1979 continue;
1980 }
1981
1982 // remove the transfer from the list first so we are sure
1983 // it doesn't get canceled while we still process it
1984 transfer_data *next = transfer->link;
1985 if (Lock()) {
1986 if (lastTransfer)
1987 lastTransfer->link = transfer->link;
1988
1989 if (transfer == fFirstTransfer)
1990 fFirstTransfer = transfer->link;
1991 if (transfer == fLastTransfer)
1992 fLastTransfer = lastTransfer;
1993
1994 // store the currently processing pipe here so we can wait
1995 // in cancel if we are processing something on the target pipe
1996 if (!transfer->canceled)
1997 fProcessingPipe = transfer->transfer->TransferPipe();
1998
1999 transfer->link = NULL;
2000 Unlock();
2001 }
2002
2003 // if canceled the callback has already been called
2004 if (!transfer->canceled) {
2005 size_t actualLength = 0;
2006
2007 if (callbackStatus == B_OK) {
2008 bool nextDataToggle = false;
2009 if (transfer->data_descriptor && transfer->incoming) {
2010 // data to read out
2011 generic_io_vec *vector = transfer->transfer->Vector();
2012 size_t vectorCount = transfer->transfer->VectorCount();
2013 callbackStatus = transfer->transfer->PrepareKernelAccess();
2014 if (callbackStatus == B_OK) {
2015 actualLength = ReadDescriptorChain(
2016 transfer->data_descriptor,
2017 vector, vectorCount, transfer->transfer->IsPhysical(),
2018 &nextDataToggle);
2019 }
2020 } else if (transfer->data_descriptor) {
2021 // calculate transfered length
2022 actualLength = ReadActualLength(
2023 transfer->data_descriptor, &nextDataToggle);
2024 }
2025
2026 transfer->transfer->TransferPipe()->SetDataToggle(
2027 nextDataToggle);
2028 }
2029
2030 if (callbackStatus == B_OK && transfer->transfer->IsFragmented()) {
2031 // this transfer may still have data left
2032 transfer->transfer->AdvanceByFragment(actualLength);
2033 if (transfer->transfer->FragmentLength() > 0) {
2034 FreeDescriptorChain(transfer->data_descriptor);
2035 status_t result = FillQueueWithData(
2036 transfer->transfer,
2037 transfer->queue_head,
2038 &transfer->data_descriptor, NULL, true);
2039
2040 if (result == B_OK && Lock()) {
2041 // reappend the transfer
2042 if (fLastTransfer)
2043 fLastTransfer->link = transfer;
2044 if (!fFirstTransfer)
2045 fFirstTransfer = transfer;
2046
2047 fLastTransfer = transfer;
2048 Unlock();
2049
2050 transfer = next;
2051 continue;
2052 }
2053 }
2054
2055 // the transfer is done, but we already set the
2056 // actualLength with AdvanceByFragment()
2057 actualLength = 0;
2058 }
2059
2060 transfer->transfer->Finished(callbackStatus, actualLength);
2061 fProcessingPipe = NULL;
2062 }
2063
2064 // unlink hardware queue and delete the transfer
2065 UnlinkQueueHead(transfer->queue_head, &fFreeListHead);
2066 delete transfer->transfer;
2067 delete transfer;
2068 transfer = next;
2069 release_sem(fCleanupSem);
2070 }
2071 }
2072 }
2073
2074
2075 int32
CleanupThread(void * data)2076 EHCI::CleanupThread(void *data)
2077 {
2078 ((EHCI *)data)->Cleanup();
2079 return B_OK;
2080 }
2081
2082
2083 void
Cleanup()2084 EHCI::Cleanup()
2085 {
2086 ehci_qh *lastFreeListHead = NULL;
2087
2088 while (!fStopThreads) {
2089 if (acquire_sem(fCleanupSem) != B_OK)
2090 continue;
2091
2092 ehci_qh *freeListHead = fFreeListHead;
2093 if (freeListHead == lastFreeListHead)
2094 continue;
2095
2096 // set the doorbell and wait for the host controller to notify us
2097 WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD);
2098 if (acquire_sem(fAsyncAdvanceSem) != B_OK)
2099 continue;
2100
2101 ehci_qh *current = freeListHead;
2102 while (current != lastFreeListHead) {
2103 ehci_qh *next = current->next_log;
2104 FreeQueueHead(current);
2105 current = next;
2106 }
2107
2108 lastFreeListHead = freeListHead;
2109 }
2110 }
2111
2112
2113 int32
FinishIsochronousThread(void * data)2114 EHCI::FinishIsochronousThread(void *data)
2115 {
2116 ((EHCI *)data)->FinishIsochronousTransfers();
2117 return B_OK;
2118 }
2119
2120
2121 void
FinishIsochronousTransfers()2122 EHCI::FinishIsochronousTransfers()
2123 {
2124 /* This thread stays one position behind the controller and processes every
2125 * isochronous descriptor. Once it finds the last isochronous descriptor
2126 * of a transfer, it processes the entire transfer.
2127 */
2128 while (!fStopThreads) {
2129 // Go to sleep if there are no isochronous transfers to process
2130 if (acquire_sem(fFinishIsochronousTransfersSem) != B_OK)
2131 return;
2132
2133 bool transferDone = false;
2134
2135 uint32 frame = (ReadOpReg(EHCI_FRINDEX) / 8 )
2136 & (EHCI_FRAMELIST_ENTRIES_COUNT - 1);
2137 uint32 currentFrame = (frame + EHCI_VFRAMELIST_ENTRIES_COUNT - 5)
2138 & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1);
2139 uint32 loop = 0;
2140
2141 // Process the frame list until one transfer is processed
2142 while (!transferDone && loop++ < EHCI_VFRAMELIST_ENTRIES_COUNT) {
2143 // wait 1ms in order to be sure to be one position behind
2144 // the controller
2145 while (currentFrame == (((ReadOpReg(EHCI_FRINDEX) / 8)
2146 & (EHCI_VFRAMELIST_ENTRIES_COUNT - 1)))) {
2147 snooze(1000);
2148 }
2149
2150 ehci_itd *itd = fItdEntries[currentFrame];
2151
2152 TRACE("FinishIsochronousTransfers itd %p phy 0x%" B_PRIx32
2153 " prev (%p/0x%" B_PRIx32 ") at frame %" B_PRId32 "\n", itd,
2154 itd->this_phy, itd->prev, itd->prev != NULL
2155 ? itd->prev->this_phy : 0, currentFrame);
2156
2157 if (!LockIsochronous())
2158 continue;
2159
2160 // Process the frame till it has isochronous descriptors in it.
2161 while (!(itd->next_phy & EHCI_ITEM_TERMINATE) && itd->prev != NULL) {
2162 TRACE("FinishIsochronousTransfers checking itd %p last_token"
2163 " %" B_PRId32 "\n", itd, itd->last_token);
2164 TRACE("FinishIsochronousTransfers tokens 0x%" B_PRIx32 " 0x%"
2165 B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx32
2166 " 0x%" B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx32 "\n",
2167 itd->token[0], itd->token[1], itd->token[2], itd->token[3],
2168 itd->token[4], itd->token[5], itd->token[6], itd->token[7]);
2169 if (((itd->token[itd->last_token] >> EHCI_ITD_STATUS_SHIFT)
2170 & EHCI_ITD_STATUS_ACTIVE) == EHCI_ITD_STATUS_ACTIVE) {
2171 TRACE("FinishIsochronousTransfers unprocessed active itd\n");
2172 }
2173 UnlinkITDescriptors(itd, &fItdEntries[currentFrame]);
2174
2175 // Process the transfer if we found the last descriptor
2176 isochronous_transfer_data *transfer
2177 = FindIsochronousTransfer(itd);
2178 // Process the descriptors only if it is still active and
2179 // belongs to an inbound transfer. If the transfer is not
2180 // active, it means the request has been removed, so simply
2181 // remove the descriptors.
2182 if (transfer && transfer->is_active) {
2183 TRACE("FinishIsochronousTransfers active transfer\n");
2184 size_t actualLength = 0;
2185 status_t status = B_OK;
2186 if (((itd->buffer_phy[1] >> EHCI_ITD_DIR_SHIFT) & 1) != 0) {
2187 status = transfer->transfer->PrepareKernelAccess();
2188 if (status == B_OK)
2189 actualLength = ReadIsochronousDescriptorChain(transfer);
2190 }
2191
2192 // Remove the transfer
2193 if (transfer == fFirstIsochronousTransfer) {
2194 fFirstIsochronousTransfer = transfer->link;
2195 if (transfer == fLastIsochronousTransfer)
2196 fLastIsochronousTransfer = NULL;
2197 } else {
2198 isochronous_transfer_data *temp
2199 = fFirstIsochronousTransfer;
2200 while (temp != NULL && transfer != temp->link)
2201 temp = temp->link;
2202
2203 if (transfer == fLastIsochronousTransfer)
2204 fLastIsochronousTransfer = temp;
2205 if (temp != NULL && temp->link != NULL)
2206 temp->link = temp->link->link;
2207 }
2208 transfer->link = NULL;
2209
2210 transfer->transfer->Finished(status, actualLength);
2211
2212 itd = itd->prev;
2213
2214 for (uint32 i = 0; i <= transfer->last_to_process; i++)
2215 FreeDescriptor(transfer->descriptors[i]);
2216
2217 TRACE("FinishIsochronousTransfers descriptors freed\n");
2218
2219 delete [] transfer->descriptors;
2220 delete transfer->transfer;
2221 fStack->FreeChunk(transfer->buffer_log,
2222 (phys_addr_t)transfer->buffer_phy,
2223 transfer->buffer_size);
2224 delete transfer;
2225 transferDone = true;
2226 } else {
2227 TRACE("FinishIsochronousTransfers not end of transfer\n");
2228 itd = itd->prev;
2229 }
2230 }
2231
2232 UnlockIsochronous();
2233
2234 TRACE("FinishIsochronousTransfers next frame\n");
2235
2236 // Make sure to reset the frame bandwidth
2237 fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH;
2238 currentFrame = (currentFrame + 1) % EHCI_VFRAMELIST_ENTRIES_COUNT;
2239 }
2240 }
2241 }
2242
2243
2244 ehci_qh *
CreateQueueHead()2245 EHCI::CreateQueueHead()
2246 {
2247 ehci_qh *result;
2248 phys_addr_t physicalAddress;
2249 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2250 sizeof(ehci_qh)) != B_OK) {
2251 TRACE_ERROR("failed to allocate queue head\n");
2252 return NULL;
2253 }
2254
2255 result->this_phy = (addr_t)physicalAddress | EHCI_ITEM_TYPE_QH;
2256 result->next_phy = EHCI_ITEM_TERMINATE;
2257 result->next_log = NULL;
2258 result->prev_log = NULL;
2259
2260 ehci_qtd *descriptor = CreateDescriptor(0, 0);
2261 if (!descriptor) {
2262 TRACE_ERROR("failed to allocate initial qtd for queue head\n");
2263 fStack->FreeChunk(result, physicalAddress, sizeof(ehci_qh));
2264 return NULL;
2265 }
2266
2267 descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
2268 result->stray_log = descriptor;
2269 result->element_log = descriptor;
2270 result->current_qtd_phy = 0;
2271 result->overlay.next_phy = descriptor->this_phy;
2272 result->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
2273 result->overlay.token = 0;
2274 for (int32 i = 0; i < 5; i++) {
2275 result->overlay.buffer_phy[i] = 0;
2276 result->overlay.ext_buffer_phy[i] = 0;
2277 }
2278
2279 return result;
2280 }
2281
2282
2283 status_t
InitQueueHead(ehci_qh * queueHead,Pipe * pipe)2284 EHCI::InitQueueHead(ehci_qh *queueHead, Pipe *pipe)
2285 {
2286 switch (pipe->Speed()) {
2287 case USB_SPEED_LOWSPEED:
2288 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_LOW;
2289 break;
2290 case USB_SPEED_FULLSPEED:
2291 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_FULL;
2292 break;
2293 case USB_SPEED_HIGHSPEED:
2294 queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH;
2295 break;
2296 default:
2297 TRACE_ERROR("unknown pipe speed\n");
2298 return B_ERROR;
2299 }
2300
2301 queueHead->endpoint_chars |= (3 << EHCI_QH_CHARS_RL_SHIFT)
2302 | (pipe->MaxPacketSize() << EHCI_QH_CHARS_MPL_SHIFT)
2303 | (pipe->EndpointAddress() << EHCI_QH_CHARS_EPT_SHIFT)
2304 | (pipe->DeviceAddress() << EHCI_QH_CHARS_DEV_SHIFT)
2305 | EHCI_QH_CHARS_TOGGLE;
2306
2307 queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT);
2308 if (pipe->Speed() != USB_SPEED_HIGHSPEED) {
2309 if ((pipe->Type() & USB_OBJECT_CONTROL_PIPE) != 0)
2310 queueHead->endpoint_chars |= EHCI_QH_CHARS_CONTROL;
2311
2312 queueHead->endpoint_caps |= (pipe->HubPort() << EHCI_QH_CAPS_PORT_SHIFT)
2313 | (pipe->HubAddress() << EHCI_QH_CAPS_HUB_SHIFT);
2314 }
2315
2316 return B_OK;
2317 }
2318
2319
2320 void
FreeQueueHead(ehci_qh * queueHead)2321 EHCI::FreeQueueHead(ehci_qh *queueHead)
2322 {
2323 if (!queueHead)
2324 return;
2325
2326 FreeDescriptorChain(queueHead->element_log);
2327 FreeDescriptor(queueHead->stray_log);
2328 fStack->FreeChunk(queueHead, (phys_addr_t)queueHead->this_phy,
2329 sizeof(ehci_qh));
2330 }
2331
2332
2333 status_t
LinkQueueHead(ehci_qh * queueHead)2334 EHCI::LinkQueueHead(ehci_qh *queueHead)
2335 {
2336 if (!Lock())
2337 return B_ERROR;
2338
2339 ehci_qh *prevHead = fAsyncQueueHead->prev_log;
2340 queueHead->next_phy = fAsyncQueueHead->this_phy;
2341 queueHead->next_log = fAsyncQueueHead;
2342 queueHead->prev_log = prevHead;
2343 fAsyncQueueHead->prev_log = queueHead;
2344 prevHead->next_log = queueHead;
2345 prevHead->next_phy = queueHead->this_phy;
2346
2347 Unlock();
2348 return B_OK;
2349 }
2350
2351
2352 status_t
LinkInterruptQueueHead(ehci_qh * queueHead,Pipe * pipe)2353 EHCI::LinkInterruptQueueHead(ehci_qh *queueHead, Pipe *pipe)
2354 {
2355 uint8 interval = pipe->Interval();
2356 if (pipe->Speed() == USB_SPEED_HIGHSPEED) {
2357 // Allow interrupts to be scheduled on each possible micro frame.
2358 queueHead->endpoint_caps |= (0xff << EHCI_QH_CAPS_ISM_SHIFT);
2359 } else {
2360 // As we do not yet support FSTNs to correctly reference low/full
2361 // speed interrupt transfers, we simply put them into the 1 or 8 interval
2362 // queue. This way we ensure that we reach them on every micro frame
2363 // and can do the corresponding start/complete split transactions.
2364 // ToDo: use FSTNs to correctly link non high speed interrupt transfers
2365 if (pipe->Speed() == USB_SPEED_LOWSPEED) {
2366 // Low speed devices can't be polled faster than 8ms, so just use
2367 // that.
2368 interval = 4;
2369 } else
2370 interval = 1;
2371
2372 // For now we also force start splits to be in micro frame 0 and
2373 // complete splits to be in micro frame 2, 3 and 4.
2374 queueHead->endpoint_caps |= (0x01 << EHCI_QH_CAPS_ISM_SHIFT);
2375 queueHead->endpoint_caps |= (0x1c << EHCI_QH_CAPS_SCM_SHIFT);
2376 }
2377
2378 // this should not happen
2379 if (interval < 1)
2380 interval = 1;
2381
2382 // this may happen as intervals can go up to 16; we limit the value to
2383 // EHCI_INTERRUPT_ENTRIES_COUNT as you cannot support intervals above
2384 // that with a frame list of just EHCI_VFRAMELIST_ENTRIES_COUNT entries...
2385 if (interval > EHCI_INTERRUPT_ENTRIES_COUNT)
2386 interval = EHCI_INTERRUPT_ENTRIES_COUNT;
2387
2388 if (!Lock())
2389 return B_ERROR;
2390
2391 ehci_qh *interruptQueue = &fInterruptEntries[interval - 1].queue_head;
2392 queueHead->next_phy = interruptQueue->next_phy;
2393 queueHead->next_log = interruptQueue->next_log;
2394 queueHead->prev_log = interruptQueue;
2395 if (interruptQueue->next_log)
2396 interruptQueue->next_log->prev_log = queueHead;
2397 interruptQueue->next_log = queueHead;
2398 interruptQueue->next_phy = queueHead->this_phy;
2399
2400 Unlock();
2401 return B_OK;
2402 }
2403
2404
2405 status_t
UnlinkQueueHead(ehci_qh * queueHead,ehci_qh ** freeListHead)2406 EHCI::UnlinkQueueHead(ehci_qh *queueHead, ehci_qh **freeListHead)
2407 {
2408 if (!Lock())
2409 return B_ERROR;
2410
2411 ehci_qh *prevHead = queueHead->prev_log;
2412 ehci_qh *nextHead = queueHead->next_log;
2413 if (prevHead) {
2414 prevHead->next_phy = queueHead->next_phy;
2415 prevHead->next_log = queueHead->next_log;
2416 }
2417
2418 if (nextHead)
2419 nextHead->prev_log = queueHead->prev_log;
2420
2421 queueHead->next_phy = fAsyncQueueHead->this_phy;
2422 queueHead->prev_log = NULL;
2423
2424 queueHead->next_log = *freeListHead;
2425 *freeListHead = queueHead;
2426
2427 Unlock();
2428 return B_OK;
2429 }
2430
2431
2432 status_t
FillQueueWithRequest(Transfer * transfer,ehci_qh * queueHead,ehci_qtd ** _dataDescriptor,bool * _directionIn,bool prepareKernelAccess)2433 EHCI::FillQueueWithRequest(Transfer *transfer, ehci_qh *queueHead,
2434 ehci_qtd **_dataDescriptor, bool *_directionIn, bool prepareKernelAccess)
2435 {
2436 Pipe *pipe = transfer->TransferPipe();
2437 usb_request_data *requestData = transfer->RequestData();
2438 bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
2439
2440 ehci_qtd *setupDescriptor = CreateDescriptor(sizeof(usb_request_data),
2441 EHCI_QTD_PID_SETUP);
2442 ehci_qtd *statusDescriptor = CreateDescriptor(0,
2443 directionIn ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN);
2444
2445 if (!setupDescriptor || !statusDescriptor) {
2446 TRACE_ERROR("failed to allocate descriptors\n");
2447 FreeDescriptor(setupDescriptor);
2448 FreeDescriptor(statusDescriptor);
2449 return B_NO_MEMORY;
2450 }
2451
2452 generic_io_vec vector;
2453 vector.base = (generic_addr_t)requestData;
2454 vector.length = sizeof(usb_request_data);
2455 WriteDescriptorChain(setupDescriptor, &vector, 1, false);
2456
2457 ehci_qtd *strayDescriptor = queueHead->stray_log;
2458 statusDescriptor->token |= EHCI_QTD_IOC | EHCI_QTD_DATA_TOGGLE;
2459
2460 ehci_qtd *dataDescriptor = NULL;
2461 if (transfer->VectorCount() > 0) {
2462 ehci_qtd *lastDescriptor = NULL;
2463 status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
2464 &lastDescriptor, statusDescriptor, transfer->FragmentLength(),
2465 directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
2466
2467 if (result != B_OK) {
2468 FreeDescriptor(setupDescriptor);
2469 FreeDescriptor(statusDescriptor);
2470 return result;
2471 }
2472
2473 if (!directionIn) {
2474 if (prepareKernelAccess) {
2475 result = transfer->PrepareKernelAccess();
2476 if (result != B_OK) {
2477 FreeDescriptor(setupDescriptor);
2478 FreeDescriptor(statusDescriptor);
2479 return result;
2480 }
2481 }
2482 WriteDescriptorChain(dataDescriptor, transfer->Vector(),
2483 transfer->VectorCount(), transfer->IsPhysical());
2484 }
2485
2486 LinkDescriptors(setupDescriptor, dataDescriptor, strayDescriptor);
2487 LinkDescriptors(lastDescriptor, statusDescriptor, statusDescriptor);
2488 } else {
2489 // no data: link setup and status descriptors directly
2490 LinkDescriptors(setupDescriptor, statusDescriptor, strayDescriptor);
2491 }
2492
2493 queueHead->element_log = setupDescriptor;
2494 queueHead->overlay.next_phy = setupDescriptor->this_phy;
2495 queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
2496
2497 *_dataDescriptor = dataDescriptor;
2498 *_directionIn = directionIn;
2499 return B_OK;
2500 }
2501
2502
2503 status_t
FillQueueWithData(Transfer * transfer,ehci_qh * queueHead,ehci_qtd ** _dataDescriptor,bool * _directionIn,bool prepareKernelAccess)2504 EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead,
2505 ehci_qtd **_dataDescriptor, bool *_directionIn, bool prepareKernelAccess)
2506 {
2507 Pipe *pipe = transfer->TransferPipe();
2508 bool directionIn = (pipe->Direction() == Pipe::In);
2509
2510 ehci_qtd *firstDescriptor = NULL;
2511 ehci_qtd *lastDescriptor = NULL;
2512 ehci_qtd *strayDescriptor = queueHead->stray_log;
2513 status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
2514 &lastDescriptor, strayDescriptor, transfer->FragmentLength(),
2515 directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
2516
2517 if (result != B_OK)
2518 return result;
2519
2520 lastDescriptor->token |= EHCI_QTD_IOC;
2521 if (!directionIn) {
2522 if (prepareKernelAccess) {
2523 result = transfer->PrepareKernelAccess();
2524 if (result != B_OK) {
2525 FreeDescriptorChain(firstDescriptor);
2526 return result;
2527 }
2528 }
2529 WriteDescriptorChain(firstDescriptor, transfer->Vector(),
2530 transfer->VectorCount(), transfer->IsPhysical());
2531 }
2532
2533 queueHead->element_log = firstDescriptor;
2534 queueHead->overlay.next_phy = firstDescriptor->this_phy;
2535 queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
2536
2537 *_dataDescriptor = firstDescriptor;
2538 if (_directionIn)
2539 *_directionIn = directionIn;
2540 return B_OK;
2541 }
2542
2543
2544 ehci_qtd *
CreateDescriptor(size_t bufferSize,uint8 pid)2545 EHCI::CreateDescriptor(size_t bufferSize, uint8 pid)
2546 {
2547 ehci_qtd *result;
2548 phys_addr_t physicalAddress;
2549 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2550 sizeof(ehci_qtd)) != B_OK) {
2551 TRACE_ERROR("failed to allocate a qtd\n");
2552 return NULL;
2553 }
2554
2555 result->this_phy = (addr_t)physicalAddress;
2556 result->next_phy = EHCI_ITEM_TERMINATE;
2557 result->next_log = NULL;
2558 result->alt_next_phy = EHCI_ITEM_TERMINATE;
2559 result->alt_next_log = NULL;
2560 result->buffer_size = bufferSize;
2561 result->token = bufferSize << EHCI_QTD_BYTES_SHIFT;
2562 result->token |= 3 << EHCI_QTD_ERRCOUNT_SHIFT;
2563 result->token |= pid << EHCI_QTD_PID_SHIFT;
2564 result->token |= EHCI_QTD_STATUS_ACTIVE;
2565 if (bufferSize == 0) {
2566 result->buffer_log = NULL;
2567 for (int32 i = 0; i < 5; i++) {
2568 result->buffer_phy[i] = 0;
2569 result->ext_buffer_phy[i] = 0;
2570 }
2571
2572 return result;
2573 }
2574
2575 if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress,
2576 bufferSize) != B_OK) {
2577 TRACE_ERROR("unable to allocate qtd buffer\n");
2578 fStack->FreeChunk(result, (phys_addr_t)result->this_phy,
2579 sizeof(ehci_qtd));
2580 return NULL;
2581 }
2582
2583 addr_t physicalBase = (addr_t)physicalAddress;
2584 result->buffer_phy[0] = physicalBase;
2585 result->ext_buffer_phy[0] = 0;
2586 for (int32 i = 1; i < 5; i++) {
2587 physicalBase += B_PAGE_SIZE;
2588 result->buffer_phy[i] = physicalBase & EHCI_QTD_PAGE_MASK;
2589 result->ext_buffer_phy[i] = 0;
2590 }
2591
2592 return result;
2593 }
2594
2595
2596 status_t
CreateDescriptorChain(Pipe * pipe,ehci_qtd ** _firstDescriptor,ehci_qtd ** _lastDescriptor,ehci_qtd * strayDescriptor,size_t bufferSize,uint8 pid)2597 EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor,
2598 ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize,
2599 uint8 pid)
2600 {
2601 size_t packetSize = B_PAGE_SIZE * 4;
2602 int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
2603
2604 bool dataToggle = pipe->DataToggle();
2605 ehci_qtd *firstDescriptor = NULL;
2606 ehci_qtd *lastDescriptor = *_firstDescriptor;
2607 for (int32 i = 0; i < descriptorCount; i++) {
2608 ehci_qtd *descriptor = CreateDescriptor(min_c(packetSize, bufferSize),
2609 pid);
2610
2611 if (!descriptor) {
2612 FreeDescriptorChain(firstDescriptor);
2613 return B_NO_MEMORY;
2614 }
2615
2616 if (dataToggle)
2617 descriptor->token |= EHCI_QTD_DATA_TOGGLE;
2618
2619 if (lastDescriptor)
2620 LinkDescriptors(lastDescriptor, descriptor, strayDescriptor);
2621
2622 bufferSize -= packetSize;
2623 lastDescriptor = descriptor;
2624 if (!firstDescriptor)
2625 firstDescriptor = descriptor;
2626 }
2627
2628 *_firstDescriptor = firstDescriptor;
2629 *_lastDescriptor = lastDescriptor;
2630 return B_OK;
2631 }
2632
2633
2634 void
FreeDescriptor(ehci_qtd * descriptor)2635 EHCI::FreeDescriptor(ehci_qtd *descriptor)
2636 {
2637 if (!descriptor)
2638 return;
2639
2640 if (descriptor->buffer_log) {
2641 fStack->FreeChunk(descriptor->buffer_log,
2642 (phys_addr_t)descriptor->buffer_phy[0], descriptor->buffer_size);
2643 }
2644
2645 fStack->FreeChunk(descriptor, (phys_addr_t)descriptor->this_phy,
2646 sizeof(ehci_qtd));
2647 }
2648
2649
2650 void
FreeDescriptorChain(ehci_qtd * topDescriptor)2651 EHCI::FreeDescriptorChain(ehci_qtd *topDescriptor)
2652 {
2653 ehci_qtd *current = topDescriptor;
2654 ehci_qtd *next = NULL;
2655
2656 while (current) {
2657 next = current->next_log;
2658 FreeDescriptor(current);
2659 current = next;
2660 }
2661 }
2662
2663
2664 ehci_itd *
CreateItdDescriptor()2665 EHCI::CreateItdDescriptor()
2666 {
2667 ehci_itd *result;
2668 phys_addr_t physicalAddress;
2669 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2670 sizeof(ehci_itd)) != B_OK) {
2671 TRACE_ERROR("failed to allocate a itd\n");
2672 return NULL;
2673 }
2674
2675 memset(result, 0, sizeof(ehci_itd));
2676 result->this_phy = (addr_t)physicalAddress;
2677 result->next_phy = EHCI_ITEM_TERMINATE;
2678
2679 return result;
2680 }
2681
2682
2683 ehci_sitd *
CreateSitdDescriptor()2684 EHCI::CreateSitdDescriptor()
2685 {
2686 ehci_sitd *result;
2687 phys_addr_t physicalAddress;
2688 if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2689 sizeof(ehci_sitd)) != B_OK) {
2690 TRACE_ERROR("failed to allocate a sitd\n");
2691 return NULL;
2692 }
2693
2694 memset(result, 0, sizeof(ehci_sitd));
2695 result->this_phy = (addr_t)physicalAddress | EHCI_ITEM_TYPE_SITD;
2696 result->next_phy = EHCI_ITEM_TERMINATE;
2697
2698 return result;
2699 }
2700
2701
2702 void
FreeDescriptor(ehci_itd * descriptor)2703 EHCI::FreeDescriptor(ehci_itd *descriptor)
2704 {
2705 if (!descriptor)
2706 return;
2707
2708 fStack->FreeChunk(descriptor, (phys_addr_t)descriptor->this_phy,
2709 sizeof(ehci_itd));
2710 }
2711
2712
2713 void
FreeDescriptor(ehci_sitd * descriptor)2714 EHCI::FreeDescriptor(ehci_sitd *descriptor)
2715 {
2716 if (!descriptor)
2717 return;
2718
2719 fStack->FreeChunk(descriptor, (phys_addr_t)descriptor->this_phy,
2720 sizeof(ehci_sitd));
2721 }
2722
2723
2724 void
LinkDescriptors(ehci_qtd * first,ehci_qtd * last,ehci_qtd * alt)2725 EHCI::LinkDescriptors(ehci_qtd *first, ehci_qtd *last, ehci_qtd *alt)
2726 {
2727 first->next_phy = last->this_phy;
2728 first->next_log = last;
2729
2730 if (alt) {
2731 first->alt_next_phy = alt->this_phy;
2732 first->alt_next_log = alt;
2733 } else {
2734 first->alt_next_phy = EHCI_ITEM_TERMINATE;
2735 first->alt_next_log = NULL;
2736 }
2737 }
2738
2739
2740 void
LinkITDescriptors(ehci_itd * itd,ehci_itd ** _last)2741 EHCI::LinkITDescriptors(ehci_itd *itd, ehci_itd **_last)
2742 {
2743 ehci_itd *last = *_last;
2744 itd->next_phy = last->next_phy;
2745 itd->next = NULL;
2746 itd->prev = last;
2747 last->next = itd;
2748 last->next_phy = itd->this_phy;
2749 *_last = itd;
2750 }
2751
2752
2753 void
LinkSITDescriptors(ehci_sitd * sitd,ehci_sitd ** _last)2754 EHCI::LinkSITDescriptors(ehci_sitd *sitd, ehci_sitd **_last)
2755 {
2756 ehci_sitd *last = *_last;
2757 sitd->next_phy = last->next_phy;
2758 sitd->next = NULL;
2759 sitd->prev = last;
2760 last->next = sitd;
2761 last->next_phy = sitd->this_phy;
2762 *_last = sitd;
2763 }
2764
2765
2766 void
UnlinkITDescriptors(ehci_itd * itd,ehci_itd ** last)2767 EHCI::UnlinkITDescriptors(ehci_itd *itd, ehci_itd **last)
2768 {
2769 itd->prev->next_phy = itd->next_phy;
2770 itd->prev->next = itd->next;
2771 if (itd->next != NULL)
2772 itd->next->prev = itd->prev;
2773 if (itd == *last)
2774 *last = itd->prev;
2775 }
2776
2777
2778 void
UnlinkSITDescriptors(ehci_sitd * sitd,ehci_sitd ** last)2779 EHCI::UnlinkSITDescriptors(ehci_sitd *sitd, ehci_sitd **last)
2780 {
2781 sitd->prev->next_phy = sitd->next_phy;
2782 sitd->prev->next = sitd->next;
2783 if (sitd->next != NULL)
2784 sitd->next->prev = sitd->prev;
2785 if (sitd == *last)
2786 *last = sitd->prev;
2787 }
2788
2789
2790 size_t
WriteDescriptorChain(ehci_qtd * topDescriptor,generic_io_vec * vector,size_t vectorCount,bool physical)2791 EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, generic_io_vec *vector,
2792 size_t vectorCount, bool physical)
2793 {
2794 ehci_qtd *current = topDescriptor;
2795 size_t actualLength = 0;
2796 size_t vectorIndex = 0;
2797 size_t vectorOffset = 0;
2798 size_t bufferOffset = 0;
2799
2800 while (current) {
2801 if (!current->buffer_log)
2802 break;
2803
2804 while (true) {
2805 size_t length = min_c(current->buffer_size - bufferOffset,
2806 vector[vectorIndex].length - vectorOffset);
2807
2808 status_t status = generic_memcpy(
2809 (generic_addr_t)current->buffer_log + bufferOffset, false,
2810 vector[vectorIndex].base + vectorOffset, physical, length);
2811 ASSERT_ALWAYS(status == B_OK);
2812
2813 actualLength += length;
2814 vectorOffset += length;
2815 bufferOffset += length;
2816
2817 if (vectorOffset >= vector[vectorIndex].length) {
2818 if (++vectorIndex >= vectorCount) {
2819 TRACE("wrote descriptor chain (%ld bytes, no more vectors)"
2820 "\n", actualLength);
2821 return actualLength;
2822 }
2823
2824 vectorOffset = 0;
2825 }
2826
2827 if (bufferOffset >= current->buffer_size) {
2828 bufferOffset = 0;
2829 break;
2830 }
2831 }
2832
2833 if (current->next_phy & EHCI_ITEM_TERMINATE)
2834 break;
2835
2836 current = current->next_log;
2837 }
2838
2839 TRACE("wrote descriptor chain (%ld bytes)\n", actualLength);
2840 return actualLength;
2841 }
2842
2843
2844 size_t
ReadDescriptorChain(ehci_qtd * topDescriptor,generic_io_vec * vector,size_t vectorCount,bool physical,bool * nextDataToggle)2845 EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, generic_io_vec *vector,
2846 size_t vectorCount, bool physical, bool *nextDataToggle)
2847 {
2848 uint32 dataToggle = 0;
2849 ehci_qtd *current = topDescriptor;
2850 size_t actualLength = 0;
2851 size_t vectorIndex = 0;
2852 size_t vectorOffset = 0;
2853 size_t bufferOffset = 0;
2854
2855 while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) {
2856 if (!current->buffer_log)
2857 break;
2858
2859 dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
2860 size_t bufferSize = current->buffer_size;
2861 bufferSize -= (current->token >> EHCI_QTD_BYTES_SHIFT)
2862 & EHCI_QTD_BYTES_MASK;
2863
2864 while (true) {
2865 size_t length = min_c(bufferSize - bufferOffset,
2866 vector[vectorIndex].length - vectorOffset);
2867
2868 status_t status = generic_memcpy(
2869 vector[vectorIndex].base + vectorOffset, physical,
2870 (generic_addr_t)current->buffer_log + bufferOffset, false, length);
2871 ASSERT_ALWAYS(status == B_OK);
2872
2873 actualLength += length;
2874 vectorOffset += length;
2875 bufferOffset += length;
2876
2877 if (vectorOffset >= vector[vectorIndex].length) {
2878 if (++vectorIndex >= vectorCount) {
2879 TRACE("read descriptor chain (%ld bytes, no more vectors)"
2880 "\n", actualLength);
2881 *nextDataToggle = dataToggle > 0 ? true : false;
2882 return actualLength;
2883 }
2884
2885 vectorOffset = 0;
2886 }
2887
2888 if (bufferOffset >= bufferSize) {
2889 bufferOffset = 0;
2890 break;
2891 }
2892 }
2893
2894 if (current->next_phy & EHCI_ITEM_TERMINATE)
2895 break;
2896
2897 current = current->next_log;
2898 }
2899
2900 TRACE("read descriptor chain (%ld bytes)\n", actualLength);
2901 *nextDataToggle = dataToggle > 0 ? true : false;
2902 return actualLength;
2903 }
2904
2905
2906 size_t
ReadActualLength(ehci_qtd * topDescriptor,bool * nextDataToggle)2907 EHCI::ReadActualLength(ehci_qtd *topDescriptor, bool *nextDataToggle)
2908 {
2909 size_t actualLength = 0;
2910 ehci_qtd *current = topDescriptor;
2911 uint32 dataToggle = 0;
2912
2913 while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) {
2914 dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
2915 size_t length = current->buffer_size;
2916 length -= (current->token >> EHCI_QTD_BYTES_SHIFT)
2917 & EHCI_QTD_BYTES_MASK;
2918 actualLength += length;
2919
2920 if (current->next_phy & EHCI_ITEM_TERMINATE)
2921 break;
2922
2923 current = current->next_log;
2924 }
2925
2926 TRACE("read actual length (%ld bytes)\n", actualLength);
2927 *nextDataToggle = dataToggle > 0 ? true : false;
2928 return actualLength;
2929 }
2930
2931
2932 size_t
WriteIsochronousDescriptorChain(isochronous_transfer_data * transfer)2933 EHCI::WriteIsochronousDescriptorChain(isochronous_transfer_data *transfer)
2934 {
2935 // TODO implement
2936 return 0;
2937 }
2938
2939
2940 size_t
ReadIsochronousDescriptorChain(isochronous_transfer_data * transfer)2941 EHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer)
2942 {
2943 generic_io_vec *vector = transfer->transfer->Vector();
2944 size_t vectorCount = transfer->transfer->VectorCount();
2945 const bool physical = transfer->transfer->IsPhysical();
2946 size_t vectorOffset = 0;
2947 size_t vectorIndex = 0;
2948 usb_isochronous_data *isochronousData
2949 = transfer->transfer->IsochronousData();
2950 uint32 packet = 0;
2951 size_t totalLength = 0;
2952 size_t bufferOffset = 0;
2953
2954 size_t packetSize = transfer->transfer->DataLength();
2955 packetSize /= isochronousData->packet_count;
2956
2957 for (uint32 i = 0; i <= transfer->last_to_process; i++) {
2958 ehci_itd *itd = transfer->descriptors[i];
2959 for (uint32 j = 0; j <= itd->last_token
2960 && packet < isochronousData->packet_count; j++) {
2961
2962 size_t bufferSize = (itd->token[j] >> EHCI_ITD_TLENGTH_SHIFT)
2963 & EHCI_ITD_TLENGTH_MASK;
2964 if (((itd->token[j] >> EHCI_ITD_STATUS_SHIFT)
2965 & EHCI_ITD_STATUS_MASK) != 0) {
2966 bufferSize = 0;
2967 }
2968 isochronousData->packet_descriptors[packet].actual_length
2969 = bufferSize;
2970
2971 if (bufferSize > 0)
2972 isochronousData->packet_descriptors[packet].status = B_OK;
2973 else
2974 isochronousData->packet_descriptors[packet].status = B_ERROR;
2975
2976 totalLength += bufferSize;
2977
2978 size_t offset = bufferOffset;
2979 size_t skipSize = packetSize - bufferSize;
2980 while (bufferSize > 0) {
2981 size_t length = min_c(bufferSize,
2982 vector[vectorIndex].length - vectorOffset);
2983 status_t status = generic_memcpy(
2984 vector[vectorIndex].base + vectorOffset, physical,
2985 (generic_addr_t)transfer->buffer_log + bufferOffset, false, length);
2986 ASSERT_ALWAYS(status == B_OK);
2987
2988 offset += length;
2989 vectorOffset += length;
2990 bufferSize -= length;
2991
2992 if (vectorOffset >= vector[vectorIndex].length) {
2993 if (++vectorIndex >= vectorCount) {
2994 TRACE("read isodescriptor chain (%ld bytes, no more "
2995 "vectors)\n", totalLength);
2996 return totalLength;
2997 }
2998
2999 vectorOffset = 0;
3000 }
3001 }
3002
3003 // skip to next packet offset
3004 while (skipSize > 0) {
3005 size_t length = min_c(skipSize,
3006 vector[vectorIndex].length - vectorOffset);
3007 vectorOffset += length;
3008 skipSize -= length;
3009 if (vectorOffset >= vector[vectorIndex].length) {
3010 if (++vectorIndex >= vectorCount) {
3011 TRACE("read isodescriptor chain (%ld bytes, no more "
3012 "vectors)\n", totalLength);
3013 return totalLength;
3014 }
3015
3016 vectorOffset = 0;
3017 }
3018 }
3019
3020 bufferOffset += packetSize;
3021 if (bufferOffset >= transfer->buffer_size)
3022 return totalLength;
3023
3024 packet++;
3025 }
3026 }
3027
3028 TRACE("ReadIsochronousDescriptorChain packet count %" B_PRId32 "\n",
3029 packet);
3030
3031 return totalLength;
3032 }
3033
3034
3035 bool
LockIsochronous()3036 EHCI::LockIsochronous()
3037 {
3038 return (mutex_lock(&fIsochronousLock) == B_OK);
3039 }
3040
3041
3042 void
UnlockIsochronous()3043 EHCI::UnlockIsochronous()
3044 {
3045 mutex_unlock(&fIsochronousLock);
3046 }
3047
3048
3049 inline void
WriteOpReg(uint32 reg,uint32 value)3050 EHCI::WriteOpReg(uint32 reg, uint32 value)
3051 {
3052 *(volatile uint32 *)(fOperationalRegisters + reg) = value;
3053 }
3054
3055
3056 inline uint32
ReadOpReg(uint32 reg)3057 EHCI::ReadOpReg(uint32 reg)
3058 {
3059 return *(volatile uint32 *)(fOperationalRegisters + reg);
3060 }
3061
3062
3063 inline uint8
ReadCapReg8(uint32 reg)3064 EHCI::ReadCapReg8(uint32 reg)
3065 {
3066 return *(volatile uint8 *)(fCapabilityRegisters + reg);
3067 }
3068
3069
3070 inline uint16
ReadCapReg16(uint32 reg)3071 EHCI::ReadCapReg16(uint32 reg)
3072 {
3073 return *(volatile uint16 *)(fCapabilityRegisters + reg);
3074 }
3075
3076
3077 inline uint32
ReadCapReg32(uint32 reg)3078 EHCI::ReadCapReg32(uint32 reg)
3079 {
3080 return *(volatile uint32 *)(fCapabilityRegisters + reg);
3081 }
3082