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