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