xref: /haiku/src/add-ons/kernel/busses/usb/uhci.cpp (revision 67b05100d24245964653dbd7e1efb518b1aee274)
1 /*
2  * Copyright 2004-2011, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  *		Niels S. Reedijk
8  *		Salvatore Benedetto <salvatore.benedetto@gmail.com>
9  */
10 
11 #include <module.h>
12 #include <PCI.h>
13 #include <PCI_x86.h>
14 #include <USB3.h>
15 #include <KernelExport.h>
16 
17 #include "uhci.h"
18 
19 #define USB_MODULE_NAME "uhci"
20 
21 pci_module_info *UHCI::sPCIModule = NULL;
22 pci_x86_module_info *UHCI::sPCIx86Module = NULL;
23 
24 
25 static int32
26 uhci_std_ops(int32 op, ...)
27 {
28 	switch (op) {
29 		case B_MODULE_INIT:
30 			TRACE_MODULE("init module\n");
31 			return B_OK;
32 		case B_MODULE_UNINIT:
33 			TRACE_MODULE("uninit module\n");
34 			break;
35 		default:
36 			return EINVAL;
37 	}
38 
39 	return B_OK;
40 }
41 
42 
43 usb_host_controller_info uhci_module = {
44 	{
45 		"busses/usb/uhci",
46 		0,
47 		uhci_std_ops
48 	},
49 	NULL,
50 	UHCI::AddTo
51 };
52 
53 
54 module_info *modules[] = {
55 	(module_info *)&uhci_module,
56 	NULL
57 };
58 
59 
60 //
61 // #pragma mark -
62 //
63 
64 
65 #ifdef TRACE_USB
66 
67 void
68 print_descriptor_chain(uhci_td *descriptor)
69 {
70 	while (descriptor) {
71 		dprintf("ph: 0x%08" B_PRIx32 "; lp: 0x%08" B_PRIx32 "; vf: %s; q: %s; "
72 			"t: %s; st: 0x%08" B_PRIx32 "; to: 0x%08" B_PRIx32 "\n",
73 			descriptor->this_phy & 0xffffffff, descriptor->link_phy & 0xfffffff0,
74 			descriptor->link_phy & 0x4 ? "y" : "n",
75 			descriptor->link_phy & 0x2 ? "qh" : "td",
76 			descriptor->link_phy & 0x1 ? "y" : "n",
77 			descriptor->status, descriptor->token);
78 
79 		if (descriptor->link_phy & TD_TERMINATE)
80 			break;
81 
82 		descriptor = (uhci_td *)descriptor->link_log;
83 	}
84 }
85 
86 #endif // TRACE_USB
87 
88 
89 //
90 // #pragma mark -
91 //
92 
93 
94 Queue::Queue(Stack *stack)
95 {
96 	fStack = stack;
97 
98 	mutex_init(&fLock, "uhci queue lock");
99 
100 	phys_addr_t physicalAddress;
101 	fStatus = fStack->AllocateChunk((void **)&fQueueHead, &physicalAddress,
102 		sizeof(uhci_qh));
103 	if (fStatus < B_OK)
104 		return;
105 
106 	fQueueHead->this_phy = (uint32)physicalAddress;
107 	fQueueHead->element_phy = QH_TERMINATE;
108 
109 	fStrayDescriptor = NULL;
110 	fQueueTop = NULL;
111 }
112 
113 
114 Queue::~Queue()
115 {
116 	Lock();
117 	mutex_destroy(&fLock);
118 
119 	fStack->FreeChunk(fQueueHead, fQueueHead->this_phy, sizeof(uhci_qh));
120 
121 	if (fStrayDescriptor)
122 		fStack->FreeChunk(fStrayDescriptor, fStrayDescriptor->this_phy,
123 			sizeof(uhci_td));
124 }
125 
126 
127 status_t
128 Queue::InitCheck()
129 {
130 	return fStatus;
131 }
132 
133 
134 bool
135 Queue::Lock()
136 {
137 	return (mutex_lock(&fLock) == B_OK);
138 }
139 
140 
141 void
142 Queue::Unlock()
143 {
144 	mutex_unlock(&fLock);
145 }
146 
147 
148 status_t
149 Queue::LinkTo(Queue *other)
150 {
151 	if (!other)
152 		return B_BAD_VALUE;
153 
154 	if (!Lock())
155 		return B_ERROR;
156 
157 	fQueueHead->link_phy = other->fQueueHead->this_phy | QH_NEXT_IS_QH;
158 	fQueueHead->link_log = other->fQueueHead;
159 	Unlock();
160 
161 	return B_OK;
162 }
163 
164 
165 status_t
166 Queue::TerminateByStrayDescriptor()
167 {
168 	// According to the *BSD USB sources, there needs to be a stray transfer
169 	// descriptor in order to get some chipset to work nicely (like the PIIX).
170 	phys_addr_t physicalAddress;
171 	status_t result = fStack->AllocateChunk((void **)&fStrayDescriptor,
172 		&physicalAddress, sizeof(uhci_td));
173 	if (result < B_OK) {
174 		TRACE_ERROR("failed to allocate a stray transfer descriptor\n");
175 		return result;
176 	}
177 
178 	fStrayDescriptor->status = 0;
179 	fStrayDescriptor->this_phy = (uint32)physicalAddress;
180 	fStrayDescriptor->link_phy = TD_TERMINATE;
181 	fStrayDescriptor->link_log = NULL;
182 	fStrayDescriptor->buffer_phy = 0;
183 	fStrayDescriptor->buffer_log = NULL;
184 	fStrayDescriptor->buffer_size = 0;
185 	fStrayDescriptor->token = TD_TOKEN_NULL_DATA
186 		| (0x7f << TD_TOKEN_DEVADDR_SHIFT) | TD_TOKEN_IN;
187 
188 	if (!Lock()) {
189 		fStack->FreeChunk(fStrayDescriptor, fStrayDescriptor->this_phy,
190 			sizeof(uhci_td));
191 		return B_ERROR;
192 	}
193 
194 	fQueueHead->link_phy = fStrayDescriptor->this_phy;
195 	fQueueHead->link_log = fStrayDescriptor;
196 	Unlock();
197 
198 	return B_OK;
199 }
200 
201 
202 status_t
203 Queue::AppendTransfer(uhci_qh *transfer, bool lock)
204 {
205 	if (lock && !Lock())
206 		return B_ERROR;
207 
208 	transfer->link_log = NULL;
209 	transfer->link_phy = fQueueHead->link_phy;
210 
211 	if (!fQueueTop) {
212 		// the list is empty, make this the first element
213 		fQueueTop = transfer;
214 		fQueueHead->element_phy = transfer->this_phy | QH_NEXT_IS_QH;
215 	} else {
216 		// append the transfer queue to the list
217 		uhci_qh *element = fQueueTop;
218 		while (element && element->link_log)
219 			element = (uhci_qh *)element->link_log;
220 
221 		element->link_log = transfer;
222 		element->link_phy = transfer->this_phy | QH_NEXT_IS_QH;
223 	}
224 
225 	if (lock)
226 		Unlock();
227 	return B_OK;
228 }
229 
230 
231 status_t
232 Queue::RemoveTransfer(uhci_qh *transfer, bool lock)
233 {
234 	if (lock && !Lock())
235 		return B_ERROR;
236 
237 	if (fQueueTop == transfer) {
238 		// this was the top element
239 		fQueueTop = (uhci_qh *)transfer->link_log;
240 		if (!fQueueTop) {
241 			// this was the only element, terminate this queue
242 			fQueueHead->element_phy = QH_TERMINATE;
243 		} else {
244 			// there are elements left, adjust the element pointer
245 			fQueueHead->element_phy = transfer->link_phy;
246 		}
247 
248 		if (lock)
249 			Unlock();
250 		return B_OK;
251 	} else {
252 		uhci_qh *element = fQueueTop;
253 		while (element) {
254 			if (element->link_log == transfer) {
255 				element->link_log = transfer->link_log;
256 				element->link_phy = transfer->link_phy;
257 				if (lock)
258 					Unlock();
259 				return B_OK;
260 			}
261 
262 			element = (uhci_qh *)element->link_log;
263 		}
264 	}
265 
266 	if (lock)
267 		Unlock();
268 	return B_BAD_VALUE;
269 }
270 
271 
272 uint32
273 Queue::PhysicalAddress()
274 {
275 	return fQueueHead->this_phy;
276 }
277 
278 
279 void
280 Queue::PrintToStream()
281 {
282 #ifdef TRACE_USB
283 	TRACE("queue:\n");
284 	dprintf("link phy: 0x%08" B_PRIx32 "; link type: %s; terminate: %s\n",
285 		fQueueHead->link_phy & 0xfff0,
286 		fQueueHead->link_phy & 0x0002 ? "QH" : "TD",
287 		fQueueHead->link_phy & 0x0001 ? "yes" : "no");
288 	dprintf("elem phy: 0x%08" B_PRIx32 "; elem type: %s; terminate: %s\n",
289 		fQueueHead->element_phy & 0xfff0,
290 		fQueueHead->element_phy & 0x0002 ? "QH" : "TD",
291 		fQueueHead->element_phy & 0x0001 ? "yes" : "no");
292 #endif
293 }
294 
295 
296 //
297 // #pragma mark -
298 //
299 
300 
301 status_t
302 UHCI::AddTo(Stack *stack)
303 {
304 	if (!sPCIModule) {
305 		status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule);
306 		if (status < B_OK) {
307 			TRACE_MODULE_ERROR("AddTo(): getting pci module failed! 0x%08"
308 				B_PRIx32 "\n", status);
309 			return status;
310 		}
311 	}
312 
313 	TRACE_MODULE("AddTo(): setting up hardware\n");
314 
315 	bool found = false;
316 	pci_info *item = new(std::nothrow) pci_info;
317 	if (!item) {
318 		sPCIModule = NULL;
319 		put_module(B_PCI_MODULE_NAME);
320 		return B_NO_MEMORY;
321 	}
322 
323 	// Try to get the PCI x86 module as well so we can enable possible MSIs.
324 	if (sPCIx86Module == NULL && get_module(B_PCI_X86_MODULE_NAME,
325 			(module_info **)&sPCIx86Module) != B_OK) {
326 		// If it isn't there, that's not critical though.
327 		TRACE_MODULE_ERROR("failed to get pci x86 module\n");
328 		sPCIx86Module = NULL;
329 	}
330 
331 	for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) {
332 		if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb
333 			&& item->class_api == PCI_usb_uhci) {
334 			TRACE_MODULE("found device at PCI:%d:%d:%d\n",
335 				item->bus, item->device, item->function);
336 			UHCI *bus = new(std::nothrow) UHCI(item, stack);
337 			if (!bus) {
338 				delete item;
339 				sPCIModule = NULL;
340 				put_module(B_PCI_MODULE_NAME);
341 				return B_NO_MEMORY;
342 			}
343 
344 			if (bus->InitCheck() < B_OK) {
345 				TRACE_MODULE_ERROR("AddTo(): InitCheck() failed 0x%08" B_PRIx32
346 					"\n", bus->InitCheck());
347 				delete bus;
348 				continue;
349 			}
350 
351 			// the bus took it away
352 			item = new(std::nothrow) pci_info;
353 
354 			if (bus->Start() != B_OK) {
355 				delete bus;
356 				continue;
357 			}
358 			found = true;
359 		}
360 	}
361 
362 	if (!found) {
363 		TRACE_MODULE_ERROR("no devices found\n");
364 		delete item;
365 		sPCIModule = NULL;
366 		put_module(B_PCI_MODULE_NAME);
367 		return ENODEV;
368 	}
369 
370 	delete item;
371 	return B_OK;
372 }
373 
374 
375 UHCI::UHCI(pci_info *info, Stack *stack)
376 	:	BusManager(stack),
377 		fPCIInfo(info),
378 		fStack(stack),
379 		fEnabledInterrupts(0),
380 		fFrameArea(-1),
381 		fFrameList(NULL),
382 		fFrameBandwidth(NULL),
383 		fFirstIsochronousDescriptor(NULL),
384 		fLastIsochronousDescriptor(NULL),
385 		fQueueCount(0),
386 		fQueues(NULL),
387 		fFirstTransfer(NULL),
388 		fLastTransfer(NULL),
389 		fFinishTransfersSem(-1),
390 		fFinishThread(-1),
391 		fStopThreads(false),
392 		fProcessingPipe(NULL),
393 		fFreeList(NULL),
394 		fCleanupThread(-1),
395 		fCleanupSem(-1),
396 		fCleanupCount(0),
397 		fFirstIsochronousTransfer(NULL),
398 		fLastIsochronousTransfer(NULL),
399 		fFinishIsochronousTransfersSem(-1),
400 		fFinishIsochronousThread(-1),
401 		fRootHub(NULL),
402 		fRootHubAddress(0),
403 		fPortResetChange(0),
404 		fIRQ(0),
405 		fUseMSI(false)
406 {
407 	// Create a lock for the isochronous transfer list
408 	mutex_init(&fIsochronousLock, "UHCI isochronous lock");
409 
410 	if (!fInitOK) {
411 		TRACE_ERROR("bus manager failed to init\n");
412 		return;
413 	}
414 
415 	TRACE("constructing new UHCI host controller driver\n");
416 	fInitOK = false;
417 
418 	fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus,
419 		fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4);
420 	fRegisterBase &= PCI_address_io_mask;
421 	TRACE("iospace offset: 0x%08" B_PRIx32 "\n", fRegisterBase);
422 
423 	if (fRegisterBase == 0) {
424 		fRegisterBase = fPCIInfo->u.h0.base_registers[0];
425 		TRACE_ALWAYS("register base: 0x%08" B_PRIx32 "\n", fRegisterBase);
426 	}
427 
428 	// enable pci address access
429 	uint16 command = PCI_command_io | PCI_command_master | PCI_command_memory;
430 	command |= sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device,
431 		fPCIInfo->function, PCI_command, 2);
432 
433 	sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
434 		fPCIInfo->function, PCI_command, 2, command);
435 
436 	// disable interrupts
437 	WriteReg16(UHCI_USBINTR, 0);
438 
439 	// make sure we gain control of the UHCI controller instead of the BIOS
440 	sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
441 		fPCIInfo->function, PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN
442 		| PCI_LEGSUP_CLEAR_SMI);
443 
444 	// do a global and host reset
445 	GlobalReset();
446 	if (ControllerReset() < B_OK) {
447 		TRACE_ERROR("host failed to reset\n");
448 		return;
449 	}
450 
451 	// Setup the frame list
452 	phys_addr_t physicalAddress;
453 	fFrameArea = fStack->AllocateArea((void **)&fFrameList, &physicalAddress,
454 		4096, "USB UHCI framelist");
455 
456 	if (fFrameArea < B_OK) {
457 		TRACE_ERROR("unable to create an area for the frame pointer list\n");
458 		return;
459 	}
460 
461 	// Set base pointer and reset frame number
462 	WriteReg32(UHCI_FRBASEADD, (uint32)physicalAddress);
463 	WriteReg16(UHCI_FRNUM, 0);
464 
465 	// Set the max packet size for bandwidth reclamation to 64 bytes
466 	WriteReg16(UHCI_USBCMD, ReadReg16(UHCI_USBCMD) | UHCI_USBCMD_MAXP);
467 
468 	// we will create four queues:
469 	// 0: interrupt transfers
470 	// 1: low speed control transfers
471 	// 2: full speed control transfers
472 	// 3: bulk transfers
473 	// 4: debug queue
474 	// TODO: 4: bandwidth reclamation queue
475 	fQueueCount = 5;
476 	fQueues = new(std::nothrow) Queue *[fQueueCount];
477 	if (!fQueues) {
478 		delete_area(fFrameArea);
479 		return;
480 	}
481 
482 	for (int32 i = 0; i < fQueueCount; i++) {
483 		fQueues[i] = new(std::nothrow) Queue(fStack);
484 		if (!fQueues[i] || fQueues[i]->InitCheck() < B_OK) {
485 			TRACE_ERROR("cannot create queues\n");
486 			delete_area(fFrameArea);
487 			return;
488 		}
489 
490 		if (i > 0)
491 			fQueues[i - 1]->LinkTo(fQueues[i]);
492 	}
493 
494 	// Make sure the last queue terminates
495 	fQueues[fQueueCount - 1]->TerminateByStrayDescriptor();
496 
497 	// Create the array that will keep bandwidth information
498 	fFrameBandwidth = new(std::nothrow) uint16[NUMBER_OF_FRAMES];
499 
500 	// Create lists for managing isochronous transfer descriptors
501 	fFirstIsochronousDescriptor = new(std::nothrow) uhci_td *[NUMBER_OF_FRAMES];
502 	if (!fFirstIsochronousDescriptor) {
503 		TRACE_ERROR("faild to allocate memory for first isochronous descriptor\n");
504 		return;
505 	}
506 
507 	fLastIsochronousDescriptor = new(std::nothrow) uhci_td *[NUMBER_OF_FRAMES];
508 	if (!fLastIsochronousDescriptor) {
509 		TRACE_ERROR("failed to allocate memory for last isochronous descriptor\n");
510 		delete [] fFirstIsochronousDescriptor;
511 		return;
512 	}
513 
514 	for (int32 i = 0; i < NUMBER_OF_FRAMES; i++) {
515 		fFrameList[i] =	fQueues[UHCI_INTERRUPT_QUEUE]->PhysicalAddress()
516 			| FRAMELIST_NEXT_IS_QH;
517 		fFrameBandwidth[i] = MAX_AVAILABLE_BANDWIDTH;
518 		fFirstIsochronousDescriptor[i] = NULL;
519 		fLastIsochronousDescriptor[i] = NULL;
520 	}
521 
522 	// Create semaphore the finisher and cleanup threads will wait for
523 	fFinishTransfersSem = create_sem(0, "UHCI Finish Transfers");
524 	if (fFinishTransfersSem < B_OK) {
525 		TRACE_ERROR("failed to create finisher semaphore\n");
526 		return;
527 	}
528 
529 	fCleanupSem = create_sem(0, "UHCI Cleanup");
530 	if (fCleanupSem < B_OK) {
531 		TRACE_ERROR("failed to create cleanup semaphore\n");
532 		return;
533 	}
534 
535 	// Create the finisher service and cleanup threads
536 	fFinishThread = spawn_kernel_thread(FinishThread,
537 		"uhci finish thread", B_URGENT_DISPLAY_PRIORITY, (void *)this);
538 	resume_thread(fFinishThread);
539 
540 	fCleanupThread = spawn_kernel_thread(CleanupThread,
541 		"uhci cleanup thread", B_NORMAL_PRIORITY, (void *)this);
542 	resume_thread(fCleanupThread);
543 
544 	// Create semaphore the isochronous finisher thread will wait for
545 	fFinishIsochronousTransfersSem = create_sem(0,
546 		"UHCI Isochronous Finish Transfers");
547 	if (fFinishIsochronousTransfersSem < B_OK) {
548 		TRACE_ERROR("failed to create isochronous finisher semaphore\n");
549 		return;
550 	}
551 
552 	// Create the isochronous finisher service thread
553 	fFinishIsochronousThread = spawn_kernel_thread(FinishIsochronousThread,
554 		"uhci isochronous finish thread", B_URGENT_DISPLAY_PRIORITY,
555 		(void *)this);
556 	resume_thread(fFinishIsochronousThread);
557 
558 	// Find the right interrupt vector, using MSIs if available.
559 	fIRQ = fPCIInfo->u.h0.interrupt_line;
560 	if (sPCIx86Module != NULL && sPCIx86Module->get_msi_count(fPCIInfo->bus,
561 			fPCIInfo->device, fPCIInfo->function) >= 1) {
562 		uint8 msiVector = 0;
563 		if (sPCIx86Module->configure_msi(fPCIInfo->bus, fPCIInfo->device,
564 				fPCIInfo->function, 1, &msiVector) == B_OK
565 			&& sPCIx86Module->enable_msi(fPCIInfo->bus, fPCIInfo->device,
566 				fPCIInfo->function) == B_OK) {
567 			TRACE_ALWAYS("using message signaled interrupts\n");
568 			fIRQ = msiVector;
569 			fUseMSI = true;
570 		}
571 	}
572 
573 	if (fIRQ == 0 || fIRQ == 0xFF) {
574 		TRACE_MODULE_ERROR("device was assigned an invalid IRQ\n");
575 		return;
576 	}
577 
578 	// Install the interrupt handler
579 	TRACE("installing interrupt handler\n");
580 	install_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this, 0);
581 
582 	// Enable interrupts
583 	fEnabledInterrupts = UHCI_USBSTS_USBINT | UHCI_USBSTS_ERRINT
584 		| UHCI_USBSTS_HOSTERR | UHCI_USBSTS_HCPRERR | UHCI_USBSTS_HCHALT;
585 	WriteReg16(UHCI_USBINTR, UHCI_USBINTR_CRC | UHCI_USBINTR_IOC
586 		| UHCI_USBINTR_SHORT);
587 
588 	TRACE("UHCI host controller driver constructed\n");
589 	fInitOK = true;
590 }
591 
592 
593 UHCI::~UHCI()
594 {
595 	int32 result = 0;
596 	fStopThreads = true;
597 	delete_sem(fFinishTransfersSem);
598 	delete_sem(fCleanupSem);
599 	delete_sem(fFinishIsochronousTransfersSem);
600 	wait_for_thread(fFinishThread, &result);
601 	wait_for_thread(fCleanupThread, &result);
602 	wait_for_thread(fFinishIsochronousThread, &result);
603 
604 	remove_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this);
605 
606 	LockIsochronous();
607 	isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer;
608 	while (isoTransfer) {
609 		isochronous_transfer_data *next = isoTransfer->link;
610 		delete isoTransfer;
611 		isoTransfer = next;
612 	}
613 	mutex_destroy(&fIsochronousLock);
614 
615 	Lock();
616 	transfer_data *transfer = fFirstTransfer;
617 	while (transfer) {
618 		transfer->transfer->Finished(B_CANCELED, 0);
619 		delete transfer->transfer;
620 
621 		transfer_data *next = transfer->link;
622 		delete transfer;
623 		transfer = next;
624 	}
625 
626 	for (int32 i = 0; i < fQueueCount; i++)
627 		delete fQueues[i];
628 
629 	delete [] fQueues;
630 	delete [] fFrameBandwidth;
631 	delete [] fFirstIsochronousDescriptor;
632 	delete [] fLastIsochronousDescriptor;
633 	delete fRootHub;
634 	delete_area(fFrameArea);
635 
636 	if (fUseMSI && sPCIx86Module != NULL) {
637 		sPCIx86Module->disable_msi(fPCIInfo->bus,
638 			fPCIInfo->device, fPCIInfo->function);
639 		sPCIx86Module->unconfigure_msi(fPCIInfo->bus,
640 			fPCIInfo->device, fPCIInfo->function);
641 	}
642 	put_module(B_PCI_MODULE_NAME);
643 	if (sPCIx86Module != NULL) {
644 		sPCIx86Module = NULL;
645 		put_module(B_PCI_X86_MODULE_NAME);
646 	}
647 	Unlock();
648 }
649 
650 
651 status_t
652 UHCI::Start()
653 {
654 	// Start the host controller, then start the Busmanager
655 	TRACE("starting UHCI BusManager\n");
656 	TRACE("usbcmd reg 0x%04x, usbsts reg 0x%04x\n",
657 		ReadReg16(UHCI_USBCMD), ReadReg16(UHCI_USBSTS));
658 
659 	// Set the run bit in the command register
660 	WriteReg16(UHCI_USBCMD, ReadReg16(UHCI_USBCMD) | UHCI_USBCMD_RS);
661 
662 	bool running = false;
663 	for (int32 i = 0; i < 10; i++) {
664 		uint16 status = ReadReg16(UHCI_USBSTS);
665 		TRACE("current loop %" B_PRId32 ", status 0x%04x\n", i, status);
666 
667 		if (status & UHCI_USBSTS_HCHALT)
668 			snooze(10000);
669 		else {
670 			running = true;
671 			break;
672 		}
673 	}
674 
675 	if (!running) {
676 		TRACE_ERROR("controller won't start running\n");
677 		return B_ERROR;
678 	}
679 
680 	fRootHubAddress = AllocateAddress();
681 	fRootHub = new(std::nothrow) UHCIRootHub(RootObject(), fRootHubAddress);
682 	if (!fRootHub) {
683 		TRACE_ERROR("no memory to allocate root hub\n");
684 		return B_NO_MEMORY;
685 	}
686 
687 	if (fRootHub->InitCheck() < B_OK) {
688 		TRACE_ERROR("root hub failed init check\n");
689 		delete fRootHub;
690 		return B_ERROR;
691 	}
692 
693 	SetRootHub(fRootHub);
694 
695 	TRACE("controller is started. status: %u curframe: %u\n",
696 		ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM));
697 	TRACE_ALWAYS("successfully started the controller\n");
698 	return BusManager::Start();
699 }
700 
701 
702 status_t
703 UHCI::SubmitTransfer(Transfer *transfer)
704 {
705 	// Short circuit the root hub
706 	Pipe *pipe = transfer->TransferPipe();
707 	if (pipe->DeviceAddress() == fRootHubAddress)
708 		return fRootHub->ProcessTransfer(this, transfer);
709 
710 	TRACE("submit transfer called for device %d\n", pipe->DeviceAddress());
711 	if (pipe->Type() & USB_OBJECT_CONTROL_PIPE)
712 		return SubmitRequest(transfer);
713 
714 	// Process isochronous transfers
715 	if (pipe->Type() & USB_OBJECT_ISO_PIPE)
716 		return SubmitIsochronous(transfer);
717 
718 	uhci_td *firstDescriptor = NULL;
719 	uhci_qh *transferQueue = NULL;
720 	status_t result = CreateFilledTransfer(transfer, &firstDescriptor,
721 		&transferQueue);
722 	if (result < B_OK)
723 		return result;
724 
725 	Queue *queue = NULL;
726 	if (pipe->Type() & USB_OBJECT_INTERRUPT_PIPE)
727 		queue = fQueues[UHCI_INTERRUPT_QUEUE];
728 	else
729 		queue = fQueues[UHCI_BULK_QUEUE];
730 
731 	bool directionIn = (pipe->Direction() == Pipe::In);
732 	result = AddPendingTransfer(transfer, queue, transferQueue,
733 		firstDescriptor, firstDescriptor, directionIn);
734 	if (result < B_OK) {
735 		TRACE_ERROR("failed to add pending transfer\n");
736 		FreeDescriptorChain(firstDescriptor);
737 		FreeTransferQueue(transferQueue);
738 		return result;
739 	}
740 
741 	queue->AppendTransfer(transferQueue);
742 	return B_OK;
743 }
744 
745 
746 status_t
747 UHCI::StartDebugTransfer(Transfer *transfer)
748 {
749 	if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) != 0)
750 		return B_UNSUPPORTED;
751 
752 	static transfer_data transferData;
753 	transferData.first_descriptor = NULL;
754 	transferData.transfer_queue = NULL;
755 	status_t result = CreateFilledTransfer(transfer,
756 		&transferData.first_descriptor, &transferData.transfer_queue);
757 	if (result < B_OK)
758 		return result;
759 
760 	fQueues[UHCI_DEBUG_QUEUE]->AppendTransfer(transferData.transfer_queue,
761 		false);
762 
763 	// we abuse the callback cookie to hold our transfer data
764 	transfer->SetCallback(NULL, &transferData);
765 	return B_OK;
766 }
767 
768 
769 status_t
770 UHCI::CheckDebugTransfer(Transfer *transfer)
771 {
772 	bool transferOK = false;
773 	bool transferError = false;
774 	transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
775 	uhci_td *descriptor = transferData->first_descriptor;
776 
777 	while (descriptor) {
778 		uint32 status = descriptor->status;
779 		if (status & TD_STATUS_ACTIVE)
780 			break;
781 
782 		if (status & TD_ERROR_MASK) {
783 			transferError = true;
784 			break;
785 		}
786 
787 		if ((descriptor->link_phy & TD_TERMINATE)
788 			|| uhci_td_actual_length(descriptor)
789 				< uhci_td_maximum_length(descriptor)) {
790 			transferOK = true;
791 			break;
792 		}
793 
794 		descriptor = (uhci_td *)descriptor->link_log;
795 	}
796 
797 	if (!transferOK && !transferError) {
798 		spin(200);
799 		return B_DEV_PENDING;
800 	}
801 
802 	if (transferOK) {
803 		uint8 lastDataToggle = 0;
804 		if (transfer->TransferPipe()->Direction() == Pipe::In) {
805 			// data to read out
806 			iovec *vector = transfer->Vector();
807 			size_t vectorCount = transfer->VectorCount();
808 
809 			ReadDescriptorChain(transferData->first_descriptor,
810 				vector, vectorCount, &lastDataToggle);
811 		} else {
812 			// read the actual length that was sent
813 			ReadActualLength(transferData->first_descriptor, &lastDataToggle);
814 		}
815 
816 		transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
817 	}
818 
819 	fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transferData->transfer_queue,
820 		false);
821 	FreeDescriptorChain(transferData->first_descriptor);
822 	FreeTransferQueue(transferData->transfer_queue);
823 	return transferOK ? B_OK : B_IO_ERROR;
824 }
825 
826 
827 void
828 UHCI::CancelDebugTransfer(Transfer *transfer)
829 {
830 	transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
831 
832 	// clear the active bit so the descriptors are canceled
833 	uhci_td *descriptor = transferData->first_descriptor;
834 	while (descriptor) {
835 		descriptor->status &= ~TD_STATUS_ACTIVE;
836 		descriptor = (uhci_td *)descriptor->link_log;
837 	}
838 
839 	transfer->Finished(B_CANCELED, 0);
840 
841 	// dequeue and free resources
842 	fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transferData->transfer_queue,
843 		false);
844 	FreeDescriptorChain(transferData->first_descriptor);
845 	FreeTransferQueue(transferData->transfer_queue);
846 	// TODO: [bonefish] The Free*() calls cause "PMA: provided address resulted
847 	// in invalid index" to be printed, so apparently something is not right.
848 	// Though I have not clue what. This is the same cleanup code as in
849 	// CheckDebugTransfer() that should undo the CreateFilledTransfer() from
850 	// StartDebugTransfer().
851 }
852 
853 
854 status_t
855 UHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
856 {
857 	if (pipe->Type() & USB_OBJECT_ISO_PIPE)
858 		return CancelQueuedIsochronousTransfers(pipe, force);
859 
860 	if (!Lock())
861 		return B_ERROR;
862 
863 	struct transfer_entry {
864 		Transfer *			transfer;
865 		transfer_entry *	next;
866 	};
867 
868 	transfer_entry *list = NULL;
869 	transfer_data *current = fFirstTransfer;
870 	while (current) {
871 		if (current->transfer && current->transfer->TransferPipe() == pipe) {
872 			// clear the active bit so the descriptors are canceled
873 			uhci_td *descriptor = current->first_descriptor;
874 			while (descriptor) {
875 				descriptor->status &= ~TD_STATUS_ACTIVE;
876 				descriptor = (uhci_td *)descriptor->link_log;
877 			}
878 
879 			if (!force) {
880 				// if the transfer is canceled by force, the one causing the
881 				// cancel is probably not the one who initiated the transfer
882 				// and the callback is likely not safe anymore
883 				transfer_entry *entry
884 					= (transfer_entry *)malloc(sizeof(transfer_entry));
885 				if (entry != NULL) {
886 					entry->transfer = current->transfer;
887 					current->transfer = NULL;
888 					entry->next = list;
889 					list = entry;
890 				}
891 			}
892 
893 			current->canceled = true;
894 		}
895 		current = current->link;
896 	}
897 
898 	Unlock();
899 
900 	while (list != NULL) {
901 		transfer_entry *next = list->next;
902 		list->transfer->Finished(B_CANCELED, 0);
903 		delete list->transfer;
904 		free(list);
905 		list = next;
906 	}
907 
908 	// wait for any transfers that might have made it before canceling
909 	while (fProcessingPipe == pipe)
910 		snooze(1000);
911 
912 	// notify the finisher so it can clean up the canceled transfers
913 	release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
914 	return B_OK;
915 }
916 
917 
918 status_t
919 UHCI::CancelQueuedIsochronousTransfers(Pipe *pipe, bool force)
920 {
921 	isochronous_transfer_data *current = fFirstIsochronousTransfer;
922 
923 	while (current) {
924 		if (current->transfer->TransferPipe() == pipe) {
925 			int32 packetCount
926 				= current->transfer->IsochronousData()->packet_count;
927 			// Set the active bit off on every descriptor in order to prevent
928 			// the controller from processing them. Then set off the is_active
929 			// field of the transfer in order to make the finisher thread skip
930 			// the transfer. The FinishIsochronousThread will do the rest.
931 			for (int32 i = 0; i < packetCount; i++)
932 				current->descriptors[i]->status &= ~TD_STATUS_ACTIVE;
933 
934 			// TODO: Use the force paramater in order to avoid calling
935 			// invalid callbacks
936 			current->is_active = false;
937 		}
938 
939 		current = current->link;
940 	}
941 
942 	TRACE_ERROR("no isochronous transfer found!\n");
943 	return B_ERROR;
944 }
945 
946 
947 status_t
948 UHCI::SubmitRequest(Transfer *transfer)
949 {
950 	Pipe *pipe = transfer->TransferPipe();
951 	usb_request_data *requestData = transfer->RequestData();
952 	bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
953 
954 	uhci_td *setupDescriptor = CreateDescriptor(pipe, TD_TOKEN_SETUP,
955 		sizeof(usb_request_data));
956 
957 	uhci_td *statusDescriptor = CreateDescriptor(pipe,
958 		directionIn ? TD_TOKEN_OUT : TD_TOKEN_IN, 0);
959 
960 	if (!setupDescriptor || !statusDescriptor) {
961 		TRACE_ERROR("failed to allocate descriptors\n");
962 		FreeDescriptor(setupDescriptor);
963 		FreeDescriptor(statusDescriptor);
964 		return B_NO_MEMORY;
965 	}
966 
967 	iovec vector;
968 	vector.iov_base = requestData;
969 	vector.iov_len = sizeof(usb_request_data);
970 	WriteDescriptorChain(setupDescriptor, &vector, 1);
971 
972 	statusDescriptor->status |= TD_CONTROL_IOC;
973 	statusDescriptor->token |= TD_TOKEN_DATA1;
974 	statusDescriptor->link_phy = TD_TERMINATE;
975 	statusDescriptor->link_log = NULL;
976 
977 	uhci_td *dataDescriptor = NULL;
978 	if (transfer->VectorCount() > 0) {
979 		uhci_td *lastDescriptor = NULL;
980 		status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
981 			&lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
982 			transfer->VectorLength());
983 
984 		if (result < B_OK) {
985 			FreeDescriptor(setupDescriptor);
986 			FreeDescriptor(statusDescriptor);
987 			return result;
988 		}
989 
990 		if (!directionIn) {
991 			WriteDescriptorChain(dataDescriptor, transfer->Vector(),
992 				transfer->VectorCount());
993 		}
994 
995 		LinkDescriptors(setupDescriptor, dataDescriptor);
996 		LinkDescriptors(lastDescriptor, statusDescriptor);
997 	} else {
998 		// Link transfer and status descriptors directly
999 		LinkDescriptors(setupDescriptor, statusDescriptor);
1000 	}
1001 
1002 	Queue *queue = NULL;
1003 	if (pipe->Speed() == USB_SPEED_LOWSPEED)
1004 		queue = fQueues[UHCI_LOW_SPEED_CONTROL_QUEUE];
1005 	else
1006 		queue = fQueues[UHCI_FULL_SPEED_CONTROL_QUEUE];
1007 
1008 	uhci_qh *transferQueue = CreateTransferQueue(setupDescriptor);
1009 	status_t result = AddPendingTransfer(transfer, queue, transferQueue,
1010 		setupDescriptor, dataDescriptor, directionIn);
1011 	if (result < B_OK) {
1012 		TRACE_ERROR("failed to add pending transfer\n");
1013 		FreeDescriptorChain(setupDescriptor);
1014 		FreeTransferQueue(transferQueue);
1015 		return result;
1016 	}
1017 
1018 	queue->AppendTransfer(transferQueue);
1019 	return B_OK;
1020 }
1021 
1022 
1023 status_t
1024 UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue,
1025 	uhci_qh *transferQueue, uhci_td *firstDescriptor, uhci_td *dataDescriptor,
1026 	bool directionIn)
1027 {
1028 	if (!transfer || !queue || !transferQueue || !firstDescriptor)
1029 		return B_BAD_VALUE;
1030 
1031 	transfer_data *data = new(std::nothrow) transfer_data;
1032 	if (!data)
1033 		return B_NO_MEMORY;
1034 
1035 	status_t result = transfer->InitKernelAccess();
1036 	if (result < B_OK) {
1037 		delete data;
1038 		return result;
1039 	}
1040 
1041 	data->transfer = transfer;
1042 	data->queue = queue;
1043 	data->transfer_queue = transferQueue;
1044 	data->first_descriptor = firstDescriptor;
1045 	data->data_descriptor = dataDescriptor;
1046 	data->incoming = directionIn;
1047 	data->canceled = false;
1048 	data->link = NULL;
1049 
1050 	if (!Lock()) {
1051 		delete data;
1052 		return B_ERROR;
1053 	}
1054 
1055 	if (fLastTransfer)
1056 		fLastTransfer->link = data;
1057 	if (!fFirstTransfer)
1058 		fFirstTransfer = data;
1059 
1060 	fLastTransfer = data;
1061 	Unlock();
1062 	return B_OK;
1063 }
1064 
1065 
1066 status_t
1067 UHCI::AddPendingIsochronousTransfer(Transfer *transfer, uhci_td **isoRequest,
1068 	bool directionIn)
1069 {
1070 	if (!transfer || !isoRequest)
1071 		return B_BAD_VALUE;
1072 
1073 	isochronous_transfer_data *data
1074 		= new(std::nothrow) isochronous_transfer_data;
1075 	if (!data)
1076 		return B_NO_MEMORY;
1077 
1078 	status_t result = transfer->InitKernelAccess();
1079 	if (result < B_OK) {
1080 		delete data;
1081 		return result;
1082 	}
1083 
1084 	data->transfer = transfer;
1085 	data->descriptors = isoRequest;
1086 	data->last_to_process = transfer->IsochronousData()->packet_count - 1;
1087 	data->incoming = directionIn;
1088 	data->is_active = true;
1089 	data->link = NULL;
1090 
1091 	// Put in the isochronous transfer list
1092 	if (!LockIsochronous()) {
1093 		delete data;
1094 		return B_ERROR;
1095 	}
1096 
1097 	if (fLastIsochronousTransfer)
1098 		fLastIsochronousTransfer->link = data;
1099 	if (!fFirstIsochronousTransfer)
1100 		fFirstIsochronousTransfer = data;
1101 
1102 	fLastIsochronousTransfer = data;
1103 	UnlockIsochronous();
1104 	return B_OK;
1105 }
1106 
1107 
1108 status_t
1109 UHCI::SubmitIsochronous(Transfer *transfer)
1110 {
1111 	Pipe *pipe = transfer->TransferPipe();
1112 	bool directionIn = (pipe->Direction() == Pipe::In);
1113 	usb_isochronous_data *isochronousData = transfer->IsochronousData();
1114 	size_t packetSize = transfer->DataLength();
1115 	size_t restSize = packetSize % isochronousData->packet_count;
1116 	packetSize /= isochronousData->packet_count;
1117 	uint16 currentFrame;
1118 
1119 	if (packetSize > pipe->MaxPacketSize()) {
1120 		TRACE_ERROR("isochronous packetSize is bigger than pipe MaxPacketSize\n");
1121 		return B_BAD_VALUE;
1122 	}
1123 
1124 	// Ignore the fact that the last descriptor might need less bandwidth.
1125 	// The overhead is not worthy.
1126 	uint16 bandwidth = transfer->Bandwidth() / isochronousData->packet_count;
1127 
1128 	TRACE("isochronous transfer descriptor bandwidth %d\n", bandwidth);
1129 
1130 	// The following holds the list of transfer descriptor of the
1131 	// isochronous request. It is used to quickly remove all the isochronous
1132 	// descriptors from the frame list, as descriptors are not link to each
1133 	// other in a queue like for every other transfer.
1134 	uhci_td **isoRequest
1135 		= new(std::nothrow) uhci_td *[isochronousData->packet_count];
1136 	if (isoRequest == NULL) {
1137 		TRACE("failed to create isoRequest array!\n");
1138 		return B_NO_MEMORY;
1139 	}
1140 
1141 	// Create the list of transfer descriptors
1142 	for (uint32 i = 0; i < (isochronousData->packet_count - 1); i++) {
1143 		isoRequest[i] = CreateDescriptor(pipe,
1144 			directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, packetSize);
1145 		// If we ran out of memory, clean up and return
1146 		if (isoRequest[i] == NULL) {
1147 			for (uint32 j = 0; j < i; j++)
1148 				FreeDescriptor(isoRequest[j]);
1149 			delete [] isoRequest;
1150 			return B_NO_MEMORY;
1151 		}
1152 		// Make sure data toggle is set to zero
1153 		isoRequest[i]->token &= ~TD_TOKEN_DATA1;
1154 	}
1155 
1156 	// Create the last transfer descriptor which should be of smaller size
1157 	// and set the IOC bit
1158 	isoRequest[isochronousData->packet_count - 1] = CreateDescriptor(pipe,
1159 		directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
1160 		(restSize) ? restSize : packetSize);
1161 	// If we are that unlucky...
1162 	if (!isoRequest[isochronousData->packet_count - 1]) {
1163 		for (uint32 i = 0; i < (isochronousData->packet_count - 2); i++)
1164 			FreeDescriptor(isoRequest[i]);
1165 		delete [] isoRequest;
1166 		return B_NO_MEMORY;
1167 	}
1168 	isoRequest[isochronousData->packet_count - 1]->token &= ~TD_TOKEN_DATA1;
1169 
1170 	// If direction is out set every descriptor data
1171 	if (!directionIn) {
1172 		iovec *vector = transfer->Vector();
1173 		WriteIsochronousDescriptorChain(isoRequest,
1174 			isochronousData->packet_count, vector);
1175 	} else {
1176 		// Initialize the packet descriptors
1177 		for (uint32 i = 0; i < isochronousData->packet_count; i++) {
1178 			isochronousData->packet_descriptors[i].actual_length = 0;
1179 			isochronousData->packet_descriptors[i].status = B_NO_INIT;
1180 		}
1181 	}
1182 
1183 	TRACE("isochronous submitted size=%ld bytes, TDs=%" B_PRId32 ", "
1184 		"packetSize=%ld, restSize=%ld\n", transfer->DataLength(),
1185 		isochronousData->packet_count, packetSize, restSize);
1186 
1187 	// Find the entry where to start inserting the first Isochronous descriptor
1188 	if (isochronousData->flags & USB_ISO_ASAP ||
1189 		isochronousData->starting_frame_number == NULL) {
1190 		// find the first available frame with enough bandwidth.
1191 		// This should always be the case, as defining the starting frame
1192 		// number in the driver makes no sense for many reason, one of which
1193 		// is that frame numbers value are host controller specific, and the
1194 		// driver does not know which host controller is running.
1195 		currentFrame = ReadReg16(UHCI_FRNUM);
1196 
1197 		// Make sure that:
1198 		// 1. We are at least 5ms ahead the controller
1199 		// 2. We stay in the range 0-1023
1200 		// 3. There is enough bandwidth in the first entry
1201 		currentFrame = (currentFrame + 5) % NUMBER_OF_FRAMES;
1202 	} else {
1203 		// Find out if the frame number specified has enough bandwidth,
1204 		// otherwise find the first next available frame with enough bandwidth
1205 		currentFrame = *isochronousData->starting_frame_number;
1206 	}
1207 
1208 	// Find the first entry with enough bandwidth
1209 	// TODO: should we also check the bandwidth of the following packet_count frames?
1210 	uint16 startSeekingFromFrame = currentFrame;
1211 	while (fFrameBandwidth[currentFrame] < bandwidth) {
1212 		currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
1213 		if (currentFrame == startSeekingFromFrame) {
1214 			TRACE_ERROR("not enough bandwidth to queue the isochronous request");
1215 			for (uint32 i = 0; i < isochronousData->packet_count; i++)
1216 				FreeDescriptor(isoRequest[i]);
1217 			delete [] isoRequest;
1218 		return B_ERROR;
1219 		}
1220 	}
1221 
1222 	if (isochronousData->starting_frame_number)
1223 		*isochronousData->starting_frame_number = currentFrame;
1224 
1225 	// Add transfer to the list
1226 	status_t result = AddPendingIsochronousTransfer(transfer, isoRequest,
1227 		directionIn);
1228 	if (result < B_OK) {
1229 		TRACE_ERROR("failed to add pending isochronous transfer\n");
1230 		for (uint32 i = 0; i < isochronousData->packet_count; i++)
1231 			FreeDescriptor(isoRequest[i]);
1232 		delete [] isoRequest;
1233 		return result;
1234 	}
1235 
1236 	TRACE("appended isochronous transfer by starting at frame number %d\n",
1237 		currentFrame);
1238 
1239 	// Insert the Transfer Descriptor by starting at
1240 	// the starting_frame_number entry
1241 	// TODO: We don't consider bInterval, and assume it's 1!
1242 	for (uint32 i = 0; i < isochronousData->packet_count; i++) {
1243 		result = LinkIsochronousDescriptor(isoRequest[i], currentFrame);
1244 		if (result < B_OK) {
1245 			TRACE_ERROR("failed to add pending isochronous transfer\n");
1246 			for (uint32 i = 0; i < isochronousData->packet_count; i++)
1247 				FreeDescriptor(isoRequest[i]);
1248 			delete [] isoRequest;
1249 			return result;
1250 		}
1251 
1252 		fFrameBandwidth[currentFrame] -= bandwidth;
1253 		currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
1254 	}
1255 
1256 	// Wake up the isochronous finisher thread
1257 	release_sem_etc(fFinishIsochronousTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1258 
1259 	return B_OK;
1260 }
1261 
1262 
1263 isochronous_transfer_data *
1264 UHCI::FindIsochronousTransfer(uhci_td *descriptor)
1265 {
1266 	// Simply check every last descriptor of the isochronous transfer list
1267 	if (LockIsochronous()) {
1268 		isochronous_transfer_data *transfer = fFirstIsochronousTransfer;
1269 		if (transfer) {
1270 			while (transfer->descriptors[transfer->last_to_process]
1271 				!= descriptor) {
1272 				transfer = transfer->link;
1273 				if (!transfer)
1274 					break;
1275 			}
1276 		}
1277 		UnlockIsochronous();
1278 		return transfer;
1279 	}
1280 	return NULL;
1281 }
1282 
1283 
1284 status_t
1285 UHCI::LinkIsochronousDescriptor(uhci_td *descriptor, uint16 frame)
1286 {
1287 	// The transfer descriptor is appended to the last
1288 	// existing isochronous transfer descriptor (if any)
1289 	// in that frame.
1290 	if (LockIsochronous()) {
1291 		if (!fFirstIsochronousDescriptor[frame]) {
1292 			// Insert the transfer descriptor in the first position
1293 			fFrameList[frame] = descriptor->this_phy & ~FRAMELIST_NEXT_IS_QH;
1294 			fFirstIsochronousDescriptor[frame] = descriptor;
1295 			fLastIsochronousDescriptor[frame] = descriptor;
1296 		} else {
1297 			// Append to the last transfer descriptor
1298 			fLastIsochronousDescriptor[frame]->link_log = descriptor;
1299 			fLastIsochronousDescriptor[frame]->link_phy
1300 				= descriptor->this_phy & ~TD_NEXT_IS_QH;
1301 			fLastIsochronousDescriptor[frame] = descriptor;
1302 		}
1303 
1304 		descriptor->link_phy
1305 			= fQueues[UHCI_INTERRUPT_QUEUE]->PhysicalAddress() | TD_NEXT_IS_QH;
1306 		UnlockIsochronous();
1307 		return B_OK;
1308 	}
1309 	return B_ERROR;
1310 }
1311 
1312 
1313 uhci_td *
1314 UHCI::UnlinkIsochronousDescriptor(uint16 frame)
1315 {
1316 	// We always unlink from the top
1317 	if (LockIsochronous()) {
1318 		uhci_td *descriptor = fFirstIsochronousDescriptor[frame];
1319 		if (descriptor) {
1320 			// The descriptor will be freed later.
1321 			fFrameList[frame] = descriptor->link_phy;
1322 			if (descriptor->link_log) {
1323 				fFirstIsochronousDescriptor[frame]
1324 					= (uhci_td *)descriptor->link_log;
1325 			} else {
1326 				fFirstIsochronousDescriptor[frame] = NULL;
1327 				fLastIsochronousDescriptor[frame] = NULL;
1328 			}
1329 		}
1330 		UnlockIsochronous();
1331 		return descriptor;
1332 	}
1333 	return NULL;
1334 }
1335 
1336 
1337 int32
1338 UHCI::FinishThread(void *data)
1339 {
1340 	((UHCI *)data)->FinishTransfers();
1341 	return B_OK;
1342 }
1343 
1344 
1345 void
1346 UHCI::FinishTransfers()
1347 {
1348 	while (!fStopThreads) {
1349 		if (acquire_sem(fFinishTransfersSem) < B_OK)
1350 			continue;
1351 
1352 		// eat up sems that have been released by multiple interrupts
1353 		int32 semCount = 0;
1354 		get_sem_count(fFinishTransfersSem, &semCount);
1355 		if (semCount > 0)
1356 			acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
1357 
1358 		if (!Lock())
1359 			continue;
1360 
1361 		TRACE("finishing transfers (first transfer: 0x%08lx; last"
1362 			" transfer: 0x%08lx)\n", (addr_t)fFirstTransfer,
1363 			(addr_t)fLastTransfer);
1364 		transfer_data *lastTransfer = NULL;
1365 		transfer_data *transfer = fFirstTransfer;
1366 		Unlock();
1367 
1368 		while (transfer) {
1369 			bool transferDone = false;
1370 			uhci_td *descriptor = transfer->first_descriptor;
1371 			status_t callbackStatus = B_OK;
1372 
1373 			while (descriptor) {
1374 				uint32 status = descriptor->status;
1375 				if (status & TD_STATUS_ACTIVE) {
1376 					// still in progress
1377 					TRACE("td (0x%08" B_PRIx32 ") still active\n",
1378 						descriptor->this_phy);
1379 					break;
1380 				}
1381 
1382 				if (status & TD_ERROR_MASK) {
1383 					// an error occured
1384 					TRACE_ERROR("td (0x%08" B_PRIx32 ") error: status: 0x%08"
1385 						B_PRIx32 "; token: 0x%08" B_PRIx32 ";\n",
1386 						descriptor->this_phy, status, descriptor->token);
1387 
1388 					uint8 errorCount = status >> TD_ERROR_COUNT_SHIFT;
1389 					errorCount &= TD_ERROR_COUNT_MASK;
1390 					if (errorCount == 0) {
1391 						// the error counter counted down to zero, report why
1392 						int32 reasons = 0;
1393 						if (status & TD_STATUS_ERROR_BUFFER) {
1394 							callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN;
1395 							reasons++;
1396 						}
1397 						if (status & TD_STATUS_ERROR_TIMEOUT) {
1398 							callbackStatus = transfer->incoming ? B_DEV_CRC_ERROR : B_TIMED_OUT;
1399 							reasons++;
1400 						}
1401 						if (status & TD_STATUS_ERROR_NAK) {
1402 							callbackStatus = B_DEV_UNEXPECTED_PID;
1403 							reasons++;
1404 						}
1405 						if (status & TD_STATUS_ERROR_BITSTUFF) {
1406 							callbackStatus = B_DEV_CRC_ERROR;
1407 							reasons++;
1408 						}
1409 
1410 						if (reasons > 1)
1411 							callbackStatus = B_DEV_MULTIPLE_ERRORS;
1412 					} else if (status & TD_STATUS_ERROR_BABBLE) {
1413 						// there is a babble condition
1414 						callbackStatus = transfer->incoming ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN;
1415 					} else {
1416 						// if the error counter didn't count down to zero
1417 						// and there was no babble, then this halt was caused
1418 						// by a stall handshake
1419 						callbackStatus = B_DEV_STALLED;
1420 					}
1421 
1422 					transferDone = true;
1423 					break;
1424 				}
1425 
1426 				if ((descriptor->link_phy & TD_TERMINATE)
1427 					|| ((descriptor->status & TD_CONTROL_SPD) != 0
1428 						&& uhci_td_actual_length(descriptor)
1429 							< uhci_td_maximum_length(descriptor))) {
1430 					// all descriptors are done, or we have a short packet
1431 					TRACE("td (0x%08" B_PRIx32 ") ok\n", descriptor->this_phy);
1432 					callbackStatus = B_OK;
1433 					transferDone = true;
1434 					break;
1435 				}
1436 
1437 				descriptor = (uhci_td *)descriptor->link_log;
1438 			}
1439 
1440 			if (!transferDone) {
1441 				lastTransfer = transfer;
1442 				transfer = transfer->link;
1443 				continue;
1444 			}
1445 
1446 			// remove the transfer from the list first so we are sure
1447 			// it doesn't get canceled while we still process it
1448 			transfer_data *next = transfer->link;
1449 			if (Lock()) {
1450 				if (lastTransfer)
1451 					lastTransfer->link = transfer->link;
1452 
1453 				if (transfer == fFirstTransfer)
1454 					fFirstTransfer = transfer->link;
1455 				if (transfer == fLastTransfer)
1456 					fLastTransfer = lastTransfer;
1457 
1458 				// store the currently processing pipe here so we can wait
1459 				// in cancel if we are processing something on the target pipe
1460 				if (!transfer->canceled)
1461 					fProcessingPipe = transfer->transfer->TransferPipe();
1462 
1463 				transfer->link = NULL;
1464 				Unlock();
1465 			}
1466 
1467 			// if canceled the callback has already been called
1468 			if (!transfer->canceled) {
1469 				size_t actualLength = 0;
1470 				if (callbackStatus == B_OK) {
1471 					uint8 lastDataToggle = 0;
1472 					if (transfer->data_descriptor && transfer->incoming) {
1473 						// data to read out
1474 						iovec *vector = transfer->transfer->Vector();
1475 						size_t vectorCount = transfer->transfer->VectorCount();
1476 
1477 						transfer->transfer->PrepareKernelAccess();
1478 						actualLength = ReadDescriptorChain(
1479 							transfer->data_descriptor,
1480 							vector, vectorCount,
1481 							&lastDataToggle);
1482 					} else if (transfer->data_descriptor) {
1483 						// read the actual length that was sent
1484 						actualLength = ReadActualLength(
1485 							transfer->data_descriptor, &lastDataToggle);
1486 					}
1487 
1488 					transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
1489 
1490 					if (transfer->transfer->IsFragmented()) {
1491 						// this transfer may still have data left
1492 						TRACE("advancing fragmented transfer\n");
1493 						transfer->transfer->AdvanceByFragment(actualLength);
1494 						if (transfer->transfer->VectorLength() > 0) {
1495 							TRACE("still %ld bytes left on transfer\n",
1496 								transfer->transfer->VectorLength());
1497 
1498 							Transfer *resubmit = transfer->transfer;
1499 
1500 							// free the used descriptors
1501 							transfer->queue->RemoveTransfer(
1502 								transfer->transfer_queue);
1503 							AddToFreeList(transfer);
1504 
1505 							// resubmit the advanced transfer so the rest
1506 							// of the buffers are transmitted over the bus
1507 							resubmit->PrepareKernelAccess();
1508 							if (SubmitTransfer(resubmit) != B_OK)
1509 								resubmit->Finished(B_ERROR, 0);
1510 
1511 							transfer = next;
1512 							continue;
1513 						}
1514 
1515 						// the transfer is done, but we already set the
1516 						// actualLength with AdvanceByFragment()
1517 						actualLength = 0;
1518 					}
1519 				}
1520 
1521 				transfer->transfer->Finished(callbackStatus, actualLength);
1522 				fProcessingPipe = NULL;
1523 			}
1524 
1525 			// remove and free the hardware queue and its descriptors
1526 			transfer->queue->RemoveTransfer(transfer->transfer_queue);
1527 			delete transfer->transfer;
1528 			AddToFreeList(transfer);
1529 			transfer = next;
1530 		}
1531 	}
1532 }
1533 
1534 
1535 void
1536 UHCI::AddToFreeList(transfer_data *transfer)
1537 {
1538 	transfer->free_after_frame = ReadReg16(UHCI_FRNUM);
1539 	if (!Lock())
1540 		return;
1541 
1542 	transfer->link = fFreeList;
1543 	fFreeList = transfer;
1544 	Unlock();
1545 
1546 	if (atomic_add(&fCleanupCount, 1) == 0)
1547 		release_sem(fCleanupSem);
1548 }
1549 
1550 
1551 int32
1552 UHCI::CleanupThread(void *data)
1553 {
1554 	((UHCI *)data)->Cleanup();
1555 	return B_OK;
1556 }
1557 
1558 
1559 void
1560 UHCI::Cleanup()
1561 {
1562 	while (!fStopThreads) {
1563 		if (acquire_sem(fCleanupSem) != B_OK)
1564 			continue;
1565 
1566 		bigtime_t nextTime = system_time() + 1000;
1567 		while (atomic_get(&fCleanupCount) != 0) {
1568 			// wait for the frame to pass
1569 			snooze_until(nextTime, B_SYSTEM_TIMEBASE);
1570 			nextTime += 1000;
1571 
1572 			if (!Lock())
1573 				continue;
1574 
1575 			// find the first entry we may free
1576 			transfer_data **link = &fFreeList;
1577 			transfer_data *transfer = fFreeList;
1578 			uint16 frameNumber = ReadReg16(UHCI_FRNUM);
1579 			while (transfer) {
1580 				if (transfer->free_after_frame != frameNumber) {
1581 					*link = NULL;
1582 					break;
1583 				}
1584 
1585 				link = &transfer->link;
1586 				transfer = transfer->link;
1587 			}
1588 
1589 			Unlock();
1590 
1591 			// the transfers below this one are all freeable
1592 			while (transfer) {
1593 				transfer_data *next = transfer->link;
1594 				FreeDescriptorChain(transfer->first_descriptor);
1595 				FreeTransferQueue(transfer->transfer_queue);
1596 				delete transfer;
1597 				atomic_add(&fCleanupCount, -1);
1598 				transfer = next;
1599 			}
1600 		}
1601 	}
1602 }
1603 
1604 
1605 int32
1606 UHCI::FinishIsochronousThread(void *data)
1607 {
1608        ((UHCI *)data)->FinishIsochronousTransfers();
1609        return B_OK;
1610 }
1611 
1612 
1613 void
1614 UHCI::FinishIsochronousTransfers()
1615 {
1616 	/* This thread stays one position behind the controller and processes every
1617 	 * isochronous descriptor. Once it finds the last isochronous descriptor
1618 	 * of a transfer, it processes the entire transfer.
1619 	 */
1620 
1621 	while (!fStopThreads) {
1622 		// Go to sleep if there are not isochronous transfer to process
1623 		if (acquire_sem(fFinishIsochronousTransfersSem) < B_OK)
1624 			return;
1625 
1626 		bool transferDone = false;
1627 		uint16 currentFrame = ReadReg16(UHCI_FRNUM);
1628 
1629 		// Process the frame list until one transfer is processed
1630 		while (!transferDone) {
1631 			// wait 1ms in order to be sure to be one position behind
1632 			// the controller
1633 			if (currentFrame == ReadReg16(UHCI_FRNUM))
1634 				snooze(1000);
1635 
1636 			// Process the frame till it has isochronous descriptors in it.
1637 			while (!(fFrameList[currentFrame] & FRAMELIST_NEXT_IS_QH)) {
1638 				uhci_td *current = UnlinkIsochronousDescriptor(currentFrame);
1639 
1640 				// Process the transfer if we found the last descriptor
1641 				isochronous_transfer_data *transfer
1642 					= FindIsochronousTransfer(current);
1643 					// Process the descriptors only if it is still active and
1644 					// belongs to an inbound transfer. If the transfer is not
1645 					// active, it means the request has been removed, so simply
1646 					// remove the descriptors.
1647 				if (transfer && transfer->is_active) {
1648 					if (current->token & TD_TOKEN_IN) {
1649 						iovec *vector = transfer->transfer->Vector();
1650 						transfer->transfer->PrepareKernelAccess();
1651 						ReadIsochronousDescriptorChain(transfer, vector);
1652 					}
1653 
1654 					// Remove the transfer
1655 					if (LockIsochronous()) {
1656 						if (transfer == fFirstIsochronousTransfer) {
1657 							fFirstIsochronousTransfer = transfer->link;
1658 							if (transfer == fLastIsochronousTransfer)
1659 								fLastIsochronousTransfer = NULL;
1660 						} else {
1661 							isochronous_transfer_data *temp
1662 								= fFirstIsochronousTransfer;
1663 							while (transfer != temp->link)
1664 								temp = temp->link;
1665 
1666 							if (transfer == fLastIsochronousTransfer)
1667 								fLastIsochronousTransfer = temp;
1668 							temp->link = temp->link->link;
1669 						}
1670 						UnlockIsochronous();
1671 					}
1672 
1673 					transfer->transfer->Finished(B_OK, 0);
1674 
1675 					uint32 packetCount =
1676 						transfer->transfer->IsochronousData()->packet_count;
1677 					for (uint32 i = 0; i < packetCount; i++)
1678 						FreeDescriptor(transfer->descriptors[i]);
1679 
1680 					delete [] transfer->descriptors;
1681 					delete transfer->transfer;
1682 					delete transfer;
1683 					transferDone = true;
1684 				}
1685 			}
1686 
1687 			// Make sure to reset the frame bandwidth
1688 			fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH;
1689 			currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
1690 		}
1691 	}
1692 }
1693 
1694 
1695 void
1696 UHCI::GlobalReset()
1697 {
1698 	uint8 sofValue = ReadReg8(UHCI_SOFMOD);
1699 
1700 	WriteReg16(UHCI_USBCMD, UHCI_USBCMD_GRESET);
1701 	snooze(100000);
1702 	WriteReg16(UHCI_USBCMD, 0);
1703 	snooze(10000);
1704 
1705 	WriteReg8(UHCI_SOFMOD, sofValue);
1706 }
1707 
1708 
1709 status_t
1710 UHCI::ControllerReset()
1711 {
1712 	WriteReg16(UHCI_USBCMD, UHCI_USBCMD_HCRESET);
1713 
1714 	int32 tries = 5;
1715 	while (ReadReg16(UHCI_USBCMD) & UHCI_USBCMD_HCRESET) {
1716 		snooze(10000);
1717 		if (tries-- < 0)
1718 			return B_ERROR;
1719 	}
1720 
1721 	return B_OK;
1722 }
1723 
1724 
1725 status_t
1726 UHCI::GetPortStatus(uint8 index, usb_port_status *status)
1727 {
1728 	if (index > 1)
1729 		return B_BAD_INDEX;
1730 
1731 	status->status = status->change = 0;
1732 	uint16 portStatus = ReadReg16(UHCI_PORTSC1 + index * 2);
1733 
1734 	// build the status
1735 	if (portStatus & UHCI_PORTSC_CURSTAT)
1736 		status->status |= PORT_STATUS_CONNECTION;
1737 	if (portStatus & UHCI_PORTSC_ENABLED)
1738 		status->status |= PORT_STATUS_ENABLE;
1739 	if (portStatus & UHCI_PORTSC_RESET)
1740 		status->status |= PORT_STATUS_RESET;
1741 	if (portStatus & UHCI_PORTSC_LOWSPEED)
1742 		status->status |= PORT_STATUS_LOW_SPEED;
1743 
1744 	// build the change
1745 	if (portStatus & UHCI_PORTSC_STATCHA)
1746 		status->change |= PORT_STATUS_CONNECTION;
1747 	if (portStatus & UHCI_PORTSC_ENABCHA)
1748 		status->change |= PORT_STATUS_ENABLE;
1749 
1750 	// ToDo: work out suspended/resume
1751 
1752 	// there are no bits to indicate reset change
1753 	if (fPortResetChange & (1 << index))
1754 		status->change |= PORT_STATUS_RESET;
1755 
1756 	// the port is automagically powered on
1757 	status->status |= PORT_STATUS_POWER;
1758 	return B_OK;
1759 }
1760 
1761 
1762 status_t
1763 UHCI::SetPortFeature(uint8 index, uint16 feature)
1764 {
1765 	if (index > 1)
1766 		return B_BAD_INDEX;
1767 
1768 	switch (feature) {
1769 		case PORT_RESET:
1770 			return ResetPort(index);
1771 
1772 		case PORT_POWER:
1773 			// the ports are automatically powered
1774 			return B_OK;
1775 	}
1776 
1777 	return B_BAD_VALUE;
1778 }
1779 
1780 
1781 status_t
1782 UHCI::ClearPortFeature(uint8 index, uint16 feature)
1783 {
1784 	if (index > 1)
1785 		return B_BAD_INDEX;
1786 
1787 	uint32 portRegister = UHCI_PORTSC1 + index * 2;
1788 	uint16 portStatus = ReadReg16(portRegister) & UHCI_PORTSC_DATAMASK;
1789 
1790 	switch (feature) {
1791 		case C_PORT_RESET:
1792 			fPortResetChange &= ~(1 << index);
1793 			return B_OK;
1794 
1795 		case C_PORT_CONNECTION:
1796 			WriteReg16(portRegister, portStatus | UHCI_PORTSC_STATCHA);
1797 			return B_OK;
1798 
1799 		case C_PORT_ENABLE:
1800 			WriteReg16(portRegister, portStatus | UHCI_PORTSC_ENABCHA);
1801 			return B_OK;
1802 	}
1803 
1804 	return B_BAD_VALUE;
1805 }
1806 
1807 
1808 status_t
1809 UHCI::ResetPort(uint8 index)
1810 {
1811 	if (index > 1)
1812 		return B_BAD_INDEX;
1813 
1814 	TRACE("reset port %d\n", index);
1815 
1816 	uint32 port = UHCI_PORTSC1 + index * 2;
1817 	uint16 status = ReadReg16(port);
1818 	status &= UHCI_PORTSC_DATAMASK;
1819 	WriteReg16(port, status | UHCI_PORTSC_RESET);
1820 	snooze(250000);
1821 
1822 	status = ReadReg16(port);
1823 	status &= UHCI_PORTSC_DATAMASK;
1824 	WriteReg16(port, status & ~UHCI_PORTSC_RESET);
1825 	snooze(1000);
1826 
1827 	for (int32 i = 10; i > 0; i--) {
1828 		// try to enable the port
1829 		status = ReadReg16(port);
1830 		status &= UHCI_PORTSC_DATAMASK;
1831 		WriteReg16(port, status | UHCI_PORTSC_ENABLED);
1832 		snooze(50000);
1833 
1834 		status = ReadReg16(port);
1835 
1836 		if ((status & UHCI_PORTSC_CURSTAT) == 0) {
1837 			// no device connected. since we waited long enough we can assume
1838 			// that the port was reset and no device is connected.
1839 			break;
1840 		}
1841 
1842 		if (status & (UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA)) {
1843 			// port enabled changed or connection status were set.
1844 			// acknowledge either / both and wait again.
1845 			status &= UHCI_PORTSC_DATAMASK;
1846 			WriteReg16(port, status | UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA);
1847 			continue;
1848 		}
1849 
1850 		if (status & UHCI_PORTSC_ENABLED) {
1851 			// the port is enabled
1852 			break;
1853 		}
1854 	}
1855 
1856 	fPortResetChange |= (1 << index);
1857 	TRACE("port was reset: 0x%04x\n", ReadReg16(port));
1858 	return B_OK;
1859 }
1860 
1861 
1862 int32
1863 UHCI::InterruptHandler(void *data)
1864 {
1865 	return ((UHCI *)data)->Interrupt();
1866 }
1867 
1868 
1869 int32
1870 UHCI::Interrupt()
1871 {
1872 	static spinlock lock = B_SPINLOCK_INITIALIZER;
1873 	acquire_spinlock(&lock);
1874 
1875 	// Check if we really had an interrupt
1876 	uint16 status = ReadReg16(UHCI_USBSTS);
1877 	if ((status & fEnabledInterrupts) == 0) {
1878 		if (status != 0) {
1879 			TRACE("discarding not enabled interrupts 0x%08x\n", status);
1880 			WriteReg16(UHCI_USBSTS, status);
1881 		}
1882 
1883 		release_spinlock(&lock);
1884 		return B_UNHANDLED_INTERRUPT;
1885 	}
1886 
1887 	uint16 acknowledge = 0;
1888 	bool finishTransfers = false;
1889 	int32 result = B_HANDLED_INTERRUPT;
1890 
1891 	if (status & UHCI_USBSTS_USBINT) {
1892 		TRACE_MODULE("transfer finished\n");
1893 		acknowledge |= UHCI_USBSTS_USBINT;
1894 		result = B_INVOKE_SCHEDULER;
1895 		finishTransfers = true;
1896 	}
1897 
1898 	if (status & UHCI_USBSTS_ERRINT) {
1899 		TRACE_MODULE("transfer error\n");
1900 		acknowledge |= UHCI_USBSTS_ERRINT;
1901 		result = B_INVOKE_SCHEDULER;
1902 		finishTransfers = true;
1903 	}
1904 
1905 	if (status & UHCI_USBSTS_RESDET) {
1906 		TRACE_MODULE("resume detected\n");
1907 		acknowledge |= UHCI_USBSTS_RESDET;
1908 	}
1909 
1910 	if (status & UHCI_USBSTS_HOSTERR) {
1911 		TRACE_MODULE_ERROR("host system error\n");
1912 		acknowledge |= UHCI_USBSTS_HOSTERR;
1913 	}
1914 
1915 	if (status & UHCI_USBSTS_HCPRERR) {
1916 		TRACE_MODULE_ERROR("process error\n");
1917 		acknowledge |= UHCI_USBSTS_HCPRERR;
1918 	}
1919 
1920 	if (status & UHCI_USBSTS_HCHALT) {
1921 		TRACE_MODULE_ERROR("host controller halted\n");
1922 		// at least disable interrupts so we do not flood the system
1923 		WriteReg16(UHCI_USBINTR, 0);
1924 		fEnabledInterrupts = 0;
1925 		// ToDo: cancel all transfers and reset the host controller
1926 		// acknowledge not needed
1927 	}
1928 
1929 	if (acknowledge)
1930 		WriteReg16(UHCI_USBSTS, acknowledge);
1931 
1932 	release_spinlock(&lock);
1933 
1934 	if (finishTransfers)
1935 		release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1936 
1937 	return result;
1938 }
1939 
1940 
1941 status_t
1942 UHCI::CreateFilledTransfer(Transfer *transfer, uhci_td **_firstDescriptor,
1943 	uhci_qh **_transferQueue)
1944 {
1945 	Pipe *pipe = transfer->TransferPipe();
1946 	bool directionIn = (pipe->Direction() == Pipe::In);
1947 
1948 	uhci_td *firstDescriptor = NULL;
1949 	uhci_td *lastDescriptor = NULL;
1950 	status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
1951 		&lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
1952 		transfer->VectorLength());
1953 
1954 	if (result < B_OK)
1955 		return result;
1956 	if (!firstDescriptor || !lastDescriptor)
1957 		return B_NO_MEMORY;
1958 
1959 	lastDescriptor->status |= TD_CONTROL_IOC;
1960 	lastDescriptor->link_phy = TD_TERMINATE;
1961 	lastDescriptor->link_log = NULL;
1962 
1963 	if (!directionIn) {
1964 		WriteDescriptorChain(firstDescriptor, transfer->Vector(),
1965 			transfer->VectorCount());
1966 	}
1967 
1968 	uhci_qh *transferQueue = CreateTransferQueue(firstDescriptor);
1969 	if (!transferQueue) {
1970 		FreeDescriptorChain(firstDescriptor);
1971 		return B_NO_MEMORY;
1972 	}
1973 
1974 	*_firstDescriptor = firstDescriptor;
1975 	*_transferQueue = transferQueue;
1976 	return B_OK;
1977 }
1978 
1979 
1980 uhci_qh *
1981 UHCI::CreateTransferQueue(uhci_td *descriptor)
1982 {
1983 	uhci_qh *queueHead;
1984 	phys_addr_t physicalAddress;
1985 	if (fStack->AllocateChunk((void **)&queueHead, &physicalAddress,
1986 		sizeof(uhci_qh)) < B_OK)
1987 		return NULL;
1988 
1989 	queueHead->this_phy = (uint32)physicalAddress;
1990 	queueHead->element_phy = descriptor->this_phy;
1991 	return queueHead;
1992 }
1993 
1994 
1995 void
1996 UHCI::FreeTransferQueue(uhci_qh *queueHead)
1997 {
1998 	if (!queueHead)
1999 		return;
2000 
2001 	fStack->FreeChunk(queueHead, queueHead->this_phy, sizeof(uhci_qh));
2002 }
2003 
2004 
2005 uhci_td *
2006 UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, size_t bufferSize)
2007 {
2008 	uhci_td *result;
2009 	phys_addr_t physicalAddress;
2010 
2011 	if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2012 		sizeof(uhci_td)) < B_OK) {
2013 		TRACE_ERROR("failed to allocate a transfer descriptor\n");
2014 		return NULL;
2015 	}
2016 
2017 	result->this_phy = (uint32)physicalAddress;
2018 	result->status = TD_STATUS_ACTIVE;
2019 	if (pipe->Type() & USB_OBJECT_ISO_PIPE)
2020 		result->status |= TD_CONTROL_ISOCHRONOUS;
2021 	else {
2022 		result->status |= TD_CONTROL_3_ERRORS;
2023 		if (direction == TD_TOKEN_IN)
2024 			result->status |= TD_CONTROL_SPD;
2025 	}
2026 	if (pipe->Speed() == USB_SPEED_LOWSPEED)
2027 		result->status |= TD_CONTROL_LOWSPEED;
2028 
2029 	result->buffer_size = bufferSize;
2030 	if (bufferSize == 0)
2031 		result->token = TD_TOKEN_NULL_DATA;
2032 	else
2033 		result->token = (bufferSize - 1) << TD_TOKEN_MAXLEN_SHIFT;
2034 
2035 	result->token |= (pipe->EndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT)
2036 		| (pipe->DeviceAddress() << 8) | direction;
2037 
2038 	result->link_phy = 0;
2039 	result->link_log = NULL;
2040 	if (bufferSize <= 0) {
2041 		result->buffer_log = NULL;
2042 		result->buffer_phy = 0;
2043 		return result;
2044 	}
2045 
2046 	if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress,
2047 		bufferSize) < B_OK) {
2048 		TRACE_ERROR("unable to allocate space for the buffer\n");
2049 		fStack->FreeChunk(result, result->this_phy, sizeof(uhci_td));
2050 		return NULL;
2051 	}
2052 	result->buffer_phy = physicalAddress;
2053 
2054 	return result;
2055 }
2056 
2057 
2058 status_t
2059 UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
2060 	uhci_td **_lastDescriptor, uint8 direction, size_t bufferSize)
2061 {
2062 	size_t packetSize = pipe->MaxPacketSize();
2063 	int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
2064 	if (descriptorCount == 0)
2065 		descriptorCount = 1;
2066 
2067 	bool dataToggle = pipe->DataToggle();
2068 	uhci_td *firstDescriptor = NULL;
2069 	uhci_td *lastDescriptor = *_firstDescriptor;
2070 	for (int32 i = 0; i < descriptorCount; i++) {
2071 		uhci_td *descriptor = CreateDescriptor(pipe, direction,
2072 			min_c(packetSize, bufferSize));
2073 
2074 		if (!descriptor) {
2075 			FreeDescriptorChain(firstDescriptor);
2076 			return B_NO_MEMORY;
2077 		}
2078 
2079 		if (dataToggle)
2080 			descriptor->token |= TD_TOKEN_DATA1;
2081 
2082 		// link to previous
2083 		if (lastDescriptor)
2084 			LinkDescriptors(lastDescriptor, descriptor);
2085 
2086 		dataToggle = !dataToggle;
2087 		bufferSize -= packetSize;
2088 		lastDescriptor = descriptor;
2089 		if (!firstDescriptor)
2090 			firstDescriptor = descriptor;
2091 	}
2092 
2093 	*_firstDescriptor = firstDescriptor;
2094 	*_lastDescriptor = lastDescriptor;
2095 	return B_OK;
2096 }
2097 
2098 
2099 void
2100 UHCI::FreeDescriptor(uhci_td *descriptor)
2101 {
2102 	if (!descriptor)
2103 		return;
2104 
2105 	if (descriptor->buffer_log) {
2106 		fStack->FreeChunk(descriptor->buffer_log,
2107 			descriptor->buffer_phy, descriptor->buffer_size);
2108 	}
2109 
2110 	fStack->FreeChunk(descriptor, descriptor->this_phy, sizeof(uhci_td));
2111 }
2112 
2113 
2114 void
2115 UHCI::FreeDescriptorChain(uhci_td *topDescriptor)
2116 {
2117 	uhci_td *current = topDescriptor;
2118 	uhci_td *next = NULL;
2119 
2120 	while (current) {
2121 		next = (uhci_td *)current->link_log;
2122 		FreeDescriptor(current);
2123 		current = next;
2124 	}
2125 }
2126 
2127 
2128 void
2129 UHCI::LinkDescriptors(uhci_td *first, uhci_td *second)
2130 {
2131 	first->link_phy = second->this_phy | TD_DEPTH_FIRST;
2132 	first->link_log = second;
2133 }
2134 
2135 
2136 size_t
2137 UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector,
2138 	size_t vectorCount)
2139 {
2140 	uhci_td *current = topDescriptor;
2141 	size_t actualLength = 0;
2142 	size_t vectorIndex = 0;
2143 	size_t vectorOffset = 0;
2144 	size_t bufferOffset = 0;
2145 
2146 	while (current) {
2147 		if (!current->buffer_log)
2148 			break;
2149 
2150 		while (true) {
2151 			size_t length = min_c(current->buffer_size - bufferOffset,
2152 				vector[vectorIndex].iov_len - vectorOffset);
2153 
2154 			TRACE("copying %ld bytes to bufferOffset %ld from"
2155 				" vectorOffset %ld at index %ld of %ld\n", length, bufferOffset,
2156 				vectorOffset, vectorIndex, vectorCount);
2157 			memcpy((uint8 *)current->buffer_log + bufferOffset,
2158 				(uint8 *)vector[vectorIndex].iov_base + vectorOffset, length);
2159 
2160 			actualLength += length;
2161 			vectorOffset += length;
2162 			bufferOffset += length;
2163 
2164 			if (vectorOffset >= vector[vectorIndex].iov_len) {
2165 				if (++vectorIndex >= vectorCount) {
2166 					TRACE("wrote descriptor chain (%ld bytes, no more vectors)\n",
2167 						actualLength);
2168 					return actualLength;
2169 				}
2170 
2171 				vectorOffset = 0;
2172 			}
2173 
2174 			if (bufferOffset >= current->buffer_size) {
2175 				bufferOffset = 0;
2176 				break;
2177 			}
2178 		}
2179 
2180 		if (current->link_phy & TD_TERMINATE)
2181 			break;
2182 
2183 		current = (uhci_td *)current->link_log;
2184 	}
2185 
2186 	TRACE("wrote descriptor chain (%ld bytes)\n", actualLength);
2187 	return actualLength;
2188 }
2189 
2190 
2191 size_t
2192 UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector,
2193 	size_t vectorCount, uint8 *lastDataToggle)
2194 {
2195 	uint8 dataToggle = 0;
2196 	uhci_td *current = topDescriptor;
2197 	size_t actualLength = 0;
2198 	size_t vectorIndex = 0;
2199 	size_t vectorOffset = 0;
2200 	size_t bufferOffset = 0;
2201 
2202 	while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
2203 		if (!current->buffer_log)
2204 			break;
2205 
2206 		dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
2207 		size_t bufferSize = uhci_td_actual_length(current);
2208 
2209 		while (true) {
2210 			size_t length = min_c(bufferSize - bufferOffset,
2211 				vector[vectorIndex].iov_len - vectorOffset);
2212 
2213 			TRACE("copying %ld bytes to vectorOffset %ld from"
2214 				" bufferOffset %ld at index %ld of %ld\n", length, vectorOffset,
2215 				bufferOffset, vectorIndex, vectorCount);
2216 			memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
2217 				(uint8 *)current->buffer_log + bufferOffset, length);
2218 
2219 			actualLength += length;
2220 			vectorOffset += length;
2221 			bufferOffset += length;
2222 
2223 			if (vectorOffset >= vector[vectorIndex].iov_len) {
2224 				if (++vectorIndex >= vectorCount) {
2225 					TRACE("read descriptor chain (%ld bytes, no more vectors)\n",
2226 						actualLength);
2227 					if (lastDataToggle)
2228 						*lastDataToggle = dataToggle;
2229 					return actualLength;
2230 				}
2231 
2232 				vectorOffset = 0;
2233 			}
2234 
2235 			if (bufferOffset >= bufferSize) {
2236 				bufferOffset = 0;
2237 				break;
2238 			}
2239 		}
2240 
2241 		if (current->link_phy & TD_TERMINATE)
2242 			break;
2243 
2244 		current = (uhci_td *)current->link_log;
2245 	}
2246 
2247 	if (lastDataToggle)
2248 		*lastDataToggle = dataToggle;
2249 
2250 	TRACE("read descriptor chain (%ld bytes)\n", actualLength);
2251 	return actualLength;
2252 }
2253 
2254 
2255 size_t
2256 UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle)
2257 {
2258 	size_t actualLength = 0;
2259 	uhci_td *current = topDescriptor;
2260 	uint8 dataToggle = 0;
2261 
2262 	while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
2263 		actualLength += uhci_td_actual_length(current);
2264 		dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
2265 
2266 		if (current->link_phy & TD_TERMINATE)
2267 			break;
2268 
2269 		current = (uhci_td *)current->link_log;
2270 	}
2271 
2272 	if (lastDataToggle)
2273 		*lastDataToggle = dataToggle;
2274 
2275 	TRACE("read actual length (%ld bytes)\n", actualLength);
2276 	return actualLength;
2277 }
2278 
2279 
2280 void
2281 UHCI::WriteIsochronousDescriptorChain(uhci_td **isoRequest, uint32 packetCount,
2282 	iovec *vector)
2283 {
2284 	size_t vectorOffset = 0;
2285 	for (uint32 i = 0; i < packetCount; i++) {
2286 		size_t bufferSize = isoRequest[i]->buffer_size;
2287 		memcpy((uint8 *)isoRequest[i]->buffer_log,
2288 			(uint8 *)vector->iov_base + vectorOffset, bufferSize);
2289 		vectorOffset += bufferSize;
2290 	}
2291 }
2292 
2293 
2294 void
2295 UHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer,
2296 	iovec *vector)
2297 {
2298 	size_t vectorOffset = 0;
2299 	usb_isochronous_data *isochronousData
2300 		= transfer->transfer->IsochronousData();
2301 
2302 	for (uint32 i = 0; i < isochronousData->packet_count; i++) {
2303 		uhci_td *current = transfer->descriptors[i];
2304 
2305 		size_t bufferSize = current->buffer_size;
2306 		size_t actualLength = uhci_td_actual_length(current);
2307 
2308 		isochronousData->packet_descriptors[i].actual_length = actualLength;
2309 
2310 		if (actualLength > 0)
2311 			isochronousData->packet_descriptors[i].status = B_OK;
2312 		else {
2313 			isochronousData->packet_descriptors[i].status = B_ERROR;
2314 			vectorOffset += bufferSize;
2315 			continue;
2316 		}
2317 		memcpy((uint8 *)vector->iov_base + vectorOffset,
2318 			(uint8 *)current->buffer_log, bufferSize);
2319 
2320 		vectorOffset += bufferSize;
2321 	}
2322 }
2323 
2324 
2325 bool
2326 UHCI::LockIsochronous()
2327 {
2328 	return (mutex_lock(&fIsochronousLock) == B_OK);
2329 }
2330 
2331 
2332 void
2333 UHCI::UnlockIsochronous()
2334 {
2335 	mutex_unlock(&fIsochronousLock);
2336 }
2337 
2338 
2339 inline void
2340 UHCI::WriteReg8(uint32 reg, uint8 value)
2341 {
2342 	sPCIModule->write_io_8(fRegisterBase + reg, value);
2343 }
2344 
2345 
2346 inline void
2347 UHCI::WriteReg16(uint32 reg, uint16 value)
2348 {
2349 	sPCIModule->write_io_16(fRegisterBase + reg, value);
2350 }
2351 
2352 
2353 inline void
2354 UHCI::WriteReg32(uint32 reg, uint32 value)
2355 {
2356 	sPCIModule->write_io_32(fRegisterBase + reg, value);
2357 }
2358 
2359 
2360 inline uint8
2361 UHCI::ReadReg8(uint32 reg)
2362 {
2363 	return sPCIModule->read_io_8(fRegisterBase + reg);
2364 }
2365 
2366 
2367 inline uint16
2368 UHCI::ReadReg16(uint32 reg)
2369 {
2370 	return sPCIModule->read_io_16(fRegisterBase + reg);
2371 }
2372 
2373 
2374 inline uint32
2375 UHCI::ReadReg32(uint32 reg)
2376 {
2377 	return sPCIModule->read_io_32(fRegisterBase + reg);
2378 }
2379