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