xref: /haiku/src/add-ons/kernel/busses/usb/ehci.cpp (revision c237c4ce593ee823d9867fd997e51e4c447f5623)
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
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
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
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
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
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
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
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
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
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 
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 
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
1558 EHCI::LightReset()
1559 {
1560 	return B_ERROR;
1561 }
1562 
1563 
1564 int32
1565 EHCI::InterruptHandler(void *data)
1566 {
1567 	return ((EHCI *)data)->Interrupt();
1568 }
1569 
1570 
1571 int32
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
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
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
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
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 			if (!force) {
1765 				// if the transfer is canceled by force, the one causing the
1766 				// cancel is probably not the one who initiated the transfer
1767 				// and the callback is likely not safe anymore
1768 				transfer_entry *entry
1769 					= (transfer_entry *)malloc(sizeof(transfer_entry));
1770 				if (entry != NULL) {
1771 					entry->transfer = current->transfer;
1772 					current->transfer = NULL;
1773 					entry->next = list;
1774 					list = entry;
1775 				}
1776 			}
1777 
1778 			current->canceled = true;
1779 		}
1780 
1781 		current = current->link;
1782 	}
1783 
1784 	Unlock();
1785 
1786 	while (list != NULL) {
1787 		transfer_entry *next = list->next;
1788 		list->transfer->Finished(B_CANCELED, 0);
1789 		delete list->transfer;
1790 		free(list);
1791 		list = next;
1792 	}
1793 
1794 	// wait for any transfers that might have made it before canceling
1795 	while (fProcessingPipe == pipe)
1796 		snooze(1000);
1797 
1798 	// notify the finisher so it can clean up the canceled transfers
1799 	release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1800 	return B_OK;
1801 }
1802 
1803 
1804 status_t
1805 EHCI::CancelQueuedIsochronousTransfers(Pipe *pipe, bool force)
1806 {
1807 	isochronous_transfer_data *current = fFirstIsochronousTransfer;
1808 
1809 	while (current) {
1810 		if (current->transfer->TransferPipe() == pipe) {
1811 			// TODO implement
1812 
1813 			// TODO: Use the force paramater in order to avoid calling
1814 			// invalid callbacks
1815 			current->is_active = false;
1816 		}
1817 
1818 		current = current->link;
1819 	}
1820 
1821 	TRACE_ERROR("no isochronous transfer found!\n");
1822 	return B_ERROR;
1823 }
1824 
1825 
1826 status_t
1827 EHCI::CancelAllPendingTransfers()
1828 {
1829 	if (!Lock())
1830 		return B_ERROR;
1831 
1832 	transfer_data *transfer = fFirstTransfer;
1833 	while (transfer) {
1834 		transfer->transfer->Finished(B_CANCELED, 0);
1835 		delete transfer->transfer;
1836 
1837 		transfer_data *next = transfer->link;
1838 		delete transfer;
1839 		transfer = next;
1840 	}
1841 
1842 	fFirstTransfer = NULL;
1843 	fLastTransfer = NULL;
1844 	Unlock();
1845 	return B_OK;
1846 }
1847 
1848 
1849 int32
1850 EHCI::FinishThread(void *data)
1851 {
1852 	((EHCI *)data)->FinishTransfers();
1853 	return B_OK;
1854 }
1855 
1856 
1857 void
1858 EHCI::FinishTransfers()
1859 {
1860 	while (!fStopThreads) {
1861 		if (acquire_sem(fFinishTransfersSem) != B_OK)
1862 			continue;
1863 
1864 		// eat up sems that have been released by multiple interrupts
1865 		int32 semCount = 0;
1866 		get_sem_count(fFinishTransfersSem, &semCount);
1867 		if (semCount > 0) {
1868 			acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT,
1869 				0);
1870 		}
1871 
1872 		if (!Lock())
1873 			continue;
1874 
1875 		TRACE("finishing transfers\n");
1876 		transfer_data *lastTransfer = NULL;
1877 		transfer_data *transfer = fFirstTransfer;
1878 		Unlock();
1879 
1880 		while (transfer) {
1881 			bool transferDone = false;
1882 			ehci_qtd *descriptor = transfer->queue_head->element_log;
1883 			status_t callbackStatus = B_OK;
1884 
1885 			while (descriptor) {
1886 				uint32 status = descriptor->token;
1887 				if (status & EHCI_QTD_STATUS_ACTIVE) {
1888 					// still in progress
1889 					TRACE("qtd (0x%08" B_PRIx32 ") still active\n",
1890 						descriptor->this_phy);
1891 					break;
1892 				}
1893 
1894 				if (status & EHCI_QTD_STATUS_ERRMASK) {
1895 					// a transfer error occured
1896 					TRACE_ERROR("qtd (0x%" B_PRIx32 ") error: 0x%08" B_PRIx32
1897 						"\n", descriptor->this_phy, status);
1898 
1899 					uint8 errorCount = status >> EHCI_QTD_ERRCOUNT_SHIFT;
1900 					errorCount &= EHCI_QTD_ERRCOUNT_MASK;
1901 					if (errorCount == 0) {
1902 						// the error counter counted down to zero, report why
1903 						int32 reasons = 0;
1904 						if (status & EHCI_QTD_STATUS_BUFFER) {
1905 							callbackStatus = transfer->incoming
1906 								? B_DEV_WRITE_ERROR : B_DEV_READ_ERROR;
1907 							reasons++;
1908 						}
1909 						if (status & EHCI_QTD_STATUS_TERROR) {
1910 							callbackStatus = B_DEV_CRC_ERROR;
1911 							reasons++;
1912 						}
1913 						if ((transfer->queue_head->endpoint_chars
1914 								& EHCI_QH_CHARS_EPS_HIGH) == 0) {
1915 							// For full-/lowspeed endpoints the unused ping
1916 							// state bit is used as another error bit, it is
1917 							// unspecific however.
1918 							if ((status & EHCI_QTD_STATUS_LS_ERR) != 0) {
1919 								callbackStatus = B_DEV_STALLED;
1920 								reasons++;
1921 							}
1922 						}
1923 
1924 						if (reasons > 1)
1925 							callbackStatus = B_DEV_MULTIPLE_ERRORS;
1926 						else if (reasons == 0) {
1927 							TRACE_ERROR("error counter counted down to zero "
1928 								"but none of the error bits are set\n");
1929 							callbackStatus = B_DEV_STALLED;
1930 						}
1931 					} else if (status & EHCI_QTD_STATUS_BABBLE) {
1932 						// there is a babble condition
1933 						callbackStatus = transfer->incoming
1934 							? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN;
1935 					} else {
1936 						// if the error counter didn't count down to zero
1937 						// and there was no babble, then this halt was caused
1938 						// by a stall handshake
1939 						callbackStatus = B_DEV_STALLED;
1940 					}
1941 
1942 					transferDone = true;
1943 					break;
1944 				}
1945 
1946 				if (descriptor->next_phy & EHCI_ITEM_TERMINATE) {
1947 					// we arrived at the last (stray) descriptor, we're done
1948 					TRACE("qtd (0x%08" B_PRIx32 ") done\n",
1949 						descriptor->this_phy);
1950 					callbackStatus = B_OK;
1951 					transferDone = true;
1952 					break;
1953 				}
1954 
1955 				if (((status >> EHCI_QTD_PID_SHIFT) & EHCI_QTD_PID_MASK)
1956 						== EHCI_QTD_PID_IN
1957 					&& ((status >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK)
1958 						!= 0) {
1959 					// a short packet condition existed on this descriptor,
1960 					// follow the alternate next pointer if set
1961 					if (descriptor->alt_next_log != NULL) {
1962 						descriptor = descriptor->alt_next_log;
1963 						continue;
1964 					}
1965 
1966 					// no alternate next, transfer is done
1967 					callbackStatus = B_OK;
1968 					transferDone = true;
1969 					break;
1970 				}
1971 
1972 				descriptor = descriptor->next_log;
1973 			}
1974 
1975 			if (!transferDone) {
1976 				lastTransfer = transfer;
1977 				transfer = transfer->link;
1978 				continue;
1979 			}
1980 
1981 			// remove the transfer from the list first so we are sure
1982 			// it doesn't get canceled while we still process it
1983 			transfer_data *next = transfer->link;
1984 			if (Lock()) {
1985 				if (lastTransfer)
1986 					lastTransfer->link = transfer->link;
1987 
1988 				if (transfer == fFirstTransfer)
1989 					fFirstTransfer = transfer->link;
1990 				if (transfer == fLastTransfer)
1991 					fLastTransfer = lastTransfer;
1992 
1993 				// store the currently processing pipe here so we can wait
1994 				// in cancel if we are processing something on the target pipe
1995 				if (!transfer->canceled)
1996 					fProcessingPipe = transfer->transfer->TransferPipe();
1997 
1998 				transfer->link = NULL;
1999 				Unlock();
2000 			}
2001 
2002 			// if canceled the callback has already been called
2003 			if (!transfer->canceled) {
2004 				size_t actualLength = 0;
2005 
2006 				if (callbackStatus == B_OK) {
2007 					bool nextDataToggle = false;
2008 					if (transfer->data_descriptor && transfer->incoming) {
2009 						// data to read out
2010 						generic_io_vec *vector = transfer->transfer->Vector();
2011 						size_t vectorCount = transfer->transfer->VectorCount();
2012 						callbackStatus = transfer->transfer->PrepareKernelAccess();
2013 						if (callbackStatus == B_OK) {
2014 							actualLength = ReadDescriptorChain(
2015 								transfer->data_descriptor,
2016 								vector, vectorCount, transfer->transfer->IsPhysical(),
2017 								&nextDataToggle);
2018 						}
2019 					} else if (transfer->data_descriptor) {
2020 						// calculate transfered length
2021 						actualLength = ReadActualLength(
2022 							transfer->data_descriptor, &nextDataToggle);
2023 					}
2024 
2025 					transfer->transfer->TransferPipe()->SetDataToggle(
2026 						nextDataToggle);
2027 				}
2028 
2029 				if (callbackStatus == B_OK && transfer->transfer->IsFragmented()) {
2030 					// this transfer may still have data left
2031 					transfer->transfer->AdvanceByFragment(actualLength);
2032 					if (transfer->transfer->FragmentLength() > 0) {
2033 						FreeDescriptorChain(transfer->data_descriptor);
2034 						status_t result = FillQueueWithData(
2035 							transfer->transfer,
2036 							transfer->queue_head,
2037 							&transfer->data_descriptor, NULL, true);
2038 
2039 						if (result == B_OK && Lock()) {
2040 							// reappend the transfer
2041 							if (fLastTransfer)
2042 								fLastTransfer->link = transfer;
2043 							if (!fFirstTransfer)
2044 								fFirstTransfer = transfer;
2045 
2046 							fLastTransfer = transfer;
2047 							Unlock();
2048 
2049 							transfer = next;
2050 							continue;
2051 						}
2052 					}
2053 
2054 					// the transfer is done, but we already set the
2055 					// actualLength with AdvanceByFragment()
2056 					actualLength = 0;
2057 				}
2058 
2059 				transfer->transfer->Finished(callbackStatus, actualLength);
2060 				fProcessingPipe = NULL;
2061 			}
2062 
2063 			// unlink hardware queue and delete the transfer
2064 			UnlinkQueueHead(transfer->queue_head, &fFreeListHead);
2065 			delete transfer->transfer;
2066 			delete transfer;
2067 			transfer = next;
2068 			release_sem(fCleanupSem);
2069 		}
2070 	}
2071 }
2072 
2073 
2074 int32
2075 EHCI::CleanupThread(void *data)
2076 {
2077 	((EHCI *)data)->Cleanup();
2078 	return B_OK;
2079 }
2080 
2081 
2082 void
2083 EHCI::Cleanup()
2084 {
2085 	ehci_qh *lastFreeListHead = NULL;
2086 
2087 	while (!fStopThreads) {
2088 		if (acquire_sem(fCleanupSem) != B_OK)
2089 			continue;
2090 
2091 		ehci_qh *freeListHead = fFreeListHead;
2092 		if (freeListHead == lastFreeListHead)
2093 			continue;
2094 
2095 		// set the doorbell and wait for the host controller to notify us
2096 		WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD);
2097 		if (acquire_sem(fAsyncAdvanceSem) != B_OK)
2098 			continue;
2099 
2100 		ehci_qh *current = freeListHead;
2101 		while (current != lastFreeListHead) {
2102 			ehci_qh *next = current->next_log;
2103 			FreeQueueHead(current);
2104 			current = next;
2105 		}
2106 
2107 		lastFreeListHead = freeListHead;
2108 	}
2109 }
2110 
2111 
2112 int32
2113 EHCI::FinishIsochronousThread(void *data)
2114 {
2115 	((EHCI *)data)->FinishIsochronousTransfers();
2116 	return B_OK;
2117 }
2118 
2119 
2120 void
2121 EHCI::FinishIsochronousTransfers()
2122 {
2123 	/* This thread stays one position behind the controller and processes every
2124 	* isochronous descriptor. Once it finds the last isochronous descriptor
2125 	* of a transfer, it processes the entire transfer.
2126 	*/
2127 	while (!fStopThreads) {
2128 		// Go to sleep if there are no isochronous transfers to process
2129 		if (acquire_sem(fFinishIsochronousTransfersSem) != B_OK)
2130 			return;
2131 
2132 		bool transferDone = false;
2133 
2134 		uint32 frame = (ReadOpReg(EHCI_FRINDEX) / 8 )
2135 			& (EHCI_FRAMELIST_ENTRIES_COUNT - 1);
2136 		uint32 currentFrame = (frame + EHCI_VFRAMELIST_ENTRIES_COUNT - 5)
2137 			& (EHCI_VFRAMELIST_ENTRIES_COUNT - 1);
2138 		uint32 loop = 0;
2139 
2140 		// Process the frame list until one transfer is processed
2141 		while (!transferDone && loop++ < EHCI_VFRAMELIST_ENTRIES_COUNT) {
2142 			// wait 1ms in order to be sure to be one position behind
2143 			// the controller
2144 			while (currentFrame == (((ReadOpReg(EHCI_FRINDEX) / 8)
2145 				& (EHCI_VFRAMELIST_ENTRIES_COUNT - 1)))) {
2146 				snooze(1000);
2147 			}
2148 
2149 			ehci_itd *itd = fItdEntries[currentFrame];
2150 
2151 			TRACE("FinishIsochronousTransfers itd %p phy 0x%" B_PRIx32
2152 				" prev (%p/0x%" B_PRIx32 ") at frame %" B_PRId32 "\n", itd,
2153 				itd->this_phy, itd->prev, itd->prev != NULL
2154 					? itd->prev->this_phy : 0, currentFrame);
2155 
2156 			if (!LockIsochronous())
2157 				continue;
2158 
2159 			// Process the frame till it has isochronous descriptors in it.
2160 			while (!(itd->next_phy & EHCI_ITEM_TERMINATE) && itd->prev != NULL) {
2161 				TRACE("FinishIsochronousTransfers checking itd %p last_token"
2162 					" %" B_PRId32 "\n", itd, itd->last_token);
2163 				TRACE("FinishIsochronousTransfers tokens 0x%" B_PRIx32 " 0x%"
2164 					B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx32
2165 					" 0x%" B_PRIx32 " 0x%" B_PRIx32 " 0x%" B_PRIx32 "\n",
2166 					itd->token[0], itd->token[1], itd->token[2], itd->token[3],
2167 					itd->token[4], itd->token[5], itd->token[6], itd->token[7]);
2168 				if (((itd->token[itd->last_token] >> EHCI_ITD_STATUS_SHIFT)
2169 					& EHCI_ITD_STATUS_ACTIVE) == EHCI_ITD_STATUS_ACTIVE) {
2170 					TRACE("FinishIsochronousTransfers unprocessed active itd\n");
2171 				}
2172 				UnlinkITDescriptors(itd, &fItdEntries[currentFrame]);
2173 
2174 				// Process the transfer if we found the last descriptor
2175 				isochronous_transfer_data *transfer
2176 					= FindIsochronousTransfer(itd);
2177 					// Process the descriptors only if it is still active and
2178 					// belongs to an inbound transfer. If the transfer is not
2179 					// active, it means the request has been removed, so simply
2180 					// remove the descriptors.
2181 				if (transfer && transfer->is_active) {
2182 					TRACE("FinishIsochronousTransfers active transfer\n");
2183 					size_t actualLength = 0;
2184 					status_t status = B_OK;
2185 					if (((itd->buffer_phy[1] >> EHCI_ITD_DIR_SHIFT) & 1) != 0) {
2186 						status = transfer->transfer->PrepareKernelAccess();
2187 						if (status == B_OK)
2188 							actualLength = ReadIsochronousDescriptorChain(transfer);
2189 					}
2190 
2191 					// Remove the transfer
2192 					if (transfer == fFirstIsochronousTransfer) {
2193 						fFirstIsochronousTransfer = transfer->link;
2194 						if (transfer == fLastIsochronousTransfer)
2195 							fLastIsochronousTransfer = NULL;
2196 					} else {
2197 						isochronous_transfer_data *temp
2198 							= fFirstIsochronousTransfer;
2199 						while (temp != NULL && transfer != temp->link)
2200 							temp = temp->link;
2201 
2202 						if (transfer == fLastIsochronousTransfer)
2203 							fLastIsochronousTransfer = temp;
2204 						if (temp != NULL && temp->link != NULL)
2205 							temp->link = temp->link->link;
2206 					}
2207 					transfer->link = NULL;
2208 
2209 					transfer->transfer->Finished(status, actualLength);
2210 
2211 					itd = itd->prev;
2212 
2213 					for (uint32 i = 0; i <= transfer->last_to_process; i++)
2214 						FreeDescriptor(transfer->descriptors[i]);
2215 
2216 					TRACE("FinishIsochronousTransfers descriptors freed\n");
2217 
2218 					delete [] transfer->descriptors;
2219 					delete transfer->transfer;
2220 					fStack->FreeChunk(transfer->buffer_log,
2221 						(phys_addr_t)transfer->buffer_phy,
2222 						transfer->buffer_size);
2223 					delete transfer;
2224 					transferDone = true;
2225 				} else {
2226 					TRACE("FinishIsochronousTransfers not end of transfer\n");
2227 					itd = itd->prev;
2228 				}
2229 			}
2230 
2231 			UnlockIsochronous();
2232 
2233 			TRACE("FinishIsochronousTransfers next frame\n");
2234 
2235 			// Make sure to reset the frame bandwidth
2236 			fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH;
2237 			currentFrame = (currentFrame + 1) % EHCI_VFRAMELIST_ENTRIES_COUNT;
2238 		}
2239 	}
2240 }
2241 
2242 
2243 ehci_qh *
2244 EHCI::CreateQueueHead()
2245 {
2246 	ehci_qh *result;
2247 	phys_addr_t physicalAddress;
2248 	if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2249 			sizeof(ehci_qh)) != B_OK) {
2250 		TRACE_ERROR("failed to allocate queue head\n");
2251 		return NULL;
2252 	}
2253 
2254 	result->this_phy = (addr_t)physicalAddress | EHCI_ITEM_TYPE_QH;
2255 	result->next_phy = EHCI_ITEM_TERMINATE;
2256 	result->next_log = NULL;
2257 	result->prev_log = NULL;
2258 
2259 	ehci_qtd *descriptor = CreateDescriptor(0, 0);
2260 	if (!descriptor) {
2261 		TRACE_ERROR("failed to allocate initial qtd for queue head\n");
2262 		fStack->FreeChunk(result, physicalAddress, sizeof(ehci_qh));
2263 		return NULL;
2264 	}
2265 
2266 	descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
2267 	result->stray_log = descriptor;
2268 	result->element_log = descriptor;
2269 	result->current_qtd_phy = 0;
2270 	result->overlay.next_phy = descriptor->this_phy;
2271 	result->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
2272 	result->overlay.token = 0;
2273 	for (int32 i = 0; i < 5; i++) {
2274 		result->overlay.buffer_phy[i] = 0;
2275 		result->overlay.ext_buffer_phy[i] = 0;
2276 	}
2277 
2278 	return result;
2279 }
2280 
2281 
2282 status_t
2283 EHCI::InitQueueHead(ehci_qh *queueHead, Pipe *pipe)
2284 {
2285 	switch (pipe->Speed()) {
2286 		case USB_SPEED_LOWSPEED:
2287 			queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_LOW;
2288 			break;
2289 		case USB_SPEED_FULLSPEED:
2290 			queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_FULL;
2291 			break;
2292 		case USB_SPEED_HIGHSPEED:
2293 			queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH;
2294 			break;
2295 		default:
2296 			TRACE_ERROR("unknown pipe speed\n");
2297 			return B_ERROR;
2298 	}
2299 
2300 	queueHead->endpoint_chars |= (3 << EHCI_QH_CHARS_RL_SHIFT)
2301 		| (pipe->MaxPacketSize() << EHCI_QH_CHARS_MPL_SHIFT)
2302 		| (pipe->EndpointAddress() << EHCI_QH_CHARS_EPT_SHIFT)
2303 		| (pipe->DeviceAddress() << EHCI_QH_CHARS_DEV_SHIFT)
2304 		| EHCI_QH_CHARS_TOGGLE;
2305 
2306 	queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT);
2307 	if (pipe->Speed() != USB_SPEED_HIGHSPEED) {
2308 		if ((pipe->Type() & USB_OBJECT_CONTROL_PIPE) != 0)
2309 			queueHead->endpoint_chars |= EHCI_QH_CHARS_CONTROL;
2310 
2311 		queueHead->endpoint_caps |= (pipe->HubPort() << EHCI_QH_CAPS_PORT_SHIFT)
2312 			| (pipe->HubAddress() << EHCI_QH_CAPS_HUB_SHIFT);
2313 	}
2314 
2315 	return B_OK;
2316 }
2317 
2318 
2319 void
2320 EHCI::FreeQueueHead(ehci_qh *queueHead)
2321 {
2322 	if (!queueHead)
2323 		return;
2324 
2325 	FreeDescriptorChain(queueHead->element_log);
2326 	FreeDescriptor(queueHead->stray_log);
2327 	fStack->FreeChunk(queueHead, (phys_addr_t)queueHead->this_phy,
2328 		sizeof(ehci_qh));
2329 }
2330 
2331 
2332 status_t
2333 EHCI::LinkQueueHead(ehci_qh *queueHead)
2334 {
2335 	if (!Lock())
2336 		return B_ERROR;
2337 
2338 	ehci_qh *prevHead = fAsyncQueueHead->prev_log;
2339 	queueHead->next_phy = fAsyncQueueHead->this_phy;
2340 	queueHead->next_log = fAsyncQueueHead;
2341 	queueHead->prev_log = prevHead;
2342 	fAsyncQueueHead->prev_log = queueHead;
2343 	prevHead->next_log = queueHead;
2344 	prevHead->next_phy = queueHead->this_phy;
2345 
2346 	Unlock();
2347 	return B_OK;
2348 }
2349 
2350 
2351 status_t
2352 EHCI::LinkInterruptQueueHead(ehci_qh *queueHead, Pipe *pipe)
2353 {
2354 	uint8 interval = pipe->Interval();
2355 	if (pipe->Speed() == USB_SPEED_HIGHSPEED) {
2356 		// Allow interrupts to be scheduled on each possible micro frame.
2357 		queueHead->endpoint_caps |= (0xff << EHCI_QH_CAPS_ISM_SHIFT);
2358 	} else {
2359 		// As we do not yet support FSTNs to correctly reference low/full
2360 		// speed interrupt transfers, we simply put them into the 1 or 8 interval
2361 		// queue. This way we ensure that we reach them on every micro frame
2362 		// and can do the corresponding start/complete split transactions.
2363 		// ToDo: use FSTNs to correctly link non high speed interrupt transfers
2364 		if (pipe->Speed() == USB_SPEED_LOWSPEED) {
2365 			// Low speed devices can't be polled faster than 8ms, so just use
2366 			// that.
2367 			interval = 4;
2368 		} else
2369 			interval = 1;
2370 
2371 		// For now we also force start splits to be in micro frame 0 and
2372 		// complete splits to be in micro frame 2, 3 and 4.
2373 		queueHead->endpoint_caps |= (0x01 << EHCI_QH_CAPS_ISM_SHIFT);
2374 		queueHead->endpoint_caps |= (0x1c << EHCI_QH_CAPS_SCM_SHIFT);
2375 	}
2376 
2377 	// this should not happen
2378 	if (interval < 1)
2379 		interval = 1;
2380 
2381 	// this may happen as intervals can go up to 16; we limit the value to
2382 	// EHCI_INTERRUPT_ENTRIES_COUNT as you cannot support intervals above
2383 	// that with a frame list of just EHCI_VFRAMELIST_ENTRIES_COUNT entries...
2384 	if (interval > EHCI_INTERRUPT_ENTRIES_COUNT)
2385 		interval = EHCI_INTERRUPT_ENTRIES_COUNT;
2386 
2387 	if (!Lock())
2388 		return B_ERROR;
2389 
2390 	ehci_qh *interruptQueue = &fInterruptEntries[interval - 1].queue_head;
2391 	queueHead->next_phy = interruptQueue->next_phy;
2392 	queueHead->next_log = interruptQueue->next_log;
2393 	queueHead->prev_log = interruptQueue;
2394 	if (interruptQueue->next_log)
2395 		interruptQueue->next_log->prev_log = queueHead;
2396 	interruptQueue->next_log = queueHead;
2397 	interruptQueue->next_phy = queueHead->this_phy;
2398 
2399 	Unlock();
2400 	return B_OK;
2401 }
2402 
2403 
2404 status_t
2405 EHCI::UnlinkQueueHead(ehci_qh *queueHead, ehci_qh **freeListHead)
2406 {
2407 	if (!Lock())
2408 		return B_ERROR;
2409 
2410 	ehci_qh *prevHead = queueHead->prev_log;
2411 	ehci_qh *nextHead = queueHead->next_log;
2412 	if (prevHead) {
2413 		prevHead->next_phy = queueHead->next_phy;
2414 		prevHead->next_log = queueHead->next_log;
2415 	}
2416 
2417 	if (nextHead)
2418 		nextHead->prev_log = queueHead->prev_log;
2419 
2420 	queueHead->next_phy = fAsyncQueueHead->this_phy;
2421 	queueHead->prev_log = NULL;
2422 
2423 	queueHead->next_log = *freeListHead;
2424 	*freeListHead = queueHead;
2425 
2426 	Unlock();
2427 	return B_OK;
2428 }
2429 
2430 
2431 status_t
2432 EHCI::FillQueueWithRequest(Transfer *transfer, ehci_qh *queueHead,
2433 	ehci_qtd **_dataDescriptor, bool *_directionIn, bool prepareKernelAccess)
2434 {
2435 	Pipe *pipe = transfer->TransferPipe();
2436 	usb_request_data *requestData = transfer->RequestData();
2437 	bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
2438 
2439 	ehci_qtd *setupDescriptor = CreateDescriptor(sizeof(usb_request_data),
2440 		EHCI_QTD_PID_SETUP);
2441 	ehci_qtd *statusDescriptor = CreateDescriptor(0,
2442 		directionIn ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN);
2443 
2444 	if (!setupDescriptor || !statusDescriptor) {
2445 		TRACE_ERROR("failed to allocate descriptors\n");
2446 		FreeDescriptor(setupDescriptor);
2447 		FreeDescriptor(statusDescriptor);
2448 		return B_NO_MEMORY;
2449 	}
2450 
2451 	generic_io_vec vector;
2452 	vector.base = (generic_addr_t)requestData;
2453 	vector.length = sizeof(usb_request_data);
2454 	WriteDescriptorChain(setupDescriptor, &vector, 1, false);
2455 
2456 	ehci_qtd *strayDescriptor = queueHead->stray_log;
2457 	statusDescriptor->token |= EHCI_QTD_IOC | EHCI_QTD_DATA_TOGGLE;
2458 
2459 	ehci_qtd *dataDescriptor = NULL;
2460 	if (transfer->VectorCount() > 0) {
2461 		ehci_qtd *lastDescriptor = NULL;
2462 		status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
2463 			&lastDescriptor, statusDescriptor, transfer->FragmentLength(),
2464 			directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
2465 
2466 		if (result != B_OK) {
2467 			FreeDescriptor(setupDescriptor);
2468 			FreeDescriptor(statusDescriptor);
2469 			return result;
2470 		}
2471 
2472 		if (!directionIn) {
2473 			if (prepareKernelAccess) {
2474 				result = transfer->PrepareKernelAccess();
2475 				if (result != B_OK) {
2476 					FreeDescriptor(setupDescriptor);
2477 					FreeDescriptor(statusDescriptor);
2478 					return result;
2479 				}
2480 			}
2481 			WriteDescriptorChain(dataDescriptor, transfer->Vector(),
2482 				transfer->VectorCount(), transfer->IsPhysical());
2483 		}
2484 
2485 		LinkDescriptors(setupDescriptor, dataDescriptor, strayDescriptor);
2486 		LinkDescriptors(lastDescriptor, statusDescriptor, statusDescriptor);
2487 	} else {
2488 		// no data: link setup and status descriptors directly
2489 		LinkDescriptors(setupDescriptor, statusDescriptor, strayDescriptor);
2490 	}
2491 
2492 	queueHead->element_log = setupDescriptor;
2493 	queueHead->overlay.next_phy = setupDescriptor->this_phy;
2494 	queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
2495 
2496 	*_dataDescriptor = dataDescriptor;
2497 	*_directionIn = directionIn;
2498 	return B_OK;
2499 }
2500 
2501 
2502 status_t
2503 EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead,
2504 	ehci_qtd **_dataDescriptor, bool *_directionIn, bool prepareKernelAccess)
2505 {
2506 	Pipe *pipe = transfer->TransferPipe();
2507 	bool directionIn = (pipe->Direction() == Pipe::In);
2508 
2509 	ehci_qtd *firstDescriptor = NULL;
2510 	ehci_qtd *lastDescriptor = NULL;
2511 	ehci_qtd *strayDescriptor = queueHead->stray_log;
2512 	status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
2513 		&lastDescriptor, strayDescriptor, transfer->FragmentLength(),
2514 		directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
2515 
2516 	if (result != B_OK)
2517 		return result;
2518 
2519 	lastDescriptor->token |= EHCI_QTD_IOC;
2520 	if (!directionIn) {
2521 		if (prepareKernelAccess) {
2522 			result = transfer->PrepareKernelAccess();
2523 			if (result != B_OK) {
2524 				FreeDescriptorChain(firstDescriptor);
2525 				return result;
2526 			}
2527 		}
2528 		WriteDescriptorChain(firstDescriptor, transfer->Vector(),
2529 			transfer->VectorCount(), transfer->IsPhysical());
2530 	}
2531 
2532 	queueHead->element_log = firstDescriptor;
2533 	queueHead->overlay.next_phy = firstDescriptor->this_phy;
2534 	queueHead->overlay.alt_next_phy = EHCI_ITEM_TERMINATE;
2535 
2536 	*_dataDescriptor = firstDescriptor;
2537 	if (_directionIn)
2538 		*_directionIn = directionIn;
2539 	return B_OK;
2540 }
2541 
2542 
2543 ehci_qtd *
2544 EHCI::CreateDescriptor(size_t bufferSize, uint8 pid)
2545 {
2546 	ehci_qtd *result;
2547 	phys_addr_t physicalAddress;
2548 	if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2549 			sizeof(ehci_qtd)) != B_OK) {
2550 		TRACE_ERROR("failed to allocate a qtd\n");
2551 		return NULL;
2552 	}
2553 
2554 	result->this_phy = (addr_t)physicalAddress;
2555 	result->next_phy = EHCI_ITEM_TERMINATE;
2556 	result->next_log = NULL;
2557 	result->alt_next_phy = EHCI_ITEM_TERMINATE;
2558 	result->alt_next_log = NULL;
2559 	result->buffer_size = bufferSize;
2560 	result->token = bufferSize << EHCI_QTD_BYTES_SHIFT;
2561 	result->token |= 3 << EHCI_QTD_ERRCOUNT_SHIFT;
2562 	result->token |= pid << EHCI_QTD_PID_SHIFT;
2563 	result->token |= EHCI_QTD_STATUS_ACTIVE;
2564 	if (bufferSize == 0) {
2565 		result->buffer_log = NULL;
2566 		for (int32 i = 0; i < 5; i++) {
2567 			result->buffer_phy[i] = 0;
2568 			result->ext_buffer_phy[i] = 0;
2569 		}
2570 
2571 		return result;
2572 	}
2573 
2574 	if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress,
2575 			bufferSize) != B_OK) {
2576 		TRACE_ERROR("unable to allocate qtd buffer\n");
2577 		fStack->FreeChunk(result, (phys_addr_t)result->this_phy,
2578 			sizeof(ehci_qtd));
2579 		return NULL;
2580 	}
2581 
2582 	addr_t physicalBase = (addr_t)physicalAddress;
2583 	result->buffer_phy[0] = physicalBase;
2584 	result->ext_buffer_phy[0] = 0;
2585 	for (int32 i = 1; i < 5; i++) {
2586 		physicalBase += B_PAGE_SIZE;
2587 		result->buffer_phy[i] = physicalBase & EHCI_QTD_PAGE_MASK;
2588 		result->ext_buffer_phy[i] = 0;
2589 	}
2590 
2591 	return result;
2592 }
2593 
2594 
2595 status_t
2596 EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor,
2597 	ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize,
2598 	uint8 pid)
2599 {
2600 	size_t packetSize = B_PAGE_SIZE * 4;
2601 	int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
2602 
2603 	bool dataToggle = pipe->DataToggle();
2604 	ehci_qtd *firstDescriptor = NULL;
2605 	ehci_qtd *lastDescriptor = *_firstDescriptor;
2606 	for (int32 i = 0; i < descriptorCount; i++) {
2607 		ehci_qtd *descriptor = CreateDescriptor(min_c(packetSize, bufferSize),
2608 			pid);
2609 
2610 		if (!descriptor) {
2611 			FreeDescriptorChain(firstDescriptor);
2612 			return B_NO_MEMORY;
2613 		}
2614 
2615 		if (dataToggle)
2616 			descriptor->token |= EHCI_QTD_DATA_TOGGLE;
2617 
2618 		if (lastDescriptor)
2619 			LinkDescriptors(lastDescriptor, descriptor, strayDescriptor);
2620 
2621 		bufferSize -= packetSize;
2622 		lastDescriptor = descriptor;
2623 		if (!firstDescriptor)
2624 			firstDescriptor = descriptor;
2625 	}
2626 
2627 	*_firstDescriptor = firstDescriptor;
2628 	*_lastDescriptor = lastDescriptor;
2629 	return B_OK;
2630 }
2631 
2632 
2633 void
2634 EHCI::FreeDescriptor(ehci_qtd *descriptor)
2635 {
2636 	if (!descriptor)
2637 		return;
2638 
2639 	if (descriptor->buffer_log) {
2640 		fStack->FreeChunk(descriptor->buffer_log,
2641 			(phys_addr_t)descriptor->buffer_phy[0], descriptor->buffer_size);
2642 	}
2643 
2644 	fStack->FreeChunk(descriptor, (phys_addr_t)descriptor->this_phy,
2645 		sizeof(ehci_qtd));
2646 }
2647 
2648 
2649 void
2650 EHCI::FreeDescriptorChain(ehci_qtd *topDescriptor)
2651 {
2652 	ehci_qtd *current = topDescriptor;
2653 	ehci_qtd *next = NULL;
2654 
2655 	while (current) {
2656 		next = current->next_log;
2657 		FreeDescriptor(current);
2658 		current = next;
2659 	}
2660 }
2661 
2662 
2663 ehci_itd *
2664 EHCI::CreateItdDescriptor()
2665 {
2666 	ehci_itd *result;
2667 	phys_addr_t physicalAddress;
2668 	if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2669 			sizeof(ehci_itd)) != B_OK) {
2670 		TRACE_ERROR("failed to allocate a itd\n");
2671 		return NULL;
2672 	}
2673 
2674 	memset(result, 0, sizeof(ehci_itd));
2675 	result->this_phy = (addr_t)physicalAddress;
2676 	result->next_phy = EHCI_ITEM_TERMINATE;
2677 
2678 	return result;
2679 }
2680 
2681 
2682 ehci_sitd *
2683 EHCI::CreateSitdDescriptor()
2684 {
2685 	ehci_sitd *result;
2686 	phys_addr_t physicalAddress;
2687 	if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2688 			sizeof(ehci_sitd)) != B_OK) {
2689 		TRACE_ERROR("failed to allocate a sitd\n");
2690 		return NULL;
2691 	}
2692 
2693 	memset(result, 0, sizeof(ehci_sitd));
2694 	result->this_phy = (addr_t)physicalAddress | EHCI_ITEM_TYPE_SITD;
2695 	result->next_phy = EHCI_ITEM_TERMINATE;
2696 
2697 	return result;
2698 }
2699 
2700 
2701 void
2702 EHCI::FreeDescriptor(ehci_itd *descriptor)
2703 {
2704 	if (!descriptor)
2705 		return;
2706 
2707 	fStack->FreeChunk(descriptor, (phys_addr_t)descriptor->this_phy,
2708 		sizeof(ehci_itd));
2709 }
2710 
2711 
2712 void
2713 EHCI::FreeDescriptor(ehci_sitd *descriptor)
2714 {
2715 	if (!descriptor)
2716 		return;
2717 
2718 	fStack->FreeChunk(descriptor, (phys_addr_t)descriptor->this_phy,
2719 		sizeof(ehci_sitd));
2720 }
2721 
2722 
2723 void
2724 EHCI::LinkDescriptors(ehci_qtd *first, ehci_qtd *last, ehci_qtd *alt)
2725 {
2726 	first->next_phy = last->this_phy;
2727 	first->next_log = last;
2728 
2729 	if (alt) {
2730 		first->alt_next_phy = alt->this_phy;
2731 		first->alt_next_log = alt;
2732 	} else {
2733 		first->alt_next_phy = EHCI_ITEM_TERMINATE;
2734 		first->alt_next_log = NULL;
2735 	}
2736 }
2737 
2738 
2739 void
2740 EHCI::LinkITDescriptors(ehci_itd *itd, ehci_itd **_last)
2741 {
2742 	ehci_itd *last = *_last;
2743 	itd->next_phy = last->next_phy;
2744 	itd->next = NULL;
2745 	itd->prev = last;
2746 	last->next = itd;
2747 	last->next_phy = itd->this_phy;
2748 	*_last = itd;
2749 }
2750 
2751 
2752 void
2753 EHCI::LinkSITDescriptors(ehci_sitd *sitd, ehci_sitd **_last)
2754 {
2755 	ehci_sitd *last = *_last;
2756 	sitd->next_phy = last->next_phy;
2757 	sitd->next = NULL;
2758 	sitd->prev = last;
2759 	last->next = sitd;
2760 	last->next_phy = sitd->this_phy;
2761 	*_last = sitd;
2762 }
2763 
2764 
2765 void
2766 EHCI::UnlinkITDescriptors(ehci_itd *itd, ehci_itd **last)
2767 {
2768 	itd->prev->next_phy = itd->next_phy;
2769 	itd->prev->next = itd->next;
2770 	if (itd->next != NULL)
2771 		itd->next->prev = itd->prev;
2772 	if (itd == *last)
2773 		*last = itd->prev;
2774 }
2775 
2776 
2777 void
2778 EHCI::UnlinkSITDescriptors(ehci_sitd *sitd, ehci_sitd **last)
2779 {
2780 	sitd->prev->next_phy = sitd->next_phy;
2781 	sitd->prev->next = sitd->next;
2782 	if (sitd->next != NULL)
2783 		sitd->next->prev = sitd->prev;
2784 	if (sitd == *last)
2785 		*last = sitd->prev;
2786 }
2787 
2788 
2789 size_t
2790 EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, generic_io_vec *vector,
2791 	size_t vectorCount, bool physical)
2792 {
2793 	ehci_qtd *current = topDescriptor;
2794 	size_t actualLength = 0;
2795 	size_t vectorIndex = 0;
2796 	size_t vectorOffset = 0;
2797 	size_t bufferOffset = 0;
2798 
2799 	while (current) {
2800 		if (!current->buffer_log)
2801 			break;
2802 
2803 		while (true) {
2804 			size_t length = min_c(current->buffer_size - bufferOffset,
2805 				vector[vectorIndex].length - vectorOffset);
2806 
2807 			status_t status = generic_memcpy(
2808 				(generic_addr_t)current->buffer_log + bufferOffset, false,
2809 				vector[vectorIndex].base + vectorOffset, physical, length);
2810 			ASSERT(status == B_OK);
2811 
2812 			actualLength += length;
2813 			vectorOffset += length;
2814 			bufferOffset += length;
2815 
2816 			if (vectorOffset >= vector[vectorIndex].length) {
2817 				if (++vectorIndex >= vectorCount) {
2818 					TRACE("wrote descriptor chain (%ld bytes, no more vectors)"
2819 						"\n", actualLength);
2820 					return actualLength;
2821 				}
2822 
2823 				vectorOffset = 0;
2824 			}
2825 
2826 			if (bufferOffset >= current->buffer_size) {
2827 				bufferOffset = 0;
2828 				break;
2829 			}
2830 		}
2831 
2832 		if (current->next_phy & EHCI_ITEM_TERMINATE)
2833 			break;
2834 
2835 		current = current->next_log;
2836 	}
2837 
2838 	TRACE("wrote descriptor chain (%ld bytes)\n", actualLength);
2839 	return actualLength;
2840 }
2841 
2842 
2843 size_t
2844 EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, generic_io_vec *vector,
2845 	size_t vectorCount, bool physical, bool *nextDataToggle)
2846 {
2847 	uint32 dataToggle = 0;
2848 	ehci_qtd *current = topDescriptor;
2849 	size_t actualLength = 0;
2850 	size_t vectorIndex = 0;
2851 	size_t vectorOffset = 0;
2852 	size_t bufferOffset = 0;
2853 
2854 	while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) {
2855 		if (!current->buffer_log)
2856 			break;
2857 
2858 		dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
2859 		size_t bufferSize = current->buffer_size;
2860 		bufferSize -= (current->token >> EHCI_QTD_BYTES_SHIFT)
2861 			& EHCI_QTD_BYTES_MASK;
2862 
2863 		while (true) {
2864 			size_t length = min_c(bufferSize - bufferOffset,
2865 				vector[vectorIndex].length - vectorOffset);
2866 
2867 			status_t status = generic_memcpy(
2868 				vector[vectorIndex].base + vectorOffset, physical,
2869 				(generic_addr_t)current->buffer_log + bufferOffset, false, length);
2870 			ASSERT(status == B_OK);
2871 
2872 			actualLength += length;
2873 			vectorOffset += length;
2874 			bufferOffset += length;
2875 
2876 			if (vectorOffset >= vector[vectorIndex].length) {
2877 				if (++vectorIndex >= vectorCount) {
2878 					TRACE("read descriptor chain (%ld bytes, no more vectors)"
2879 						"\n", actualLength);
2880 					*nextDataToggle = dataToggle > 0 ? true : false;
2881 					return actualLength;
2882 				}
2883 
2884 				vectorOffset = 0;
2885 			}
2886 
2887 			if (bufferOffset >= bufferSize) {
2888 				bufferOffset = 0;
2889 				break;
2890 			}
2891 		}
2892 
2893 		if (current->next_phy & EHCI_ITEM_TERMINATE)
2894 			break;
2895 
2896 		current = current->next_log;
2897 	}
2898 
2899 	TRACE("read descriptor chain (%ld bytes)\n", actualLength);
2900 	*nextDataToggle = dataToggle > 0 ? true : false;
2901 	return actualLength;
2902 }
2903 
2904 
2905 size_t
2906 EHCI::ReadActualLength(ehci_qtd *topDescriptor, bool *nextDataToggle)
2907 {
2908 	size_t actualLength = 0;
2909 	ehci_qtd *current = topDescriptor;
2910 	uint32 dataToggle = 0;
2911 
2912 	while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) {
2913 		dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
2914 		size_t length = current->buffer_size;
2915 		length -= (current->token >> EHCI_QTD_BYTES_SHIFT)
2916 			& EHCI_QTD_BYTES_MASK;
2917 		actualLength += length;
2918 
2919 		if (current->next_phy & EHCI_ITEM_TERMINATE)
2920 			break;
2921 
2922 		current = current->next_log;
2923 	}
2924 
2925 	TRACE("read actual length (%ld bytes)\n", actualLength);
2926 	*nextDataToggle = dataToggle > 0 ? true : false;
2927 	return actualLength;
2928 }
2929 
2930 
2931 size_t
2932 EHCI::WriteIsochronousDescriptorChain(isochronous_transfer_data *transfer)
2933 {
2934 	// TODO implement
2935 	return 0;
2936 }
2937 
2938 
2939 size_t
2940 EHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer)
2941 {
2942 	generic_io_vec *vector = transfer->transfer->Vector();
2943 	size_t vectorCount = transfer->transfer->VectorCount();
2944 	const bool physical = transfer->transfer->IsPhysical();
2945 	size_t vectorOffset = 0;
2946 	size_t vectorIndex = 0;
2947 	usb_isochronous_data *isochronousData
2948 		= transfer->transfer->IsochronousData();
2949 	uint32 packet = 0;
2950 	size_t totalLength = 0;
2951 	size_t bufferOffset = 0;
2952 
2953 	size_t packetSize = transfer->transfer->DataLength();
2954 	packetSize /= isochronousData->packet_count;
2955 
2956 	for (uint32 i = 0; i <= transfer->last_to_process; i++) {
2957 		ehci_itd *itd = transfer->descriptors[i];
2958 		for (uint32 j = 0; j <= itd->last_token
2959 			&& packet < isochronousData->packet_count; j++) {
2960 
2961 			size_t bufferSize = (itd->token[j] >> EHCI_ITD_TLENGTH_SHIFT)
2962 				& EHCI_ITD_TLENGTH_MASK;
2963 			if (((itd->token[j] >> EHCI_ITD_STATUS_SHIFT)
2964 				& EHCI_ITD_STATUS_MASK) != 0) {
2965 				bufferSize = 0;
2966 			}
2967 			isochronousData->packet_descriptors[packet].actual_length
2968 				= bufferSize;
2969 
2970 			if (bufferSize > 0)
2971 				isochronousData->packet_descriptors[packet].status = B_OK;
2972 			else
2973 				isochronousData->packet_descriptors[packet].status = B_ERROR;
2974 
2975 			totalLength += bufferSize;
2976 
2977 			size_t offset = bufferOffset;
2978 			size_t skipSize = packetSize - bufferSize;
2979 			while (bufferSize > 0) {
2980 				size_t length = min_c(bufferSize,
2981 					vector[vectorIndex].length - vectorOffset);
2982 				status_t status = generic_memcpy(
2983 					vector[vectorIndex].base + vectorOffset, physical,
2984 					(generic_addr_t)transfer->buffer_log + bufferOffset, false, length);
2985 				ASSERT(status == B_OK);
2986 
2987 				offset += length;
2988 				vectorOffset += length;
2989 				bufferSize -= length;
2990 
2991 				if (vectorOffset >= vector[vectorIndex].length) {
2992 					if (++vectorIndex >= vectorCount) {
2993 						TRACE("read isodescriptor chain (%ld bytes, no more "
2994 							"vectors)\n", totalLength);
2995 						return totalLength;
2996 					}
2997 
2998 					vectorOffset = 0;
2999 				}
3000 			}
3001 
3002 			// skip to next packet offset
3003 			while (skipSize > 0) {
3004 				size_t length = min_c(skipSize,
3005 					vector[vectorIndex].length - vectorOffset);
3006 				vectorOffset += length;
3007 				skipSize -= length;
3008 				if (vectorOffset >= vector[vectorIndex].length) {
3009 					if (++vectorIndex >= vectorCount) {
3010 						TRACE("read isodescriptor chain (%ld bytes, no more "
3011 							"vectors)\n", totalLength);
3012 						return totalLength;
3013 					}
3014 
3015 					vectorOffset = 0;
3016 				}
3017 			}
3018 
3019 			bufferOffset += packetSize;
3020 			if (bufferOffset >= transfer->buffer_size)
3021 				return totalLength;
3022 
3023 			packet++;
3024 		}
3025 	}
3026 
3027 	TRACE("ReadIsochronousDescriptorChain packet count %" B_PRId32 "\n",
3028 		packet);
3029 
3030 	return totalLength;
3031 }
3032 
3033 
3034 bool
3035 EHCI::LockIsochronous()
3036 {
3037 	return (mutex_lock(&fIsochronousLock) == B_OK);
3038 }
3039 
3040 
3041 void
3042 EHCI::UnlockIsochronous()
3043 {
3044 	mutex_unlock(&fIsochronousLock);
3045 }
3046 
3047 
3048 inline void
3049 EHCI::WriteOpReg(uint32 reg, uint32 value)
3050 {
3051 	*(volatile uint32 *)(fOperationalRegisters + reg) = value;
3052 }
3053 
3054 
3055 inline uint32
3056 EHCI::ReadOpReg(uint32 reg)
3057 {
3058 	return *(volatile uint32 *)(fOperationalRegisters + reg);
3059 }
3060 
3061 
3062 inline uint8
3063 EHCI::ReadCapReg8(uint32 reg)
3064 {
3065 	return *(volatile uint8 *)(fCapabilityRegisters + reg);
3066 }
3067 
3068 
3069 inline uint16
3070 EHCI::ReadCapReg16(uint32 reg)
3071 {
3072 	return *(volatile uint16 *)(fCapabilityRegisters + reg);
3073 }
3074 
3075 
3076 inline uint32
3077 EHCI::ReadCapReg32(uint32 reg)
3078 {
3079 	return *(volatile uint32 *)(fCapabilityRegisters + reg);
3080 }
3081