xref: /haiku/src/add-ons/kernel/busses/usb/uhci.cpp (revision c90684742e7361651849be4116d0e5de3a817194)
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 bandwdith %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 						else {
1549 							isochronous_transfer_data *temp
1550 								= fFirstIsochronousTransfer;
1551 							while (transfer != temp->link)
1552 								temp = temp->link;
1553 
1554 							if (transfer == fLastIsochronousTransfer)
1555 								fLastIsochronousTransfer = temp;
1556 							temp->link = temp->link->link;
1557 						}
1558 						UnlockIsochronous();
1559 					}
1560 
1561 					transfer->transfer->Finished(B_OK, 0);
1562 
1563 					uint32 packetCount =
1564 						transfer->transfer->IsochronousData()->packet_count;
1565 					for (uint32 i = 0; i < packetCount; i++)
1566 						FreeDescriptor(transfer->descriptors[i]);
1567 
1568 					delete [] transfer->descriptors;
1569 					delete transfer->transfer;
1570 					delete transfer;
1571 					transferDone = true;
1572 				}
1573 			}
1574 
1575 			// Make sure to reset the frame bandwidth
1576 			fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH;
1577 			currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
1578 		}
1579 	}
1580 }
1581 
1582 
1583 void
1584 UHCI::GlobalReset()
1585 {
1586 	uint8 sofValue = ReadReg8(UHCI_SOFMOD);
1587 
1588 	WriteReg16(UHCI_USBCMD, UHCI_USBCMD_GRESET);
1589 	snooze(100000);
1590 	WriteReg16(UHCI_USBCMD, 0);
1591 	snooze(10000);
1592 
1593 	WriteReg8(UHCI_SOFMOD, sofValue);
1594 }
1595 
1596 
1597 status_t
1598 UHCI::ControllerReset()
1599 {
1600 	WriteReg16(UHCI_USBCMD, UHCI_USBCMD_HCRESET);
1601 
1602 	int32 tries = 5;
1603 	while (ReadReg16(UHCI_USBCMD) & UHCI_USBCMD_HCRESET) {
1604 		snooze(10000);
1605 		if (tries-- < 0)
1606 			return B_ERROR;
1607 	}
1608 
1609 	return B_OK;
1610 }
1611 
1612 
1613 status_t
1614 UHCI::GetPortStatus(uint8 index, usb_port_status *status)
1615 {
1616 	if (index > 1)
1617 		return B_BAD_INDEX;
1618 
1619 	status->status = status->change = 0;
1620 	uint16 portStatus = ReadReg16(UHCI_PORTSC1 + index * 2);
1621 
1622 	// build the status
1623 	if (portStatus & UHCI_PORTSC_CURSTAT)
1624 		status->status |= PORT_STATUS_CONNECTION;
1625 	if (portStatus & UHCI_PORTSC_ENABLED)
1626 		status->status |= PORT_STATUS_ENABLE;
1627 	if (portStatus & UHCI_PORTSC_RESET)
1628 		status->status |= PORT_STATUS_RESET;
1629 	if (portStatus & UHCI_PORTSC_LOWSPEED)
1630 		status->status |= PORT_STATUS_LOW_SPEED;
1631 
1632 	// build the change
1633 	if (portStatus & UHCI_PORTSC_STATCHA)
1634 		status->change |= PORT_STATUS_CONNECTION;
1635 	if (portStatus & UHCI_PORTSC_ENABCHA)
1636 		status->change |= PORT_STATUS_ENABLE;
1637 
1638 	// ToDo: work out suspended/resume
1639 
1640 	// there are no bits to indicate reset change
1641 	if (fPortResetChange & (1 << index))
1642 		status->change |= PORT_STATUS_RESET;
1643 
1644 	// the port is automagically powered on
1645 	status->status |= PORT_STATUS_POWER;
1646 	return B_OK;
1647 }
1648 
1649 
1650 status_t
1651 UHCI::SetPortFeature(uint8 index, uint16 feature)
1652 {
1653 	if (index > 1)
1654 		return B_BAD_INDEX;
1655 
1656 	switch (feature) {
1657 		case PORT_RESET:
1658 			return ResetPort(index);
1659 
1660 		case PORT_POWER:
1661 			// the ports are automatically powered
1662 			return B_OK;
1663 	}
1664 
1665 	return B_BAD_VALUE;
1666 }
1667 
1668 
1669 status_t
1670 UHCI::ClearPortFeature(uint8 index, uint16 feature)
1671 {
1672 	if (index > 1)
1673 		return B_BAD_INDEX;
1674 
1675 	uint32 portRegister = UHCI_PORTSC1 + index * 2;
1676 	uint16 portStatus = ReadReg16(portRegister) & UHCI_PORTSC_DATAMASK;
1677 
1678 	switch (feature) {
1679 		case C_PORT_RESET:
1680 			fPortResetChange &= ~(1 << index);
1681 			return B_OK;
1682 
1683 		case C_PORT_CONNECTION:
1684 			WriteReg16(portRegister, portStatus | UHCI_PORTSC_STATCHA);
1685 			return B_OK;
1686 
1687 		case C_PORT_ENABLE:
1688 			WriteReg16(portRegister, portStatus | UHCI_PORTSC_ENABCHA);
1689 			return B_OK;
1690 	}
1691 
1692 	return B_BAD_VALUE;
1693 }
1694 
1695 
1696 status_t
1697 UHCI::ResetPort(uint8 index)
1698 {
1699 	if (index > 1)
1700 		return B_BAD_INDEX;
1701 
1702 	TRACE("reset port %d\n", index);
1703 
1704 	uint32 port = UHCI_PORTSC1 + index * 2;
1705 	uint16 status = ReadReg16(port);
1706 	status &= UHCI_PORTSC_DATAMASK;
1707 	WriteReg16(port, status | UHCI_PORTSC_RESET);
1708 	snooze(250000);
1709 
1710 	status = ReadReg16(port);
1711 	status &= UHCI_PORTSC_DATAMASK;
1712 	WriteReg16(port, status & ~UHCI_PORTSC_RESET);
1713 	snooze(1000);
1714 
1715 	for (int32 i = 10; i > 0; i--) {
1716 		// try to enable the port
1717 		status = ReadReg16(port);
1718 		status &= UHCI_PORTSC_DATAMASK;
1719 		WriteReg16(port, status | UHCI_PORTSC_ENABLED);
1720 		snooze(50000);
1721 
1722 		status = ReadReg16(port);
1723 
1724 		if ((status & UHCI_PORTSC_CURSTAT) == 0) {
1725 			// no device connected. since we waited long enough we can assume
1726 			// that the port was reset and no device is connected.
1727 			break;
1728 		}
1729 
1730 		if (status & (UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA)) {
1731 			// port enabled changed or connection status were set.
1732 			// acknowledge either / both and wait again.
1733 			status &= UHCI_PORTSC_DATAMASK;
1734 			WriteReg16(port, status | UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA);
1735 			continue;
1736 		}
1737 
1738 		if (status & UHCI_PORTSC_ENABLED) {
1739 			// the port is enabled
1740 			break;
1741 		}
1742 	}
1743 
1744 	fPortResetChange |= (1 << index);
1745 	TRACE("port was reset: 0x%04x\n", ReadReg16(port));
1746 	return B_OK;
1747 }
1748 
1749 
1750 int32
1751 UHCI::InterruptHandler(void *data)
1752 {
1753 	return ((UHCI *)data)->Interrupt();
1754 }
1755 
1756 
1757 int32
1758 UHCI::Interrupt()
1759 {
1760 	static spinlock lock = B_SPINLOCK_INITIALIZER;
1761 	acquire_spinlock(&lock);
1762 
1763 	// Check if we really had an interrupt
1764 	uint16 status = ReadReg16(UHCI_USBSTS);
1765 	if ((status & fEnabledInterrupts) == 0) {
1766 		if (status != 0) {
1767 			TRACE("discarding not enabled interrupts 0x%08x\n", status);
1768 			WriteReg16(UHCI_USBSTS, status);
1769 		}
1770 
1771 		release_spinlock(&lock);
1772 		return B_UNHANDLED_INTERRUPT;
1773 	}
1774 
1775 	uint16 acknowledge = 0;
1776 	bool finishTransfers = false;
1777 	int32 result = B_HANDLED_INTERRUPT;
1778 
1779 	if (status & UHCI_USBSTS_USBINT) {
1780 		TRACE_MODULE("transfer finished\n");
1781 		acknowledge |= UHCI_USBSTS_USBINT;
1782 		result = B_INVOKE_SCHEDULER;
1783 		finishTransfers = true;
1784 	}
1785 
1786 	if (status & UHCI_USBSTS_ERRINT) {
1787 		TRACE_MODULE("transfer error\n");
1788 		acknowledge |= UHCI_USBSTS_ERRINT;
1789 		result = B_INVOKE_SCHEDULER;
1790 		finishTransfers = true;
1791 	}
1792 
1793 	if (status & UHCI_USBSTS_RESDET) {
1794 		TRACE_MODULE("resume detected\n");
1795 		acknowledge |= UHCI_USBSTS_RESDET;
1796 	}
1797 
1798 	if (status & UHCI_USBSTS_HOSTERR) {
1799 		TRACE_MODULE_ERROR("host system error\n");
1800 		acknowledge |= UHCI_USBSTS_HOSTERR;
1801 	}
1802 
1803 	if (status & UHCI_USBSTS_HCPRERR) {
1804 		TRACE_MODULE_ERROR("process error\n");
1805 		acknowledge |= UHCI_USBSTS_HCPRERR;
1806 	}
1807 
1808 	if (status & UHCI_USBSTS_HCHALT) {
1809 		TRACE_MODULE_ERROR("host controller halted\n");
1810 		// at least disable interrupts so we do not flood the system
1811 		WriteReg16(UHCI_USBINTR, 0);
1812 		fEnabledInterrupts = 0;
1813 		// ToDo: cancel all transfers and reset the host controller
1814 		// acknowledge not needed
1815 	}
1816 
1817 	if (acknowledge)
1818 		WriteReg16(UHCI_USBSTS, acknowledge);
1819 
1820 	release_spinlock(&lock);
1821 
1822 	if (finishTransfers)
1823 		release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1824 
1825 	return result;
1826 }
1827 
1828 
1829 status_t
1830 UHCI::AddTo(Stack *stack)
1831 {
1832 #ifdef TRACE_USB
1833 	set_dprintf_enabled(true);
1834 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
1835 	load_driver_symbols("uhci");
1836 #endif
1837 #endif
1838 
1839 	if (!sPCIModule) {
1840 		status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule);
1841 		if (status < B_OK) {
1842 			TRACE_MODULE_ERROR("AddTo(): getting pci module failed! 0x%08lx\n",
1843 				status);
1844 			return status;
1845 		}
1846 	}
1847 
1848 	TRACE_MODULE("AddTo(): setting up hardware\n");
1849 
1850 	bool found = false;
1851 	pci_info *item = new(std::nothrow) pci_info;
1852 	if (!item) {
1853 		sPCIModule = NULL;
1854 		put_module(B_PCI_MODULE_NAME);
1855 		return B_NO_MEMORY;
1856 	}
1857 
1858 	for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) {
1859 
1860 		if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb
1861 			&& item->class_api == PCI_usb_uhci) {
1862 			if (item->u.h0.interrupt_line == 0
1863 				|| item->u.h0.interrupt_line == 0xFF) {
1864 				TRACE_MODULE_ERROR("AddTo(): found with invalid IRQ - check IRQ assignement\n");
1865 				continue;
1866 			}
1867 
1868 			TRACE_MODULE("AddTo(): found at IRQ %u\n",
1869 				item->u.h0.interrupt_line);
1870 			UHCI *bus = new(std::nothrow) UHCI(item, stack);
1871 			if (!bus) {
1872 				delete item;
1873 				sPCIModule = NULL;
1874 				put_module(B_PCI_MODULE_NAME);
1875 				return B_NO_MEMORY;
1876 			}
1877 
1878 			if (bus->InitCheck() < B_OK) {
1879 				TRACE_MODULE_ERROR("AddTo(): InitCheck() failed 0x%08lx\n",
1880 					bus->InitCheck());
1881 				delete bus;
1882 				continue;
1883 			}
1884 
1885 			// the bus took it away
1886 			item = new(std::nothrow) pci_info;
1887 
1888 			bus->Start();
1889 			stack->AddBusManager(bus);
1890 			found = true;
1891 		}
1892 	}
1893 
1894 	if (!found) {
1895 		TRACE_MODULE_ERROR("no devices found\n");
1896 		delete item;
1897 		sPCIModule = NULL;
1898 		put_module(B_PCI_MODULE_NAME);
1899 		return ENODEV;
1900 	}
1901 
1902 	delete item;
1903 	return B_OK;
1904 }
1905 
1906 
1907 status_t
1908 UHCI::CreateFilledTransfer(Transfer *transfer, uhci_td **_firstDescriptor,
1909 	uhci_qh **_transferQueue)
1910 {
1911 	Pipe *pipe = transfer->TransferPipe();
1912 	bool directionIn = (pipe->Direction() == Pipe::In);
1913 
1914 	uhci_td *firstDescriptor = NULL;
1915 	uhci_td *lastDescriptor = NULL;
1916 	status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
1917 		&lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
1918 		transfer->VectorLength());
1919 
1920 	if (result < B_OK)
1921 		return result;
1922 	if (!firstDescriptor || !lastDescriptor)
1923 		return B_NO_MEMORY;
1924 
1925 	lastDescriptor->status |= TD_CONTROL_IOC;
1926 	lastDescriptor->link_phy = TD_TERMINATE;
1927 	lastDescriptor->link_log = NULL;
1928 
1929 	if (!directionIn) {
1930 		WriteDescriptorChain(firstDescriptor, transfer->Vector(),
1931 			transfer->VectorCount());
1932 	}
1933 
1934 	uhci_qh *transferQueue = CreateTransferQueue(firstDescriptor);
1935 	if (!transferQueue) {
1936 		FreeDescriptorChain(firstDescriptor);
1937 		return B_NO_MEMORY;
1938 	}
1939 
1940 	*_firstDescriptor = firstDescriptor;
1941 	*_transferQueue = transferQueue;
1942 	return B_OK;
1943 }
1944 
1945 
1946 uhci_qh *
1947 UHCI::CreateTransferQueue(uhci_td *descriptor)
1948 {
1949 	uhci_qh *queueHead;
1950 	void *physicalAddress;
1951 	if (fStack->AllocateChunk((void **)&queueHead,
1952 		&physicalAddress, sizeof(uhci_qh)) < B_OK)
1953 		return NULL;
1954 
1955 	queueHead->this_phy = (addr_t)physicalAddress;
1956 	queueHead->element_phy = descriptor->this_phy;
1957 	return queueHead;
1958 }
1959 
1960 
1961 void
1962 UHCI::FreeTransferQueue(uhci_qh *queueHead)
1963 {
1964 	if (!queueHead)
1965 		return;
1966 
1967 	fStack->FreeChunk(queueHead, (void *)queueHead->this_phy, sizeof(uhci_qh));
1968 }
1969 
1970 
1971 uhci_td *
1972 UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, size_t bufferSize)
1973 {
1974 	uhci_td *result;
1975 	void *physicalAddress;
1976 
1977 	if (fStack->AllocateChunk((void **)&result, &physicalAddress,
1978 		sizeof(uhci_td)) < B_OK) {
1979 		TRACE_ERROR("failed to allocate a transfer descriptor\n");
1980 		return NULL;
1981 	}
1982 
1983 	result->this_phy = (addr_t)physicalAddress;
1984 	result->status = TD_STATUS_ACTIVE;
1985 	if (pipe->Type() & USB_OBJECT_ISO_PIPE)
1986 		result->status |= TD_CONTROL_ISOCHRONOUS;
1987 	else {
1988 		result->status |= TD_CONTROL_3_ERRORS;
1989 		if (direction == TD_TOKEN_IN
1990 			&& (pipe->Type() & USB_OBJECT_CONTROL_PIPE) == 0)
1991 			result->status |= TD_CONTROL_SPD;
1992 	}
1993 	if (pipe->Speed() == USB_SPEED_LOWSPEED)
1994 		result->status |= TD_CONTROL_LOWSPEED;
1995 
1996 	result->buffer_size = bufferSize;
1997 	if (bufferSize == 0)
1998 		result->token = TD_TOKEN_NULL_DATA;
1999 	else
2000 		result->token = (bufferSize - 1) << TD_TOKEN_MAXLEN_SHIFT;
2001 
2002 	result->token |= (pipe->EndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT)
2003 		| (pipe->DeviceAddress() << 8) | direction;
2004 
2005 	result->link_phy = 0;
2006 	result->link_log = NULL;
2007 	if (bufferSize <= 0) {
2008 		result->buffer_log = NULL;
2009 		result->buffer_phy = 0;
2010 		return result;
2011 	}
2012 
2013 	if (fStack->AllocateChunk(&result->buffer_log, (void **)&result->buffer_phy,
2014 		bufferSize) < B_OK) {
2015 		TRACE_ERROR("unable to allocate space for the buffer\n");
2016 		fStack->FreeChunk(result, (void *)result->this_phy, sizeof(uhci_td));
2017 		return NULL;
2018 	}
2019 
2020 	return result;
2021 }
2022 
2023 
2024 status_t
2025 UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
2026 	uhci_td **_lastDescriptor, uint8 direction, size_t bufferSize)
2027 {
2028 	size_t packetSize = pipe->MaxPacketSize();
2029 	int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
2030 	if (descriptorCount == 0)
2031 		descriptorCount = 1;
2032 
2033 	bool dataToggle = pipe->DataToggle();
2034 	uhci_td *firstDescriptor = NULL;
2035 	uhci_td *lastDescriptor = *_firstDescriptor;
2036 	for (int32 i = 0; i < descriptorCount; i++) {
2037 		uhci_td *descriptor = CreateDescriptor(pipe, direction,
2038 			min_c(packetSize, bufferSize));
2039 
2040 		if (!descriptor) {
2041 			FreeDescriptorChain(firstDescriptor);
2042 			return B_NO_MEMORY;
2043 		}
2044 
2045 		if (dataToggle)
2046 			descriptor->token |= TD_TOKEN_DATA1;
2047 
2048 		// link to previous
2049 		if (lastDescriptor)
2050 			LinkDescriptors(lastDescriptor, descriptor);
2051 
2052 		dataToggle = !dataToggle;
2053 		bufferSize -= packetSize;
2054 		lastDescriptor = descriptor;
2055 		if (!firstDescriptor)
2056 			firstDescriptor = descriptor;
2057 	}
2058 
2059 	*_firstDescriptor = firstDescriptor;
2060 	*_lastDescriptor = lastDescriptor;
2061 	return B_OK;
2062 }
2063 
2064 
2065 void
2066 UHCI::FreeDescriptor(uhci_td *descriptor)
2067 {
2068 	if (!descriptor)
2069 		return;
2070 
2071 	if (descriptor->buffer_log) {
2072 		fStack->FreeChunk(descriptor->buffer_log,
2073 			(void *)descriptor->buffer_phy, descriptor->buffer_size);
2074 	}
2075 
2076 	fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(uhci_td));
2077 }
2078 
2079 
2080 void
2081 UHCI::FreeDescriptorChain(uhci_td *topDescriptor)
2082 {
2083 	uhci_td *current = topDescriptor;
2084 	uhci_td *next = NULL;
2085 
2086 	while (current) {
2087 		next = (uhci_td *)current->link_log;
2088 		FreeDescriptor(current);
2089 		current = next;
2090 	}
2091 }
2092 
2093 
2094 void
2095 UHCI::LinkDescriptors(uhci_td *first, uhci_td *second)
2096 {
2097 	first->link_phy = second->this_phy | TD_DEPTH_FIRST;
2098 	first->link_log = second;
2099 }
2100 
2101 
2102 size_t
2103 UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector,
2104 	size_t vectorCount)
2105 {
2106 	uhci_td *current = topDescriptor;
2107 	size_t actualLength = 0;
2108 	size_t vectorIndex = 0;
2109 	size_t vectorOffset = 0;
2110 	size_t bufferOffset = 0;
2111 
2112 	while (current) {
2113 		if (!current->buffer_log)
2114 			break;
2115 
2116 		while (true) {
2117 			size_t length = min_c(current->buffer_size - bufferOffset,
2118 				vector[vectorIndex].iov_len - vectorOffset);
2119 
2120 			TRACE("copying %ld bytes to bufferOffset %ld from"
2121 				" vectorOffset %ld at index %ld of %ld\n", length, bufferOffset,
2122 				vectorOffset, vectorIndex, vectorCount);
2123 			memcpy((uint8 *)current->buffer_log + bufferOffset,
2124 				(uint8 *)vector[vectorIndex].iov_base + vectorOffset, length);
2125 
2126 			actualLength += length;
2127 			vectorOffset += length;
2128 			bufferOffset += length;
2129 
2130 			if (vectorOffset >= vector[vectorIndex].iov_len) {
2131 				if (++vectorIndex >= vectorCount) {
2132 					TRACE("wrote descriptor chain (%ld bytes, no more vectors)\n",
2133 						actualLength);
2134 					return actualLength;
2135 				}
2136 
2137 				vectorOffset = 0;
2138 			}
2139 
2140 			if (bufferOffset >= current->buffer_size) {
2141 				bufferOffset = 0;
2142 				break;
2143 			}
2144 		}
2145 
2146 		if (current->link_phy & TD_TERMINATE)
2147 			break;
2148 
2149 		current = (uhci_td *)current->link_log;
2150 	}
2151 
2152 	TRACE("wrote descriptor chain (%ld bytes)\n", actualLength);
2153 	return actualLength;
2154 }
2155 
2156 
2157 size_t
2158 UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector,
2159 	size_t vectorCount, uint8 *lastDataToggle)
2160 {
2161 	uint8 dataToggle = 0;
2162 	uhci_td *current = topDescriptor;
2163 	size_t actualLength = 0;
2164 	size_t vectorIndex = 0;
2165 	size_t vectorOffset = 0;
2166 	size_t bufferOffset = 0;
2167 
2168 	while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
2169 		if (!current->buffer_log)
2170 			break;
2171 
2172 		dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
2173 		size_t bufferSize = uhci_td_actual_length(current);
2174 
2175 		while (true) {
2176 			size_t length = min_c(bufferSize - bufferOffset,
2177 				vector[vectorIndex].iov_len - vectorOffset);
2178 
2179 			TRACE("copying %ld bytes to vectorOffset %ld from"
2180 				" bufferOffset %ld at index %ld of %ld\n", length, vectorOffset,
2181 				bufferOffset, vectorIndex, vectorCount);
2182 			memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
2183 				(uint8 *)current->buffer_log + bufferOffset, length);
2184 
2185 			actualLength += length;
2186 			vectorOffset += length;
2187 			bufferOffset += length;
2188 
2189 			if (vectorOffset >= vector[vectorIndex].iov_len) {
2190 				if (++vectorIndex >= vectorCount) {
2191 					TRACE("read descriptor chain (%ld bytes, no more vectors)\n",
2192 						actualLength);
2193 					if (lastDataToggle)
2194 						*lastDataToggle = dataToggle;
2195 					return actualLength;
2196 				}
2197 
2198 				vectorOffset = 0;
2199 			}
2200 
2201 			if (bufferOffset >= bufferSize) {
2202 				bufferOffset = 0;
2203 				break;
2204 			}
2205 		}
2206 
2207 		if (current->link_phy & TD_TERMINATE)
2208 			break;
2209 
2210 		current = (uhci_td *)current->link_log;
2211 	}
2212 
2213 	if (lastDataToggle)
2214 		*lastDataToggle = dataToggle;
2215 
2216 	TRACE("read descriptor chain (%ld bytes)\n", actualLength);
2217 	return actualLength;
2218 }
2219 
2220 
2221 size_t
2222 UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle)
2223 {
2224 	size_t actualLength = 0;
2225 	uhci_td *current = topDescriptor;
2226 	uint8 dataToggle = 0;
2227 
2228 	while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
2229 		actualLength += uhci_td_actual_length(current);
2230 		dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
2231 
2232 		if (current->link_phy & TD_TERMINATE)
2233 			break;
2234 
2235 		current = (uhci_td *)current->link_log;
2236 	}
2237 
2238 	if (lastDataToggle)
2239 		*lastDataToggle = dataToggle;
2240 
2241 	TRACE("read actual length (%ld bytes)\n", actualLength);
2242 	return actualLength;
2243 }
2244 
2245 
2246 void
2247 UHCI::WriteIsochronousDescriptorChain(uhci_td **isoRequest, uint32 packetCount,
2248 	iovec *vector)
2249 {
2250 	size_t vectorOffset = 0;
2251 	for (uint32 i = 0; i < packetCount; i++) {
2252 		size_t bufferSize = isoRequest[i]->buffer_size;
2253 		memcpy((uint8 *)isoRequest[i]->buffer_log,
2254 			(uint8 *)vector->iov_base + vectorOffset, bufferSize);
2255 		vectorOffset += bufferSize;
2256 	}
2257 }
2258 
2259 
2260 void
2261 UHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer,
2262 	iovec *vector)
2263 {
2264 	size_t vectorOffset = 0;
2265 	usb_isochronous_data *isochronousData
2266 		= transfer->transfer->IsochronousData();
2267 
2268 	for (uint32 i = 0; i < isochronousData->packet_count; i++) {
2269 		uhci_td *current = transfer->descriptors[i];
2270 
2271 		size_t bufferSize = current->buffer_size;
2272 		size_t actualLength = uhci_td_actual_length(current);
2273 
2274 		isochronousData->packet_descriptors[i].actual_length = actualLength;
2275 
2276 		if (actualLength > 0)
2277 			isochronousData->packet_descriptors[i].status = B_OK;
2278 		else {
2279 			isochronousData->packet_descriptors[i].status = B_ERROR;
2280 			vectorOffset += bufferSize;
2281 			continue;
2282 		}
2283 		memcpy((uint8 *)vector->iov_base + vectorOffset,
2284 			(uint8 *)current->buffer_log, bufferSize);
2285 
2286 		vectorOffset += bufferSize;
2287 	}
2288 }
2289 
2290 
2291 bool
2292 UHCI::LockIsochronous()
2293 {
2294 	return (mutex_lock(&fIsochronousLock) == B_OK);
2295 }
2296 
2297 
2298 void
2299 UHCI::UnlockIsochronous()
2300 {
2301 	mutex_unlock(&fIsochronousLock);
2302 }
2303 
2304 
2305 inline void
2306 UHCI::WriteReg8(uint32 reg, uint8 value)
2307 {
2308 	sPCIModule->write_io_8(fRegisterBase + reg, value);
2309 }
2310 
2311 
2312 inline void
2313 UHCI::WriteReg16(uint32 reg, uint16 value)
2314 {
2315 	sPCIModule->write_io_16(fRegisterBase + reg, value);
2316 }
2317 
2318 
2319 inline void
2320 UHCI::WriteReg32(uint32 reg, uint32 value)
2321 {
2322 	sPCIModule->write_io_32(fRegisterBase + reg, value);
2323 }
2324 
2325 
2326 inline uint8
2327 UHCI::ReadReg8(uint32 reg)
2328 {
2329 	return sPCIModule->read_io_8(fRegisterBase + reg);
2330 }
2331 
2332 
2333 inline uint16
2334 UHCI::ReadReg16(uint32 reg)
2335 {
2336 	return sPCIModule->read_io_16(fRegisterBase + reg);
2337 }
2338 
2339 
2340 inline uint32
2341 UHCI::ReadReg32(uint32 reg)
2342 {
2343 	return sPCIModule->read_io_32(fRegisterBase + reg);
2344 }
2345