xref: /haiku/src/add-ons/kernel/busses/usb/ehci.cpp (revision 3cb015b1ee509d69c643506e8ff573808c86dcfc)
1 /*
2  * Copyright 2006, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  */
8 
9 #include <module.h>
10 #include <PCI.h>
11 #include <USB3.h>
12 #include <KernelExport.h>
13 
14 #include "ehci.h"
15 
16 pci_module_info *EHCI::sPCIModule = NULL;
17 
18 
19 static int32
20 ehci_std_ops(int32 op, ...)
21 {
22 	switch (op) {
23 		case B_MODULE_INIT:
24 			TRACE(("usb_ehci_module: init module\n"));
25 			return B_OK;
26 		case B_MODULE_UNINIT:
27 			TRACE(("usb_ehci_module: uninit module\n"));
28 			return B_OK;
29 	}
30 
31 	return EINVAL;
32 }
33 
34 
35 host_controller_info ehci_module = {
36 	{
37 		"busses/usb/ehci",
38 		0,
39 		ehci_std_ops
40 	},
41 	NULL,
42 	EHCI::AddTo
43 };
44 
45 
46 module_info *modules[] = {
47 	(module_info *)&ehci_module,
48 	NULL
49 };
50 
51 
52 //
53 // #pragma mark -
54 //
55 
56 
57 #ifdef TRACE_USB
58 
59 void
60 print_descriptor_chain(ehci_qtd *descriptor)
61 {
62 	while (descriptor) {
63 		dprintf(" %08lx n%08lx a%08lx t%08lx %08lx %08lx %08lx %08lx %08lx s%ld\n",
64 			descriptor->this_phy, descriptor->next_phy,
65 			descriptor->alt_next_phy, descriptor->token,
66 			descriptor->buffer_phy[0], descriptor->buffer_phy[1],
67 			descriptor->buffer_phy[2], descriptor->buffer_phy[3],
68 			descriptor->buffer_phy[4], descriptor->buffer_size);
69 
70 		if (descriptor->next_phy & EHCI_QTD_TERMINATE)
71 			break;
72 
73 		descriptor = (ehci_qtd *)descriptor->next_log;
74 	}
75 }
76 
77 void
78 print_queue(ehci_qh *queueHead)
79 {
80 	dprintf("queue:    t%08lx n%08lx ch%08lx ca%08lx cu%08lx\n",
81 		queueHead->this_phy, queueHead->next_phy, queueHead->endpoint_chars,
82 		queueHead->endpoint_caps, queueHead->current_qtd_phy);
83 	dprintf("overlay:  n%08lx a%08lx t%08lx %08lx %08lx %08lx %08lx %08lx\n",
84 		queueHead->overlay.next_phy, queueHead->overlay.alt_next_phy,
85 		queueHead->overlay.token, queueHead->overlay.buffer_phy[0],
86 		queueHead->overlay.buffer_phy[1], queueHead->overlay.buffer_phy[2],
87 		queueHead->overlay.buffer_phy[3], queueHead->overlay.buffer_phy[4]);
88 	print_descriptor_chain((ehci_qtd *)queueHead->element_log);
89 }
90 
91 #endif // TRACE_USB
92 
93 
94 //
95 // #pragma mark -
96 //
97 
98 
99 EHCI::EHCI(pci_info *info, Stack *stack)
100 	:	BusManager(stack),
101 		fPCIInfo(info),
102 		fStack(stack),
103 		fPeriodicFrameListArea(-1),
104 		fPeriodicFrameList(NULL),
105 		fFirstTransfer(NULL),
106 		fLastTransfer(NULL),
107 		fFinishThread(-1),
108 		fCleanupThread(-1),
109 		fStopThreads(false),
110 		fFreeListHead(NULL),
111 		fRootHub(NULL),
112 		fRootHubAddress(0),
113 		fPortCount(0),
114 		fPortResetChange(0),
115 		fPortSuspendChange(0)
116 {
117 	if (BusManager::InitCheck() < B_OK) {
118 		TRACE_ERROR(("usb_ehci: bus manager failed to init\n"));
119 		return;
120 	}
121 
122 	TRACE(("usb_ehci: constructing new EHCI Host Controller Driver\n"));
123 	fInitOK = false;
124 
125 	// enable busmaster and memory mapped access
126 	uint16 command = sPCIModule->read_pci_config(fPCIInfo->bus,
127 		fPCIInfo->device, fPCIInfo->function, PCI_command, 2);
128 	command &= ~PCI_command_io;
129 	command |= PCI_command_master | PCI_command_memory;
130 
131 	sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
132 		fPCIInfo->function, PCI_command, 2, command);
133 
134 	// map the registers
135 	uint32 offset = fPCIInfo->u.h0.base_registers[0] & (B_PAGE_SIZE - 1);
136 	addr_t physicalAddress = fPCIInfo->u.h0.base_registers[0] - offset;
137 	size_t mapSize = (fPCIInfo->u.h0.base_register_sizes[0] + offset
138 		+ B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
139 
140 	TRACE(("usb_ehci: map physical memory 0x%08lx (base: 0x%08lx; offset: %lx); size: %ld\n", fPCIInfo->u.h0.base_registers[0], physicalAddress, offset, fPCIInfo->u.h0.base_register_sizes[0]));
141 	fRegisterArea = map_physical_memory("EHCI memory mapped registers",
142 		(void *)physicalAddress, mapSize, B_ANY_KERNEL_BLOCK_ADDRESS,
143 		B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA,
144 		(void **)&fCapabilityRegisters);
145 	if (fRegisterArea < B_OK) {
146 		TRACE(("usb_ehci: failed to map register memory\n"));
147 		return;
148 	}
149 
150 	fCapabilityRegisters += offset;
151 	fOperationalRegisters = fCapabilityRegisters + ReadCapReg8(EHCI_CAPLENGTH);
152 	TRACE(("usb_ehci: mapped capability registers: 0x%08lx\n", (uint32)fCapabilityRegisters));
153 	TRACE(("usb_ehci: mapped operational registers: 0x%08lx\n", (uint32)fOperationalRegisters));
154 
155 	TRACE(("usb_ehci: structural parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCSPARAMS)));
156 	TRACE(("usb_ehci: capability parameters: 0x%08lx\n", ReadCapReg32(EHCI_HCCPARAMS)));
157 
158 	// read port count from capability register
159 	fPortCount = ReadCapReg32(EHCI_HCSPARAMS) & 0x0f;
160 
161 	uint32 extendedCapPointer = ReadCapReg32(EHCI_HCCPARAMS) >> EHCI_ECP_SHIFT;
162 	extendedCapPointer &= EHCI_ECP_MASK;
163 	if (extendedCapPointer > 0) {
164 		TRACE(("usb_ehci: extended capabilities register at %ld\n", extendedCapPointer));
165 
166 		uint32 legacySupport = sPCIModule->read_pci_config(fPCIInfo->bus,
167 			fPCIInfo->device, fPCIInfo->function, extendedCapPointer, 4);
168 		if ((legacySupport & EHCI_LEGSUP_CAPID_MASK) == EHCI_LEGSUP_CAPID) {
169 			if (legacySupport & EHCI_LEGSUP_BIOSOWNED) {
170 				TRACE(("usb_ehci: the host controller is bios owned\n"));
171 			}
172 
173 			TRACE(("usb_ehci: claiming ownership of the host controller\n"));
174 			sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
175 				fPCIInfo->function, extendedCapPointer, 4, EHCI_LEGSUP_OSOWNED);
176 
177 			for (int32 i = 0; i < 10; i++) {
178 				legacySupport = sPCIModule->read_pci_config(fPCIInfo->bus,
179 					fPCIInfo->device, fPCIInfo->function, extendedCapPointer, 4);
180 
181 				if (legacySupport & EHCI_LEGSUP_BIOSOWNED) {
182 					TRACE(("usb_ehci: controller is still bios owned, waiting\n"));
183 					snooze(50000);
184 				} else
185 					break;
186 			}
187 
188 			if (legacySupport & EHCI_LEGSUP_BIOSOWNED) {
189 				TRACE_ERROR(("usb_ehci: bios won't give up control over the host controller\n"));
190 				return;
191 			} else if (legacySupport & EHCI_LEGSUP_OSOWNED) {
192 				TRACE(("usb_ehci: successfully took ownership of the host controller\n"));
193 			}
194 		} else {
195 			TRACE(("usb_ehci: extended capability is not a legacy support register\n"));
196 		}
197 	} else {
198 		TRACE(("usb_ehci: no extended capabilities register\n"));
199 	}
200 
201 	// disable interrupts
202 	WriteOpReg(EHCI_USBINTR, 0);
203 
204 	// reset the segment register
205 	WriteOpReg(EHCI_CTRDSSEGMENT, 0);
206 
207 	// reset the host controller
208 	if (ControllerReset() < B_OK) {
209 		TRACE_ERROR(("usb_ehci: host controller failed to reset\n"));
210 		return;
211 	}
212 
213 	// create semaphores the finisher thread will wait for
214 	fAsyncAdvanceSem = create_sem(0, "EHCI Async Advance");
215 	fFinishTransfersSem = create_sem(0, "EHCI Finish Transfers");
216 	fCleanupSem = create_sem(0, "EHCI Cleanup");
217 	if (fFinishTransfersSem < B_OK || fAsyncAdvanceSem < B_OK
218 		|| fCleanupSem < B_OK) {
219 		TRACE_ERROR(("usb_ehci: failed to create semaphores\n"));
220 		return;
221 	}
222 
223 	// create finisher service thread
224 	fFinishThread = spawn_kernel_thread(FinishThread, "ehci finish thread",
225 		B_NORMAL_PRIORITY, (void *)this);
226 	resume_thread(fFinishThread);
227 
228 	// create cleanup service thread
229 	fCleanupThread = spawn_kernel_thread(CleanupThread, "ehci cleanup thread",
230 		B_NORMAL_PRIORITY, (void *)this);
231 	resume_thread(fCleanupThread);
232 
233 	// install the interrupt handler and enable interrupts
234 	install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
235 		InterruptHandler, (void *)this, 0);
236 	WriteOpReg(EHCI_USBINTR, EHCI_USBINTR_HOSTSYSERR
237 		| EHCI_USBINTR_USBERRINT | EHCI_USBINTR_USBINT | EHCI_USBINTR_INTONAA);
238 
239 	// allocate the periodic frame list
240 	fPeriodicFrameListArea = fStack->AllocateArea((void **)&fPeriodicFrameList,
241 		(void **)&physicalAddress, B_PAGE_SIZE, "USB EHCI Periodic Framelist");
242 	if (fPeriodicFrameListArea < B_OK) {
243 		TRACE_ERROR(("usb_ehci: unable to allocate periodic framelist\n"));
244 		return;
245 	}
246 
247 	// terminate all elements
248 	for (int32 i = 0; i < 1024; i++)
249 		fPeriodicFrameList[i] = EHCI_PFRAMELIST_TERM;
250 
251 	WriteOpReg(EHCI_PERIODICLISTBASE, (uint32)physicalAddress);
252 
253 	// allocate a queue head that will always stay in the async frame list
254 	fAsyncQueueHead = CreateQueueHead();
255 	if (!fAsyncQueueHead) {
256 		TRACE_ERROR(("usb_ehci: unable to allocate stray async queue head\n"));
257 		return;
258 	}
259 
260 	fAsyncQueueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH;
261 	fAsyncQueueHead->next_log = fAsyncQueueHead;
262 	fAsyncQueueHead->prev_log = fAsyncQueueHead;
263 	fAsyncQueueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH | EHCI_QH_CHARS_RECHEAD;
264 	fAsyncQueueHead->endpoint_caps = 1 << EHCI_QH_CAPS_MULT_SHIFT;
265 	fAsyncQueueHead->current_qtd_phy = EHCI_QTD_TERMINATE;
266 	fAsyncQueueHead->overlay.next_phy = EHCI_QTD_TERMINATE;
267 
268 	WriteOpReg(EHCI_ASYNCLISTADDR, (uint32)fAsyncQueueHead->this_phy
269 		| EHCI_QH_TYPE_QH);
270 	TRACE(("usb_ehci: set the async list addr to 0x%08lx\n", ReadOpReg(EHCI_ASYNCLISTADDR)));
271 
272 	fInitOK = true;
273 	TRACE(("usb_ehci: EHCI Host Controller Driver constructed\n"));
274 }
275 
276 
277 EHCI::~EHCI()
278 {
279 	TRACE(("usb_ehci: tear down EHCI Host Controller Driver\n"));
280 
281 	WriteOpReg(EHCI_USBCMD, 0);
282 	WriteOpReg(EHCI_CONFIGFLAG, 0);
283 	CancelAllPendingTransfers();
284 
285 	int32 result = 0;
286 	fStopThreads = true;
287 	delete_sem(fAsyncAdvanceSem);
288 	delete_sem(fFinishTransfersSem);
289 	wait_for_thread(fFinishThread, &result);
290 	wait_for_thread(fCleanupThread, &result);
291 
292 	delete fRootHub;
293 	delete_area(fPeriodicFrameListArea);
294 	delete_area(fRegisterArea);
295 	put_module(B_PCI_MODULE_NAME);
296 }
297 
298 
299 status_t
300 EHCI::Start()
301 {
302 	TRACE(("usb_ehci: starting EHCI Host Controller\n"));
303 	TRACE(("usb_ehci: usbcmd: 0x%08lx; usbsts: 0x%08lx\n", ReadOpReg(EHCI_USBCMD), ReadOpReg(EHCI_USBSTS)));
304 
305 	uint32 frameListSize = (ReadOpReg(EHCI_USBCMD) >> EHCI_USBCMD_FLS_SHIFT)
306 		& EHCI_USBCMD_FLS_MASK;
307 	WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_RUNSTOP
308 		| EHCI_USBCMD_ASENABLE /*| EHCI_USBCMD_PSENABLE*/
309 		| (frameListSize << EHCI_USBCMD_FLS_SHIFT)
310 		| (2 << EHCI_USBCMD_ITC_SHIFT));
311 
312 	// route all ports to us
313 	WriteOpReg(EHCI_CONFIGFLAG, EHCI_CONFIGFLAG_FLAG);
314 
315 	bool running = false;
316 	for (int32 i = 0; i < 10; i++) {
317 		uint32 status = ReadOpReg(EHCI_USBSTS);
318 		TRACE(("usb_ehci: try %ld: status 0x%08lx\n", i, status));
319 
320 		if (status & EHCI_USBSTS_HCHALTED) {
321 			snooze(10000);
322 		} else {
323 			running = true;
324 			break;
325 		}
326 	}
327 
328 	// set the interrupt threshold
329 	WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD)
330 		| (1 << EHCI_USBCMD_ITC_SHIFT));
331 
332 	if (!running) {
333 		TRACE(("usb_ehci: Host Controller didn't start\n"));
334 		return B_ERROR;
335 	}
336 
337 	fRootHubAddress = AllocateAddress();
338 	fRootHub = new(std::nothrow) EHCIRootHub(RootObject(), fRootHubAddress);
339 	if (!fRootHub) {
340 		TRACE_ERROR(("usb_ehci: no memory to allocate root hub\n"));
341 		return B_NO_MEMORY;
342 	}
343 
344 	if (fRootHub->InitCheck() < B_OK) {
345 		TRACE_ERROR(("usb_ehci: root hub failed init check\n"));
346 		return fRootHub->InitCheck();
347 	}
348 
349 	SetRootHub(fRootHub);
350 	TRACE(("usb_ehci: Host Controller started\n"));
351 	return BusManager::Start();
352 }
353 
354 
355 status_t
356 EHCI::SubmitTransfer(Transfer *transfer)
357 {
358 	// short circuit the root hub
359 	if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
360 		return fRootHub->ProcessTransfer(this, transfer);
361 
362 	uint32 type = transfer->TransferPipe()->Type();
363 	if ((type & USB_OBJECT_CONTROL_PIPE) > 0
364 		|| (type & USB_OBJECT_BULK_PIPE) > 0) {
365 		TRACE(("usb_ehci: submitting async transfer\n"));
366 		return SubmitAsyncTransfer(transfer);
367 	}
368 
369 	if ((type & USB_OBJECT_INTERRUPT_PIPE) > 0
370 		|| (type & USB_OBJECT_ISO_PIPE) > 0) {
371 		TRACE(("usb_ehci: submitting periodic transfer\n"));
372 		return SubmitPeriodicTransfer(transfer);
373 	}
374 
375 	TRACE_ERROR(("usb_ehci: tried to submit transfer for unknown pipe type %lu\n", type));
376  	return B_ERROR;
377 }
378 
379 
380 status_t
381 EHCI::SubmitAsyncTransfer(Transfer *transfer)
382 {
383 	ehci_qh *queueHead = CreateQueueHead();
384 	if (!queueHead) {
385 		TRACE_ERROR(("usb_ehci: failed to allocate async queue head\n"));
386 		return B_NO_MEMORY;
387 	}
388 
389 	Pipe *pipe = transfer->TransferPipe();
390 	switch (pipe->Speed()) {
391 		case USB_SPEED_LOWSPEED:
392 			queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_LOW;
393 			break;
394 		case USB_SPEED_FULLSPEED:
395 			queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_FULL;
396 			break;
397 		case USB_SPEED_HIGHSPEED:
398 			queueHead->endpoint_chars = EHCI_QH_CHARS_EPS_HIGH;
399 			break;
400 		default:
401 			TRACE_ERROR(("usb_ehci: unknown pipe speed\n"));
402 			FreeQueueHead(queueHead);
403 			return B_ERROR;
404 	}
405 
406 	if (pipe->Type() & USB_OBJECT_CONTROL_PIPE) {
407 		queueHead->endpoint_chars |=
408 			(pipe->Speed() != USB_SPEED_HIGHSPEED ? EHCI_QH_CHARS_CONTROL : 0);
409 	}
410 
411 	queueHead->endpoint_chars |= (3 << EHCI_QH_CHARS_RL_SHIFT)
412 		| (pipe->MaxPacketSize() << EHCI_QH_CHARS_MPL_SHIFT)
413 		| (pipe->EndpointAddress() << EHCI_QH_CHARS_EPT_SHIFT)
414 		| (pipe->DeviceAddress() << EHCI_QH_CHARS_DEV_SHIFT)
415 		| EHCI_QH_CHARS_TOGGLE;
416 	queueHead->endpoint_caps = (1 << EHCI_QH_CAPS_MULT_SHIFT)
417 		| (0x1c << EHCI_QH_CAPS_SCM_SHIFT);
418 
419 	status_t result;
420 	bool directionIn;
421 	ehci_qtd *dataDescriptor;
422 	if (pipe->Type() & USB_OBJECT_CONTROL_PIPE)
423 		result = FillQueueWithRequest(transfer, queueHead, &dataDescriptor,
424 			&directionIn);
425 	else
426 		result = FillQueueWithData(transfer, queueHead, &dataDescriptor,
427 			&directionIn);
428 
429 	if (result < B_OK) {
430 		TRACE_ERROR(("usb_ehci: failed to fill transfer queue with data\n"));
431 		FreeQueueHead(queueHead);
432 		return result;
433 	}
434 
435 	result = AddPendingTransfer(transfer, queueHead, dataDescriptor, directionIn);
436 	if (result < B_OK) {
437 		TRACE_ERROR(("usb_ehci: failed to add pending transfer\n"));
438 		FreeQueueHead(queueHead);
439 		return result;
440 	}
441 
442 #ifdef TRACE_USB
443 	TRACE(("usb_ehci: linking queue\n"));
444 	print_queue(queueHead);
445 #endif
446 
447 	result = LinkQueueHead(queueHead);
448 	if (result < B_OK) {
449 		TRACE_ERROR(("usb_ehci: failed to link queue head to the async list\n"));
450 		FreeQueueHead(queueHead);
451 		return result;
452 	}
453 
454 	return B_OK;
455 }
456 
457 
458 status_t
459 EHCI::SubmitPeriodicTransfer(Transfer *transfer)
460 {
461 	return B_ERROR;
462 }
463 
464 
465 status_t
466 EHCI::NotifyPipeChange(Pipe *pipe, usb_change change)
467 {
468 	TRACE_ERROR(("usb_ehci: pipe change %d for pipe 0x%08lx\n", change, (uint32)pipe));
469 	switch (change) {
470 		case USB_CHANGE_CREATED:
471 		case USB_CHANGE_DESTROYED: {
472 			// ToDo: we should create and keep a single queue head
473 			// for all transfers to/from this pipe
474 			break;
475 		}
476 
477 		case USB_CHANGE_PIPE_POLICY_CHANGED: {
478 			// ToDo: for isochronous pipes we might need to adapt to new
479 			// pipe policy settings here
480 			break;
481 		}
482 	}
483 
484 	return B_OK;
485 }
486 
487 
488 status_t
489 EHCI::AddTo(Stack *stack)
490 {
491 #ifdef TRACE_USB
492 	set_dprintf_enabled(true);
493 	load_driver_symbols("ehci");
494 #endif
495 
496 	if (!sPCIModule) {
497 		status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule);
498 		if (status < B_OK) {
499 			TRACE_ERROR(("usb_ehci: getting pci module failed! 0x%08lx\n", status));
500 			return status;
501 		}
502 	}
503 
504 	TRACE(("usb_ehci: searching devices\n"));
505 	bool found = false;
506 	pci_info *item = new(std::nothrow) pci_info;
507 	if (!item) {
508 		sPCIModule = NULL;
509 		put_module(B_PCI_MODULE_NAME);
510 		return B_NO_MEMORY;
511 	}
512 
513 	for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) {
514 
515 		if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb
516 			&& item->class_api == PCI_usb_ehci) {
517 			if (item->u.h0.interrupt_line == 0
518 				|| item->u.h0.interrupt_line == 0xFF) {
519 				TRACE_ERROR(("usb_ehci: found device with invalid IRQ - check IRQ assignement\n"));
520 				continue;
521 			}
522 
523 			TRACE(("usb_ehci: found device at IRQ %u\n", item->u.h0.interrupt_line));
524 			EHCI *bus = new(std::nothrow) EHCI(item, stack);
525 			if (!bus) {
526 				delete item;
527 				sPCIModule = NULL;
528 				put_module(B_PCI_MODULE_NAME);
529 				return B_NO_MEMORY;
530 			}
531 
532 			if (bus->InitCheck() < B_OK) {
533 				TRACE_ERROR(("usb_ehci: bus failed init check\n"));
534 				delete bus;
535 				continue;
536 			}
537 
538 			// the bus took it away
539 			item = new(std::nothrow) pci_info;
540 
541 			bus->Start();
542 			stack->AddBusManager(bus);
543 			found = true;
544 		}
545 	}
546 
547 	if (!found) {
548 		TRACE_ERROR(("usb_ehci: no devices found\n"));
549 		delete item;
550 		sPCIModule = NULL;
551 		put_module(B_PCI_MODULE_NAME);
552 		return ENODEV;
553 	}
554 
555 	delete item;
556 	return B_OK;
557 }
558 
559 
560 status_t
561 EHCI::GetPortStatus(uint8 index, usb_port_status *status)
562 {
563 	if (index >= fPortCount)
564 		return B_BAD_INDEX;
565 
566 	status->status = status->change = 0;
567 	uint32 portStatus = ReadOpReg(EHCI_PORTSC + index * sizeof(uint32));
568 
569 	// build the status
570 	if (portStatus & EHCI_PORTSC_CONNSTATUS)
571 		status->status |= PORT_STATUS_CONNECTION;
572 	if (portStatus & EHCI_PORTSC_ENABLE)
573 		status->status |= PORT_STATUS_ENABLE;
574 	if (portStatus & EHCI_PORTSC_ENABLE)
575 		status->status |= PORT_STATUS_HIGH_SPEED;
576 	if (portStatus & EHCI_PORTSC_OCACTIVE)
577 		status->status |= PORT_STATUS_OVER_CURRENT;
578 	if (portStatus & EHCI_PORTSC_PORTRESET)
579 		status->status |= PORT_STATUS_RESET;
580 	if (portStatus & EHCI_PORTSC_PORTPOWER)
581 		status->status |= PORT_STATUS_POWER;
582 	if (portStatus & EHCI_PORTSC_SUSPEND)
583 		status->status |= PORT_STATUS_SUSPEND;
584 	if (portStatus & EHCI_PORTSC_DMINUS)
585 		status->status |= PORT_STATUS_LOW_SPEED;
586 
587 	// build the change
588 	if (portStatus & EHCI_PORTSC_CONNCHANGE)
589 		status->change |= PORT_STATUS_CONNECTION;
590 	if (portStatus & EHCI_PORTSC_ENABLECHANGE)
591 		status->change |= PORT_STATUS_ENABLE;
592 	if (portStatus & EHCI_PORTSC_OCCHANGE)
593 		status->change |= PORT_STATUS_OVER_CURRENT;
594 
595 	// there are no bits to indicate suspend and reset change
596 	if (fPortResetChange & (1 << index))
597 		status->change |= PORT_STATUS_RESET;
598 	if (fPortSuspendChange & (1 << index))
599 		status->change |= PORT_STATUS_SUSPEND;
600 
601 	return B_OK;
602 }
603 
604 
605 status_t
606 EHCI::SetPortFeature(uint8 index, uint16 feature)
607 {
608 	if (index >= fPortCount)
609 		return B_BAD_INDEX;
610 
611 	uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
612 	uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
613 
614 	switch (feature) {
615 		case PORT_SUSPEND:
616 			return SuspendPort(index);
617 
618 		case PORT_RESET:
619 			return ResetPort(index);
620 
621 		case PORT_POWER:
622 			WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTPOWER);
623 			return B_OK;
624 	}
625 
626 	return B_BAD_VALUE;
627 }
628 
629 
630 status_t
631 EHCI::ClearPortFeature(uint8 index, uint16 feature)
632 {
633 	if (index >= fPortCount)
634 		return B_BAD_INDEX;
635 
636 	uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
637 	uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
638 
639 	switch (feature) {
640 		case PORT_ENABLE:
641 			WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_ENABLE);
642 			return B_OK;
643 
644 		case PORT_POWER:
645 			WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTPOWER);
646 			return B_OK;
647 
648 		case C_PORT_CONNECTION:
649 			WriteOpReg(portRegister, portStatus | EHCI_PORTSC_CONNCHANGE);
650 			return B_OK;
651 
652 		case C_PORT_ENABLE:
653 			WriteOpReg(portRegister, portStatus | EHCI_PORTSC_ENABLECHANGE);
654 			return B_OK;
655 
656 		case C_PORT_OVER_CURRENT:
657 			WriteOpReg(portRegister, portStatus | EHCI_PORTSC_OCCHANGE);
658 			return B_OK;
659 
660 		case C_PORT_RESET:
661 			fPortResetChange &= ~(1 << index);
662 			return B_OK;
663 
664 		case C_PORT_SUSPEND:
665 			fPortSuspendChange &= ~(1 << index);
666 			return B_OK;
667 	}
668 
669 	return B_BAD_VALUE;
670 }
671 
672 
673 status_t
674 EHCI::ResetPort(uint8 index)
675 {
676 	TRACE(("usb_ehci: reset port %d\n", index));
677 	uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
678 	uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
679 
680 	if (portStatus & EHCI_PORTSC_DMINUS) {
681 		TRACE(("usb_ehci: lowspeed device connected, giving up port ownership\n"));
682 		// there is a lowspeed device connected.
683 		// we give the ownership to a companion controller.
684 		WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER);
685 		fPortResetChange |= (1 << index);
686 		return B_OK;
687 	}
688 
689 	// enable reset signaling
690 	WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTRESET);
691 	snooze(250000);
692 
693 	// disable reset signaling
694 	portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
695 	WriteOpReg(portRegister, portStatus & ~EHCI_PORTSC_PORTRESET);
696 	snooze(2000);
697 
698 	portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
699 	if (portStatus & EHCI_PORTSC_PORTRESET) {
700 		TRACE(("usb_ehci: port reset won't complete\n"));
701 		return B_ERROR;
702 	}
703 
704 	if ((portStatus & EHCI_PORTSC_ENABLE) == 0) {
705 		TRACE(("usb_ehci: fullspeed device connected, giving up port ownership\n"));
706 		// the port was not enabled, this means that no high speed device is
707 		// attached to this port. we give up ownership to a companion controler
708 		WriteOpReg(portRegister, portStatus | EHCI_PORTSC_PORTOWNER);
709 	}
710 
711 	fPortResetChange |= (1 << index);
712 	return B_OK;
713 }
714 
715 
716 status_t
717 EHCI::SuspendPort(uint8 index)
718 {
719 	uint32 portRegister = EHCI_PORTSC + index * sizeof(uint32);
720 	uint32 portStatus = ReadOpReg(portRegister) & EHCI_PORTSC_DATAMASK;
721 	WriteOpReg(portRegister, portStatus | EHCI_PORTSC_SUSPEND);
722 	fPortSuspendChange |= (1 << index);
723 	return B_OK;
724 }
725 
726 
727 status_t
728 EHCI::ControllerReset()
729 {
730 	// halt the controller first
731 	WriteOpReg(EHCI_USBCMD, 0);
732 	snooze(10000);
733 
734 	// then reset it
735 	WriteOpReg(EHCI_USBCMD, EHCI_USBCMD_HCRESET);
736 
737 	int32 tries = 5;
738 	while (ReadOpReg(EHCI_USBCMD) & EHCI_USBCMD_HCRESET) {
739 		snooze(10000);
740 		if (tries-- < 0)
741 			return B_ERROR;
742 	}
743 
744 	return B_OK;
745 }
746 
747 
748 status_t
749 EHCI::LightReset()
750 {
751 	return B_ERROR;
752 }
753 
754 
755 int32
756 EHCI::InterruptHandler(void *data)
757 {
758 	return ((EHCI *)data)->Interrupt();
759 }
760 
761 
762 int32
763 EHCI::Interrupt()
764 {
765 	spinlock lock = 0;
766 	acquire_spinlock(&lock);
767 
768 	// check if any interrupt was generated
769 	uint32 status = ReadOpReg(EHCI_USBSTS);
770 	if ((status & EHCI_USBSTS_INTMASK) == 0) {
771 		release_spinlock(&lock);
772 		return B_UNHANDLED_INTERRUPT;
773 	}
774 
775 	uint32 acknowledge = 0;
776 	bool asyncAdvance = false;
777 	bool finishTransfers = false;
778 	int32 result = B_HANDLED_INTERRUPT;
779 
780 	if (status & EHCI_USBSTS_USBINT) {
781 		TRACE(("usb_ehci: transfer finished\n"));
782 		acknowledge |= EHCI_USBSTS_USBINT;
783 		result = B_INVOKE_SCHEDULER;
784 		finishTransfers = true;
785 	}
786 
787 	if (status & EHCI_USBSTS_USBERRINT) {
788 		TRACE(("usb_ehci: transfer error\n"));
789 		acknowledge |= EHCI_USBSTS_USBERRINT;
790 		result = B_INVOKE_SCHEDULER;
791 		finishTransfers = true;
792 	}
793 
794 	if (status & EHCI_USBSTS_PORTCHANGE) {
795 		TRACE(("usb_ehci: port change detected\n"));
796 		acknowledge |= EHCI_USBSTS_PORTCHANGE;
797 	}
798 
799 	if (status & EHCI_USBSTS_FLROLLOVER) {
800 		TRACE(("usb_ehci: frame list rolled over\n"));
801 		acknowledge |= EHCI_USBSTS_FLROLLOVER;
802 	}
803 
804 	if (status & EHCI_USBSTS_INTONAA) {
805 		TRACE(("usb_ehci: interrupt on async advance\n"));
806 		acknowledge |= EHCI_USBSTS_INTONAA;
807 		asyncAdvance = true;
808 		result = B_INVOKE_SCHEDULER;
809 	}
810 
811 	if (status & EHCI_USBSTS_HOSTSYSERR) {
812 		TRACE_ERROR(("usb_ehci: host system error!\n"));
813 		acknowledge |= EHCI_USBSTS_HOSTSYSERR;
814 	}
815 
816 	if (acknowledge)
817 		WriteOpReg(EHCI_USBSTS, acknowledge);
818 
819 	release_spinlock(&lock);
820 
821 	if (asyncAdvance)
822 		release_sem_etc(fAsyncAdvanceSem, 1, B_DO_NOT_RESCHEDULE);
823 	if (finishTransfers)
824 		release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
825 
826 	return result;
827 }
828 
829 
830 status_t
831 EHCI::AddPendingTransfer(Transfer *transfer, ehci_qh *queueHead,
832 	ehci_qtd *dataDescriptor, bool directionIn)
833 {
834 	transfer_data *data = new(std::nothrow) transfer_data();
835 	if (!data)
836 		return B_NO_MEMORY;
837 
838 	data->transfer = transfer;
839 	data->queue_head = queueHead;
840 	data->data_descriptor = dataDescriptor;
841 	data->user_area = -1;
842 	data->incoming = directionIn;
843 	data->link = NULL;
844 
845 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
846 	if (directionIn) {
847 		// we might need to access a buffer in userspace. this will not
848 		// be possible in the kernel space finisher thread unless we
849 		// get the proper area id for the space we need and then clone it
850 		// before writing to it. this is of course terribly inefficient...
851 		iovec *vector = transfer->Vector();
852 		size_t vectorCount = transfer->VectorCount();
853 		for (size_t i = 0; i < vectorCount; i++) {
854 			if (IS_USER_ADDRESS(vector[i].iov_base)) {
855 				data->user_area = area_for(vector[i].iov_base);
856 				if (data->user_area < B_OK) {
857 					TRACE_ERROR(("usb_ehci: failed to get area of userspace buffer\n"));
858 					delete data;
859 					return B_BAD_ADDRESS;
860 				}
861 
862 				break;
863 			}
864 		}
865 
866 		if (data->user_area >= B_OK) {
867 			area_info areaInfo;
868 			if (get_area_info(data->user_area, &areaInfo) < B_OK) {
869 				TRACE_ERROR(("usb_ehci: failed to get info about user area\n"));
870 				delete data;
871 				return B_BAD_ADDRESS;
872 			}
873 
874 			for (size_t i = 0; i < vectorCount; i++) {
875 				(uint8 *)vector[i].iov_base -= (uint8 *)areaInfo.address;
876 
877 				if ((size_t)vector[i].iov_base > areaInfo.size
878 					|| (size_t)vector[i].iov_base + vector[i].iov_len > areaInfo.size) {
879 					TRACE_ERROR(("usb_ehci: output data buffer spans across multiple areas!\n"));
880 					delete data;
881 					return B_BAD_ADDRESS;
882 				}
883 			}
884 		}
885 	}
886 #endif // !HAIKU_TARGET_PLATFORM_HAIKU
887 
888 	if (!Lock()) {
889 		delete data;
890 		return B_ERROR;
891 	}
892 
893 	if (fLastTransfer)
894 		fLastTransfer->link = data;
895 	else
896 		fFirstTransfer = data;
897 
898 	fLastTransfer = data;
899 	Unlock();
900 
901 	return B_OK;
902 }
903 
904 
905 status_t
906 EHCI::CancelPendingTransfer(Transfer *transfer)
907 {
908 	if (!Lock())
909 		return B_ERROR;
910 
911 	transfer_data *last = NULL;
912 	transfer_data *current = fFirstTransfer;
913 	while (current) {
914 		if (current->transfer == transfer) {
915 			current->transfer->Finished(B_CANCELED, 0);
916 			delete current->transfer;
917 
918 			if (last)
919 				last->link = current->link;
920 			else
921 				fFirstTransfer = current->link;
922 
923 			if (fLastTransfer == current)
924 				fLastTransfer = last;
925 
926 			delete current;
927 			Unlock();
928 			return B_OK;
929 		}
930 
931 		last = current;
932 		current = current->link;
933 	}
934 
935 	Unlock();
936 	return B_BAD_VALUE;
937 }
938 
939 
940 status_t
941 EHCI::CancelAllPendingTransfers()
942 {
943 	if (!Lock())
944 		return B_ERROR;
945 
946 	transfer_data *transfer = fFirstTransfer;
947 	while (transfer) {
948 		transfer->transfer->Finished(B_CANCELED, 0);
949 		delete transfer->transfer;
950 
951 		transfer_data *next = transfer->link;
952 		delete transfer;
953 		transfer = next;
954 	}
955 
956 	fFirstTransfer = NULL;
957 	fLastTransfer = NULL;
958 	Unlock();
959 	return B_OK;
960 }
961 
962 
963 int32
964 EHCI::FinishThread(void *data)
965 {
966 	((EHCI *)data)->FinishTransfers();
967 	return B_OK;
968 }
969 
970 
971 void
972 EHCI::FinishTransfers()
973 {
974 	while (!fStopThreads) {
975 		if (acquire_sem(fFinishTransfersSem) < B_OK)
976 			continue;
977 
978 		// eat up sems that have been released by multiple interrupts
979 		int32 semCount = 0;
980 		get_sem_count(fFinishTransfersSem, &semCount);
981 		if (semCount > 0)
982 			acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
983 
984 		if (!Lock())
985 			continue;
986 
987 		TRACE(("usb_ehci: finishing transfers\n"));
988 		transfer_data *lastTransfer = NULL;
989 		transfer_data *transfer = fFirstTransfer;
990 		Unlock();
991 
992 		while (transfer) {
993 			bool transferDone = false;
994 			ehci_qtd *descriptor = (ehci_qtd *)transfer->queue_head->element_log;
995 
996 #ifdef TRACE_USB
997 			print_queue(transfer->queue_head);
998 #endif
999 
1000 			while (descriptor) {
1001 				uint32 status = descriptor->token;
1002 				if (status & EHCI_QTD_STATUS_ACTIVE) {
1003 					// still in progress
1004 					TRACE(("usb_ehci: qtd (0x%08lx) still active\n", descriptor->this_phy));
1005 					break;
1006 				}
1007 
1008 				if (status & EHCI_QTD_STATUS_ERRMASK) {
1009 					// a transfer error occured
1010 					TRACE_ERROR(("usb_ehci: qtd (0x%08lx) error: 0x%08lx\n", descriptor->this_phy, status));
1011 
1012 					status_t callbackStatus = B_ERROR;
1013 					uint8 errorCount = status >> EHCI_QTD_ERRCOUNT_SHIFT;
1014 					errorCount &= EHCI_QTD_ERRCOUNT_MASK;
1015 					if (errorCount == 0) {
1016 						// the error counter counted down to zero, report why
1017 						int32 reasons = 0;
1018 						if (status & EHCI_QTD_STATUS_BUFFER) {
1019 							callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN;
1020 							reasons++;
1021 						}
1022 						if (status & EHCI_QTD_STATUS_TERROR) {
1023 							callbackStatus = B_DEV_CRC_ERROR;
1024 							reasons++;
1025 						}
1026 
1027 						if (reasons > 1)
1028 							callbackStatus = B_DEV_MULTIPLE_ERRORS;
1029 					} else if (status & EHCI_QTD_STATUS_BABBLE) {
1030 						// there is a babble condition
1031 						callbackStatus = transfer->incoming ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN;
1032 					} else {
1033 						// if the error counter didn't count down to zero
1034 						// and there was no babble, then this halt was caused
1035 						// by a stall handshake
1036 						callbackStatus = B_DEV_STALLED;
1037 					}
1038 
1039 					UnlinkQueueHead(transfer->queue_head, &fFreeListHead);
1040 					transfer->transfer->Finished(callbackStatus, 0);
1041 					transferDone = true;
1042 					break;
1043 				}
1044 
1045 				if (descriptor->next_phy & EHCI_QTD_TERMINATE) {
1046 					// we arrived at the last (stray) descriptor, we're done
1047 					TRACE(("usb_ehci: qtd (0x%08lx) done\n", descriptor->this_phy));
1048 
1049 					size_t actualLength = 0;
1050 					bool nextDataToggle = false;
1051 					if (transfer->data_descriptor && transfer->incoming) {
1052 						// data to read out
1053 						iovec *vector = transfer->transfer->Vector();
1054 						size_t vectorCount = transfer->transfer->VectorCount();
1055 
1056 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
1057 						area_id clonedArea = -1;
1058 						if (transfer->user_area >= B_OK) {
1059 							// we got a userspace output buffer, need to clone
1060 							// the area for that space first and map the iovecs
1061 							// to this cloned area.
1062 							void *clonedMemory = NULL;
1063 							clonedArea = clone_area("userspace accessor",
1064 								&clonedMemory, B_ANY_ADDRESS,
1065 								B_WRITE_AREA | B_KERNEL_WRITE_AREA,
1066 								transfer->user_area);
1067 
1068 							for (size_t i = 0; i < vectorCount; i++)
1069 								(uint8 *)vector[i].iov_base += (addr_t)clonedMemory;
1070 						}
1071 #endif // !HAIKU_TARGET_PLATFORM_HAIKU
1072 
1073 						actualLength = ReadDescriptorChain(
1074 							transfer->data_descriptor,
1075 							vector, vectorCount,
1076 							&nextDataToggle);
1077 
1078 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
1079 						if (clonedArea >= B_OK)
1080 							delete_area(clonedArea);
1081 #endif // !HAIKU_TARGET_PLATFORM_HAIKU
1082 					} else {
1083 						// calculate transfered length
1084 						actualLength = ReadActualLength(
1085 							(ehci_qtd *)transfer->queue_head->element_log,
1086 							&nextDataToggle);
1087 					}
1088 
1089 					UnlinkQueueHead(transfer->queue_head, &fFreeListHead);
1090 					transfer->transfer->TransferPipe()->SetDataToggle(nextDataToggle);
1091 					transfer->transfer->Finished(B_OK, actualLength);
1092 					transferDone = true;
1093 					break;
1094 				}
1095 
1096 				descriptor = (ehci_qtd *)descriptor->next_log;
1097 			}
1098 
1099 			if (transferDone) {
1100 				if (Lock()) {
1101 					if (lastTransfer)
1102 						lastTransfer->link = transfer->link;
1103 
1104 					if (transfer == fFirstTransfer)
1105 						fFirstTransfer = transfer->link;
1106 					if (transfer == fLastTransfer)
1107 						fLastTransfer = lastTransfer;
1108 
1109 					transfer_data *next = transfer->link;
1110 					delete transfer->transfer;
1111 					delete transfer;
1112 					transfer = next;
1113 					Unlock();
1114 				}
1115 			} else {
1116 				if (Lock()) {
1117 					lastTransfer = transfer;
1118 					transfer = transfer->link;
1119 					Unlock();
1120 				}
1121 			}
1122 
1123 			release_sem(fCleanupSem);
1124 		}
1125 	}
1126 }
1127 
1128 
1129 int32
1130 EHCI::CleanupThread(void *data)
1131 {
1132 	((EHCI *)data)->Cleanup();
1133 	return B_OK;
1134 }
1135 
1136 
1137 void
1138 EHCI::Cleanup()
1139 {
1140 	ehci_qh *lastFreeListHead = NULL;
1141 
1142 	while (!fStopThreads) {
1143 		if (acquire_sem(fCleanupSem) < B_OK)
1144 			continue;
1145 
1146 		ehci_qh *freeListHead = fFreeListHead;
1147 		if (freeListHead == lastFreeListHead)
1148 			continue;
1149 
1150 		// set the doorbell and wait for the host controller to notify us
1151 		WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD);
1152 		if (acquire_sem(fAsyncAdvanceSem) < B_OK)
1153 			continue;
1154 
1155 		ehci_qh *current = freeListHead;
1156 		while (current != lastFreeListHead) {
1157 			ehci_qh *next = (ehci_qh *)current->next_log;
1158 			FreeQueueHead(current);
1159 			current = next;
1160 		}
1161 
1162 		lastFreeListHead = freeListHead;
1163 	}
1164 }
1165 
1166 
1167 ehci_qh *
1168 EHCI::CreateQueueHead()
1169 {
1170 	ehci_qh *result;
1171 	void *physicalAddress;
1172 	if (fStack->AllocateChunk((void **)&result, &physicalAddress,
1173 		sizeof(ehci_qh)) < B_OK) {
1174 		TRACE_ERROR(("usb_ehci: failed to allocate queue head\n"));
1175 		return NULL;
1176 	}
1177 
1178 	result->this_phy = (addr_t)physicalAddress;
1179 	result->next_phy = EHCI_QH_TERMINATE;
1180 	result->next_log = NULL;
1181 	result->prev_log = NULL;
1182 
1183 	ehci_qtd *descriptor = CreateDescriptor(0, 0);
1184 	if (!descriptor) {
1185 		TRACE_ERROR(("usb_ehci: failed to allocate initial qtd for queue head\n"));
1186 		fStack->FreeChunk(result, (void *)result->this_phy, sizeof(ehci_qh));
1187 		return NULL;
1188 	}
1189 
1190 	descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
1191 	result->stray_log = descriptor;
1192 	result->element_log = descriptor;
1193 	result->current_qtd_phy = EHCI_QTD_TERMINATE;
1194 	result->overlay.next_phy = descriptor->this_phy;
1195 	result->overlay.alt_next_phy = EHCI_QTD_TERMINATE;
1196 	result->overlay.token = 0;
1197 	for (int32 i = 0; i < 5; i++) {
1198 		result->overlay.buffer_phy[i] = 0;
1199 		result->overlay.ext_buffer_phy[i] = 0;
1200 	}
1201 
1202 	return result;
1203 }
1204 
1205 
1206 void
1207 EHCI::FreeQueueHead(ehci_qh *queueHead)
1208 {
1209 	if (!queueHead)
1210 		return;
1211 
1212 	FreeDescriptorChain((ehci_qtd *)queueHead->element_log);
1213 	FreeDescriptor((ehci_qtd *)queueHead->stray_log);
1214 	fStack->FreeChunk(queueHead, (void *)queueHead->this_phy, sizeof(ehci_qh));
1215 }
1216 
1217 
1218 status_t
1219 EHCI::LinkQueueHead(ehci_qh *queueHead)
1220 {
1221 	if (!Lock())
1222 		return B_ERROR;
1223 
1224 	ehci_qh *prevHead = (ehci_qh *)fAsyncQueueHead->prev_log;
1225 	queueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH;
1226 	queueHead->next_log = fAsyncQueueHead;
1227 	queueHead->prev_log = prevHead;
1228 	fAsyncQueueHead->prev_log = queueHead;
1229 	prevHead->next_log = queueHead;
1230 	prevHead->next_phy = queueHead->this_phy | EHCI_QH_TYPE_QH;
1231 
1232 	Unlock();
1233 	return B_OK;
1234 }
1235 
1236 
1237 status_t
1238 EHCI::UnlinkQueueHead(ehci_qh *queueHead, ehci_qh **freeListHead)
1239 {
1240 	if (!Lock())
1241 		return B_ERROR;
1242 
1243 	ehci_qh *prevHead = (ehci_qh *)queueHead->prev_log;
1244 	ehci_qh *nextHead = (ehci_qh *)queueHead->next_log;
1245 	prevHead->next_phy = queueHead->next_phy | EHCI_QH_TYPE_QH;
1246 	prevHead->next_log = queueHead->next_log;
1247 	nextHead->prev_log = queueHead->prev_log;
1248 	queueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH;
1249 	queueHead->next_log = NULL;
1250 	queueHead->prev_log = NULL;
1251 
1252 	queueHead->next_log = *freeListHead;
1253 	*freeListHead = queueHead;
1254 
1255 	Unlock();
1256 	return B_OK;
1257 }
1258 
1259 
1260 status_t
1261 EHCI::FillQueueWithRequest(Transfer *transfer, ehci_qh *queueHead,
1262 	ehci_qtd **_dataDescriptor, bool *_directionIn)
1263 {
1264 	Pipe *pipe = transfer->TransferPipe();
1265 	usb_request_data *requestData = transfer->RequestData();
1266 	bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
1267 
1268 	ehci_qtd *setupDescriptor = CreateDescriptor(sizeof(usb_request_data),
1269 		EHCI_QTD_PID_SETUP);
1270 	ehci_qtd *statusDescriptor = CreateDescriptor(0,
1271 		directionIn ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN);
1272 
1273 	if (!setupDescriptor || !statusDescriptor) {
1274 		TRACE_ERROR(("usb_ehci: failed to allocate descriptors\n"));
1275 		FreeDescriptor(setupDescriptor);
1276 		FreeDescriptor(statusDescriptor);
1277 		return B_NO_MEMORY;
1278 	}
1279 
1280 	iovec vector;
1281 	vector.iov_base = requestData;
1282 	vector.iov_len = sizeof(usb_request_data);
1283 	WriteDescriptorChain(setupDescriptor, &vector, 1);
1284 
1285 	ehci_qtd *strayDescriptor = (ehci_qtd *)queueHead->stray_log;
1286 	statusDescriptor->token |= EHCI_QTD_IOC | EHCI_QTD_DATA_TOGGLE;
1287 
1288 	ehci_qtd *dataDescriptor = NULL;
1289 	if (transfer->VectorCount() > 0) {
1290 		ehci_qtd *lastDescriptor = NULL;
1291 		status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
1292 			&lastDescriptor, strayDescriptor, transfer->VectorLength(),
1293 			directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
1294 
1295 		if (result < B_OK) {
1296 			FreeDescriptor(setupDescriptor);
1297 			FreeDescriptor(statusDescriptor);
1298 			return result;
1299 		}
1300 
1301 		if (!directionIn) {
1302 			WriteDescriptorChain(dataDescriptor, transfer->Vector(),
1303 				transfer->VectorCount());
1304 		}
1305 
1306 		LinkDescriptors(setupDescriptor, dataDescriptor, strayDescriptor);
1307 		LinkDescriptors(lastDescriptor, statusDescriptor, strayDescriptor);
1308 	} else {
1309 		// no data: link setup and status descriptors directly
1310 		LinkDescriptors(setupDescriptor, statusDescriptor, strayDescriptor);
1311 	}
1312 
1313 	queueHead->element_log = setupDescriptor;
1314 	queueHead->overlay.next_phy = setupDescriptor->this_phy;
1315 	queueHead->overlay.alt_next_phy = EHCI_QTD_TERMINATE;
1316 
1317 	*_dataDescriptor = dataDescriptor;
1318 	*_directionIn = directionIn;
1319 	return B_OK;
1320 }
1321 
1322 
1323 status_t
1324 EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead,
1325 	ehci_qtd **_dataDescriptor, bool *_directionIn)
1326 {
1327 	Pipe *pipe = transfer->TransferPipe();
1328 	bool directionIn = (pipe->Direction() == Pipe::In);
1329 
1330 	ehci_qtd *firstDescriptor = NULL;
1331 	ehci_qtd *lastDescriptor = NULL;
1332 	ehci_qtd *strayDescriptor = (ehci_qtd *)queueHead->stray_log;
1333 	status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
1334 		&lastDescriptor, strayDescriptor, transfer->VectorLength(),
1335 		directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
1336 
1337 	if (result < B_OK)
1338 		return result;
1339 
1340 	lastDescriptor->token |= EHCI_QTD_IOC;
1341 	if (!directionIn) {
1342 		WriteDescriptorChain(firstDescriptor, transfer->Vector(),
1343 			transfer->VectorCount());
1344 	}
1345 
1346 	queueHead->element_log = firstDescriptor;
1347 	queueHead->overlay.next_phy = firstDescriptor->this_phy;
1348 	queueHead->overlay.alt_next_phy = EHCI_QTD_TERMINATE;
1349 
1350 	*_dataDescriptor = firstDescriptor;
1351 	*_directionIn = directionIn;
1352 	return B_OK;
1353 }
1354 
1355 
1356 ehci_qtd *
1357 EHCI::CreateDescriptor(size_t bufferSize, uint8 pid)
1358 {
1359 	ehci_qtd *result;
1360 	void *physicalAddress;
1361 	if (fStack->AllocateChunk((void **)&result, &physicalAddress,
1362 		sizeof(ehci_qtd)) < B_OK) {
1363 		TRACE_ERROR(("usb_ehci: failed to allocate a qtd\n"));
1364 		return NULL;
1365 	}
1366 
1367 	result->this_phy = (addr_t)physicalAddress;
1368 	result->next_phy = EHCI_QTD_TERMINATE;
1369 	result->next_log = NULL;
1370 	result->alt_next_phy = EHCI_QTD_TERMINATE;
1371 	result->alt_next_log = NULL;
1372 	result->buffer_size = bufferSize;
1373 	result->token = bufferSize << EHCI_QTD_BYTES_SHIFT;
1374 	result->token |= 3 << EHCI_QTD_ERRCOUNT_SHIFT;
1375 	result->token |= pid << EHCI_QTD_PID_SHIFT;
1376 	result->token |= EHCI_QTD_STATUS_ACTIVE;
1377 	if (bufferSize == 0) {
1378 		result->buffer_log = NULL;
1379 		for (int32 i = 0; i < 5; i++) {
1380 			result->buffer_phy[i] = 0;
1381 			result->ext_buffer_phy[i] = 0;
1382 		}
1383 
1384 		return result;
1385 	}
1386 
1387 	if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress,
1388 		bufferSize) < B_OK) {
1389 		TRACE_ERROR(("usb_ehci: unable to allocate qtd buffer\n"));
1390 		fStack->FreeChunk(result, (void *)result->this_phy, sizeof(ehci_qtd));
1391 		return NULL;
1392 	}
1393 
1394 	addr_t physicalBase = (addr_t)physicalAddress;
1395 	result->buffer_phy[0] = physicalBase;
1396 	result->ext_buffer_phy[0] = 0;
1397 	for (int32 i = 1; i < 5; i++) {
1398 		physicalBase += B_PAGE_SIZE;
1399 		result->buffer_phy[i] = physicalBase & EHCI_QTD_PAGE_MASK;
1400 		result->ext_buffer_phy[i] = 0;
1401 	}
1402 
1403 	return result;
1404 }
1405 
1406 
1407 status_t
1408 EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor,
1409 	ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize,
1410 	uint8 pid)
1411 {
1412 	size_t packetSize = B_PAGE_SIZE * 4;
1413 	int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
1414 
1415 	bool dataToggle = pipe->DataToggle();
1416 	ehci_qtd *firstDescriptor = NULL;
1417 	ehci_qtd *lastDescriptor = *_firstDescriptor;
1418 	for (int32 i = 0; i < descriptorCount; i++) {
1419 		ehci_qtd *descriptor = CreateDescriptor(min_c(packetSize, bufferSize),
1420 			pid);
1421 
1422 		if (!descriptor) {
1423 			FreeDescriptorChain(firstDescriptor);
1424 			return B_NO_MEMORY;
1425 		}
1426 
1427 		if (dataToggle)
1428 			descriptor->token |= EHCI_QTD_DATA_TOGGLE;
1429 
1430 		if (lastDescriptor)
1431 			LinkDescriptors(lastDescriptor, descriptor, strayDescriptor);
1432 
1433 		bufferSize -= packetSize;
1434 		lastDescriptor = descriptor;
1435 		if (!firstDescriptor)
1436 			firstDescriptor = descriptor;
1437 	}
1438 
1439 	*_firstDescriptor = firstDescriptor;
1440 	*_lastDescriptor = lastDescriptor;
1441 	return B_OK;
1442 }
1443 
1444 
1445 void
1446 EHCI::FreeDescriptor(ehci_qtd *descriptor)
1447 {
1448 	if (!descriptor)
1449 		return;
1450 
1451 	if (descriptor->buffer_log) {
1452 		fStack->FreeChunk(descriptor->buffer_log,
1453 			(void *)descriptor->buffer_phy[0], descriptor->buffer_size);
1454 	}
1455 
1456 	fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(ehci_qtd));
1457 }
1458 
1459 
1460 void
1461 EHCI::FreeDescriptorChain(ehci_qtd *topDescriptor)
1462 {
1463 	ehci_qtd *current = topDescriptor;
1464 	ehci_qtd *next = NULL;
1465 
1466 	while (current) {
1467 		next = (ehci_qtd *)current->next_log;
1468 		FreeDescriptor(current);
1469 		current = next;
1470 	}
1471 }
1472 
1473 
1474 void
1475 EHCI::LinkDescriptors(ehci_qtd *first, ehci_qtd *last, ehci_qtd *alt)
1476 {
1477 	first->next_phy = last->this_phy;
1478 	first->next_log = last;
1479 
1480 	if (alt) {
1481 		first->alt_next_phy = alt->this_phy;
1482 		first->alt_next_log = alt;
1483 	} else {
1484 		first->alt_next_phy = EHCI_QTD_TERMINATE;
1485 		first->alt_next_log = NULL;
1486 	}
1487 }
1488 
1489 
1490 size_t
1491 EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
1492 	size_t vectorCount)
1493 {
1494 	ehci_qtd *current = topDescriptor;
1495 	size_t actualLength = 0;
1496 	size_t vectorIndex = 0;
1497 	size_t vectorOffset = 0;
1498 	size_t bufferOffset = 0;
1499 
1500 	while (current) {
1501 		if (!current->buffer_log)
1502 			break;
1503 
1504 		while (true) {
1505 			size_t length = min_c(current->buffer_size - bufferOffset,
1506 				vector[vectorIndex].iov_len - vectorOffset);
1507 
1508 			memcpy((uint8 *)current->buffer_log + bufferOffset,
1509 				(uint8 *)vector[vectorIndex].iov_base + vectorOffset, length);
1510 
1511 			actualLength += length;
1512 			vectorOffset += length;
1513 			bufferOffset += length;
1514 
1515 			if (vectorOffset >= vector[vectorIndex].iov_len) {
1516 				if (++vectorIndex >= vectorCount) {
1517 					TRACE(("usb_ehci: wrote descriptor chain (%ld bytes, no more vectors)\n", actualLength));
1518 					return actualLength;
1519 				}
1520 
1521 				vectorOffset = 0;
1522 			}
1523 
1524 			if (bufferOffset >= current->buffer_size) {
1525 				bufferOffset = 0;
1526 				break;
1527 			}
1528 		}
1529 
1530 		if (current->next_phy & EHCI_QTD_TERMINATE)
1531 			break;
1532 
1533 		current = (ehci_qtd *)current->next_log;
1534 	}
1535 
1536 	TRACE(("usb_ehci: wrote descriptor chain (%ld bytes)\n", actualLength));
1537 	return actualLength;
1538 }
1539 
1540 
1541 size_t
1542 EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
1543 	size_t vectorCount, bool *nextDataToggle)
1544 {
1545 	uint32 dataToggle = 0;
1546 	ehci_qtd *current = topDescriptor;
1547 	size_t actualLength = 0;
1548 	size_t vectorIndex = 0;
1549 	size_t vectorOffset = 0;
1550 	size_t bufferOffset = 0;
1551 
1552 	while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) {
1553 		if (!current->buffer_log)
1554 			break;
1555 
1556 		dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
1557 		size_t bufferSize = current->buffer_size;
1558 		bufferSize -= (current->token >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK;
1559 
1560 		while (true) {
1561 			size_t length = min_c(bufferSize - bufferOffset,
1562 				vector[vectorIndex].iov_len - vectorOffset);
1563 
1564 			memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
1565 				(uint8 *)current->buffer_log + bufferOffset, length);
1566 
1567 			actualLength += length;
1568 			vectorOffset += length;
1569 			bufferOffset += length;
1570 
1571 			if (vectorOffset >= vector[vectorIndex].iov_len) {
1572 				if (++vectorIndex >= vectorCount) {
1573 					TRACE(("usb_ehci: read descriptor chain (%ld bytes, no more vectors)\n", actualLength));
1574 					*nextDataToggle = dataToggle > 0 ? true : false;
1575 					return actualLength;
1576 				}
1577 
1578 				vectorOffset = 0;
1579 			}
1580 
1581 			if (bufferOffset >= bufferSize) {
1582 				bufferOffset = 0;
1583 				break;
1584 			}
1585 		}
1586 
1587 		if (current->next_phy & EHCI_QTD_TERMINATE)
1588 			break;
1589 
1590 		current = (ehci_qtd *)current->next_log;
1591 	}
1592 
1593 	TRACE(("usb_ehci: read descriptor chain (%ld bytes)\n", actualLength));
1594 	*nextDataToggle = dataToggle > 0 ? true : false;
1595 	return actualLength;
1596 }
1597 
1598 
1599 size_t
1600 EHCI::ReadActualLength(ehci_qtd *topDescriptor, bool *nextDataToggle)
1601 {
1602 	size_t actualLength = 0;
1603 	ehci_qtd *current = topDescriptor;
1604 	uint32 dataToggle = 0;
1605 
1606 	while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) {
1607 		dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
1608 		size_t length = current->buffer_size;
1609 		length -= (current->token >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK;
1610 		actualLength += length;
1611 
1612 		if (current->next_phy & EHCI_QTD_TERMINATE)
1613 			break;
1614 
1615 		current = (ehci_qtd *)current->next_log;
1616 	}
1617 
1618 	TRACE(("usb_ehci: read actual length (%ld bytes)\n", actualLength));
1619 	*nextDataToggle = dataToggle > 0 ? true : false;
1620 	return actualLength;
1621 }
1622 
1623 
1624 inline void
1625 EHCI::WriteOpReg(uint32 reg, uint32 value)
1626 {
1627 	*(volatile uint32 *)(fOperationalRegisters + reg) = value;
1628 }
1629 
1630 
1631 inline uint32
1632 EHCI::ReadOpReg(uint32 reg)
1633 {
1634 	return *(volatile uint32 *)(fOperationalRegisters + reg);
1635 }
1636 
1637 
1638 inline uint8
1639 EHCI::ReadCapReg8(uint32 reg)
1640 {
1641 	return *(volatile uint8 *)(fCapabilityRegisters + reg);
1642 }
1643 
1644 
1645 inline uint16
1646 EHCI::ReadCapReg16(uint32 reg)
1647 {
1648 	return *(volatile uint16 *)(fCapabilityRegisters + reg);
1649 }
1650 
1651 
1652 inline uint32
1653 EHCI::ReadCapReg32(uint32 reg)
1654 {
1655 	return *(volatile uint32 *)(fCapabilityRegisters + reg);
1656 }
1657