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