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