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