xref: /haiku/src/add-ons/kernel/busses/usb/uhci.cpp (revision 9ecf9d1c1d4888d341a6eac72112c72d1ae3a4cb)
1 /*
2  * Copyright 2004-2006, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  *		Niels S. Reedijk
8  */
9 
10 #include <module.h>
11 #include <PCI.h>
12 #include <USB3.h>
13 #include <KernelExport.h>
14 #include <stdlib.h>
15 
16 #include "uhci.h"
17 #include "uhci_hardware.h"
18 #include "usb_p.h"
19 
20 
21 pci_module_info *UHCI::sPCIModule = NULL;
22 
23 
24 static int32
25 uhci_std_ops(int32 op, ...)
26 {
27 	switch (op) {
28 		case B_MODULE_INIT:
29 			TRACE(("usb_uhci_module: init module\n"));
30 			return B_OK;
31 		case B_MODULE_UNINIT:
32 			TRACE(("usb_uhci_module: uninit module\n"));
33 			break;
34 		default:
35 			return EINVAL;
36 	}
37 
38 	return B_OK;
39 }
40 
41 
42 host_controller_info uhci_module = {
43 	{
44 		"busses/usb/uhci/nielx",
45 		NULL,
46 		uhci_std_ops
47 	},
48 	NULL,
49 	UHCI::AddTo
50 };
51 
52 
53 module_info *modules[] = {
54 	(module_info *)&uhci_module,
55 	NULL
56 };
57 
58 
59 //
60 // #pragma mark -
61 //
62 
63 
64 #ifdef TRACE_USB
65 
66 void
67 print_descriptor_chain(uhci_td *descriptor)
68 {
69 	while (descriptor) {
70 		dprintf("ph: 0x%08x; lp: 0x%08x; vf: %s; q: %s; t: %s; st: 0x%08x; to: 0x%08x\n",
71 			descriptor->this_phy & 0xffffffff, descriptor->link_phy & 0xfffffff0,
72 			descriptor->link_phy & 0x4 ? "y" : "n",
73 			descriptor->link_phy & 0x2 ? "qh" : "td",
74 			descriptor->link_phy & 0x1 ? "y" : "n",
75 			descriptor->status, descriptor->token);
76 
77 		if (descriptor->link_phy & TD_TERMINATE)
78 			break;
79 
80 		descriptor = (uhci_td *)descriptor->link_log;
81 	}
82 }
83 
84 #endif // TRACE_USB
85 
86 
87 //
88 // #pragma mark -
89 //
90 
91 
92 Queue::Queue(Stack *stack)
93 {
94 	fStack = stack;
95 
96 	if (benaphore_init(&fLock, "uhci queue lock") < B_OK) {
97 		TRACE_ERROR(("usb_uhci: failed to create queue lock\n"));
98 		return;
99 	}
100 
101 	void *physicalAddress;
102 	fStatus = fStack->AllocateChunk((void **)&fQueueHead, &physicalAddress, 32);
103 	if (fStatus < B_OK)
104 		return;
105 
106 	fQueueHead->this_phy = (addr_t)physicalAddress;
107 	fQueueHead->element_phy = QH_TERMINATE;
108 
109 	fStrayDescriptor = NULL;
110 	fQueueTop = NULL;
111 }
112 
113 
114 Queue::~Queue()
115 {
116 	Lock();
117 	benaphore_destroy(&fLock);
118 
119 	fStack->FreeChunk(fQueueHead, (void *)fQueueHead->this_phy, 32);
120 
121 	if (fStrayDescriptor)
122 		fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy, 32);
123 }
124 
125 
126 status_t
127 Queue::InitCheck()
128 {
129 	return fStatus;
130 }
131 
132 
133 bool
134 Queue::Lock()
135 {
136 	return (benaphore_lock(&fLock) == B_OK);
137 }
138 
139 
140 void
141 Queue::Unlock()
142 {
143 	benaphore_unlock(&fLock);
144 }
145 
146 
147 status_t
148 Queue::LinkTo(Queue *other)
149 {
150 	if (!other)
151 		return B_BAD_VALUE;
152 
153 	if (!Lock())
154 		return B_ERROR;
155 
156 	fQueueHead->link_phy = other->fQueueHead->this_phy | QH_NEXT_IS_QH;
157 	fQueueHead->link_log = other->fQueueHead;
158 	Unlock();
159 
160 	return B_OK;
161 }
162 
163 
164 status_t
165 Queue::TerminateByStrayDescriptor()
166 {
167 	// According to the *BSD USB sources, there needs to be a stray transfer
168 	// descriptor in order to get some chipset to work nicely (like the PIIX).
169 	void *physicalAddress;
170 	status_t result = fStack->AllocateChunk((void **)&fStrayDescriptor,
171 		&physicalAddress, 32);
172 	if (result < B_OK) {
173 		TRACE_ERROR(("usb_uhci: failed to allocate a stray transfer descriptor\n"));
174 		return result;
175 	}
176 
177 	fStrayDescriptor->status = 0;
178 	fStrayDescriptor->this_phy = (addr_t)physicalAddress;
179 	fStrayDescriptor->link_phy = TD_TERMINATE;
180 	fStrayDescriptor->link_log = 0;
181 	fStrayDescriptor->buffer_phy = 0;
182 	fStrayDescriptor->buffer_log = 0;
183 	fStrayDescriptor->buffer_size = 0;
184 	fStrayDescriptor->token = TD_TOKEN_NULL_DATA
185 		| (0x7f << TD_TOKEN_DEVADDR_SHIFT) | TD_TOKEN_IN;
186 
187 	if (!Lock()) {
188 		fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy,
189 			32);
190 		return B_ERROR;
191 	}
192 
193 	fQueueHead->link_phy = fStrayDescriptor->this_phy;
194 	fQueueHead->link_log = fStrayDescriptor;
195 	fQueueHead->element_phy = QH_TERMINATE;
196 	Unlock();
197 
198 	return B_OK;
199 }
200 
201 
202 status_t
203 Queue::AppendDescriptorChain(uhci_td *descriptor)
204 {
205 	TRACE(("usb_uhci: appending descriptor chain\n"));
206 
207 	if (!Lock())
208 		return B_ERROR;
209 
210 #ifdef TRACE_USB
211 	print_descriptor_chain(descriptor);
212 #endif
213 
214 	if (fQueueTop == NULL) {
215 		// the queue is empty, make this the first element
216 		fQueueTop = descriptor;
217 		fQueueHead->element_phy = descriptor->this_phy;
218 		TRACE(("usb_uhci: first transfer in queue\n"));
219 	} else {
220 		// there are transfers linked, append to the queue
221 		uhci_td *element = fQueueTop;
222 		while ((element->link_phy & TD_TERMINATE) == 0)
223 			element = (uhci_td *)element->link_log;
224 
225 		element->link_log = descriptor;
226 		element->link_phy = descriptor->this_phy | TD_DEPTH_FIRST;
227 		TRACE(("usb_uhci: appended transfer to queue\n"));
228 	}
229 
230 	Unlock();
231 	return B_OK;
232 }
233 
234 
235 status_t
236 Queue::RemoveDescriptorChain(uhci_td *firstDescriptor, uhci_td *lastDescriptor)
237 {
238 	TRACE(("usb_uhci: removing descriptor chain\n"));
239 
240 	if (!Lock())
241 		return B_ERROR;
242 
243 	if (fQueueTop == firstDescriptor) {
244 		// it is the first chain in this queue
245 		if ((lastDescriptor->link_phy & TD_TERMINATE) > 0) {
246 			// it is the only chain in this queue
247 			fQueueTop = NULL;
248 			fQueueHead->element_phy = QH_TERMINATE;
249 		} else {
250 			// there are still linked transfers
251 			fQueueTop = (uhci_td *)lastDescriptor->link_log;
252 			fQueueHead->element_phy = fQueueTop->this_phy & TD_LINK_MASK;
253 		}
254 	} else {
255 		// unlink the chain
256 		uhci_td *element = fQueueTop;
257 		while (element) {
258 			if (element->link_log == firstDescriptor) {
259 				element->link_log = lastDescriptor->link_log;
260 				element->link_phy = lastDescriptor->link_phy;
261 				break;
262 			}
263 
264 			element = (uhci_td *)element->link_log;
265 		}
266 
267 		element = firstDescriptor;
268 		while (element && element != lastDescriptor) {
269 			if ((fQueueHead->element_phy & TD_LINK_MASK) == element->this_phy) {
270 				fQueueHead->element_phy = lastDescriptor->link_phy;
271 				break;
272 			}
273 
274 			element = (uhci_td *)element->link_log;
275 		}
276 	}
277 
278 	lastDescriptor->link_log = NULL;
279 	lastDescriptor->link_phy = TD_TERMINATE;
280 
281 #ifdef TRACE_USB
282 	print_descriptor_chain(firstDescriptor);
283 #endif
284 
285 	Unlock();
286 	return B_OK;
287 }
288 
289 
290 addr_t
291 Queue::PhysicalAddress()
292 {
293 	return fQueueHead->this_phy;
294 }
295 
296 
297 void
298 Queue::PrintToStream()
299 {
300 #ifdef TRACE_USB
301 	dprintf("USB UHCI Queue:\n");
302 	dprintf("link phy: 0x%08x; link type: %s; terminate: %s\n", fQueueHead->link_phy & 0xfff0, fQueueHead->link_phy & 0x0002 ? "QH" : "TD", fQueueHead->link_phy & 0x0001 ? "yes" : "no");
303 	dprintf("elem phy: 0x%08x; elem type: %s; terminate: %s\n", fQueueHead->element_phy & 0xfff0, fQueueHead->element_phy & 0x0002 ? "QH" : "TD", fQueueHead->element_phy & 0x0001 ? "yes" : "no");
304 	dprintf("elements:\n");
305 	print_descriptor_chain(fQueueTop);
306 #endif
307 }
308 
309 
310 //
311 // #pragma mark -
312 //
313 
314 
315 UHCI::UHCI(pci_info *info, Stack *stack)
316 	:	BusManager(stack),
317 		fPCIInfo(info),
318 		fStack(stack),
319 		fFrameArea(-1),
320 		fFrameList(NULL),
321 		fQueueCount(0),
322 		fQueues(NULL),
323 		fFirstTransfer(NULL),
324 		fLastTransfer(NULL),
325 		fFinishTransfers(false),
326 		fFinishThread(-1),
327 		fStopFinishThread(false),
328 		fRootHub(NULL),
329 		fRootHubAddress(0)
330 {
331 	if (!fInitOK) {
332 		TRACE_ERROR(("usb_uhci: bus manager failed to init\n"));
333 		return;
334 	}
335 
336 	TRACE(("usb_uhci: constructing new UHCI Host Controller Driver\n"));
337 	fInitOK = false;
338 
339 	fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus,
340 		fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4);
341 	fRegisterBase &= PCI_address_io_mask;
342 	TRACE_ERROR(("usb_uhci: iospace offset: 0x%08x\n", fRegisterBase));
343 
344 	if (fRegisterBase == 0) {
345 		fRegisterBase = fPCIInfo->u.h0.base_registers[0];
346 		TRACE_ERROR(("usb_uhci: register base: 0x%08x\n", fRegisterBase));
347 	}
348 
349 	// enable pci address access
350 	uint16 command = PCI_command_io | PCI_command_master | PCI_command_memory;
351 	command |= sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device,
352 		fPCIInfo->function, PCI_command, 2);
353 
354 	sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
355 		fPCIInfo->function, PCI_command, 2, command);
356 
357 	// make sure we gain controll of the UHCI controller instead of the BIOS
358 	sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device, 2,
359 		PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN);
360 
361 	// disable interrupts
362 	WriteReg16(UHCI_USBINTR, 0);
363 
364 	// do a global and host reset
365 	GlobalReset();
366 	if (ControllerReset() < B_OK) {
367 		TRACE_ERROR(("usb_uhci: host failed to reset\n"));
368 		return;
369 	}
370 
371 	// Setup the frame list
372 	void *physicalAddress;
373 	fFrameArea = fStack->AllocateArea((void **)&fFrameList,
374 		(void **)&physicalAddress, 4096, "USB UHCI framelist");
375 
376 	if (fFrameArea < B_OK) {
377 		TRACE_ERROR(("usb_uhci: unable to create an area for the frame pointer list\n"));
378 		return;
379 	}
380 
381 	// Set base pointer and reset frame number
382 	WriteReg32(UHCI_FRBASEADD, (uint32)physicalAddress);
383 	WriteReg16(UHCI_FRNUM, 0);
384 
385 	fQueueCount = 4;
386 	fQueues = new(std::nothrow) Queue *[fQueueCount];
387 	if (!fQueues) {
388 		delete_area(fFrameArea);
389 		return;
390 	}
391 
392 	for (int32 i = 0; i < fQueueCount; i++) {
393 		fQueues[i] = new(std::nothrow) Queue(fStack);
394 		if (!fQueues[i] || fQueues[i]->InitCheck() < B_OK) {
395 			TRACE_ERROR(("usb_uhci: cannot create queues\n"));
396 			delete_area(fFrameArea);
397 			return;
398 		}
399 
400 		if (i > 0)
401 			fQueues[i - 1]->LinkTo(fQueues[i]);
402 	}
403 
404 	// Make sure the last queue terminates
405 	fQueues[fQueueCount - 1]->TerminateByStrayDescriptor();
406 
407 	for (int32 i = 0; i < 1024; i++)
408 		fFrameList[i] = fQueues[0]->PhysicalAddress() | FRAMELIST_NEXT_IS_QH;
409 
410 	// Create the finisher service thread
411 	fFinishThread = spawn_kernel_thread(FinishThread,
412 		"uhci finish thread", B_NORMAL_PRIORITY, (void *)this);
413 	resume_thread(fFinishThread);
414 
415 	// Install the interrupt handler
416 	TRACE(("usb_uhci: installing interrupt handler\n"));
417 	install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
418 		InterruptHandler, (void *)this, 0);
419 
420 	// Enable interrupts
421 	WriteReg16(UHCI_USBINTR, UHCI_USBINTR_CRC | UHCI_USBINTR_RESUME
422 		| UHCI_USBINTR_IOC | UHCI_USBINTR_SHORT);
423 
424 	TRACE(("usb_uhci: UHCI Host Controller Driver constructed\n"));
425 	fInitOK = true;
426 }
427 
428 
429 UHCI::~UHCI()
430 {
431 	int32 result = 0;
432 	fStopFinishThread = true;
433 	wait_for_thread(fFinishThread, &result);
434 
435 	Lock();
436 	transfer_data *transfer = fFirstTransfer;
437 	while (transfer) {
438 		transfer_data *next = transfer->link;
439 		delete transfer;
440 		transfer = next;
441 	}
442 
443 	for (int32 i = 0; i < fQueueCount; i++)
444 		delete fQueues[i];
445 
446 	delete [] fQueues;
447 	delete fRootHub;
448 	delete_area(fFrameArea);
449 
450 	put_module(B_PCI_MODULE_NAME);
451 	Unlock();
452 }
453 
454 
455 status_t
456 UHCI::Start()
457 {
458 	// Start the host controller, then start the Busmanager
459 	TRACE(("usb_uhci: starting UHCI BusManager\n"));
460 	TRACE(("usb_uhci: usbcmd reg 0x%04x, usbsts reg 0x%04x\n",
461 		ReadReg16(UHCI_USBCMD), ReadReg16(UHCI_USBSTS)));
462 
463 	// Set the run bit in the command register
464 	WriteReg16(UHCI_USBCMD, ReadReg16(UHCI_USBCMD) | UHCI_USBCMD_RS);
465 
466 	bool running = false;
467 	for (int32 i = 0; i < 10; i++) {
468 		uint16 status = ReadReg16(UHCI_USBSTS);
469 		TRACE(("usb_uhci: current loop %u, status 0x%04x\n", i, status));
470 
471 		if (status & UHCI_USBSTS_HCHALT)
472 			snooze(10000);
473 		else {
474 			running = true;
475 			break;
476 		}
477 	}
478 
479 	if (!running) {
480 		TRACE_ERROR(("usb_uhci: controller won't start running\n"));
481 		return B_ERROR;
482 	}
483 
484 	fPortResetChange[0] = fPortResetChange[1] = false;
485 	fRootHubAddress = AllocateAddress();
486 	fRootHub = new(std::nothrow) UHCIRootHub(this, fRootHubAddress);
487 	if (!fRootHub) {
488 		TRACE_ERROR(("usb_uhci: no memory to allocate root hub\n"));
489 		return B_NO_MEMORY;
490 	}
491 
492 	if (fRootHub->InitCheck() < B_OK) {
493 		TRACE_ERROR(("usb_uhci: root hub failed init check\n"));
494 		delete fRootHub;
495 		return B_ERROR;
496 	}
497 
498 	SetRootHub(fRootHub);
499 
500 	TRACE(("usb_uhci: controller is started. status: %u curframe: %u\n",
501 		ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM)));
502 	return BusManager::Start();
503 }
504 
505 
506 status_t
507 UHCI::SubmitTransfer(Transfer *transfer)
508 {
509 	TRACE(("usb_uhci: submit transfer called for device %d\n", transfer->TransferPipe()->DeviceAddress()));
510 
511 	// Short circuit the root hub
512 	if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
513 		return fRootHub->SubmitTransfer(transfer);
514 
515 	if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE)
516 		return SubmitRequest(transfer);
517 
518 	if (transfer->VectorCount() == 0)
519 		return B_BAD_VALUE;
520 
521 	Pipe *pipe = transfer->TransferPipe();
522 	bool directionIn = (pipe->Direction() == Pipe::In);
523 
524 	uhci_td *firstDescriptor = NULL;
525 	uhci_td *lastDescriptor = NULL;
526 	status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
527 		&lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
528 		transfer->VectorLength());
529 
530 	if (result < B_OK)
531 		return result;
532 	if (!firstDescriptor || !lastDescriptor)
533 		return B_NO_MEMORY;
534 
535 	lastDescriptor->status |= TD_CONTROL_IOC;
536 	lastDescriptor->link_phy = TD_TERMINATE;
537 	lastDescriptor->link_log = 0;
538 
539 	if (!directionIn) {
540 		WriteDescriptorChain(firstDescriptor, transfer->Vector(),
541 			transfer->VectorCount());
542 	}
543 
544 	Queue *queue = fQueues[3];
545 	if (pipe->Type() & USB_OBJECT_INTERRUPT_PIPE)
546 		queue = fQueues[2];
547 
548 	result = AddPendingTransfer(transfer, queue, firstDescriptor,
549 		firstDescriptor, lastDescriptor, directionIn);
550 	if (result < B_OK) {
551 		TRACE_ERROR(("usb_uhci: failed to add pending transfer\n"));
552 		FreeDescriptorChain(firstDescriptor);
553 		return result;
554 	}
555 
556 	result = queue->AppendDescriptorChain(firstDescriptor);
557 	if (result < B_OK) {
558 		TRACE_ERROR(("usb_uhci: failed to append descriptor chain\n"));
559 		FreeDescriptorChain(firstDescriptor);
560 		return result;
561 	}
562 
563 	return B_OK;
564 }
565 
566 
567 status_t
568 UHCI::SubmitRequest(Transfer *transfer)
569 {
570 	Pipe *pipe = transfer->TransferPipe();
571 	usb_request_data *requestData = transfer->RequestData();
572 	bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
573 
574 	uhci_td *setupDescriptor = CreateDescriptor(pipe, TD_TOKEN_SETUP,
575 		sizeof(usb_request_data));
576 
577 	uhci_td *statusDescriptor = CreateDescriptor(pipe,
578 		directionIn ? TD_TOKEN_OUT : TD_TOKEN_IN, 0);
579 
580 	if (!setupDescriptor || !statusDescriptor) {
581 		TRACE_ERROR(("usb_uhci: failed to allocate descriptors\n"));
582 		FreeDescriptor(setupDescriptor);
583 		FreeDescriptor(statusDescriptor);
584 		return B_NO_MEMORY;
585 	}
586 
587 	iovec vector;
588 	vector.iov_base = requestData;
589 	vector.iov_len = sizeof(usb_request_data);
590 	WriteDescriptorChain(setupDescriptor, &vector, 1);
591 
592 	statusDescriptor->status |= TD_CONTROL_IOC;
593 	statusDescriptor->token |= TD_TOKEN_DATA1;
594 	statusDescriptor->link_phy = TD_TERMINATE;
595 	statusDescriptor->link_log = NULL;
596 
597 	uhci_td *dataDescriptor = NULL;
598 	if (transfer->VectorCount() > 0) {
599 		uhci_td *lastDescriptor = NULL;
600 		status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
601 			&lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
602 			transfer->VectorLength());
603 
604 		if (result < B_OK) {
605 			FreeDescriptor(setupDescriptor);
606 			FreeDescriptor(statusDescriptor);
607 			return result;
608 		}
609 
610 		if (!directionIn) {
611 			WriteDescriptorChain(dataDescriptor, transfer->Vector(),
612 				transfer->VectorCount());
613 		}
614 
615 		LinkDescriptors(setupDescriptor, dataDescriptor);
616 		LinkDescriptors(lastDescriptor, statusDescriptor);
617 	} else {
618 		// Link transfer and status descriptors directly
619 		LinkDescriptors(setupDescriptor, statusDescriptor);
620 	}
621 
622 	status_t result = AddPendingTransfer(transfer, fQueues[1], setupDescriptor,
623 		dataDescriptor, statusDescriptor, directionIn);
624 	if (result < B_OK) {
625 		TRACE_ERROR(("usb_uhci: failed to add pending transfer\n"));
626 		FreeDescriptorChain(setupDescriptor);
627 		return result;
628 	}
629 
630 	result = fQueues[1]->AppendDescriptorChain(setupDescriptor);
631 	if (result < B_OK) {
632 		TRACE_ERROR(("usb_uhci: failed to append descriptor chain\n"));
633 		FreeDescriptorChain(setupDescriptor);
634 		return result;
635 	}
636 
637 	return B_OK;
638 }
639 
640 
641 status_t
642 UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue,
643 	uhci_td *firstDescriptor, uhci_td *dataDescriptor, uhci_td *lastDescriptor,
644 	bool directionIn)
645 {
646 	transfer_data *data = new(std::nothrow) transfer_data();
647 	if (!data)
648 		return B_NO_MEMORY;
649 
650 	data->transfer = transfer;
651 	data->queue = queue;
652 	data->first_descriptor = firstDescriptor;
653 	data->data_descriptor = dataDescriptor;
654 	data->last_descriptor = lastDescriptor;
655 	data->incoming = directionIn;
656 	data->link = NULL;
657 
658 	if (!Lock()) {
659 		delete data;
660 		return B_ERROR;
661 	}
662 
663 	if (fLastTransfer)
664 		fLastTransfer->link = data;
665 	else
666 		fFirstTransfer = data;
667 
668 	fLastTransfer = data;
669 	Unlock();
670 
671 	return B_OK;
672 }
673 
674 
675 int32
676 UHCI::FinishThread(void *data)
677 {
678 	((UHCI *)data)->FinishTransfers();
679 	return B_OK;
680 }
681 
682 
683 void
684 UHCI::FinishTransfers()
685 {
686 	while (!fStopFinishThread) {
687 		while (!fFinishTransfers) {
688 			if (fStopFinishThread)
689 				return;
690 
691 			snooze(1000);
692 		}
693 
694 		fFinishTransfers = false;
695 		if (!Lock())
696 			continue;
697 
698 		TRACE(("usb_uhci: finishing transfers (first transfer: 0x%08x; last transfer: 0x%08x)\n", fFirstTransfer, fLastTransfer));
699 		transfer_data *lastTransfer = NULL;
700 		transfer_data *transfer = fFirstTransfer;
701 		Unlock();
702 
703 		while (transfer) {
704 			bool transferDone = false;
705 			uhci_td *descriptor = transfer->first_descriptor;
706 
707 			while (descriptor) {
708 				uint32 status = descriptor->status;
709 				if (status & TD_STATUS_ACTIVE) {
710 					TRACE(("usb_uhci: td (0x%08x) still active\n", descriptor->this_phy));
711 					// still in progress
712 					break;
713 				}
714 
715 				if (status & TD_ERROR_MASK) {
716 					TRACE_ERROR(("usb_uhci: td (0x%08lx) error: 0x%08lx\n", descriptor->this_phy, status));
717 					// an error occured. we have to remove the
718 					// transfer from the queue and clean up
719 
720 					uint32 callbackStatus = 0;
721 					if (status & TD_STATUS_ERROR_STALLED)
722 						callbackStatus |= B_USB_STATUS_DEVICE_STALLED;
723 					if (status & TD_STATUS_ERROR_TIMEOUT) {
724 						if (transfer->incoming)
725 							callbackStatus |= B_USB_STATUS_DEVICE_CRC_ERROR;
726 						else
727 							callbackStatus |= B_USB_STATUS_DEVICE_TIMEOUT;
728 					}
729 
730 					transfer->queue->RemoveDescriptorChain(
731 						transfer->first_descriptor,
732 						transfer->last_descriptor);
733 
734 					FreeDescriptorChain(transfer->first_descriptor);
735 					transfer->transfer->Finished(callbackStatus, 0);
736 					transferDone = true;
737 					break;
738 				}
739 
740 				// either all descriptors are done, or we have a short packet
741 				if (descriptor == transfer->last_descriptor
742 					|| (descriptor->status & TD_STATUS_ACTLEN_MASK)
743 					< (descriptor->token >> TD_TOKEN_MAXLEN_SHIFT)) {
744 					TRACE(("usb_uhci: td (0x%08x) ok\n", descriptor->this_phy));
745 					// we got through without errors so we are finished
746 					transfer->queue->RemoveDescriptorChain(
747 						transfer->first_descriptor,
748 						transfer->last_descriptor);
749 
750 					size_t actualLength = 0;
751 					uint8 lastDataToggle = 0;
752 					if (transfer->data_descriptor && transfer->incoming) {
753 						// data to read out
754 						actualLength = ReadDescriptorChain(
755 							transfer->data_descriptor,
756 							transfer->transfer->Vector(),
757 							transfer->transfer->VectorCount(),
758 							&lastDataToggle);
759 					} else {
760 						// read the actual length that was sent
761 						actualLength = ReadActualLength(
762 							transfer->first_descriptor, &lastDataToggle);
763 					}
764 
765 					FreeDescriptorChain(transfer->first_descriptor);
766 					transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
767 					transfer->transfer->Finished(B_USB_STATUS_SUCCESS, actualLength);
768 					transferDone = true;
769 					break;
770 				}
771 
772 				descriptor = (uhci_td *)descriptor->link_log;
773 			}
774 
775 			if (transferDone) {
776 				if (Lock()) {
777 					if (lastTransfer)
778 						lastTransfer->link = transfer->link;
779 
780 					if (transfer == fFirstTransfer)
781 						fFirstTransfer = transfer->link;
782 					if (transfer == fLastTransfer)
783 						fLastTransfer = lastTransfer;
784 
785 					transfer_data *next = transfer->link;
786 					delete transfer->transfer;
787 					delete transfer;
788 					transfer = next;
789 
790 					Unlock();
791 				}
792 			} else {
793 				lastTransfer = transfer;
794 				transfer = transfer->link;
795 			}
796 		}
797 	}
798 }
799 
800 
801 void
802 UHCI::GlobalReset()
803 {
804 	uint8 sofValue = ReadReg8(UHCI_SOFMOD);
805 
806 	WriteReg16(UHCI_USBCMD, UHCI_USBCMD_GRESET);
807 	snooze(100000);
808 	WriteReg16(UHCI_USBCMD, 0);
809 	snooze(10000);
810 
811 	WriteReg8(UHCI_SOFMOD, sofValue);
812 }
813 
814 
815 status_t
816 UHCI::ControllerReset()
817 {
818 	WriteReg16(UHCI_USBCMD, UHCI_USBCMD_HCRESET);
819 
820 	int32 tries = 5;
821 	while (ReadReg16(UHCI_USBCMD) & UHCI_USBCMD_HCRESET) {
822 		snooze(10000);
823 		if (tries-- < 0)
824 			return B_ERROR;
825 	}
826 
827 	return B_OK;
828 }
829 
830 
831 uint16
832 UHCI::PortStatus(int32 index)
833 {
834 	if (index > 1)
835 		return B_BAD_VALUE;
836 
837 	return ReadReg16(UHCI_PORTSC1 + index * 2);
838 }
839 
840 
841 status_t
842 UHCI::SetPortStatus(int32 index, uint16 status)
843 {
844 	if (index > 1)
845 		return B_BAD_VALUE;
846 
847 	TRACE(("usb_uhci: set port status of port %d: 0x%04x\n", index, status));
848 	WriteReg16(UHCI_PORTSC1 + index * 2, status);
849 	snooze(1000);
850 	return B_OK;
851 }
852 
853 
854 status_t
855 UHCI::ResetPort(int32 index)
856 {
857 	if (index > 1)
858 		return B_BAD_VALUE;
859 
860 	TRACE(("usb_uhci: reset port %d\n", index));
861 
862 	uint32 port = UHCI_PORTSC1 + index * 2;
863 	uint16 status = ReadReg16(port);
864 	status &= UHCI_PORTSC_DATAMASK;
865 	WriteReg16(port, status | UHCI_PORTSC_RESET);
866 	snooze(250000);
867 
868 	status = ReadReg16(port);
869 	status &= UHCI_PORTSC_DATAMASK;
870 	WriteReg16(port, status & ~UHCI_PORTSC_RESET);
871 	snooze(1000);
872 
873 	for (int32 i = 10; i > 0; i--) {
874 		// try to enable the port
875 		status = ReadReg16(port);
876 		status &= UHCI_PORTSC_DATAMASK;
877 		WriteReg16(port, status | UHCI_PORTSC_ENABLED);
878 		snooze(50000);
879 
880 		status = ReadReg16(port);
881 
882 		if ((status & UHCI_PORTSC_CURSTAT) == 0) {
883 			// no device connected. since we waited long enough we can assume
884 			// that the port was reset and no device is connected.
885 			break;
886 		}
887 
888 		if (status & (UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA)) {
889 			// port enabled changed or connection status were set.
890 			// acknowledge either / both and wait again.
891 			status &= UHCI_PORTSC_DATAMASK;
892 			WriteReg16(port, status | UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA);
893 			continue;
894 		}
895 
896 		if (status & UHCI_PORTSC_ENABLED) {
897 			// the port is enabled
898 			break;
899 		}
900 	}
901 
902 	SetPortResetChange(index, true);
903 	TRACE(("usb_uhci: port was reset: 0x%04x\n", ReadReg16(port)));
904 	return B_OK;
905 }
906 
907 
908 bool
909 UHCI::PortResetChange(int32 index)
910 {
911 	if (index > 1)
912 		return false;
913 
914 	return fPortResetChange[index];
915 }
916 
917 
918 void
919 UHCI::SetPortResetChange(int32 index, bool value)
920 {
921 	if (index > 1)
922 		return;
923 
924 	fPortResetChange[index] = value;
925 }
926 
927 
928 int32
929 UHCI::InterruptHandler(void *data)
930 {
931 	cpu_status status = disable_interrupts();
932 	spinlock lock = 0;
933 	acquire_spinlock(&lock);
934 
935 	int32 result = ((UHCI *)data)->Interrupt();
936 
937 	release_spinlock(&lock);
938 	restore_interrupts(status);
939 	return result;
940 }
941 
942 
943 int32
944 UHCI::Interrupt()
945 {
946 	// Check if we really had an interrupt
947 	uint16 status = ReadReg16(UHCI_USBSTS);
948 	if ((status & UHCI_INTERRUPT_MASK) == 0)
949 		return B_UNHANDLED_INTERRUPT;
950 
951 	uint16 acknowledge = 0;
952 	if (status & UHCI_USBSTS_USBINT) {
953 		TRACE(("usb_uhci: transfer finished\n"));
954 		acknowledge |= UHCI_USBSTS_USBINT;
955 	}
956 
957 	if (status & UHCI_USBSTS_ERRINT) {
958 		TRACE(("usb_uhci: transfer error\n"));
959 		acknowledge |= UHCI_USBSTS_ERRINT;
960 	}
961 
962 	if (status & UHCI_USBSTS_RESDET) {
963 		TRACE(("usb_uhci: resume detected\n"));
964 		acknowledge |= UHCI_USBSTS_RESDET;
965 	}
966 
967 	if (status & UHCI_USBSTS_HOSTERR) {
968 		TRACE(("usb_uhci: host system error\n"));
969 		acknowledge |= UHCI_USBSTS_HOSTERR;
970 	}
971 
972 	if (status & UHCI_USBSTS_HCPRERR) {
973 		TRACE(("usb_uhci: process error\n"));
974 		acknowledge |= UHCI_USBSTS_HCPRERR;
975 	}
976 
977 	if (status & UHCI_USBSTS_HCHALT) {
978 		TRACE(("usb_uhci: host controller halted\n"));
979 		// ToDo: cancel all transfers and reset the host controller
980 		// acknowledge not needed
981 	}
982 
983 	if (acknowledge)
984 		WriteReg16(UHCI_USBSTS, acknowledge);
985 
986 	fFinishTransfers = true;
987 	return B_HANDLED_INTERRUPT;
988 }
989 
990 
991 status_t
992 UHCI::AddTo(Stack *stack)
993 {
994 #ifdef TRACE_USB
995 	set_dprintf_enabled(true);
996 	load_driver_symbols("uhci");
997 #endif
998 
999 	if (!sPCIModule) {
1000 		status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule);
1001 		if (status < B_OK) {
1002 			TRACE_ERROR(("usb_uhci: AddTo(): getting pci module failed! 0x%08lx\n",
1003 				status));
1004 			return status;
1005 		}
1006 	}
1007 
1008 	TRACE(("usb_uhci: AddTo(): setting up hardware\n"));
1009 
1010 	bool found = false;
1011 	pci_info *item = new(std::nothrow) pci_info;
1012 	if (!item) {
1013 		sPCIModule = NULL;
1014 		put_module(B_PCI_MODULE_NAME);
1015 		return B_NO_MEMORY;
1016 	}
1017 
1018 	for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) {
1019 		//class_base = 0C (serial bus) class_sub = 03 (usb) prog_int: 00 (UHCI)
1020 		if (item->class_base == 0x0C && item->class_sub == 0x03
1021 			&& item->class_api == 0x00) {
1022 			if (item->u.h0.interrupt_line == 0
1023 				|| item->u.h0.interrupt_line == 0xFF) {
1024 				TRACE_ERROR(("usb_uhci: AddTo(): found with invalid IRQ - check IRQ assignement\n"));
1025 				continue;
1026 			}
1027 
1028 			TRACE(("usb_uhci: AddTo(): found at IRQ %u\n", item->u.h0.interrupt_line));
1029 			UHCI *bus = new(std::nothrow) UHCI(item, stack);
1030 			if (!bus) {
1031 				delete item;
1032 				sPCIModule = NULL;
1033 				put_module(B_PCI_MODULE_NAME);
1034 				return B_NO_MEMORY;
1035 			}
1036 
1037 			if (bus->InitCheck() < B_OK) {
1038 				TRACE_ERROR(("usb_uhci: AddTo(): InitCheck() failed 0x%08lx\n", bus->InitCheck()));
1039 				delete bus;
1040 				continue;
1041 			}
1042 
1043 			// the bus took it away
1044 			item = new(std::nothrow) pci_info;
1045 
1046 			bus->Start();
1047 			stack->AddBusManager(bus);
1048 			found = true;
1049 		}
1050 	}
1051 
1052 	if (!found) {
1053 		TRACE_ERROR(("usb_uhci: no devices found\n"));
1054 		delete item;
1055 		sPCIModule = NULL;
1056 		put_module(B_PCI_MODULE_NAME);
1057 		return ENODEV;
1058 	}
1059 
1060 	delete item;
1061 	return B_OK;
1062 }
1063 
1064 
1065 uhci_td *
1066 UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, size_t bufferSize)
1067 {
1068 	uhci_td *result;
1069 	void *physicalAddress;
1070 
1071 	if (fStack->AllocateChunk((void **)&result, &physicalAddress, 32) < B_OK) {
1072 		TRACE_ERROR(("usb_uhci: failed to allocate a transfer descriptor\n"));
1073 		return NULL;
1074 	}
1075 
1076 	result->this_phy = (addr_t)physicalAddress;
1077 	result->status = TD_STATUS_ACTIVE | TD_CONTROL_3_ERRORS | TD_CONTROL_SPD;
1078 	if (pipe->Speed() == Pipe::LowSpeed)
1079 		result->status |= TD_CONTROL_LOWSPEED;
1080 
1081 	result->buffer_size = bufferSize;
1082 	if (bufferSize == 0)
1083 		result->token = TD_TOKEN_NULL_DATA;
1084 	else
1085 		result->token = (bufferSize - 1) << TD_TOKEN_MAXLEN_SHIFT;
1086 
1087 	result->token |= (pipe->EndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT)
1088 		| (pipe->DeviceAddress() << 8) | direction;
1089 
1090 	result->link_phy = 0;
1091 	result->link_log = NULL;
1092 	if (bufferSize <= 0) {
1093 		result->buffer_log = NULL;
1094 		result->buffer_phy = NULL;
1095 		return result;
1096 	}
1097 
1098 	if (fStack->AllocateChunk(&result->buffer_log, &result->buffer_phy,
1099 		bufferSize) < B_OK) {
1100 		TRACE_ERROR(("usb_uhci: unable to allocate space for the buffer\n"));
1101 		fStack->FreeChunk(result, (void *)result->this_phy, 32);
1102 		return NULL;
1103 	}
1104 
1105 	return result;
1106 }
1107 
1108 
1109 status_t
1110 UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
1111 	uhci_td **_lastDescriptor, uint8 direction, size_t bufferSize)
1112 {
1113 	size_t packetSize = pipe->MaxPacketSize();
1114 	int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
1115 
1116 	bool dataToggle = pipe->DataToggle();
1117 	uhci_td *firstDescriptor = NULL;
1118 	uhci_td *lastDescriptor = *_firstDescriptor;
1119 	for (int32 i = 0; i < descriptorCount; i++) {
1120 		uhci_td *descriptor = CreateDescriptor(pipe, direction,
1121 			min_c(packetSize, bufferSize));
1122 
1123 		if (!descriptor) {
1124 			FreeDescriptorChain(firstDescriptor);
1125 			return B_NO_MEMORY;
1126 		}
1127 
1128 		if (dataToggle)
1129 			descriptor->token |= TD_TOKEN_DATA1;
1130 
1131 		// link to previous
1132 		if (lastDescriptor)
1133 			LinkDescriptors(lastDescriptor, descriptor);
1134 
1135 		dataToggle = !dataToggle;
1136 		bufferSize -= packetSize;
1137 		lastDescriptor = descriptor;
1138 		if (!firstDescriptor)
1139 			firstDescriptor = descriptor;
1140 	}
1141 
1142 	*_firstDescriptor = firstDescriptor;
1143 	*_lastDescriptor = lastDescriptor;
1144 	return B_OK;
1145 }
1146 
1147 
1148 void
1149 UHCI::FreeDescriptor(uhci_td *descriptor)
1150 {
1151 	if (!descriptor)
1152 		return;
1153 
1154 	if (descriptor->buffer_log) {
1155 		fStack->FreeChunk(descriptor->buffer_log,
1156 			(void *)descriptor->buffer_phy, descriptor->buffer_size);
1157 	}
1158 
1159 	fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, 32);
1160 }
1161 
1162 
1163 void
1164 UHCI::FreeDescriptorChain(uhci_td *topDescriptor)
1165 {
1166 	uhci_td *current = topDescriptor;
1167 	uhci_td *next = NULL;
1168 
1169 	while (current) {
1170 		next = (uhci_td *)current->link_log;
1171 		FreeDescriptor(current);
1172 		current = next;
1173 	}
1174 }
1175 
1176 
1177 void
1178 UHCI::LinkDescriptors(uhci_td *first, uhci_td *second)
1179 {
1180 	first->link_phy = second->this_phy | TD_DEPTH_FIRST;
1181 	first->link_log = second;
1182 }
1183 
1184 
1185 size_t
1186 UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector,
1187 	size_t vectorCount)
1188 {
1189 	uhci_td *current = topDescriptor;
1190 	size_t actualLength = 0;
1191 	size_t vectorIndex = 0;
1192 	size_t vectorOffset = 0;
1193 	size_t bufferOffset = 0;
1194 
1195 	while (current) {
1196 		if (!current->buffer_log)
1197 			break;
1198 
1199 		while (true) {
1200 			size_t length = min_c(current->buffer_size - bufferOffset,
1201 				vector[vectorIndex].iov_len - vectorOffset);
1202 
1203 			TRACE(("usb_uhci: copying %d bytes to bufferOffset %d from vectorOffset %d at index %d of %d\n", length, bufferOffset, vectorOffset, vectorIndex, vectorCount));
1204 			memcpy((uint8 *)current->buffer_log + bufferOffset,
1205 				(uint8 *)vector[vectorIndex].iov_base + vectorOffset, length);
1206 
1207 			actualLength += length;
1208 			vectorOffset += length;
1209 			bufferOffset += length;
1210 
1211 			if (vectorOffset >= vector[vectorIndex].iov_len) {
1212 				if (++vectorIndex >= vectorCount) {
1213 					TRACE(("usb_uhci: wrote descriptor chain (%d bytes, no more vectors)\n", actualLength));
1214 					return actualLength;
1215 				}
1216 
1217 				vectorOffset = 0;
1218 			}
1219 
1220 			if (bufferOffset >= current->buffer_size) {
1221 				bufferOffset = 0;
1222 				break;
1223 			}
1224 		}
1225 
1226 		if (current->link_phy & TD_TERMINATE)
1227 			break;
1228 
1229 		current = (uhci_td *)current->link_log;
1230 	}
1231 
1232 	TRACE(("usb_uhci: wrote descriptor chain (%d bytes)\n", actualLength));
1233 	return actualLength;
1234 }
1235 
1236 
1237 size_t
1238 UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector,
1239 	size_t vectorCount, uint8 *lastDataToggle)
1240 {
1241 	uint8 dataToggle = 0;
1242 	uhci_td *current = topDescriptor;
1243 	size_t actualLength = 0;
1244 	size_t vectorIndex = 0;
1245 	size_t vectorOffset = 0;
1246 	size_t bufferOffset = 0;
1247 
1248 	while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
1249 		if (!current->buffer_log)
1250 			break;
1251 
1252 		dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
1253 		size_t bufferSize = (current->status & TD_STATUS_ACTLEN_MASK) + 1;
1254 		if (bufferSize == TD_STATUS_ACTLEN_NULL + 1)
1255 			bufferSize = 0;
1256 
1257 		while (true) {
1258 			size_t length = min_c(bufferSize - bufferOffset,
1259 				vector[vectorIndex].iov_len - vectorOffset);
1260 
1261 			TRACE(("usb_uhci: copying %d bytes to vectorOffset %d from bufferOffset %d at index %d of %d\n", length, vectorOffset, bufferOffset, vectorIndex, vectorCount));
1262 			memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
1263 				(uint8 *)current->buffer_log + bufferOffset, length);
1264 
1265 			actualLength += length;
1266 			vectorOffset += length;
1267 			bufferOffset += length;
1268 
1269 			if (vectorOffset >= vector[vectorIndex].iov_len) {
1270 				if (++vectorIndex >= vectorCount) {
1271 					TRACE(("usb_uhci: read descriptor chain (%d bytes, no more vectors)\n", actualLength));
1272 					if (lastDataToggle)
1273 						*lastDataToggle = dataToggle;
1274 					return actualLength;
1275 				}
1276 
1277 				vectorOffset = 0;
1278 			}
1279 
1280 			if (bufferOffset >= bufferSize) {
1281 				bufferOffset = 0;
1282 				break;
1283 			}
1284 		}
1285 
1286 		if (current->link_phy & TD_TERMINATE)
1287 			break;
1288 
1289 		current = (uhci_td *)current->link_log;
1290 	}
1291 
1292 	if (lastDataToggle)
1293 		*lastDataToggle = dataToggle;
1294 
1295 	TRACE(("usb_uhci: read descriptor chain (%d bytes)\n", actualLength));
1296 	return actualLength;
1297 }
1298 
1299 
1300 size_t
1301 UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle)
1302 {
1303 	size_t actualLength = 0;
1304 	uhci_td *current = topDescriptor;
1305 	uint8 dataToggle = 0;
1306 
1307 	while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
1308 		size_t length = (current->status & TD_STATUS_ACTLEN_MASK) + 1;
1309 		if (length == TD_STATUS_ACTLEN_NULL + 1)
1310 			length = 0;
1311 
1312 		actualLength += length;
1313 		dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
1314 
1315 		if (current->link_phy & TD_TERMINATE)
1316 			break;
1317 
1318 		current = (uhci_td *)current->link_log;
1319 	}
1320 
1321 	if (lastDataToggle)
1322 		*lastDataToggle = dataToggle;
1323 
1324 	TRACE(("usb_uhci: read actual length (%d bytes)\n", actualLength));
1325 	return actualLength;
1326 }
1327 
1328 
1329 inline void
1330 UHCI::WriteReg8(uint32 reg, uint8 value)
1331 {
1332 	sPCIModule->write_io_8(fRegisterBase + reg, value);
1333 }
1334 
1335 
1336 inline void
1337 UHCI::WriteReg16(uint32 reg, uint16 value)
1338 {
1339 	sPCIModule->write_io_16(fRegisterBase + reg, value);
1340 }
1341 
1342 
1343 inline void
1344 UHCI::WriteReg32(uint32 reg, uint32 value)
1345 {
1346 	sPCIModule->write_io_32(fRegisterBase + reg, value);
1347 }
1348 
1349 
1350 inline uint8
1351 UHCI::ReadReg8(uint32 reg)
1352 {
1353 	return sPCIModule->read_io_8(fRegisterBase + reg);
1354 }
1355 
1356 
1357 inline uint16
1358 UHCI::ReadReg16(uint32 reg)
1359 {
1360 	return sPCIModule->read_io_16(fRegisterBase + reg);
1361 }
1362 
1363 
1364 inline uint32
1365 UHCI::ReadReg32(uint32 reg)
1366 {
1367 	return sPCIModule->read_io_32(fRegisterBase + reg);
1368 }
1369