xref: /haiku/src/add-ons/kernel/busses/usb/ehci.cpp (revision 6dcd0ccf238263a3e5eb2e2a44e2ed0da1617a42)
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 	static 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 	status_t result = transfer->InitKernelAccess();
839 	if (result < B_OK)
840 		return result;
841 
842 	data->transfer = transfer;
843 	data->queue_head = queueHead;
844 	data->data_descriptor = dataDescriptor;
845 	data->user_area = -1;
846 	data->incoming = directionIn;
847 	data->link = NULL;
848 
849 	if (!Lock()) {
850 		delete data;
851 		return B_ERROR;
852 	}
853 
854 	if (fLastTransfer)
855 		fLastTransfer->link = data;
856 	else
857 		fFirstTransfer = data;
858 
859 	fLastTransfer = data;
860 	Unlock();
861 
862 	return B_OK;
863 }
864 
865 
866 status_t
867 EHCI::CancelQueuedTransfers(Pipe *pipe)
868 {
869 	if (!Lock())
870 		return B_ERROR;
871 
872 	transfer_data *last = NULL;
873 	transfer_data *current = fFirstTransfer;
874 	while (current) {
875 		if (current->transfer->TransferPipe() == pipe) {
876 			UnlinkQueueHead(current->queue_head, &fFreeListHead);
877 			current->transfer->Finished(B_CANCELED, 0);
878 			delete current->transfer;
879 
880 			transfer_data *next = current->link;
881 			if (last)
882 				last->link = next;
883 			else
884 				fFirstTransfer = next;
885 
886 			if (fLastTransfer == current)
887 				fLastTransfer = last;
888 
889 			delete current;
890 			current = next;
891 		} else {
892 			last = current;
893 			current = current->link;
894 		}
895 	}
896 
897 	Unlock();
898 	return B_OK;
899 }
900 
901 
902 status_t
903 EHCI::CancelAllPendingTransfers()
904 {
905 	if (!Lock())
906 		return B_ERROR;
907 
908 	transfer_data *transfer = fFirstTransfer;
909 	while (transfer) {
910 		transfer->transfer->Finished(B_CANCELED, 0);
911 		delete transfer->transfer;
912 
913 		transfer_data *next = transfer->link;
914 		delete transfer;
915 		transfer = next;
916 	}
917 
918 	fFirstTransfer = NULL;
919 	fLastTransfer = NULL;
920 	Unlock();
921 	return B_OK;
922 }
923 
924 
925 int32
926 EHCI::FinishThread(void *data)
927 {
928 	((EHCI *)data)->FinishTransfers();
929 	return B_OK;
930 }
931 
932 
933 void
934 EHCI::FinishTransfers()
935 {
936 	while (!fStopThreads) {
937 		if (acquire_sem(fFinishTransfersSem) < B_OK)
938 			continue;
939 
940 		// eat up sems that have been released by multiple interrupts
941 		int32 semCount = 0;
942 		get_sem_count(fFinishTransfersSem, &semCount);
943 		if (semCount > 0)
944 			acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
945 
946 		if (!Lock())
947 			continue;
948 
949 		TRACE(("usb_ehci: finishing transfers\n"));
950 		transfer_data *lastTransfer = NULL;
951 		transfer_data *transfer = fFirstTransfer;
952 		Unlock();
953 
954 		while (transfer) {
955 			bool transferDone = false;
956 			ehci_qtd *descriptor = (ehci_qtd *)transfer->queue_head->element_log;
957 
958 #ifdef TRACE_USB
959 			print_queue(transfer->queue_head);
960 #endif
961 
962 			while (descriptor) {
963 				uint32 status = descriptor->token;
964 				if (status & EHCI_QTD_STATUS_ACTIVE) {
965 					// still in progress
966 					TRACE(("usb_ehci: qtd (0x%08lx) still active\n", descriptor->this_phy));
967 					break;
968 				}
969 
970 				if (status & EHCI_QTD_STATUS_ERRMASK) {
971 					// a transfer error occured
972 					TRACE_ERROR(("usb_ehci: qtd (0x%08lx) error: 0x%08lx\n", descriptor->this_phy, status));
973 
974 					status_t callbackStatus = B_ERROR;
975 					uint8 errorCount = status >> EHCI_QTD_ERRCOUNT_SHIFT;
976 					errorCount &= EHCI_QTD_ERRCOUNT_MASK;
977 					if (errorCount == 0) {
978 						// the error counter counted down to zero, report why
979 						int32 reasons = 0;
980 						if (status & EHCI_QTD_STATUS_BUFFER) {
981 							callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN;
982 							reasons++;
983 						}
984 						if (status & EHCI_QTD_STATUS_TERROR) {
985 							callbackStatus = B_DEV_CRC_ERROR;
986 							reasons++;
987 						}
988 
989 						if (reasons > 1)
990 							callbackStatus = B_DEV_MULTIPLE_ERRORS;
991 					} else if (status & EHCI_QTD_STATUS_BABBLE) {
992 						// there is a babble condition
993 						callbackStatus = transfer->incoming ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN;
994 					} else {
995 						// if the error counter didn't count down to zero
996 						// and there was no babble, then this halt was caused
997 						// by a stall handshake
998 						callbackStatus = B_DEV_STALLED;
999 					}
1000 
1001 					UnlinkQueueHead(transfer->queue_head, &fFreeListHead);
1002 					transfer->transfer->Finished(callbackStatus, 0);
1003 					transferDone = true;
1004 					break;
1005 				}
1006 
1007 				if (descriptor->next_phy & EHCI_QTD_TERMINATE) {
1008 					// we arrived at the last (stray) descriptor, we're done
1009 					TRACE(("usb_ehci: qtd (0x%08lx) done\n", descriptor->this_phy));
1010 
1011 					size_t actualLength = 0;
1012 					bool nextDataToggle = false;
1013 					if (transfer->data_descriptor && transfer->incoming) {
1014 						// data to read out
1015 						iovec *vector = transfer->transfer->Vector();
1016 						size_t vectorCount = transfer->transfer->VectorCount();
1017 						transfer->transfer->PrepareKernelAccess();
1018 						actualLength = ReadDescriptorChain(
1019 							transfer->data_descriptor,
1020 							vector, vectorCount,
1021 							&nextDataToggle);
1022 					} else {
1023 						// calculate transfered length
1024 						actualLength = ReadActualLength(
1025 							(ehci_qtd *)transfer->queue_head->element_log,
1026 							&nextDataToggle);
1027 					}
1028 
1029 					transfer->transfer->TransferPipe()->SetDataToggle(nextDataToggle);
1030 					if (transfer->transfer->IsFragmented()) {
1031 						// this transfer may still have data left
1032 						transfer->transfer->AdvanceByFragment(actualLength);
1033 						if (transfer->transfer->VectorLength() > 0) {
1034 							FreeDescriptorChain(transfer->data_descriptor);
1035 							transfer->transfer->PrepareKernelAccess();
1036 							FillQueueWithData(transfer->transfer,
1037 								transfer->queue_head,
1038 								&transfer->data_descriptor, NULL);
1039 							break;
1040 						}
1041 
1042 						// the transfer is done, but we already set the
1043 						// actualLength with AdvanceByFragment()
1044 						actualLength = 0;
1045 					}
1046 
1047 					UnlinkQueueHead(transfer->queue_head, &fFreeListHead);
1048 					transfer->transfer->Finished(B_OK, actualLength);
1049 					transferDone = true;
1050 					break;
1051 				}
1052 
1053 				descriptor = (ehci_qtd *)descriptor->next_log;
1054 			}
1055 
1056 			if (transferDone) {
1057 				if (Lock()) {
1058 					if (lastTransfer)
1059 						lastTransfer->link = transfer->link;
1060 
1061 					if (transfer == fFirstTransfer)
1062 						fFirstTransfer = transfer->link;
1063 					if (transfer == fLastTransfer)
1064 						fLastTransfer = lastTransfer;
1065 
1066 					transfer_data *next = transfer->link;
1067 					delete transfer->transfer;
1068 					delete transfer;
1069 					transfer = next;
1070 					Unlock();
1071 				}
1072 			} else {
1073 				if (Lock()) {
1074 					lastTransfer = transfer;
1075 					transfer = transfer->link;
1076 					Unlock();
1077 				}
1078 			}
1079 
1080 			release_sem(fCleanupSem);
1081 		}
1082 	}
1083 }
1084 
1085 
1086 int32
1087 EHCI::CleanupThread(void *data)
1088 {
1089 	((EHCI *)data)->Cleanup();
1090 	return B_OK;
1091 }
1092 
1093 
1094 void
1095 EHCI::Cleanup()
1096 {
1097 	ehci_qh *lastFreeListHead = NULL;
1098 
1099 	while (!fStopThreads) {
1100 		if (acquire_sem(fCleanupSem) < B_OK)
1101 			continue;
1102 
1103 		ehci_qh *freeListHead = fFreeListHead;
1104 		if (freeListHead == lastFreeListHead)
1105 			continue;
1106 
1107 		// set the doorbell and wait for the host controller to notify us
1108 		WriteOpReg(EHCI_USBCMD, ReadOpReg(EHCI_USBCMD) | EHCI_USBCMD_INTONAAD);
1109 		if (acquire_sem(fAsyncAdvanceSem) < B_OK)
1110 			continue;
1111 
1112 		ehci_qh *current = freeListHead;
1113 		while (current != lastFreeListHead) {
1114 			ehci_qh *next = (ehci_qh *)current->next_log;
1115 			FreeQueueHead(current);
1116 			current = next;
1117 		}
1118 
1119 		lastFreeListHead = freeListHead;
1120 	}
1121 }
1122 
1123 
1124 ehci_qh *
1125 EHCI::CreateQueueHead()
1126 {
1127 	ehci_qh *result;
1128 	void *physicalAddress;
1129 	if (fStack->AllocateChunk((void **)&result, &physicalAddress,
1130 		sizeof(ehci_qh)) < B_OK) {
1131 		TRACE_ERROR(("usb_ehci: failed to allocate queue head\n"));
1132 		return NULL;
1133 	}
1134 
1135 	result->this_phy = (addr_t)physicalAddress;
1136 	result->next_phy = EHCI_QH_TERMINATE;
1137 	result->next_log = NULL;
1138 	result->prev_log = NULL;
1139 
1140 	ehci_qtd *descriptor = CreateDescriptor(0, 0);
1141 	if (!descriptor) {
1142 		TRACE_ERROR(("usb_ehci: failed to allocate initial qtd for queue head\n"));
1143 		fStack->FreeChunk(result, (void *)result->this_phy, sizeof(ehci_qh));
1144 		return NULL;
1145 	}
1146 
1147 	descriptor->token &= ~EHCI_QTD_STATUS_ACTIVE;
1148 	result->stray_log = descriptor;
1149 	result->element_log = descriptor;
1150 	result->current_qtd_phy = EHCI_QTD_TERMINATE;
1151 	result->overlay.next_phy = descriptor->this_phy;
1152 	result->overlay.alt_next_phy = EHCI_QTD_TERMINATE;
1153 	result->overlay.token = 0;
1154 	for (int32 i = 0; i < 5; i++) {
1155 		result->overlay.buffer_phy[i] = 0;
1156 		result->overlay.ext_buffer_phy[i] = 0;
1157 	}
1158 
1159 	return result;
1160 }
1161 
1162 
1163 void
1164 EHCI::FreeQueueHead(ehci_qh *queueHead)
1165 {
1166 	if (!queueHead)
1167 		return;
1168 
1169 	FreeDescriptorChain((ehci_qtd *)queueHead->element_log);
1170 	FreeDescriptor((ehci_qtd *)queueHead->stray_log);
1171 	fStack->FreeChunk(queueHead, (void *)queueHead->this_phy, sizeof(ehci_qh));
1172 }
1173 
1174 
1175 status_t
1176 EHCI::LinkQueueHead(ehci_qh *queueHead)
1177 {
1178 	if (!Lock())
1179 		return B_ERROR;
1180 
1181 	ehci_qh *prevHead = (ehci_qh *)fAsyncQueueHead->prev_log;
1182 	queueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH;
1183 	queueHead->next_log = fAsyncQueueHead;
1184 	queueHead->prev_log = prevHead;
1185 	fAsyncQueueHead->prev_log = queueHead;
1186 	prevHead->next_log = queueHead;
1187 	prevHead->next_phy = queueHead->this_phy | EHCI_QH_TYPE_QH;
1188 
1189 	Unlock();
1190 	return B_OK;
1191 }
1192 
1193 
1194 status_t
1195 EHCI::UnlinkQueueHead(ehci_qh *queueHead, ehci_qh **freeListHead)
1196 {
1197 	if (!Lock())
1198 		return B_ERROR;
1199 
1200 	ehci_qh *prevHead = (ehci_qh *)queueHead->prev_log;
1201 	ehci_qh *nextHead = (ehci_qh *)queueHead->next_log;
1202 	prevHead->next_phy = queueHead->next_phy | EHCI_QH_TYPE_QH;
1203 	prevHead->next_log = queueHead->next_log;
1204 	nextHead->prev_log = queueHead->prev_log;
1205 	queueHead->next_phy = fAsyncQueueHead->this_phy | EHCI_QH_TYPE_QH;
1206 	queueHead->next_log = NULL;
1207 	queueHead->prev_log = NULL;
1208 
1209 	queueHead->next_log = *freeListHead;
1210 	*freeListHead = queueHead;
1211 
1212 	Unlock();
1213 	return B_OK;
1214 }
1215 
1216 
1217 status_t
1218 EHCI::FillQueueWithRequest(Transfer *transfer, ehci_qh *queueHead,
1219 	ehci_qtd **_dataDescriptor, bool *_directionIn)
1220 {
1221 	Pipe *pipe = transfer->TransferPipe();
1222 	usb_request_data *requestData = transfer->RequestData();
1223 	bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
1224 
1225 	ehci_qtd *setupDescriptor = CreateDescriptor(sizeof(usb_request_data),
1226 		EHCI_QTD_PID_SETUP);
1227 	ehci_qtd *statusDescriptor = CreateDescriptor(0,
1228 		directionIn ? EHCI_QTD_PID_OUT : EHCI_QTD_PID_IN);
1229 
1230 	if (!setupDescriptor || !statusDescriptor) {
1231 		TRACE_ERROR(("usb_ehci: failed to allocate descriptors\n"));
1232 		FreeDescriptor(setupDescriptor);
1233 		FreeDescriptor(statusDescriptor);
1234 		return B_NO_MEMORY;
1235 	}
1236 
1237 	iovec vector;
1238 	vector.iov_base = requestData;
1239 	vector.iov_len = sizeof(usb_request_data);
1240 	WriteDescriptorChain(setupDescriptor, &vector, 1);
1241 
1242 	ehci_qtd *strayDescriptor = (ehci_qtd *)queueHead->stray_log;
1243 	statusDescriptor->token |= EHCI_QTD_IOC | EHCI_QTD_DATA_TOGGLE;
1244 
1245 	ehci_qtd *dataDescriptor = NULL;
1246 	if (transfer->VectorCount() > 0) {
1247 		ehci_qtd *lastDescriptor = NULL;
1248 		status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
1249 			&lastDescriptor, strayDescriptor, transfer->VectorLength(),
1250 			directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
1251 
1252 		if (result < B_OK) {
1253 			FreeDescriptor(setupDescriptor);
1254 			FreeDescriptor(statusDescriptor);
1255 			return result;
1256 		}
1257 
1258 		if (!directionIn) {
1259 			WriteDescriptorChain(dataDescriptor, transfer->Vector(),
1260 				transfer->VectorCount());
1261 		}
1262 
1263 		LinkDescriptors(setupDescriptor, dataDescriptor, strayDescriptor);
1264 		LinkDescriptors(lastDescriptor, statusDescriptor, strayDescriptor);
1265 	} else {
1266 		// no data: link setup and status descriptors directly
1267 		LinkDescriptors(setupDescriptor, statusDescriptor, strayDescriptor);
1268 	}
1269 
1270 	queueHead->element_log = setupDescriptor;
1271 	queueHead->overlay.next_phy = setupDescriptor->this_phy;
1272 	queueHead->overlay.alt_next_phy = EHCI_QTD_TERMINATE;
1273 
1274 	*_dataDescriptor = dataDescriptor;
1275 	*_directionIn = directionIn;
1276 	return B_OK;
1277 }
1278 
1279 
1280 status_t
1281 EHCI::FillQueueWithData(Transfer *transfer, ehci_qh *queueHead,
1282 	ehci_qtd **_dataDescriptor, bool *_directionIn)
1283 {
1284 	Pipe *pipe = transfer->TransferPipe();
1285 	bool directionIn = (pipe->Direction() == Pipe::In);
1286 
1287 	ehci_qtd *firstDescriptor = NULL;
1288 	ehci_qtd *lastDescriptor = NULL;
1289 	ehci_qtd *strayDescriptor = (ehci_qtd *)queueHead->stray_log;
1290 	status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
1291 		&lastDescriptor, strayDescriptor, transfer->VectorLength(),
1292 		directionIn ? EHCI_QTD_PID_IN : EHCI_QTD_PID_OUT);
1293 
1294 	if (result < B_OK)
1295 		return result;
1296 
1297 	lastDescriptor->token |= EHCI_QTD_IOC;
1298 	if (!directionIn) {
1299 		WriteDescriptorChain(firstDescriptor, transfer->Vector(),
1300 			transfer->VectorCount());
1301 	}
1302 
1303 	queueHead->element_log = firstDescriptor;
1304 	queueHead->overlay.next_phy = firstDescriptor->this_phy;
1305 	queueHead->overlay.alt_next_phy = EHCI_QTD_TERMINATE;
1306 
1307 	*_dataDescriptor = firstDescriptor;
1308 	if (_directionIn)
1309 		*_directionIn = directionIn;
1310 	return B_OK;
1311 }
1312 
1313 
1314 ehci_qtd *
1315 EHCI::CreateDescriptor(size_t bufferSize, uint8 pid)
1316 {
1317 	ehci_qtd *result;
1318 	void *physicalAddress;
1319 	if (fStack->AllocateChunk((void **)&result, &physicalAddress,
1320 		sizeof(ehci_qtd)) < B_OK) {
1321 		TRACE_ERROR(("usb_ehci: failed to allocate a qtd\n"));
1322 		return NULL;
1323 	}
1324 
1325 	result->this_phy = (addr_t)physicalAddress;
1326 	result->next_phy = EHCI_QTD_TERMINATE;
1327 	result->next_log = NULL;
1328 	result->alt_next_phy = EHCI_QTD_TERMINATE;
1329 	result->alt_next_log = NULL;
1330 	result->buffer_size = bufferSize;
1331 	result->token = bufferSize << EHCI_QTD_BYTES_SHIFT;
1332 	result->token |= 3 << EHCI_QTD_ERRCOUNT_SHIFT;
1333 	result->token |= pid << EHCI_QTD_PID_SHIFT;
1334 	result->token |= EHCI_QTD_STATUS_ACTIVE;
1335 	if (bufferSize == 0) {
1336 		result->buffer_log = NULL;
1337 		for (int32 i = 0; i < 5; i++) {
1338 			result->buffer_phy[i] = 0;
1339 			result->ext_buffer_phy[i] = 0;
1340 		}
1341 
1342 		return result;
1343 	}
1344 
1345 	if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress,
1346 		bufferSize) < B_OK) {
1347 		TRACE_ERROR(("usb_ehci: unable to allocate qtd buffer\n"));
1348 		fStack->FreeChunk(result, (void *)result->this_phy, sizeof(ehci_qtd));
1349 		return NULL;
1350 	}
1351 
1352 	addr_t physicalBase = (addr_t)physicalAddress;
1353 	result->buffer_phy[0] = physicalBase;
1354 	result->ext_buffer_phy[0] = 0;
1355 	for (int32 i = 1; i < 5; i++) {
1356 		physicalBase += B_PAGE_SIZE;
1357 		result->buffer_phy[i] = physicalBase & EHCI_QTD_PAGE_MASK;
1358 		result->ext_buffer_phy[i] = 0;
1359 	}
1360 
1361 	return result;
1362 }
1363 
1364 
1365 status_t
1366 EHCI::CreateDescriptorChain(Pipe *pipe, ehci_qtd **_firstDescriptor,
1367 	ehci_qtd **_lastDescriptor, ehci_qtd *strayDescriptor, size_t bufferSize,
1368 	uint8 pid)
1369 {
1370 	size_t packetSize = B_PAGE_SIZE * 4;
1371 	int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
1372 
1373 	bool dataToggle = pipe->DataToggle();
1374 	ehci_qtd *firstDescriptor = NULL;
1375 	ehci_qtd *lastDescriptor = *_firstDescriptor;
1376 	for (int32 i = 0; i < descriptorCount; i++) {
1377 		ehci_qtd *descriptor = CreateDescriptor(min_c(packetSize, bufferSize),
1378 			pid);
1379 
1380 		if (!descriptor) {
1381 			FreeDescriptorChain(firstDescriptor);
1382 			return B_NO_MEMORY;
1383 		}
1384 
1385 		if (dataToggle)
1386 			descriptor->token |= EHCI_QTD_DATA_TOGGLE;
1387 
1388 		if (lastDescriptor)
1389 			LinkDescriptors(lastDescriptor, descriptor, strayDescriptor);
1390 
1391 		bufferSize -= packetSize;
1392 		lastDescriptor = descriptor;
1393 		if (!firstDescriptor)
1394 			firstDescriptor = descriptor;
1395 	}
1396 
1397 	*_firstDescriptor = firstDescriptor;
1398 	*_lastDescriptor = lastDescriptor;
1399 	return B_OK;
1400 }
1401 
1402 
1403 void
1404 EHCI::FreeDescriptor(ehci_qtd *descriptor)
1405 {
1406 	if (!descriptor)
1407 		return;
1408 
1409 	if (descriptor->buffer_log) {
1410 		fStack->FreeChunk(descriptor->buffer_log,
1411 			(void *)descriptor->buffer_phy[0], descriptor->buffer_size);
1412 	}
1413 
1414 	fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(ehci_qtd));
1415 }
1416 
1417 
1418 void
1419 EHCI::FreeDescriptorChain(ehci_qtd *topDescriptor)
1420 {
1421 	ehci_qtd *current = topDescriptor;
1422 	ehci_qtd *next = NULL;
1423 
1424 	while (current) {
1425 		next = (ehci_qtd *)current->next_log;
1426 		FreeDescriptor(current);
1427 		current = next;
1428 	}
1429 }
1430 
1431 
1432 void
1433 EHCI::LinkDescriptors(ehci_qtd *first, ehci_qtd *last, ehci_qtd *alt)
1434 {
1435 	first->next_phy = last->this_phy;
1436 	first->next_log = last;
1437 
1438 	if (alt) {
1439 		first->alt_next_phy = alt->this_phy;
1440 		first->alt_next_log = alt;
1441 	} else {
1442 		first->alt_next_phy = EHCI_QTD_TERMINATE;
1443 		first->alt_next_log = NULL;
1444 	}
1445 }
1446 
1447 
1448 size_t
1449 EHCI::WriteDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
1450 	size_t vectorCount)
1451 {
1452 	ehci_qtd *current = topDescriptor;
1453 	size_t actualLength = 0;
1454 	size_t vectorIndex = 0;
1455 	size_t vectorOffset = 0;
1456 	size_t bufferOffset = 0;
1457 
1458 	while (current) {
1459 		if (!current->buffer_log)
1460 			break;
1461 
1462 		while (true) {
1463 			size_t length = min_c(current->buffer_size - bufferOffset,
1464 				vector[vectorIndex].iov_len - vectorOffset);
1465 
1466 			memcpy((uint8 *)current->buffer_log + bufferOffset,
1467 				(uint8 *)vector[vectorIndex].iov_base + vectorOffset, length);
1468 
1469 			actualLength += length;
1470 			vectorOffset += length;
1471 			bufferOffset += length;
1472 
1473 			if (vectorOffset >= vector[vectorIndex].iov_len) {
1474 				if (++vectorIndex >= vectorCount) {
1475 					TRACE(("usb_ehci: wrote descriptor chain (%ld bytes, no more vectors)\n", actualLength));
1476 					return actualLength;
1477 				}
1478 
1479 				vectorOffset = 0;
1480 			}
1481 
1482 			if (bufferOffset >= current->buffer_size) {
1483 				bufferOffset = 0;
1484 				break;
1485 			}
1486 		}
1487 
1488 		if (current->next_phy & EHCI_QTD_TERMINATE)
1489 			break;
1490 
1491 		current = (ehci_qtd *)current->next_log;
1492 	}
1493 
1494 	TRACE(("usb_ehci: wrote descriptor chain (%ld bytes)\n", actualLength));
1495 	return actualLength;
1496 }
1497 
1498 
1499 size_t
1500 EHCI::ReadDescriptorChain(ehci_qtd *topDescriptor, iovec *vector,
1501 	size_t vectorCount, bool *nextDataToggle)
1502 {
1503 	uint32 dataToggle = 0;
1504 	ehci_qtd *current = topDescriptor;
1505 	size_t actualLength = 0;
1506 	size_t vectorIndex = 0;
1507 	size_t vectorOffset = 0;
1508 	size_t bufferOffset = 0;
1509 
1510 	while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) {
1511 		if (!current->buffer_log)
1512 			break;
1513 
1514 		dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
1515 		size_t bufferSize = current->buffer_size;
1516 		bufferSize -= (current->token >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK;
1517 
1518 		while (true) {
1519 			size_t length = min_c(bufferSize - bufferOffset,
1520 				vector[vectorIndex].iov_len - vectorOffset);
1521 
1522 			memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
1523 				(uint8 *)current->buffer_log + bufferOffset, length);
1524 
1525 			actualLength += length;
1526 			vectorOffset += length;
1527 			bufferOffset += length;
1528 
1529 			if (vectorOffset >= vector[vectorIndex].iov_len) {
1530 				if (++vectorIndex >= vectorCount) {
1531 					TRACE(("usb_ehci: read descriptor chain (%ld bytes, no more vectors)\n", actualLength));
1532 					*nextDataToggle = dataToggle > 0 ? true : false;
1533 					return actualLength;
1534 				}
1535 
1536 				vectorOffset = 0;
1537 			}
1538 
1539 			if (bufferOffset >= bufferSize) {
1540 				bufferOffset = 0;
1541 				break;
1542 			}
1543 		}
1544 
1545 		if (current->next_phy & EHCI_QTD_TERMINATE)
1546 			break;
1547 
1548 		current = (ehci_qtd *)current->next_log;
1549 	}
1550 
1551 	TRACE(("usb_ehci: read descriptor chain (%ld bytes)\n", actualLength));
1552 	*nextDataToggle = dataToggle > 0 ? true : false;
1553 	return actualLength;
1554 }
1555 
1556 
1557 size_t
1558 EHCI::ReadActualLength(ehci_qtd *topDescriptor, bool *nextDataToggle)
1559 {
1560 	size_t actualLength = 0;
1561 	ehci_qtd *current = topDescriptor;
1562 	uint32 dataToggle = 0;
1563 
1564 	while (current && (current->token & EHCI_QTD_STATUS_ACTIVE) == 0) {
1565 		dataToggle = current->token & EHCI_QTD_DATA_TOGGLE;
1566 		size_t length = current->buffer_size;
1567 		length -= (current->token >> EHCI_QTD_BYTES_SHIFT) & EHCI_QTD_BYTES_MASK;
1568 		actualLength += length;
1569 
1570 		if (current->next_phy & EHCI_QTD_TERMINATE)
1571 			break;
1572 
1573 		current = (ehci_qtd *)current->next_log;
1574 	}
1575 
1576 	TRACE(("usb_ehci: read actual length (%ld bytes)\n", actualLength));
1577 	*nextDataToggle = dataToggle > 0 ? true : false;
1578 	return actualLength;
1579 }
1580 
1581 
1582 inline void
1583 EHCI::WriteOpReg(uint32 reg, uint32 value)
1584 {
1585 	*(volatile uint32 *)(fOperationalRegisters + reg) = value;
1586 }
1587 
1588 
1589 inline uint32
1590 EHCI::ReadOpReg(uint32 reg)
1591 {
1592 	return *(volatile uint32 *)(fOperationalRegisters + reg);
1593 }
1594 
1595 
1596 inline uint8
1597 EHCI::ReadCapReg8(uint32 reg)
1598 {
1599 	return *(volatile uint8 *)(fCapabilityRegisters + reg);
1600 }
1601 
1602 
1603 inline uint16
1604 EHCI::ReadCapReg16(uint32 reg)
1605 {
1606 	return *(volatile uint16 *)(fCapabilityRegisters + reg);
1607 }
1608 
1609 
1610 inline uint32
1611 EHCI::ReadCapReg32(uint32 reg)
1612 {
1613 	return *(volatile uint32 *)(fCapabilityRegisters + reg);
1614 }
1615