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