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