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