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