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