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