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