xref: /haiku/src/add-ons/kernel/busses/usb/uhci.cpp (revision 344ded80d400028c8f561b4b876257b94c12db4a)
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 (fIRQ == 0xFF)
688 			fIRQ = 0;
689 
690 	if (fPci->get_msi_count(fDevice) >= 1) {
691 		uint32 msiVector = 0;
692 		if (fPci->configure_msi(fDevice, 1, &msiVector) == B_OK
693 			&& fPci->enable_msi(fDevice) == B_OK) {
694 			TRACE_ALWAYS("using message signaled interrupts\n");
695 			fIRQ = msiVector;
696 			fUseMSI = true;
697 		}
698 	}
699 
700 	if (fIRQ == 0) {
701 		TRACE_MODULE_ERROR("device PCI:%d:%d:%d was assigned an invalid IRQ\n",
702 			fPCIInfo->bus, fPCIInfo->device, fPCIInfo->function);
703 		return;
704 	}
705 
706 	// Install the interrupt handler
707 	TRACE("installing interrupt handler\n");
708 	install_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this, 0);
709 
710 	// Enable interrupts
711 	fEnabledInterrupts = UHCI_USBSTS_USBINT | UHCI_USBSTS_ERRINT
712 		| UHCI_USBSTS_HOSTERR | UHCI_USBSTS_HCPRERR | UHCI_USBSTS_HCHALT;
713 	WriteReg16(UHCI_USBINTR, UHCI_USBINTR_CRC | UHCI_USBINTR_IOC
714 		| UHCI_USBINTR_SHORT);
715 
716 	TRACE("UHCI host controller driver constructed\n");
717 	fInitOK = true;
718 }
719 
720 
721 UHCI::~UHCI()
722 {
723 	int32 result = 0;
724 	fStopThreads = true;
725 	delete_sem(fFinishTransfersSem);
726 	delete_sem(fCleanupSem);
727 	delete_sem(fFinishIsochronousTransfersSem);
728 	wait_for_thread(fFinishThread, &result);
729 	wait_for_thread(fCleanupThread, &result);
730 	wait_for_thread(fFinishIsochronousThread, &result);
731 
732 	remove_io_interrupt_handler(fIRQ, InterruptHandler, (void *)this);
733 
734 	LockIsochronous();
735 	isochronous_transfer_data *isoTransfer = fFirstIsochronousTransfer;
736 	while (isoTransfer) {
737 		isochronous_transfer_data *next = isoTransfer->link;
738 		delete isoTransfer;
739 		isoTransfer = next;
740 	}
741 	mutex_destroy(&fIsochronousLock);
742 
743 	Lock();
744 	transfer_data *transfer = fFirstTransfer;
745 	while (transfer) {
746 		transfer->transfer->Finished(B_CANCELED, 0);
747 		delete transfer->transfer;
748 
749 		transfer_data *next = transfer->link;
750 		delete transfer;
751 		transfer = next;
752 	}
753 
754 	for (int32 i = 0; i < fQueueCount; i++)
755 		delete fQueues[i];
756 
757 	delete [] fQueues;
758 	delete [] fFrameBandwidth;
759 	delete [] fFirstIsochronousDescriptor;
760 	delete [] fLastIsochronousDescriptor;
761 	delete fRootHub;
762 	delete_area(fFrameArea);
763 
764 	if (fUseMSI) {
765 		fPci->disable_msi(fDevice);
766 		fPci->unconfigure_msi(fDevice);
767 	}
768 
769 	Unlock();
770 }
771 
772 
773 status_t
774 UHCI::Start()
775 {
776 	// Start the host controller, then start the Busmanager
777 	TRACE("starting UHCI BusManager\n");
778 	TRACE("usbcmd reg 0x%04x, usbsts reg 0x%04x\n",
779 		ReadReg16(UHCI_USBCMD), ReadReg16(UHCI_USBSTS));
780 
781 	// Set the run bit in the command register
782 	WriteReg16(UHCI_USBCMD, ReadReg16(UHCI_USBCMD) | UHCI_USBCMD_RS);
783 
784 	bool running = false;
785 	for (int32 i = 0; i < 10; i++) {
786 		uint16 status = ReadReg16(UHCI_USBSTS);
787 		TRACE("current loop %" B_PRId32 ", status 0x%04x\n", i, status);
788 
789 		if (status & UHCI_USBSTS_HCHALT)
790 			snooze(10000);
791 		else {
792 			running = true;
793 			break;
794 		}
795 	}
796 
797 	if (!running) {
798 		TRACE_ERROR("controller won't start running\n");
799 		return B_ERROR;
800 	}
801 
802 	fRootHubAddress = AllocateAddress();
803 	fRootHub = new(std::nothrow) UHCIRootHub(RootObject(), fRootHubAddress);
804 	if (!fRootHub) {
805 		TRACE_ERROR("no memory to allocate root hub\n");
806 		return B_NO_MEMORY;
807 	}
808 
809 	if (fRootHub->InitCheck() < B_OK) {
810 		TRACE_ERROR("root hub failed init check\n");
811 		delete fRootHub;
812 		return B_ERROR;
813 	}
814 
815 	SetRootHub(fRootHub);
816 
817 	fRootHub->RegisterNode(Node());
818 
819 	TRACE("controller is started. status: %u curframe: %u\n",
820 		ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM));
821 	TRACE_ALWAYS("successfully started the controller\n");
822 	return BusManager::Start();
823 }
824 
825 
826 status_t
827 UHCI::SubmitTransfer(Transfer *transfer)
828 {
829 	// Short circuit the root hub
830 	Pipe *pipe = transfer->TransferPipe();
831 	if (pipe->DeviceAddress() == fRootHubAddress)
832 		return fRootHub->ProcessTransfer(this, transfer);
833 
834 	TRACE("submit transfer called for device %d\n", pipe->DeviceAddress());
835 	if (pipe->Type() & USB_OBJECT_CONTROL_PIPE)
836 		return SubmitRequest(transfer);
837 
838 	// Process isochronous transfers
839 #if 0
840 	if (pipe->Type() & USB_OBJECT_ISO_PIPE)
841 		return SubmitIsochronous(transfer);
842 #else
843 	// At present, isochronous transfers cause busylooping, and do not seem to work.
844 	if (pipe->Type() & USB_OBJECT_ISO_PIPE)
845 		return B_NOT_SUPPORTED;
846 #endif
847 
848 	uhci_td *firstDescriptor = NULL;
849 	uhci_qh *transferQueue = NULL;
850 	status_t result = CreateFilledTransfer(transfer, &firstDescriptor,
851 		&transferQueue);
852 	if (result < B_OK)
853 		return result;
854 
855 	Queue *queue = NULL;
856 	if (pipe->Type() & USB_OBJECT_INTERRUPT_PIPE)
857 		queue = fQueues[UHCI_INTERRUPT_QUEUE];
858 	else
859 		queue = fQueues[UHCI_BULK_QUEUE];
860 
861 	bool directionIn = (pipe->Direction() == Pipe::In);
862 	result = AddPendingTransfer(transfer, queue, transferQueue,
863 		firstDescriptor, firstDescriptor, directionIn);
864 	if (result < B_OK) {
865 		TRACE_ERROR("failed to add pending transfer\n");
866 		FreeDescriptorChain(firstDescriptor);
867 		FreeTransferQueue(transferQueue);
868 		return result;
869 	}
870 
871 	queue->AppendTransfer(transferQueue);
872 	return B_OK;
873 }
874 
875 
876 status_t
877 UHCI::StartDebugTransfer(Transfer *transfer)
878 {
879 	if ((transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE) != 0)
880 		return B_UNSUPPORTED;
881 
882 	static transfer_data transferData;
883 	transferData.first_descriptor = NULL;
884 	transferData.transfer_queue = NULL;
885 	status_t result = CreateFilledTransfer(transfer,
886 		&transferData.first_descriptor, &transferData.transfer_queue);
887 	if (result < B_OK)
888 		return result;
889 
890 	fQueues[UHCI_DEBUG_QUEUE]->AppendTransfer(transferData.transfer_queue,
891 		false);
892 
893 	// we abuse the callback cookie to hold our transfer data
894 	transfer->SetCallback(NULL, &transferData);
895 	return B_OK;
896 }
897 
898 
899 status_t
900 UHCI::CheckDebugTransfer(Transfer *transfer)
901 {
902 	bool transferOK = false;
903 	bool transferError = false;
904 	transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
905 	uhci_td *descriptor = transferData->first_descriptor;
906 
907 	while (descriptor) {
908 		uint32 status = descriptor->status;
909 		if (status & TD_STATUS_ACTIVE)
910 			break;
911 
912 		if (status & TD_ERROR_MASK) {
913 			transferError = true;
914 			break;
915 		}
916 
917 		if ((descriptor->link_phy & TD_TERMINATE)
918 			|| uhci_td_actual_length(descriptor)
919 				< uhci_td_maximum_length(descriptor)) {
920 			transferOK = true;
921 			break;
922 		}
923 
924 		descriptor = (uhci_td *)descriptor->link_log;
925 	}
926 
927 	if (!transferOK && !transferError) {
928 		spin(200);
929 		return B_DEV_PENDING;
930 	}
931 
932 	if (transferOK) {
933 		uint8 lastDataToggle = 0;
934 		if (transfer->TransferPipe()->Direction() == Pipe::In) {
935 			// data to read out
936 			generic_io_vec *vector = transfer->Vector();
937 			size_t vectorCount = transfer->VectorCount();
938 
939 			ReadDescriptorChain(transferData->first_descriptor,
940 				vector, vectorCount, transfer->IsPhysical(), &lastDataToggle);
941 		} else {
942 			// read the actual length that was sent
943 			ReadActualLength(transferData->first_descriptor, &lastDataToggle);
944 		}
945 
946 		transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
947 	}
948 
949 	fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transferData->transfer_queue,
950 		false);
951 	FreeDescriptorChain(transferData->first_descriptor);
952 	FreeTransferQueue(transferData->transfer_queue);
953 	return transferOK ? B_OK : B_IO_ERROR;
954 }
955 
956 
957 void
958 UHCI::CancelDebugTransfer(Transfer *transfer)
959 {
960 	transfer_data *transferData = (transfer_data *)transfer->CallbackCookie();
961 
962 	// clear the active bit so the descriptors are canceled
963 	uhci_td *descriptor = transferData->first_descriptor;
964 	while (descriptor) {
965 		descriptor->status &= ~TD_STATUS_ACTIVE;
966 		descriptor = (uhci_td *)descriptor->link_log;
967 	}
968 
969 	transfer->Finished(B_CANCELED, 0);
970 
971 	// dequeue and free resources
972 	fQueues[UHCI_DEBUG_QUEUE]->RemoveTransfer(transferData->transfer_queue,
973 		false);
974 	FreeDescriptorChain(transferData->first_descriptor);
975 	FreeTransferQueue(transferData->transfer_queue);
976 	// TODO: [bonefish] The Free*() calls cause "PMA: provided address resulted
977 	// in invalid index" to be printed, so apparently something is not right.
978 	// Though I have not clue what. This is the same cleanup code as in
979 	// CheckDebugTransfer() that should undo the CreateFilledTransfer() from
980 	// StartDebugTransfer().
981 }
982 
983 
984 status_t
985 UHCI::CancelQueuedTransfers(Pipe *pipe, bool force)
986 {
987 	if (pipe->Type() & USB_OBJECT_ISO_PIPE)
988 		return CancelQueuedIsochronousTransfers(pipe, force);
989 
990 	if (!Lock())
991 		return B_ERROR;
992 
993 	struct transfer_entry {
994 		Transfer *			transfer;
995 		transfer_entry *	next;
996 	};
997 
998 	transfer_entry *list = NULL;
999 	transfer_data *current = fFirstTransfer;
1000 	while (current) {
1001 		if (current->transfer && current->transfer->TransferPipe() == pipe) {
1002 			// clear the active bit so the descriptors are canceled
1003 			uhci_td *descriptor = current->first_descriptor;
1004 			while (descriptor) {
1005 				descriptor->status &= ~TD_STATUS_ACTIVE;
1006 				descriptor = (uhci_td *)descriptor->link_log;
1007 			}
1008 
1009 			transfer_entry *entry
1010 				= (transfer_entry *)malloc(sizeof(transfer_entry));
1011 			if (entry != NULL) {
1012 				entry->transfer = current->transfer;
1013 				current->transfer = NULL;
1014 				entry->next = list;
1015 				list = entry;
1016 			}
1017 
1018 			current->canceled = true;
1019 		}
1020 		current = current->link;
1021 	}
1022 
1023 	Unlock();
1024 
1025 	while (list != NULL) {
1026 		transfer_entry *next = list->next;
1027 
1028 		// if the transfer is canceled by force, the one causing the
1029 		// cancel is possibly not the one who initiated the transfer
1030 		// and the callback is likely not safe anymore
1031 		if (!force)
1032 			list->transfer->Finished(B_CANCELED, 0);
1033 
1034 		delete list->transfer;
1035 		free(list);
1036 		list = next;
1037 	}
1038 
1039 	// wait for any transfers that might have made it before canceling
1040 	while (fProcessingPipe == pipe)
1041 		snooze(1000);
1042 
1043 	// notify the finisher so it can clean up the canceled transfers
1044 	release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1045 	return B_OK;
1046 }
1047 
1048 
1049 status_t
1050 UHCI::CancelQueuedIsochronousTransfers(Pipe *pipe, bool force)
1051 {
1052 	isochronous_transfer_data *current = fFirstIsochronousTransfer;
1053 
1054 	while (current) {
1055 		if (current->transfer->TransferPipe() == pipe) {
1056 			int32 packetCount
1057 				= current->transfer->IsochronousData()->packet_count;
1058 			// Set the active bit off on every descriptor in order to prevent
1059 			// the controller from processing them. Then set off the is_active
1060 			// field of the transfer in order to make the finisher thread skip
1061 			// the transfer. The FinishIsochronousThread will do the rest.
1062 			for (int32 i = 0; i < packetCount; i++)
1063 				current->descriptors[i]->status &= ~TD_STATUS_ACTIVE;
1064 
1065 			// TODO: Use the force paramater in order to avoid calling
1066 			// invalid callbacks
1067 			current->is_active = false;
1068 		}
1069 
1070 		current = current->link;
1071 	}
1072 
1073 	TRACE_ERROR("no isochronous transfer found!\n");
1074 	return B_ERROR;
1075 }
1076 
1077 
1078 status_t
1079 UHCI::SubmitRequest(Transfer *transfer)
1080 {
1081 	Pipe *pipe = transfer->TransferPipe();
1082 	usb_request_data *requestData = transfer->RequestData();
1083 	bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
1084 
1085 	uhci_td *setupDescriptor = CreateDescriptor(pipe, TD_TOKEN_SETUP,
1086 		sizeof(usb_request_data));
1087 
1088 	uhci_td *statusDescriptor = CreateDescriptor(pipe,
1089 		directionIn ? TD_TOKEN_OUT : TD_TOKEN_IN, 0);
1090 
1091 	if (!setupDescriptor || !statusDescriptor) {
1092 		TRACE_ERROR("failed to allocate descriptors\n");
1093 		FreeDescriptor(setupDescriptor);
1094 		FreeDescriptor(statusDescriptor);
1095 		return B_NO_MEMORY;
1096 	}
1097 
1098 	generic_io_vec vector;
1099 	vector.base = (generic_addr_t)requestData;
1100 	vector.length = sizeof(usb_request_data);
1101 	WriteDescriptorChain(setupDescriptor, &vector, 1, false);
1102 
1103 	statusDescriptor->status |= TD_CONTROL_IOC;
1104 	statusDescriptor->token |= TD_TOKEN_DATA1;
1105 	statusDescriptor->link_phy = TD_TERMINATE;
1106 	statusDescriptor->link_log = NULL;
1107 
1108 	uhci_td *dataDescriptor = NULL;
1109 	if (transfer->VectorCount() > 0) {
1110 		uhci_td *lastDescriptor = NULL;
1111 		status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
1112 			&lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
1113 			transfer->FragmentLength());
1114 
1115 		if (result < B_OK) {
1116 			FreeDescriptor(setupDescriptor);
1117 			FreeDescriptor(statusDescriptor);
1118 			return result;
1119 		}
1120 
1121 		if (!directionIn) {
1122 			WriteDescriptorChain(dataDescriptor, transfer->Vector(),
1123 				transfer->VectorCount(), transfer->IsPhysical());
1124 		}
1125 
1126 		LinkDescriptors(setupDescriptor, dataDescriptor);
1127 		LinkDescriptors(lastDescriptor, statusDescriptor);
1128 	} else {
1129 		// Link transfer and status descriptors directly
1130 		LinkDescriptors(setupDescriptor, statusDescriptor);
1131 	}
1132 
1133 	Queue *queue = NULL;
1134 	if (pipe->Speed() == USB_SPEED_LOWSPEED)
1135 		queue = fQueues[UHCI_LOW_SPEED_CONTROL_QUEUE];
1136 	else
1137 		queue = fQueues[UHCI_FULL_SPEED_CONTROL_QUEUE];
1138 
1139 	uhci_qh *transferQueue = CreateTransferQueue(setupDescriptor);
1140 	status_t result = AddPendingTransfer(transfer, queue, transferQueue,
1141 		setupDescriptor, dataDescriptor, directionIn);
1142 	if (result < B_OK) {
1143 		TRACE_ERROR("failed to add pending transfer\n");
1144 		FreeDescriptorChain(setupDescriptor);
1145 		FreeTransferQueue(transferQueue);
1146 		return result;
1147 	}
1148 
1149 	queue->AppendTransfer(transferQueue);
1150 	return B_OK;
1151 }
1152 
1153 
1154 status_t
1155 UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue,
1156 	uhci_qh *transferQueue, uhci_td *firstDescriptor, uhci_td *dataDescriptor,
1157 	bool directionIn)
1158 {
1159 	if (!transfer || !queue || !transferQueue || !firstDescriptor)
1160 		return B_BAD_VALUE;
1161 
1162 	transfer_data *data = new(std::nothrow) transfer_data;
1163 	if (!data)
1164 		return B_NO_MEMORY;
1165 
1166 	status_t result = transfer->InitKernelAccess();
1167 	if (result < B_OK) {
1168 		delete data;
1169 		return result;
1170 	}
1171 
1172 	data->transfer = transfer;
1173 	data->queue = queue;
1174 	data->transfer_queue = transferQueue;
1175 	data->first_descriptor = firstDescriptor;
1176 	data->data_descriptor = dataDescriptor;
1177 	data->incoming = directionIn;
1178 	data->canceled = false;
1179 	data->link = NULL;
1180 
1181 	if (!Lock()) {
1182 		delete data;
1183 		return B_ERROR;
1184 	}
1185 
1186 	// We do not support queuing other transfers in tandem with a fragmented one.
1187 	transfer_data *it = fFirstTransfer;
1188 	while (it) {
1189 		if (it->transfer && it->transfer->TransferPipe() == transfer->TransferPipe()
1190 				&& it->transfer->IsFragmented()) {
1191 			TRACE_ERROR("cannot submit transfer: a fragmented transfer is queued\n");
1192 
1193 			Unlock();
1194 			delete data;
1195 			return B_DEV_RESOURCE_CONFLICT;
1196 		}
1197 
1198 		it = it->link;
1199 	}
1200 
1201 	if (fLastTransfer)
1202 		fLastTransfer->link = data;
1203 	if (!fFirstTransfer)
1204 		fFirstTransfer = data;
1205 
1206 	fLastTransfer = data;
1207 	Unlock();
1208 	return B_OK;
1209 }
1210 
1211 
1212 status_t
1213 UHCI::AddPendingIsochronousTransfer(Transfer *transfer, uhci_td **isoRequest,
1214 	bool directionIn)
1215 {
1216 	if (!transfer || !isoRequest)
1217 		return B_BAD_VALUE;
1218 
1219 	isochronous_transfer_data *data
1220 		= new(std::nothrow) isochronous_transfer_data;
1221 	if (!data)
1222 		return B_NO_MEMORY;
1223 
1224 	status_t result = transfer->InitKernelAccess();
1225 	if (result < B_OK) {
1226 		delete data;
1227 		return result;
1228 	}
1229 
1230 	data->transfer = transfer;
1231 	data->descriptors = isoRequest;
1232 	data->last_to_process = transfer->IsochronousData()->packet_count - 1;
1233 	data->incoming = directionIn;
1234 	data->is_active = true;
1235 	data->link = NULL;
1236 
1237 	// Put in the isochronous transfer list
1238 	if (!LockIsochronous()) {
1239 		delete data;
1240 		return B_ERROR;
1241 	}
1242 
1243 	if (fLastIsochronousTransfer)
1244 		fLastIsochronousTransfer->link = data;
1245 	if (!fFirstIsochronousTransfer)
1246 		fFirstIsochronousTransfer = data;
1247 
1248 	fLastIsochronousTransfer = data;
1249 	UnlockIsochronous();
1250 	return B_OK;
1251 }
1252 
1253 
1254 status_t
1255 UHCI::SubmitIsochronous(Transfer *transfer)
1256 {
1257 	Pipe *pipe = transfer->TransferPipe();
1258 	bool directionIn = (pipe->Direction() == Pipe::In);
1259 	usb_isochronous_data *isochronousData = transfer->IsochronousData();
1260 	size_t packetSize = transfer->DataLength();
1261 	size_t restSize = packetSize % isochronousData->packet_count;
1262 	packetSize /= isochronousData->packet_count;
1263 	uint16 currentFrame;
1264 
1265 	if (packetSize > pipe->MaxPacketSize()) {
1266 		TRACE_ERROR("isochronous packetSize is bigger than pipe MaxPacketSize\n");
1267 		return B_BAD_VALUE;
1268 	}
1269 
1270 	// Ignore the fact that the last descriptor might need less bandwidth.
1271 	// The overhead is not worthy.
1272 	uint16 bandwidth = transfer->Bandwidth() / isochronousData->packet_count;
1273 
1274 	TRACE("isochronous transfer descriptor bandwidth %d\n", bandwidth);
1275 
1276 	// The following holds the list of transfer descriptor of the
1277 	// isochronous request. It is used to quickly remove all the isochronous
1278 	// descriptors from the frame list, as descriptors are not link to each
1279 	// other in a queue like for every other transfer.
1280 	uhci_td **isoRequest
1281 		= new(std::nothrow) uhci_td *[isochronousData->packet_count];
1282 	if (isoRequest == NULL) {
1283 		TRACE("failed to create isoRequest array!\n");
1284 		return B_NO_MEMORY;
1285 	}
1286 
1287 	// Create the list of transfer descriptors
1288 	for (uint32 i = 0; i < (isochronousData->packet_count - 1); i++) {
1289 		isoRequest[i] = CreateDescriptor(pipe,
1290 			directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT, packetSize);
1291 		// If we ran out of memory, clean up and return
1292 		if (isoRequest[i] == NULL) {
1293 			for (uint32 j = 0; j < i; j++)
1294 				FreeDescriptor(isoRequest[j]);
1295 			delete [] isoRequest;
1296 			return B_NO_MEMORY;
1297 		}
1298 		// Make sure data toggle is set to zero
1299 		isoRequest[i]->token &= ~TD_TOKEN_DATA1;
1300 	}
1301 
1302 	// Create the last transfer descriptor which should be of smaller size
1303 	// and set the IOC bit
1304 	isoRequest[isochronousData->packet_count - 1] = CreateDescriptor(pipe,
1305 		directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
1306 		(restSize) ? restSize : packetSize);
1307 	// If we are that unlucky...
1308 	if (!isoRequest[isochronousData->packet_count - 1]) {
1309 		for (uint32 i = 0; i < (isochronousData->packet_count - 2); i++)
1310 			FreeDescriptor(isoRequest[i]);
1311 		delete [] isoRequest;
1312 		return B_NO_MEMORY;
1313 	}
1314 	isoRequest[isochronousData->packet_count - 1]->token &= ~TD_TOKEN_DATA1;
1315 
1316 	// If direction is out set every descriptor data
1317 	if (!directionIn) {
1318 		generic_io_vec *vector = transfer->Vector();
1319 		WriteIsochronousDescriptorChain(isoRequest,
1320 			isochronousData->packet_count, vector);
1321 	}
1322 
1323 	TRACE("isochronous submitted size=%ld bytes, TDs=%" B_PRId32 ", "
1324 		"packetSize=%ld, restSize=%ld\n", transfer->DataLength(),
1325 		isochronousData->packet_count, packetSize, restSize);
1326 
1327 	// Find the entry where to start inserting the first Isochronous descriptor
1328 	if (isochronousData->flags & USB_ISO_ASAP ||
1329 		isochronousData->starting_frame_number == NULL) {
1330 		// find the first available frame with enough bandwidth.
1331 		// This should always be the case, as defining the starting frame
1332 		// number in the driver makes no sense for many reason, one of which
1333 		// is that frame numbers value are host controller specific, and the
1334 		// driver does not know which host controller is running.
1335 		currentFrame = ReadReg16(UHCI_FRNUM);
1336 
1337 		// Make sure that:
1338 		// 1. We are at least 5ms ahead the controller
1339 		// 2. We stay in the range 0-1023
1340 		// 3. There is enough bandwidth in the first entry
1341 		currentFrame = (currentFrame + 5) % NUMBER_OF_FRAMES;
1342 	} else {
1343 		// Find out if the frame number specified has enough bandwidth,
1344 		// otherwise find the first next available frame with enough bandwidth
1345 		currentFrame = *isochronousData->starting_frame_number;
1346 	}
1347 
1348 	// Find the first entry with enough bandwidth
1349 	// TODO: should we also check the bandwidth of the following packet_count frames?
1350 	uint16 startSeekingFromFrame = currentFrame;
1351 	while (fFrameBandwidth[currentFrame] < bandwidth) {
1352 		currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
1353 		if (currentFrame == startSeekingFromFrame) {
1354 			TRACE_ERROR("not enough bandwidth to queue the isochronous request");
1355 			for (uint32 i = 0; i < isochronousData->packet_count; i++)
1356 				FreeDescriptor(isoRequest[i]);
1357 			delete [] isoRequest;
1358 		return B_ERROR;
1359 		}
1360 	}
1361 
1362 	if (isochronousData->starting_frame_number)
1363 		*isochronousData->starting_frame_number = currentFrame;
1364 
1365 	// Add transfer to the list
1366 	status_t result = AddPendingIsochronousTransfer(transfer, isoRequest,
1367 		directionIn);
1368 	if (result < B_OK) {
1369 		TRACE_ERROR("failed to add pending isochronous transfer\n");
1370 		for (uint32 i = 0; i < isochronousData->packet_count; i++)
1371 			FreeDescriptor(isoRequest[i]);
1372 		delete [] isoRequest;
1373 		return result;
1374 	}
1375 
1376 	TRACE("appended isochronous transfer by starting at frame number %d\n",
1377 		currentFrame);
1378 
1379 	// Insert the Transfer Descriptor by starting at
1380 	// the starting_frame_number entry
1381 	// TODO: We don't consider bInterval, and assume it's 1!
1382 	for (uint32 i = 0; i < isochronousData->packet_count; i++) {
1383 		result = LinkIsochronousDescriptor(isoRequest[i], currentFrame);
1384 		if (result < B_OK) {
1385 			TRACE_ERROR("failed to add pending isochronous transfer\n");
1386 			for (uint32 i = 0; i < isochronousData->packet_count; i++)
1387 				FreeDescriptor(isoRequest[i]);
1388 			delete [] isoRequest;
1389 			return result;
1390 		}
1391 
1392 		fFrameBandwidth[currentFrame] -= bandwidth;
1393 		currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
1394 	}
1395 
1396 	// Wake up the isochronous finisher thread
1397 	release_sem_etc(fFinishIsochronousTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1398 
1399 	return B_OK;
1400 }
1401 
1402 
1403 isochronous_transfer_data *
1404 UHCI::FindIsochronousTransfer(uhci_td *descriptor)
1405 {
1406 	// Simply check every last descriptor of the isochronous transfer list
1407 	if (LockIsochronous()) {
1408 		isochronous_transfer_data *transfer = fFirstIsochronousTransfer;
1409 		if (transfer) {
1410 			while (transfer->descriptors[transfer->last_to_process]
1411 				!= descriptor) {
1412 				transfer = transfer->link;
1413 				if (!transfer)
1414 					break;
1415 			}
1416 		}
1417 		UnlockIsochronous();
1418 		return transfer;
1419 	}
1420 	return NULL;
1421 }
1422 
1423 
1424 status_t
1425 UHCI::LinkIsochronousDescriptor(uhci_td *descriptor, uint16 frame)
1426 {
1427 	// The transfer descriptor is appended to the last
1428 	// existing isochronous transfer descriptor (if any)
1429 	// in that frame.
1430 	if (LockIsochronous()) {
1431 		if (!fFirstIsochronousDescriptor[frame]) {
1432 			// Insert the transfer descriptor in the first position
1433 			fFrameList[frame] = descriptor->this_phy & ~FRAMELIST_NEXT_IS_QH;
1434 			fFirstIsochronousDescriptor[frame] = descriptor;
1435 			fLastIsochronousDescriptor[frame] = descriptor;
1436 		} else {
1437 			// Append to the last transfer descriptor
1438 			fLastIsochronousDescriptor[frame]->link_log = descriptor;
1439 			fLastIsochronousDescriptor[frame]->link_phy
1440 				= descriptor->this_phy & ~TD_NEXT_IS_QH;
1441 			fLastIsochronousDescriptor[frame] = descriptor;
1442 		}
1443 
1444 		descriptor->link_phy
1445 			= fQueues[UHCI_INTERRUPT_QUEUE]->PhysicalAddress() | TD_NEXT_IS_QH;
1446 		UnlockIsochronous();
1447 		return B_OK;
1448 	}
1449 	return B_ERROR;
1450 }
1451 
1452 
1453 uhci_td *
1454 UHCI::UnlinkIsochronousDescriptor(uint16 frame)
1455 {
1456 	// We always unlink from the top
1457 	if (LockIsochronous()) {
1458 		uhci_td *descriptor = fFirstIsochronousDescriptor[frame];
1459 		if (descriptor) {
1460 			// The descriptor will be freed later.
1461 			fFrameList[frame] = descriptor->link_phy;
1462 			if (descriptor->link_log) {
1463 				fFirstIsochronousDescriptor[frame]
1464 					= (uhci_td *)descriptor->link_log;
1465 			} else {
1466 				fFirstIsochronousDescriptor[frame] = NULL;
1467 				fLastIsochronousDescriptor[frame] = NULL;
1468 			}
1469 		}
1470 		UnlockIsochronous();
1471 		return descriptor;
1472 	}
1473 	return NULL;
1474 }
1475 
1476 
1477 int32
1478 UHCI::FinishThread(void *data)
1479 {
1480 	((UHCI *)data)->FinishTransfers();
1481 	return B_OK;
1482 }
1483 
1484 
1485 void
1486 UHCI::FinishTransfers()
1487 {
1488 	while (!fStopThreads) {
1489 		if (acquire_sem(fFinishTransfersSem) < B_OK)
1490 			continue;
1491 
1492 		// eat up sems that have been released by multiple interrupts
1493 		int32 semCount = 0;
1494 		get_sem_count(fFinishTransfersSem, &semCount);
1495 		if (semCount > 0)
1496 			acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
1497 
1498 		if (!Lock())
1499 			continue;
1500 
1501 		TRACE("finishing transfers (first transfer: 0x%08lx; last"
1502 			" transfer: 0x%08lx)\n", (addr_t)fFirstTransfer,
1503 			(addr_t)fLastTransfer);
1504 		transfer_data *lastTransfer = NULL;
1505 		transfer_data *transfer = fFirstTransfer;
1506 		Unlock();
1507 
1508 		while (transfer) {
1509 			bool transferDone = false;
1510 			uhci_td *descriptor = transfer->first_descriptor;
1511 			status_t callbackStatus = B_OK;
1512 
1513 			while (descriptor) {
1514 				uint32 status = descriptor->status;
1515 				if (status & TD_STATUS_ACTIVE) {
1516 					// still in progress
1517 					TRACE("td (0x%08" B_PRIx32 ") still active\n",
1518 						descriptor->this_phy);
1519 					break;
1520 				}
1521 
1522 				if (status & TD_ERROR_MASK) {
1523 					// an error occured
1524 					TRACE_ERROR("td (0x%08" B_PRIx32 ") error: status: 0x%08"
1525 						B_PRIx32 "; token: 0x%08" B_PRIx32 ";\n",
1526 						descriptor->this_phy, status, descriptor->token);
1527 
1528 					uint8 errorCount = status >> TD_ERROR_COUNT_SHIFT;
1529 					errorCount &= TD_ERROR_COUNT_MASK;
1530 					if (errorCount == 0) {
1531 						// the error counter counted down to zero, report why
1532 						int32 reasons = 0;
1533 						if (status & TD_STATUS_ERROR_BUFFER) {
1534 							callbackStatus = transfer->incoming ? B_DEV_WRITE_ERROR : B_DEV_READ_ERROR;
1535 							reasons++;
1536 						}
1537 						if (status & TD_STATUS_ERROR_TIMEOUT) {
1538 							callbackStatus = transfer->incoming ? B_DEV_CRC_ERROR : B_TIMED_OUT;
1539 							reasons++;
1540 						}
1541 						if (status & TD_STATUS_ERROR_NAK) {
1542 							callbackStatus = B_DEV_UNEXPECTED_PID;
1543 							reasons++;
1544 						}
1545 						if (status & TD_STATUS_ERROR_BITSTUFF) {
1546 							callbackStatus = B_DEV_CRC_ERROR;
1547 							reasons++;
1548 						}
1549 
1550 						if (reasons > 1)
1551 							callbackStatus = B_DEV_MULTIPLE_ERRORS;
1552 					} else if (status & TD_STATUS_ERROR_BABBLE) {
1553 						// there is a babble condition
1554 						callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN;
1555 					} else {
1556 						// if the error counter didn't count down to zero
1557 						// and there was no babble, then this halt was caused
1558 						// by a stall handshake
1559 						callbackStatus = B_DEV_STALLED;
1560 					}
1561 
1562 					transferDone = true;
1563 					break;
1564 				}
1565 
1566 				if ((descriptor->link_phy & TD_TERMINATE)
1567 					|| ((descriptor->status & TD_CONTROL_SPD) != 0
1568 						&& uhci_td_actual_length(descriptor)
1569 							< uhci_td_maximum_length(descriptor))) {
1570 					// all descriptors are done, or we have a short packet
1571 					TRACE("td (0x%08" B_PRIx32 ") ok\n", descriptor->this_phy);
1572 					callbackStatus = B_OK;
1573 					transferDone = true;
1574 					break;
1575 				}
1576 
1577 				descriptor = (uhci_td *)descriptor->link_log;
1578 			}
1579 
1580 			if (!transferDone) {
1581 				lastTransfer = transfer;
1582 				transfer = transfer->link;
1583 				continue;
1584 			}
1585 
1586 			// remove the transfer from the list first so we are sure
1587 			// it doesn't get canceled while we still process it
1588 			transfer_data *next = transfer->link;
1589 			if (Lock()) {
1590 				if (lastTransfer)
1591 					lastTransfer->link = transfer->link;
1592 
1593 				if (transfer == fFirstTransfer)
1594 					fFirstTransfer = transfer->link;
1595 				if (transfer == fLastTransfer)
1596 					fLastTransfer = lastTransfer;
1597 
1598 				// store the currently processing pipe here so we can wait
1599 				// in cancel if we are processing something on the target pipe
1600 				if (!transfer->canceled)
1601 					fProcessingPipe = transfer->transfer->TransferPipe();
1602 
1603 				transfer->link = NULL;
1604 				Unlock();
1605 			}
1606 
1607 			// if canceled the callback has already been called
1608 			if (!transfer->canceled) {
1609 				size_t actualLength = 0;
1610 				if (callbackStatus == B_OK) {
1611 					uint8 lastDataToggle = 0;
1612 					if (transfer->data_descriptor && transfer->incoming) {
1613 						// data to read out
1614 						generic_io_vec *vector = transfer->transfer->Vector();
1615 						size_t vectorCount = transfer->transfer->VectorCount();
1616 
1617 						transfer->transfer->PrepareKernelAccess();
1618 						actualLength = ReadDescriptorChain(
1619 							transfer->data_descriptor,
1620 							vector, vectorCount, transfer->transfer->IsPhysical(),
1621 							&lastDataToggle);
1622 					} else if (transfer->data_descriptor) {
1623 						// read the actual length that was sent
1624 						actualLength = ReadActualLength(
1625 							transfer->data_descriptor, &lastDataToggle);
1626 					}
1627 
1628 					transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
1629 
1630 					if (transfer->transfer->IsFragmented()) {
1631 						// this transfer may still have data left
1632 						TRACE("advancing fragmented transfer\n");
1633 						transfer->transfer->AdvanceByFragment(actualLength);
1634 						if (transfer->transfer->FragmentLength() > 0) {
1635 							TRACE("still %ld bytes left on transfer\n",
1636 								transfer->transfer->FragmentLength());
1637 
1638 							Transfer *resubmit = transfer->transfer;
1639 
1640 							// free the used descriptors
1641 							transfer->queue->RemoveTransfer(
1642 								transfer->transfer_queue);
1643 							AddToFreeList(transfer);
1644 
1645 							// resubmit the advanced transfer so the rest
1646 							// of the buffers are transmitted over the bus
1647 							resubmit->PrepareKernelAccess();
1648 							if (SubmitTransfer(resubmit) != B_OK)
1649 								resubmit->Finished(B_ERROR, 0);
1650 
1651 							transfer = next;
1652 							continue;
1653 						}
1654 
1655 						// the transfer is done, but we already set the
1656 						// actualLength with AdvanceByFragment()
1657 						actualLength = 0;
1658 					}
1659 				}
1660 
1661 				transfer->transfer->Finished(callbackStatus, actualLength);
1662 				fProcessingPipe = NULL;
1663 			}
1664 
1665 			// remove and free the hardware queue and its descriptors
1666 			transfer->queue->RemoveTransfer(transfer->transfer_queue);
1667 			delete transfer->transfer;
1668 			AddToFreeList(transfer);
1669 			transfer = next;
1670 		}
1671 	}
1672 }
1673 
1674 
1675 void
1676 UHCI::AddToFreeList(transfer_data *transfer)
1677 {
1678 	transfer->free_after_frame = ReadReg16(UHCI_FRNUM);
1679 	if (!Lock())
1680 		return;
1681 
1682 	transfer->link = fFreeList;
1683 	fFreeList = transfer;
1684 	Unlock();
1685 
1686 	if (atomic_add(&fCleanupCount, 1) == 0)
1687 		release_sem(fCleanupSem);
1688 }
1689 
1690 
1691 int32
1692 UHCI::CleanupThread(void *data)
1693 {
1694 	((UHCI *)data)->Cleanup();
1695 	return B_OK;
1696 }
1697 
1698 
1699 void
1700 UHCI::Cleanup()
1701 {
1702 	while (!fStopThreads) {
1703 		if (acquire_sem(fCleanupSem) != B_OK)
1704 			continue;
1705 
1706 		bigtime_t nextTime = system_time() + 1000;
1707 		while (atomic_get(&fCleanupCount) != 0) {
1708 			// wait for the frame to pass
1709 			snooze_until(nextTime, B_SYSTEM_TIMEBASE);
1710 			nextTime += 1000;
1711 
1712 			if (!Lock())
1713 				continue;
1714 
1715 			// find the first entry we may free
1716 			transfer_data **link = &fFreeList;
1717 			transfer_data *transfer = fFreeList;
1718 			uint16 frameNumber = ReadReg16(UHCI_FRNUM);
1719 			while (transfer) {
1720 				if (transfer->free_after_frame != frameNumber) {
1721 					*link = NULL;
1722 					break;
1723 				}
1724 
1725 				link = &transfer->link;
1726 				transfer = transfer->link;
1727 			}
1728 
1729 			Unlock();
1730 
1731 			// the transfers below this one are all freeable
1732 			while (transfer) {
1733 				transfer_data *next = transfer->link;
1734 				FreeDescriptorChain(transfer->first_descriptor);
1735 				FreeTransferQueue(transfer->transfer_queue);
1736 				delete transfer;
1737 				atomic_add(&fCleanupCount, -1);
1738 				transfer = next;
1739 			}
1740 		}
1741 	}
1742 }
1743 
1744 
1745 int32
1746 UHCI::FinishIsochronousThread(void *data)
1747 {
1748        ((UHCI *)data)->FinishIsochronousTransfers();
1749        return B_OK;
1750 }
1751 
1752 
1753 void
1754 UHCI::FinishIsochronousTransfers()
1755 {
1756 	/* This thread stays one position behind the controller and processes every
1757 	 * isochronous descriptor. Once it finds the last isochronous descriptor
1758 	 * of a transfer, it processes the entire transfer.
1759 	 */
1760 
1761 	while (!fStopThreads) {
1762 		// Go to sleep if there are not isochronous transfer to process
1763 		if (acquire_sem(fFinishIsochronousTransfersSem) < B_OK)
1764 			return;
1765 
1766 		bool transferDone = false;
1767 		uint16 currentFrame = ReadReg16(UHCI_FRNUM);
1768 
1769 		// Process the frame list until one transfer is processed
1770 		while (!transferDone) {
1771 			// wait 1ms in order to be sure to be one position behind
1772 			// the controller
1773 			if (currentFrame == ReadReg16(UHCI_FRNUM))
1774 				snooze(1000);
1775 
1776 			// Process the frame till it has isochronous descriptors in it.
1777 			while (!(fFrameList[currentFrame] & FRAMELIST_NEXT_IS_QH)) {
1778 				uhci_td *current = UnlinkIsochronousDescriptor(currentFrame);
1779 
1780 				// Process the transfer if we found the last descriptor
1781 				isochronous_transfer_data *transfer
1782 					= FindIsochronousTransfer(current);
1783 					// Process the descriptors only if it is still active and
1784 					// belongs to an inbound transfer. If the transfer is not
1785 					// active, it means the request has been removed, so simply
1786 					// remove the descriptors.
1787 				if (transfer && transfer->is_active) {
1788 					if (current->token & TD_TOKEN_IN) {
1789 						generic_io_vec *vector = transfer->transfer->Vector();
1790 						transfer->transfer->PrepareKernelAccess();
1791 						ReadIsochronousDescriptorChain(transfer, vector);
1792 					}
1793 
1794 					// Remove the transfer
1795 					if (LockIsochronous()) {
1796 						if (transfer == fFirstIsochronousTransfer) {
1797 							fFirstIsochronousTransfer = transfer->link;
1798 							if (transfer == fLastIsochronousTransfer)
1799 								fLastIsochronousTransfer = NULL;
1800 						} else {
1801 							isochronous_transfer_data *temp
1802 								= fFirstIsochronousTransfer;
1803 							while (transfer != temp->link)
1804 								temp = temp->link;
1805 
1806 							if (transfer == fLastIsochronousTransfer)
1807 								fLastIsochronousTransfer = temp;
1808 							temp->link = temp->link->link;
1809 						}
1810 						UnlockIsochronous();
1811 					}
1812 
1813 					transfer->transfer->Finished(B_OK, 0);
1814 
1815 					uint32 packetCount =
1816 						transfer->transfer->IsochronousData()->packet_count;
1817 					for (uint32 i = 0; i < packetCount; i++)
1818 						FreeDescriptor(transfer->descriptors[i]);
1819 
1820 					delete [] transfer->descriptors;
1821 					delete transfer->transfer;
1822 					delete transfer;
1823 					transferDone = true;
1824 				}
1825 			}
1826 
1827 			// Make sure to reset the frame bandwidth
1828 			fFrameBandwidth[currentFrame] = MAX_AVAILABLE_BANDWIDTH;
1829 			currentFrame = (currentFrame + 1) % NUMBER_OF_FRAMES;
1830 		}
1831 	}
1832 }
1833 
1834 
1835 void
1836 UHCI::GlobalReset()
1837 {
1838 	uint8 sofValue = ReadReg8(UHCI_SOFMOD);
1839 
1840 	WriteReg16(UHCI_USBCMD, UHCI_USBCMD_GRESET);
1841 	snooze(100000);
1842 	WriteReg16(UHCI_USBCMD, 0);
1843 	snooze(10000);
1844 
1845 	WriteReg8(UHCI_SOFMOD, sofValue);
1846 }
1847 
1848 
1849 status_t
1850 UHCI::ControllerReset()
1851 {
1852 	WriteReg16(UHCI_USBCMD, UHCI_USBCMD_HCRESET);
1853 
1854 	int32 tries = 5;
1855 	while (ReadReg16(UHCI_USBCMD) & UHCI_USBCMD_HCRESET) {
1856 		snooze(10000);
1857 		if (tries-- < 0)
1858 			return B_ERROR;
1859 	}
1860 
1861 	return B_OK;
1862 }
1863 
1864 
1865 status_t
1866 UHCI::GetPortStatus(uint8 index, usb_port_status *status)
1867 {
1868 	if (index > 1)
1869 		return B_BAD_INDEX;
1870 
1871 	status->status = status->change = 0;
1872 	uint16 portStatus = ReadReg16(UHCI_PORTSC1 + index * 2);
1873 
1874 	// build the status
1875 	if (portStatus & UHCI_PORTSC_CURSTAT)
1876 		status->status |= PORT_STATUS_CONNECTION;
1877 	if (portStatus & UHCI_PORTSC_ENABLED)
1878 		status->status |= PORT_STATUS_ENABLE;
1879 	if (portStatus & UHCI_PORTSC_RESET)
1880 		status->status |= PORT_STATUS_RESET;
1881 	if (portStatus & UHCI_PORTSC_LOWSPEED)
1882 		status->status |= PORT_STATUS_LOW_SPEED;
1883 
1884 	// build the change
1885 	if (portStatus & UHCI_PORTSC_STATCHA)
1886 		status->change |= PORT_STATUS_CONNECTION;
1887 	if (portStatus & UHCI_PORTSC_ENABCHA)
1888 		status->change |= PORT_STATUS_ENABLE;
1889 
1890 	// ToDo: work out suspended/resume
1891 
1892 	// there are no bits to indicate reset change
1893 	if (fPortResetChange & (1 << index))
1894 		status->change |= PORT_STATUS_RESET;
1895 
1896 	// the port is automagically powered on
1897 	status->status |= PORT_STATUS_POWER;
1898 	return B_OK;
1899 }
1900 
1901 
1902 status_t
1903 UHCI::SetPortFeature(uint8 index, uint16 feature)
1904 {
1905 	if (index > 1)
1906 		return B_BAD_INDEX;
1907 
1908 	switch (feature) {
1909 		case PORT_RESET:
1910 			return ResetPort(index);
1911 
1912 		case PORT_POWER:
1913 			// the ports are automatically powered
1914 			return B_OK;
1915 	}
1916 
1917 	return B_BAD_VALUE;
1918 }
1919 
1920 
1921 status_t
1922 UHCI::ClearPortFeature(uint8 index, uint16 feature)
1923 {
1924 	if (index > 1)
1925 		return B_BAD_INDEX;
1926 
1927 	uint32 portRegister = UHCI_PORTSC1 + index * 2;
1928 	uint16 portStatus = ReadReg16(portRegister) & UHCI_PORTSC_DATAMASK;
1929 
1930 	switch (feature) {
1931 		case C_PORT_RESET:
1932 			fPortResetChange &= ~(1 << index);
1933 			return B_OK;
1934 
1935 		case C_PORT_CONNECTION:
1936 			WriteReg16(portRegister, portStatus | UHCI_PORTSC_STATCHA);
1937 			return B_OK;
1938 
1939 		case C_PORT_ENABLE:
1940 			WriteReg16(portRegister, portStatus | UHCI_PORTSC_ENABCHA);
1941 			return B_OK;
1942 	}
1943 
1944 	return B_BAD_VALUE;
1945 }
1946 
1947 
1948 status_t
1949 UHCI::ResetPort(uint8 index)
1950 {
1951 	if (index > 1)
1952 		return B_BAD_INDEX;
1953 
1954 	TRACE("reset port %d\n", index);
1955 
1956 	uint32 port = UHCI_PORTSC1 + index * 2;
1957 	uint16 status = ReadReg16(port);
1958 	status &= UHCI_PORTSC_DATAMASK;
1959 	WriteReg16(port, status | UHCI_PORTSC_RESET);
1960 	snooze(250000);
1961 
1962 	status = ReadReg16(port);
1963 	status &= UHCI_PORTSC_DATAMASK;
1964 	WriteReg16(port, status & ~UHCI_PORTSC_RESET);
1965 	snooze(1000);
1966 
1967 	for (int32 i = 10; i > 0; i--) {
1968 		// try to enable the port
1969 		status = ReadReg16(port);
1970 		status &= UHCI_PORTSC_DATAMASK;
1971 		WriteReg16(port, status | UHCI_PORTSC_ENABLED);
1972 		snooze(50000);
1973 
1974 		status = ReadReg16(port);
1975 
1976 		if ((status & UHCI_PORTSC_CURSTAT) == 0) {
1977 			// no device connected. since we waited long enough we can assume
1978 			// that the port was reset and no device is connected.
1979 			break;
1980 		}
1981 
1982 		if (status & (UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA)) {
1983 			// port enabled changed or connection status were set.
1984 			// acknowledge either / both and wait again.
1985 			status &= UHCI_PORTSC_DATAMASK;
1986 			WriteReg16(port, status | UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA);
1987 			continue;
1988 		}
1989 
1990 		if (status & UHCI_PORTSC_ENABLED) {
1991 			// the port is enabled
1992 			break;
1993 		}
1994 	}
1995 
1996 	fPortResetChange |= (1 << index);
1997 	TRACE("port was reset: 0x%04x\n", ReadReg16(port));
1998 	return B_OK;
1999 }
2000 
2001 
2002 int32
2003 UHCI::InterruptHandler(void *data)
2004 {
2005 	return ((UHCI *)data)->Interrupt();
2006 }
2007 
2008 
2009 int32
2010 UHCI::Interrupt()
2011 {
2012 	static spinlock lock = B_SPINLOCK_INITIALIZER;
2013 	acquire_spinlock(&lock);
2014 
2015 	// Check if we really had an interrupt
2016 	uint16 status = ReadReg16(UHCI_USBSTS);
2017 	if ((status & fEnabledInterrupts) == 0) {
2018 		if (status != 0) {
2019 			TRACE("discarding not enabled interrupts 0x%08x\n", status);
2020 			WriteReg16(UHCI_USBSTS, status);
2021 		}
2022 
2023 		release_spinlock(&lock);
2024 		return B_UNHANDLED_INTERRUPT;
2025 	}
2026 
2027 	uint16 acknowledge = 0;
2028 	bool finishTransfers = false;
2029 	int32 result = B_HANDLED_INTERRUPT;
2030 
2031 	if (status & UHCI_USBSTS_USBINT) {
2032 		TRACE_MODULE("transfer finished\n");
2033 		acknowledge |= UHCI_USBSTS_USBINT;
2034 		result = B_INVOKE_SCHEDULER;
2035 		finishTransfers = true;
2036 	}
2037 
2038 	if (status & UHCI_USBSTS_ERRINT) {
2039 		TRACE_MODULE("transfer error\n");
2040 		acknowledge |= UHCI_USBSTS_ERRINT;
2041 		result = B_INVOKE_SCHEDULER;
2042 		finishTransfers = true;
2043 	}
2044 
2045 	if (status & UHCI_USBSTS_RESDET) {
2046 		TRACE_MODULE("resume detected\n");
2047 		acknowledge |= UHCI_USBSTS_RESDET;
2048 	}
2049 
2050 	if (status & UHCI_USBSTS_HOSTERR) {
2051 		TRACE_MODULE_ERROR("host system error\n");
2052 		acknowledge |= UHCI_USBSTS_HOSTERR;
2053 	}
2054 
2055 	if (status & UHCI_USBSTS_HCPRERR) {
2056 		TRACE_MODULE_ERROR("process error\n");
2057 		acknowledge |= UHCI_USBSTS_HCPRERR;
2058 	}
2059 
2060 	if (status & UHCI_USBSTS_HCHALT) {
2061 		TRACE_MODULE_ERROR("host controller halted\n");
2062 		// at least disable interrupts so we do not flood the system
2063 		WriteReg16(UHCI_USBINTR, 0);
2064 		fEnabledInterrupts = 0;
2065 		// ToDo: cancel all transfers and reset the host controller
2066 		// acknowledge not needed
2067 	}
2068 
2069 	if (acknowledge)
2070 		WriteReg16(UHCI_USBSTS, acknowledge);
2071 
2072 	release_spinlock(&lock);
2073 
2074 	if (finishTransfers)
2075 		release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
2076 
2077 	return result;
2078 }
2079 
2080 
2081 status_t
2082 UHCI::CreateFilledTransfer(Transfer *transfer, uhci_td **_firstDescriptor,
2083 	uhci_qh **_transferQueue)
2084 {
2085 	Pipe *pipe = transfer->TransferPipe();
2086 	bool directionIn = (pipe->Direction() == Pipe::In);
2087 
2088 	uhci_td *firstDescriptor = NULL;
2089 	uhci_td *lastDescriptor = NULL;
2090 	status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
2091 		&lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
2092 		transfer->FragmentLength());
2093 
2094 	if (result < B_OK)
2095 		return result;
2096 	if (!firstDescriptor || !lastDescriptor)
2097 		return B_NO_MEMORY;
2098 
2099 	lastDescriptor->status |= TD_CONTROL_IOC;
2100 	lastDescriptor->link_phy = TD_TERMINATE;
2101 	lastDescriptor->link_log = NULL;
2102 
2103 	if (!directionIn) {
2104 		WriteDescriptorChain(firstDescriptor, transfer->Vector(),
2105 			transfer->VectorCount(), transfer->IsPhysical());
2106 	}
2107 
2108 	uhci_qh *transferQueue = CreateTransferQueue(firstDescriptor);
2109 	if (!transferQueue) {
2110 		FreeDescriptorChain(firstDescriptor);
2111 		return B_NO_MEMORY;
2112 	}
2113 
2114 	*_firstDescriptor = firstDescriptor;
2115 	*_transferQueue = transferQueue;
2116 	return B_OK;
2117 }
2118 
2119 
2120 uhci_qh *
2121 UHCI::CreateTransferQueue(uhci_td *descriptor)
2122 {
2123 	uhci_qh *queueHead;
2124 	phys_addr_t physicalAddress;
2125 	if (fStack->AllocateChunk((void **)&queueHead, &physicalAddress,
2126 		sizeof(uhci_qh)) < B_OK)
2127 		return NULL;
2128 
2129 	queueHead->this_phy = (uint32)physicalAddress;
2130 	queueHead->element_phy = descriptor->this_phy;
2131 	return queueHead;
2132 }
2133 
2134 
2135 void
2136 UHCI::FreeTransferQueue(uhci_qh *queueHead)
2137 {
2138 	if (!queueHead)
2139 		return;
2140 
2141 	fStack->FreeChunk(queueHead, queueHead->this_phy, sizeof(uhci_qh));
2142 }
2143 
2144 
2145 uhci_td *
2146 UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, size_t bufferSize)
2147 {
2148 	uhci_td *result;
2149 	phys_addr_t physicalAddress;
2150 
2151 	if (fStack->AllocateChunk((void **)&result, &physicalAddress,
2152 		sizeof(uhci_td)) < B_OK) {
2153 		TRACE_ERROR("failed to allocate a transfer descriptor\n");
2154 		return NULL;
2155 	}
2156 
2157 	result->this_phy = (uint32)physicalAddress;
2158 	result->status = TD_STATUS_ACTIVE;
2159 	if (pipe->Type() & USB_OBJECT_ISO_PIPE)
2160 		result->status |= TD_CONTROL_ISOCHRONOUS;
2161 	else {
2162 		result->status |= TD_CONTROL_3_ERRORS;
2163 		if (direction == TD_TOKEN_IN)
2164 			result->status |= TD_CONTROL_SPD;
2165 	}
2166 	if (pipe->Speed() == USB_SPEED_LOWSPEED)
2167 		result->status |= TD_CONTROL_LOWSPEED;
2168 
2169 	result->buffer_size = bufferSize;
2170 	if (bufferSize == 0)
2171 		result->token = TD_TOKEN_NULL_DATA;
2172 	else
2173 		result->token = (bufferSize - 1) << TD_TOKEN_MAXLEN_SHIFT;
2174 
2175 	result->token |= (pipe->EndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT)
2176 		| (pipe->DeviceAddress() << 8) | direction;
2177 
2178 	result->link_phy = 0;
2179 	result->link_log = NULL;
2180 	if (bufferSize <= 0) {
2181 		result->buffer_log = NULL;
2182 		result->buffer_phy = 0;
2183 		return result;
2184 	}
2185 
2186 	if (fStack->AllocateChunk(&result->buffer_log, &physicalAddress,
2187 		bufferSize) < B_OK) {
2188 		TRACE_ERROR("unable to allocate space for the buffer\n");
2189 		fStack->FreeChunk(result, result->this_phy, sizeof(uhci_td));
2190 		return NULL;
2191 	}
2192 	result->buffer_phy = physicalAddress;
2193 
2194 	return result;
2195 }
2196 
2197 
2198 status_t
2199 UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
2200 	uhci_td **_lastDescriptor, uint8 direction, size_t bufferSize)
2201 {
2202 	size_t packetSize = pipe->MaxPacketSize();
2203 	int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
2204 	if (descriptorCount == 0)
2205 		descriptorCount = 1;
2206 
2207 	bool dataToggle = pipe->DataToggle();
2208 	uhci_td *firstDescriptor = NULL;
2209 	uhci_td *lastDescriptor = *_firstDescriptor;
2210 	for (int32 i = 0; i < descriptorCount; i++) {
2211 		uhci_td *descriptor = CreateDescriptor(pipe, direction,
2212 			min_c(packetSize, bufferSize));
2213 
2214 		if (!descriptor) {
2215 			FreeDescriptorChain(firstDescriptor);
2216 			return B_NO_MEMORY;
2217 		}
2218 
2219 		if (dataToggle)
2220 			descriptor->token |= TD_TOKEN_DATA1;
2221 
2222 		// link to previous
2223 		if (lastDescriptor)
2224 			LinkDescriptors(lastDescriptor, descriptor);
2225 
2226 		dataToggle = !dataToggle;
2227 		bufferSize -= packetSize;
2228 		lastDescriptor = descriptor;
2229 		if (!firstDescriptor)
2230 			firstDescriptor = descriptor;
2231 	}
2232 
2233 	*_firstDescriptor = firstDescriptor;
2234 	*_lastDescriptor = lastDescriptor;
2235 	return B_OK;
2236 }
2237 
2238 
2239 void
2240 UHCI::FreeDescriptor(uhci_td *descriptor)
2241 {
2242 	if (!descriptor)
2243 		return;
2244 
2245 	if (descriptor->buffer_log) {
2246 		fStack->FreeChunk(descriptor->buffer_log,
2247 			descriptor->buffer_phy, descriptor->buffer_size);
2248 	}
2249 
2250 	fStack->FreeChunk(descriptor, descriptor->this_phy, sizeof(uhci_td));
2251 }
2252 
2253 
2254 void
2255 UHCI::FreeDescriptorChain(uhci_td *topDescriptor)
2256 {
2257 	uhci_td *current = topDescriptor;
2258 	uhci_td *next = NULL;
2259 
2260 	while (current) {
2261 		next = (uhci_td *)current->link_log;
2262 		FreeDescriptor(current);
2263 		current = next;
2264 	}
2265 }
2266 
2267 
2268 void
2269 UHCI::LinkDescriptors(uhci_td *first, uhci_td *second)
2270 {
2271 	first->link_phy = second->this_phy | TD_DEPTH_FIRST;
2272 	first->link_log = second;
2273 }
2274 
2275 
2276 size_t
2277 UHCI::WriteDescriptorChain(uhci_td *topDescriptor, generic_io_vec *vector,
2278 	size_t vectorCount, bool physical)
2279 {
2280 	uhci_td *current = topDescriptor;
2281 	size_t actualLength = 0;
2282 	size_t vectorIndex = 0;
2283 	size_t vectorOffset = 0;
2284 	size_t bufferOffset = 0;
2285 
2286 	while (current) {
2287 		if (!current->buffer_log)
2288 			break;
2289 
2290 		while (true) {
2291 			size_t length = min_c(current->buffer_size - bufferOffset,
2292 				vector[vectorIndex].length - vectorOffset);
2293 
2294 			TRACE("copying %ld bytes to bufferOffset %ld from"
2295 				" vectorOffset %ld at index %ld of %ld\n", length, bufferOffset,
2296 				vectorOffset, vectorIndex, vectorCount);
2297 			status_t status = generic_memcpy(
2298 				(generic_addr_t)current->buffer_log + bufferOffset, false,
2299 				vector[vectorIndex].base + vectorOffset, physical, length);
2300 			ASSERT_ALWAYS(status == B_OK);
2301 
2302 			actualLength += length;
2303 			vectorOffset += length;
2304 			bufferOffset += length;
2305 
2306 			if (vectorOffset >= vector[vectorIndex].length) {
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, generic_io_vec *vector,
2335 	size_t vectorCount, bool physical, 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].length - 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 			status_t status = generic_memcpy(
2359 				vector[vectorIndex].base + vectorOffset, physical,
2360 				(generic_addr_t)current->buffer_log + bufferOffset, false, length);
2361 			ASSERT_ALWAYS(status == B_OK);
2362 
2363 			actualLength += length;
2364 			vectorOffset += length;
2365 			bufferOffset += length;
2366 
2367 			if (vectorOffset >= vector[vectorIndex].length) {
2368 				if (++vectorIndex >= vectorCount) {
2369 					TRACE("read descriptor chain (%ld bytes, no more vectors)\n",
2370 						actualLength);
2371 					if (lastDataToggle)
2372 						*lastDataToggle = dataToggle;
2373 					return actualLength;
2374 				}
2375 
2376 				vectorOffset = 0;
2377 			}
2378 
2379 			if (bufferOffset >= bufferSize) {
2380 				bufferOffset = 0;
2381 				break;
2382 			}
2383 		}
2384 
2385 		if (current->link_phy & TD_TERMINATE)
2386 			break;
2387 
2388 		current = (uhci_td *)current->link_log;
2389 	}
2390 
2391 	if (lastDataToggle)
2392 		*lastDataToggle = dataToggle;
2393 
2394 	TRACE("read descriptor chain (%ld bytes)\n", actualLength);
2395 	return actualLength;
2396 }
2397 
2398 
2399 size_t
2400 UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle)
2401 {
2402 	size_t actualLength = 0;
2403 	uhci_td *current = topDescriptor;
2404 	uint8 dataToggle = 0;
2405 
2406 	while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
2407 		actualLength += uhci_td_actual_length(current);
2408 		dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
2409 
2410 		if (current->link_phy & TD_TERMINATE)
2411 			break;
2412 
2413 		current = (uhci_td *)current->link_log;
2414 	}
2415 
2416 	if (lastDataToggle)
2417 		*lastDataToggle = dataToggle;
2418 
2419 	TRACE("read actual length (%ld bytes)\n", actualLength);
2420 	return actualLength;
2421 }
2422 
2423 
2424 void
2425 UHCI::WriteIsochronousDescriptorChain(uhci_td **isoRequest, uint32 packetCount,
2426 	generic_io_vec *vector)
2427 {
2428 	size_t vectorOffset = 0;
2429 	for (uint32 i = 0; i < packetCount; i++) {
2430 		size_t bufferSize = isoRequest[i]->buffer_size;
2431 		memcpy((uint8 *)isoRequest[i]->buffer_log,
2432 			(uint8 *)vector->base + vectorOffset, bufferSize);
2433 		vectorOffset += bufferSize;
2434 	}
2435 }
2436 
2437 
2438 void
2439 UHCI::ReadIsochronousDescriptorChain(isochronous_transfer_data *transfer,
2440 	generic_io_vec *vector)
2441 {
2442 	size_t vectorOffset = 0;
2443 	usb_isochronous_data *isochronousData
2444 		= transfer->transfer->IsochronousData();
2445 
2446 	for (uint32 i = 0; i < isochronousData->packet_count; i++) {
2447 		uhci_td *current = transfer->descriptors[i];
2448 
2449 		size_t bufferSize = current->buffer_size;
2450 		size_t actualLength = uhci_td_actual_length(current);
2451 
2452 		isochronousData->packet_descriptors[i].actual_length = actualLength;
2453 
2454 		if (actualLength > 0)
2455 			isochronousData->packet_descriptors[i].status = B_OK;
2456 		else {
2457 			isochronousData->packet_descriptors[i].status = B_ERROR;
2458 			vectorOffset += bufferSize;
2459 			continue;
2460 		}
2461 		memcpy((uint8 *)vector->base + vectorOffset,
2462 			(uint8 *)current->buffer_log, bufferSize);
2463 
2464 		vectorOffset += bufferSize;
2465 	}
2466 }
2467 
2468 
2469 bool
2470 UHCI::LockIsochronous()
2471 {
2472 	return (mutex_lock(&fIsochronousLock) == B_OK);
2473 }
2474 
2475 
2476 void
2477 UHCI::UnlockIsochronous()
2478 {
2479 	mutex_unlock(&fIsochronousLock);
2480 }
2481 
2482 
2483 inline void
2484 UHCI::WriteReg8(uint32 reg, uint8 value)
2485 {
2486 	fPci->write_io_8(fDevice, fRegisterBase + reg, value);
2487 }
2488 
2489 
2490 inline void
2491 UHCI::WriteReg16(uint32 reg, uint16 value)
2492 {
2493 	fPci->write_io_16(fDevice, fRegisterBase + reg, value);
2494 }
2495 
2496 
2497 inline void
2498 UHCI::WriteReg32(uint32 reg, uint32 value)
2499 {
2500 	fPci->write_io_32(fDevice, fRegisterBase + reg, value);
2501 }
2502 
2503 
2504 inline uint8
2505 UHCI::ReadReg8(uint32 reg)
2506 {
2507 	return fPci->read_io_8(fDevice, fRegisterBase + reg);
2508 }
2509 
2510 
2511 inline uint16
2512 UHCI::ReadReg16(uint32 reg)
2513 {
2514 	return fPci->read_io_16(fDevice, fRegisterBase + reg);
2515 }
2516 
2517 
2518 inline uint32
2519 UHCI::ReadReg32(uint32 reg)
2520 {
2521 	return fPci->read_io_32(fDevice, fRegisterBase + reg);
2522 }
2523