xref: /haiku/src/add-ons/kernel/busses/usb/uhci.cpp (revision 0c93c0a807b27096abbfad677436afb7d1712d4a)
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",
45 		0,
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%08lx; lp: 0x%08lx; vf: %s; q: %s; t: %s; st: 0x%08lx; to: 0x%08lx\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,
103 		sizeof(uhci_qh));
104 	if (fStatus < B_OK)
105 		return;
106 
107 	fQueueHead->this_phy = (addr_t)physicalAddress;
108 	fQueueHead->element_phy = QH_TERMINATE;
109 
110 	fStrayDescriptor = NULL;
111 	fQueueTop = NULL;
112 }
113 
114 
115 Queue::~Queue()
116 {
117 	Lock();
118 	benaphore_destroy(&fLock);
119 
120 	fStack->FreeChunk(fQueueHead, (void *)fQueueHead->this_phy, sizeof(uhci_qh));
121 
122 	if (fStrayDescriptor)
123 		fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy,
124 			sizeof(uhci_td));
125 }
126 
127 
128 status_t
129 Queue::InitCheck()
130 {
131 	return fStatus;
132 }
133 
134 
135 bool
136 Queue::Lock()
137 {
138 	return (benaphore_lock(&fLock) == B_OK);
139 }
140 
141 
142 void
143 Queue::Unlock()
144 {
145 	benaphore_unlock(&fLock);
146 }
147 
148 
149 status_t
150 Queue::LinkTo(Queue *other)
151 {
152 	if (!other)
153 		return B_BAD_VALUE;
154 
155 	if (!Lock())
156 		return B_ERROR;
157 
158 	fQueueHead->link_phy = other->fQueueHead->this_phy | QH_NEXT_IS_QH;
159 	fQueueHead->link_log = other->fQueueHead;
160 	Unlock();
161 
162 	return B_OK;
163 }
164 
165 
166 status_t
167 Queue::TerminateByStrayDescriptor()
168 {
169 	// According to the *BSD USB sources, there needs to be a stray transfer
170 	// descriptor in order to get some chipset to work nicely (like the PIIX).
171 	void *physicalAddress;
172 	status_t result = fStack->AllocateChunk((void **)&fStrayDescriptor,
173 		&physicalAddress, sizeof(uhci_td));
174 	if (result < B_OK) {
175 		TRACE_ERROR(("usb_uhci: failed to allocate a stray transfer descriptor\n"));
176 		return result;
177 	}
178 
179 	fStrayDescriptor->status = 0;
180 	fStrayDescriptor->this_phy = (addr_t)physicalAddress;
181 	fStrayDescriptor->link_phy = TD_TERMINATE;
182 	fStrayDescriptor->link_log = 0;
183 	fStrayDescriptor->buffer_phy = 0;
184 	fStrayDescriptor->buffer_log = 0;
185 	fStrayDescriptor->buffer_size = 0;
186 	fStrayDescriptor->token = TD_TOKEN_NULL_DATA
187 		| (0x7f << TD_TOKEN_DEVADDR_SHIFT) | TD_TOKEN_IN;
188 
189 	if (!Lock()) {
190 		fStack->FreeChunk(fStrayDescriptor, (void *)fStrayDescriptor->this_phy,
191 			sizeof(uhci_td));
192 		return B_ERROR;
193 	}
194 
195 	fQueueHead->link_phy = fStrayDescriptor->this_phy;
196 	fQueueHead->link_log = fStrayDescriptor;
197 	Unlock();
198 
199 	return B_OK;
200 }
201 
202 
203 status_t
204 Queue::AppendTransfer(uhci_qh *transfer)
205 {
206 	if (!Lock())
207 		return B_ERROR;
208 
209 	transfer->link_log = NULL;
210 	transfer->link_phy = fQueueHead->link_phy;
211 
212 	if (!fQueueTop) {
213 		// the list is empty, make this the first element
214 		fQueueTop = transfer;
215 		fQueueHead->element_phy = transfer->this_phy | QH_NEXT_IS_QH;
216 	} else {
217 		// append the transfer queue to the list
218 		uhci_qh *element = fQueueTop;
219 		while (element && element->link_log)
220 			element = (uhci_qh *)element->link_log;
221 
222 		element->link_log = transfer;
223 		element->link_phy = transfer->this_phy | QH_NEXT_IS_QH;
224 	}
225 
226 	Unlock();
227 	return B_OK;
228 }
229 
230 
231 status_t
232 Queue::RemoveTransfer(uhci_qh *transfer)
233 {
234 	if (!Lock())
235 		return B_ERROR;
236 
237 	if (fQueueTop == transfer) {
238 		// this was the top element
239 		fQueueTop = (uhci_qh *)transfer->link_log;
240 		if (!fQueueTop) {
241 			// this was the only element, terminate this queue
242 			fQueueHead->element_phy = QH_TERMINATE;
243 		} else {
244 			// there are elements left, adjust the element pointer
245 			fQueueHead->element_phy = transfer->link_phy;
246 		}
247 
248 		Unlock();
249 		return B_OK;
250 	} else {
251 		uhci_qh *element = fQueueTop;
252 		while (element) {
253 			if (element->link_log == transfer) {
254 				element->link_log = transfer->link_log;
255 				element->link_phy = transfer->link_phy;
256 				Unlock();
257 				return B_OK;
258 			}
259 
260 			element = (uhci_qh *)element->link_log;
261 		}
262 	}
263 
264 	Unlock();
265 	return B_BAD_VALUE;
266 }
267 
268 
269 addr_t
270 Queue::PhysicalAddress()
271 {
272 	return fQueueHead->this_phy;
273 }
274 
275 
276 void
277 Queue::PrintToStream()
278 {
279 #ifdef TRACE_USB
280 	dprintf("USB UHCI Queue:\n");
281 	dprintf("link phy: 0x%08lx; link type: %s; terminate: %s\n", fQueueHead->link_phy & 0xfff0, fQueueHead->link_phy & 0x0002 ? "QH" : "TD", fQueueHead->link_phy & 0x0001 ? "yes" : "no");
282 	dprintf("elem phy: 0x%08lx; elem type: %s; terminate: %s\n", fQueueHead->element_phy & 0xfff0, fQueueHead->element_phy & 0x0002 ? "QH" : "TD", fQueueHead->element_phy & 0x0001 ? "yes" : "no");
283 #endif
284 }
285 
286 
287 //
288 // #pragma mark -
289 //
290 
291 
292 UHCI::UHCI(pci_info *info, Stack *stack)
293 	:	BusManager(stack),
294 		fPCIInfo(info),
295 		fStack(stack),
296 		fFrameArea(-1),
297 		fFrameList(NULL),
298 		fQueueCount(0),
299 		fQueues(NULL),
300 		fFirstTransfer(NULL),
301 		fLastTransfer(NULL),
302 		fFinishThread(-1),
303 		fStopFinishThread(false),
304 		fRootHub(NULL),
305 		fRootHubAddress(0),
306 		fPortResetChange(0)
307 {
308 	if (!fInitOK) {
309 		TRACE_ERROR(("usb_uhci: bus manager failed to init\n"));
310 		return;
311 	}
312 
313 	TRACE(("usb_uhci: constructing new UHCI Host Controller Driver\n"));
314 	fInitOK = false;
315 
316 	fRegisterBase = sPCIModule->read_pci_config(fPCIInfo->bus,
317 		fPCIInfo->device, fPCIInfo->function, PCI_memory_base, 4);
318 	fRegisterBase &= PCI_address_io_mask;
319 	TRACE_ERROR(("usb_uhci: iospace offset: 0x%08lx\n", fRegisterBase));
320 
321 	if (fRegisterBase == 0) {
322 		fRegisterBase = fPCIInfo->u.h0.base_registers[0];
323 		TRACE_ERROR(("usb_uhci: register base: 0x%08lx\n", fRegisterBase));
324 	}
325 
326 	// enable pci address access
327 	uint16 command = PCI_command_io | PCI_command_master | PCI_command_memory;
328 	command |= sPCIModule->read_pci_config(fPCIInfo->bus, fPCIInfo->device,
329 		fPCIInfo->function, PCI_command, 2);
330 
331 	sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
332 		fPCIInfo->function, PCI_command, 2, command);
333 
334 	// make sure we gain control of the UHCI controller instead of the BIOS
335 	sPCIModule->write_pci_config(fPCIInfo->bus, fPCIInfo->device,
336 		fPCIInfo->function, PCI_LEGSUP, 2, PCI_LEGSUP_USBPIRQDEN);
337 
338 	// disable interrupts
339 	WriteReg16(UHCI_USBINTR, 0);
340 
341 	// do a global and host reset
342 	GlobalReset();
343 	if (ControllerReset() < B_OK) {
344 		TRACE_ERROR(("usb_uhci: host failed to reset\n"));
345 		return;
346 	}
347 
348 	// Setup the frame list
349 	void *physicalAddress;
350 	fFrameArea = fStack->AllocateArea((void **)&fFrameList,
351 		(void **)&physicalAddress, 4096, "USB UHCI framelist");
352 
353 	if (fFrameArea < B_OK) {
354 		TRACE_ERROR(("usb_uhci: unable to create an area for the frame pointer list\n"));
355 		return;
356 	}
357 
358 	// Set base pointer and reset frame number
359 	WriteReg32(UHCI_FRBASEADD, (uint32)physicalAddress);
360 	WriteReg16(UHCI_FRNUM, 0);
361 
362 	// Set the max packet size for bandwidth reclamation to 64 bytes
363 	WriteReg16(UHCI_USBCMD, ReadReg16(UHCI_USBCMD) | UHCI_USBCMD_MAXP);
364 
365 	// we will create four queues:
366 	// 0: interrupt transfers
367 	// 1: low speed control transfers
368 	// 2: full speed control transfers
369 	// 3: bulk transfers
370 	fQueueCount = 4;
371 	fQueues = new(std::nothrow) Queue *[fQueueCount];
372 	if (!fQueues) {
373 		delete_area(fFrameArea);
374 		return;
375 	}
376 
377 	for (int32 i = 0; i < fQueueCount; i++) {
378 		fQueues[i] = new(std::nothrow) Queue(fStack);
379 		if (!fQueues[i] || fQueues[i]->InitCheck() < B_OK) {
380 			TRACE_ERROR(("usb_uhci: cannot create queues\n"));
381 			delete_area(fFrameArea);
382 			return;
383 		}
384 
385 		if (i > 0)
386 			fQueues[i - 1]->LinkTo(fQueues[i]);
387 	}
388 
389 	// Make sure the last queue terminates
390 	fQueues[fQueueCount - 1]->TerminateByStrayDescriptor();
391 
392 	for (int32 i = 0; i < 1024; i++)
393 		fFrameList[i] = fQueues[0]->PhysicalAddress() | FRAMELIST_NEXT_IS_QH;
394 
395 	// create semaphore the finisher thread will wait for
396 	fFinishTransfersSem = create_sem(0, "UHCI Finish Transfers");
397 	if (fFinishTransfersSem < B_OK) {
398 		TRACE_ERROR(("usb_uhci: failed to create semaphore\n"));
399 		return;
400 	}
401 
402 	// Create the finisher service thread
403 	fFinishThread = spawn_kernel_thread(FinishThread,
404 		"uhci finish thread", B_URGENT_DISPLAY_PRIORITY, (void *)this);
405 	resume_thread(fFinishThread);
406 
407 	// Install the interrupt handler
408 	TRACE(("usb_uhci: installing interrupt handler\n"));
409 	install_io_interrupt_handler(fPCIInfo->u.h0.interrupt_line,
410 		InterruptHandler, (void *)this, 0);
411 
412 	// Enable interrupts
413 	WriteReg16(UHCI_USBINTR, UHCI_USBINTR_CRC | UHCI_USBINTR_RESUME
414 		| UHCI_USBINTR_IOC | UHCI_USBINTR_SHORT);
415 
416 	TRACE(("usb_uhci: UHCI Host Controller Driver constructed\n"));
417 	fInitOK = true;
418 }
419 
420 
421 UHCI::~UHCI()
422 {
423 	int32 result = 0;
424 	fStopFinishThread = true;
425 	delete_sem(fFinishTransfersSem);
426 	wait_for_thread(fFinishThread, &result);
427 
428 	Lock();
429 	transfer_data *transfer = fFirstTransfer;
430 	while (transfer) {
431 		transfer_data *next = transfer->link;
432 		delete transfer;
433 		transfer = next;
434 	}
435 
436 	for (int32 i = 0; i < fQueueCount; i++)
437 		delete fQueues[i];
438 
439 	delete [] fQueues;
440 	delete fRootHub;
441 	delete_area(fFrameArea);
442 
443 	put_module(B_PCI_MODULE_NAME);
444 	Unlock();
445 }
446 
447 
448 status_t
449 UHCI::Start()
450 {
451 	// Start the host controller, then start the Busmanager
452 	TRACE(("usb_uhci: starting UHCI BusManager\n"));
453 	TRACE(("usb_uhci: usbcmd reg 0x%04x, usbsts reg 0x%04x\n",
454 		ReadReg16(UHCI_USBCMD), ReadReg16(UHCI_USBSTS)));
455 
456 	// Set the run bit in the command register
457 	WriteReg16(UHCI_USBCMD, ReadReg16(UHCI_USBCMD) | UHCI_USBCMD_RS);
458 
459 	bool running = false;
460 	for (int32 i = 0; i < 10; i++) {
461 		uint16 status = ReadReg16(UHCI_USBSTS);
462 		TRACE(("usb_uhci: current loop %ld, status 0x%04x\n", i, status));
463 
464 		if (status & UHCI_USBSTS_HCHALT)
465 			snooze(10000);
466 		else {
467 			running = true;
468 			break;
469 		}
470 	}
471 
472 	if (!running) {
473 		TRACE_ERROR(("usb_uhci: controller won't start running\n"));
474 		return B_ERROR;
475 	}
476 
477 	fRootHubAddress = AllocateAddress();
478 	fRootHub = new(std::nothrow) UHCIRootHub(RootObject(), fRootHubAddress);
479 	if (!fRootHub) {
480 		TRACE_ERROR(("usb_uhci: no memory to allocate root hub\n"));
481 		return B_NO_MEMORY;
482 	}
483 
484 	if (fRootHub->InitCheck() < B_OK) {
485 		TRACE_ERROR(("usb_uhci: root hub failed init check\n"));
486 		delete fRootHub;
487 		return B_ERROR;
488 	}
489 
490 	SetRootHub(fRootHub);
491 
492 	TRACE(("usb_uhci: controller is started. status: %u curframe: %u\n",
493 		ReadReg16(UHCI_USBSTS), ReadReg16(UHCI_FRNUM)));
494 	return BusManager::Start();
495 }
496 
497 
498 status_t
499 UHCI::SubmitTransfer(Transfer *transfer)
500 {
501 	// Short circuit the root hub
502 	if (transfer->TransferPipe()->DeviceAddress() == fRootHubAddress)
503 		return fRootHub->ProcessTransfer(this, transfer);
504 
505 	TRACE(("usb_uhci: submit transfer called for device %d\n", transfer->TransferPipe()->DeviceAddress()));
506 	if (transfer->TransferPipe()->Type() & USB_OBJECT_CONTROL_PIPE)
507 		return SubmitRequest(transfer);
508 
509 	uhci_td *firstDescriptor = NULL;
510 	uhci_qh *transferQueue = NULL;
511 	status_t result = CreateFilledTransfer(transfer, &firstDescriptor,
512 		&transferQueue);
513 	if (result < B_OK)
514 		return result;
515 
516 	Queue *queue = NULL;
517 	Pipe *pipe = transfer->TransferPipe();
518 	if (pipe->Type() & USB_OBJECT_INTERRUPT_PIPE) {
519 		// use interrupt queue
520 		queue = fQueues[0];
521 	} else {
522 		// use bulk queue
523 		queue = fQueues[3];
524 	}
525 
526 	bool directionIn = (pipe->Direction() == Pipe::In);
527 	result = AddPendingTransfer(transfer, queue, transferQueue,
528 		firstDescriptor, firstDescriptor, directionIn);
529 	if (result < B_OK) {
530 		TRACE_ERROR(("usb_uhci: failed to add pending transfer\n"));
531 		FreeDescriptorChain(firstDescriptor);
532 		FreeTransferQueue(transferQueue);
533 		return result;
534 	}
535 
536 	queue->AppendTransfer(transferQueue);
537 	return B_OK;
538 }
539 
540 
541 status_t
542 UHCI::SubmitRequest(Transfer *transfer)
543 {
544 	Pipe *pipe = transfer->TransferPipe();
545 	usb_request_data *requestData = transfer->RequestData();
546 	bool directionIn = (requestData->RequestType & USB_REQTYPE_DEVICE_IN) > 0;
547 
548 	uhci_td *setupDescriptor = CreateDescriptor(pipe, TD_TOKEN_SETUP,
549 		sizeof(usb_request_data));
550 
551 	uhci_td *statusDescriptor = CreateDescriptor(pipe,
552 		directionIn ? TD_TOKEN_OUT : TD_TOKEN_IN, 0);
553 
554 	if (!setupDescriptor || !statusDescriptor) {
555 		TRACE_ERROR(("usb_uhci: failed to allocate descriptors\n"));
556 		FreeDescriptor(setupDescriptor);
557 		FreeDescriptor(statusDescriptor);
558 		return B_NO_MEMORY;
559 	}
560 
561 	iovec vector;
562 	vector.iov_base = requestData;
563 	vector.iov_len = sizeof(usb_request_data);
564 	WriteDescriptorChain(setupDescriptor, &vector, 1);
565 
566 	statusDescriptor->status |= TD_CONTROL_IOC;
567 	statusDescriptor->token |= TD_TOKEN_DATA1;
568 	statusDescriptor->link_phy = TD_TERMINATE;
569 	statusDescriptor->link_log = NULL;
570 
571 	uhci_td *dataDescriptor = NULL;
572 	if (transfer->VectorCount() > 0) {
573 		uhci_td *lastDescriptor = NULL;
574 		status_t result = CreateDescriptorChain(pipe, &dataDescriptor,
575 			&lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
576 			transfer->VectorLength());
577 
578 		if (result < B_OK) {
579 			FreeDescriptor(setupDescriptor);
580 			FreeDescriptor(statusDescriptor);
581 			return result;
582 		}
583 
584 		if (!directionIn) {
585 			WriteDescriptorChain(dataDescriptor, transfer->Vector(),
586 				transfer->VectorCount());
587 		}
588 
589 		LinkDescriptors(setupDescriptor, dataDescriptor);
590 		LinkDescriptors(lastDescriptor, statusDescriptor);
591 	} else {
592 		// Link transfer and status descriptors directly
593 		LinkDescriptors(setupDescriptor, statusDescriptor);
594 	}
595 
596 	Queue *queue = NULL;
597 	if (pipe->Speed() == USB_SPEED_LOWSPEED) {
598 		// use the low speed control queue
599 		queue = fQueues[1];
600 	} else {
601 		// use the full speed control queue
602 		queue = fQueues[2];
603 	}
604 
605 	uhci_qh *transferQueue = CreateTransferQueue(setupDescriptor);
606 	status_t result = AddPendingTransfer(transfer, queue, transferQueue,
607 		setupDescriptor, dataDescriptor, directionIn);
608 	if (result < B_OK) {
609 		TRACE_ERROR(("usb_uhci: failed to add pending transfer\n"));
610 		FreeDescriptorChain(setupDescriptor);
611 		FreeTransferQueue(transferQueue);
612 		return result;
613 	}
614 
615 	queue->AppendTransfer(transferQueue);
616 	return B_OK;
617 }
618 
619 
620 status_t
621 UHCI::AddPendingTransfer(Transfer *transfer, Queue *queue,
622 	uhci_qh *transferQueue, uhci_td *firstDescriptor, uhci_td *dataDescriptor,
623 	bool directionIn)
624 {
625 	if (!transfer || !queue || !transferQueue || !firstDescriptor)
626 		return B_BAD_VALUE;
627 
628 	transfer_data *data = new(std::nothrow) transfer_data();
629 	if (!data)
630 		return B_NO_MEMORY;
631 
632 	data->transfer = transfer;
633 	data->queue = queue;
634 	data->transfer_queue = transferQueue;
635 	data->first_descriptor = firstDescriptor;
636 	data->data_descriptor = dataDescriptor;
637 	data->user_area = -1;
638 	data->incoming = directionIn;
639 	data->link = NULL;
640 
641 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
642 	if (directionIn) {
643 		// we might need to access a buffer in userspace. this will not
644 		// be possible in the kernel space finisher thread unless we
645 		// get the proper area id for the space we need and then clone it
646 		// before writing to it. this is of course terribly inefficient...
647 		iovec *vector = transfer->Vector();
648 		size_t vectorCount = transfer->VectorCount();
649 		for (size_t i = 0; i < vectorCount; i++) {
650 			if (IS_USER_ADDRESS(vector[i].iov_base)) {
651 				data->user_area = area_for(vector[i].iov_base);
652 				if (data->user_area < B_OK) {
653 					TRACE_ERROR(("usb_uhci: failed to get area of userspace buffer\n"));
654 					delete data;
655 					return B_BAD_ADDRESS;
656 				}
657 
658 				break;
659 			}
660 		}
661 
662 		if (data->user_area >= B_OK) {
663 			area_info areaInfo;
664 			if (get_area_info(data->user_area, &areaInfo) < B_OK) {
665 				TRACE_ERROR(("usb_uhci: failed to get info about user area\n"));
666 				delete data;
667 				return B_BAD_ADDRESS;
668 			}
669 
670 			for (size_t i = 0; i < vectorCount; i++) {
671 				(uint8 *)vector[i].iov_base -= (uint8 *)areaInfo.address;
672 
673 				if ((size_t)vector[i].iov_base > areaInfo.size
674 					|| (size_t)vector[i].iov_base + vector[i].iov_len > areaInfo.size) {
675 					TRACE_ERROR(("usb_uhci: output data buffer spans across multiple areas!\n"));
676 					delete data;
677 					return B_BAD_ADDRESS;
678 				}
679 			}
680 		}
681 	}
682 #endif // !HAIKU_TARGET_PLATFORM_HAIKU
683 
684 	if (!Lock()) {
685 		delete data;
686 		return B_ERROR;
687 	}
688 
689 	if (fLastTransfer)
690 		fLastTransfer->link = data;
691 	if (!fFirstTransfer)
692 		fFirstTransfer = data;
693 
694 	fLastTransfer = data;
695 	Unlock();
696 	return B_OK;
697 }
698 
699 
700 int32
701 UHCI::FinishThread(void *data)
702 {
703 	((UHCI *)data)->FinishTransfers();
704 	return B_OK;
705 }
706 
707 
708 void
709 UHCI::FinishTransfers()
710 {
711 	while (!fStopFinishThread) {
712 		if (acquire_sem(fFinishTransfersSem) < B_OK)
713 			continue;
714 
715 		// eat up sems that have been released by multiple interrupts
716 		int32 semCount = 0;
717 		get_sem_count(fFinishTransfersSem, &semCount);
718 		if (semCount > 0)
719 			acquire_sem_etc(fFinishTransfersSem, semCount, B_RELATIVE_TIMEOUT, 0);
720 
721 		if (!Lock())
722 			continue;
723 
724 		TRACE(("usb_uhci: finishing transfers (first transfer: 0x%08lx; last transfer: 0x%08lx)\n", (uint32)fFirstTransfer, (uint32)fLastTransfer));
725 		transfer_data *lastTransfer = NULL;
726 		transfer_data *transfer = fFirstTransfer;
727 		Unlock();
728 
729 		while (transfer) {
730 			bool transferDone = false;
731 			uhci_td *descriptor = transfer->first_descriptor;
732 
733 			while (descriptor) {
734 				uint32 status = descriptor->status;
735 				if (status & TD_STATUS_ACTIVE) {
736 					TRACE(("usb_uhci: td (0x%08lx) still active\n", descriptor->this_phy));
737 					// still in progress
738 					break;
739 				}
740 
741 				if (status & TD_ERROR_MASK) {
742 					TRACE_ERROR(("usb_uhci: td (0x%08lx) error: status: 0x%08lx; token: 0x%08lx;\n", descriptor->this_phy, status, descriptor->token));
743 					// an error occured. we have to remove the
744 					// transfer from the queue and clean up
745 
746 					status_t callbackStatus = B_ERROR;
747 					uint8 errorCount = status >> TD_ERROR_COUNT_SHIFT;
748 					errorCount &= TD_ERROR_COUNT_MASK;
749 					if (errorCount == 0) {
750 						// the error counter counted down to zero, report why
751 						int32 reasons = 0;
752 						if (status & TD_STATUS_ERROR_BUFFER) {
753 							callbackStatus = transfer->incoming ? B_DEV_DATA_OVERRUN : B_DEV_DATA_UNDERRUN;
754 							reasons++;
755 						}
756 						if (status & TD_STATUS_ERROR_TIMEOUT) {
757 							callbackStatus = transfer->incoming ? B_DEV_CRC_ERROR : B_TIMED_OUT;
758 							reasons++;
759 						}
760 						if (status & TD_STATUS_ERROR_NAK) {
761 							callbackStatus = B_DEV_UNEXPECTED_PID;
762 							reasons++;
763 						}
764 						if (status & TD_STATUS_ERROR_BITSTUFF) {
765 							callbackStatus = B_DEV_CRC_ERROR;
766 							reasons++;
767 						}
768 
769 						if (reasons > 1)
770 							callbackStatus = B_DEV_MULTIPLE_ERRORS;
771 					} else if (status & TD_STATUS_ERROR_BABBLE) {
772 						// there is a babble condition
773 						callbackStatus = transfer->incoming ? B_DEV_FIFO_OVERRUN : B_DEV_FIFO_UNDERRUN;
774 					} else {
775 						// if the error counter didn't count down to zero
776 						// and there was no babble, then this halt was caused
777 						// by a stall handshake
778 						callbackStatus = B_DEV_STALLED;
779 					}
780 
781 					transfer->queue->RemoveTransfer(transfer->transfer_queue);
782 					FreeDescriptorChain(transfer->first_descriptor);
783 					FreeTransferQueue(transfer->transfer_queue);
784 					transfer->transfer->Finished(callbackStatus, 0);
785 					transferDone = true;
786 					break;
787 				}
788 
789 				// either all descriptors are done, or we have a short packet
790 				if ((descriptor->link_phy & TD_TERMINATE)
791 					|| (descriptor->status & TD_STATUS_ACTLEN_MASK)
792 					< (descriptor->token >> TD_TOKEN_MAXLEN_SHIFT)) {
793 					TRACE(("usb_uhci: td (0x%08lx) ok\n", descriptor->this_phy));
794 					// we got through without errors so we are finished
795 					transfer->queue->RemoveTransfer(transfer->transfer_queue);
796 
797 					size_t actualLength = 0;
798 					uint8 lastDataToggle = 0;
799 					if (transfer->data_descriptor && transfer->incoming) {
800 						// data to read out
801 						iovec *vector = transfer->transfer->Vector();
802 						size_t vectorCount = transfer->transfer->VectorCount();
803 
804 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
805 						area_id clonedArea = -1;
806 						void *clonedMemory = NULL;
807 						if (transfer->user_area >= B_OK) {
808 							// we got a userspace output buffer, need to clone
809 							// the area for that space first and map the iovecs
810 							// to this cloned area.
811 							clonedArea = clone_area("userspace accessor",
812 								&clonedMemory, B_ANY_ADDRESS,
813 								B_WRITE_AREA | B_KERNEL_WRITE_AREA,
814 								transfer->user_area);
815 
816 							for (size_t i = 0; i < vectorCount; i++)
817 								(uint8 *)vector[i].iov_base += (addr_t)clonedMemory;
818 						}
819 #endif // !HAIKU_TARGET_PLATFORM_HAIKU
820 
821 						actualLength = ReadDescriptorChain(
822 							transfer->data_descriptor,
823 							vector, vectorCount,
824 							&lastDataToggle);
825 
826 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
827 						if (clonedArea >= B_OK) {
828 							for (size_t i = 0; i < vectorCount; i++)
829 								(uint8 *)vector[i].iov_base -= (addr_t)clonedMemory;
830 							delete_area(clonedArea);
831 						}
832 #endif // !HAIKU_TARGET_PLATFORM_HAIKU
833 					} else {
834 						// read the actual length that was sent
835 						actualLength = ReadActualLength(
836 							transfer->first_descriptor, &lastDataToggle);
837 					}
838 
839 					transfer->transfer->TransferPipe()->SetDataToggle(lastDataToggle == 0);
840 					FreeDescriptorChain(transfer->first_descriptor);
841 					FreeTransferQueue(transfer->transfer_queue);
842 					if (transfer->transfer->IsFragmented()) {
843 						// this transfer may still have data left
844 						TRACE(("usb_uhci: advancing fragmented transfer\n"));
845 						transfer->transfer->AdvanceByFragment(actualLength);
846 						if (transfer->transfer->VectorLength() > 0) {
847 							TRACE(("usb_uhci: still %ld bytes left on transfer\n", transfer->transfer->VectorLength()));
848 							// resubmit the advanced transfer so the rest
849 							// of the buffers are transmitted over the bus
850 							status_t result = CreateFilledTransfer(transfer->transfer,
851 								&transfer->first_descriptor,
852 								&transfer->transfer_queue);
853 							if (result < B_OK) {
854 								transfer->transfer->Finished(result, 0);
855 								transferDone = true;
856 							};
857 
858 							transfer->data_descriptor = transfer->first_descriptor;
859 							transfer->queue->AppendTransfer(transfer->transfer_queue);
860 							break;
861 						}
862 
863 						// the transfer is done, but we already set the
864 						// actualLength with AdvanceByFragment()
865 						actualLength = 0;
866 					}
867 
868 					transfer->transfer->Finished(B_OK, actualLength);
869 					transferDone = true;
870 					break;
871 				}
872 
873 				descriptor = (uhci_td *)descriptor->link_log;
874 			}
875 
876 			if (transferDone) {
877 				if (Lock()) {
878 					if (lastTransfer)
879 						lastTransfer->link = transfer->link;
880 
881 					if (transfer == fFirstTransfer)
882 						fFirstTransfer = transfer->link;
883 					if (transfer == fLastTransfer)
884 						fLastTransfer = lastTransfer;
885 
886 					transfer_data *next = transfer->link;
887 					delete transfer->transfer;
888 					delete transfer;
889 					transfer = next;
890 					Unlock();
891 				}
892 			} else {
893 				lastTransfer = transfer;
894 				transfer = transfer->link;
895 			}
896 		}
897 	}
898 }
899 
900 
901 void
902 UHCI::GlobalReset()
903 {
904 	uint8 sofValue = ReadReg8(UHCI_SOFMOD);
905 
906 	WriteReg16(UHCI_USBCMD, UHCI_USBCMD_GRESET);
907 	snooze(100000);
908 	WriteReg16(UHCI_USBCMD, 0);
909 	snooze(10000);
910 
911 	WriteReg8(UHCI_SOFMOD, sofValue);
912 }
913 
914 
915 status_t
916 UHCI::ControllerReset()
917 {
918 	WriteReg16(UHCI_USBCMD, UHCI_USBCMD_HCRESET);
919 
920 	int32 tries = 5;
921 	while (ReadReg16(UHCI_USBCMD) & UHCI_USBCMD_HCRESET) {
922 		snooze(10000);
923 		if (tries-- < 0)
924 			return B_ERROR;
925 	}
926 
927 	return B_OK;
928 }
929 
930 
931 status_t
932 UHCI::GetPortStatus(uint8 index, usb_port_status *status)
933 {
934 	if (index > 1)
935 		return B_BAD_INDEX;
936 
937 	status->status = status->change = 0;
938 	uint16 portStatus = ReadReg16(UHCI_PORTSC1 + index * 2);
939 
940 	// build the status
941 	if (portStatus & UHCI_PORTSC_CURSTAT)
942 		status->status |= PORT_STATUS_CONNECTION;
943 	if (portStatus & UHCI_PORTSC_ENABLED)
944 		status->status |= PORT_STATUS_ENABLE;
945 	if (portStatus & UHCI_PORTSC_RESET)
946 		status->status |= PORT_STATUS_RESET;
947 	if (portStatus & UHCI_PORTSC_LOWSPEED)
948 		status->status |= PORT_STATUS_LOW_SPEED;
949 
950 	// build the change
951 	if (portStatus & UHCI_PORTSC_STATCHA)
952 		status->change |= PORT_STATUS_CONNECTION;
953 	if (portStatus & UHCI_PORTSC_ENABCHA)
954 		status->change |= PORT_STATUS_ENABLE;
955 
956 	// ToDo: work out suspended/resume
957 
958 	// there are no bits to indicate reset change
959 	if (fPortResetChange & (1 << index))
960 		status->change |= PORT_STATUS_RESET;
961 
962 	// the port is automagically powered on
963 	status->status |= PORT_STATUS_POWER;
964 	return B_OK;
965 }
966 
967 
968 status_t
969 UHCI::SetPortFeature(uint8 index, uint16 feature)
970 {
971 	if (index > 1)
972 		return B_BAD_INDEX;
973 
974 	switch (feature) {
975 		case PORT_RESET:
976 			return ResetPort(index);
977 
978 		case PORT_POWER:
979 			// the ports are automatically powered
980 			return B_OK;
981 	}
982 
983 	return B_BAD_VALUE;
984 }
985 
986 
987 status_t
988 UHCI::ClearPortFeature(uint8 index, uint16 feature)
989 {
990 	if (index > 1)
991 		return B_BAD_INDEX;
992 
993 	uint32 portRegister = UHCI_PORTSC1 + index * 2;
994 	uint16 portStatus = ReadReg16(portRegister) & UHCI_PORTSC_DATAMASK;
995 
996 	switch (feature) {
997 		case C_PORT_RESET:
998 			fPortResetChange &= ~(1 << index);
999 			return B_OK;
1000 
1001 		case C_PORT_CONNECTION:
1002 			WriteReg16(portRegister, portStatus | UHCI_PORTSC_STATCHA);
1003 			return B_OK;
1004 
1005 		case C_PORT_ENABLE:
1006 			WriteReg16(portRegister, portStatus | UHCI_PORTSC_ENABCHA);
1007 			return B_OK;
1008 	}
1009 
1010 	return B_BAD_VALUE;
1011 }
1012 
1013 
1014 status_t
1015 UHCI::ResetPort(uint8 index)
1016 {
1017 	if (index > 1)
1018 		return B_BAD_INDEX;
1019 
1020 	TRACE(("usb_uhci: reset port %d\n", index));
1021 
1022 	uint32 port = UHCI_PORTSC1 + index * 2;
1023 	uint16 status = ReadReg16(port);
1024 	status &= UHCI_PORTSC_DATAMASK;
1025 	WriteReg16(port, status | UHCI_PORTSC_RESET);
1026 	snooze(250000);
1027 
1028 	status = ReadReg16(port);
1029 	status &= UHCI_PORTSC_DATAMASK;
1030 	WriteReg16(port, status & ~UHCI_PORTSC_RESET);
1031 	snooze(1000);
1032 
1033 	for (int32 i = 10; i > 0; i--) {
1034 		// try to enable the port
1035 		status = ReadReg16(port);
1036 		status &= UHCI_PORTSC_DATAMASK;
1037 		WriteReg16(port, status | UHCI_PORTSC_ENABLED);
1038 		snooze(50000);
1039 
1040 		status = ReadReg16(port);
1041 
1042 		if ((status & UHCI_PORTSC_CURSTAT) == 0) {
1043 			// no device connected. since we waited long enough we can assume
1044 			// that the port was reset and no device is connected.
1045 			break;
1046 		}
1047 
1048 		if (status & (UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA)) {
1049 			// port enabled changed or connection status were set.
1050 			// acknowledge either / both and wait again.
1051 			status &= UHCI_PORTSC_DATAMASK;
1052 			WriteReg16(port, status | UHCI_PORTSC_STATCHA | UHCI_PORTSC_ENABCHA);
1053 			continue;
1054 		}
1055 
1056 		if (status & UHCI_PORTSC_ENABLED) {
1057 			// the port is enabled
1058 			break;
1059 		}
1060 	}
1061 
1062 	fPortResetChange |= (1 << index);
1063 	TRACE(("usb_uhci: port was reset: 0x%04x\n", ReadReg16(port)));
1064 	return B_OK;
1065 }
1066 
1067 
1068 int32
1069 UHCI::InterruptHandler(void *data)
1070 {
1071 	return ((UHCI *)data)->Interrupt();
1072 }
1073 
1074 
1075 int32
1076 UHCI::Interrupt()
1077 {
1078 	static spinlock lock = 0;
1079 	acquire_spinlock(&lock);
1080 
1081 	// Check if we really had an interrupt
1082 	uint16 status = ReadReg16(UHCI_USBSTS);
1083 	if ((status & UHCI_INTERRUPT_MASK) == 0) {
1084 		release_spinlock(&lock);
1085 		return B_UNHANDLED_INTERRUPT;
1086 	}
1087 
1088 	uint16 acknowledge = 0;
1089 	bool finishTransfers = false;
1090 	int32 result = B_HANDLED_INTERRUPT;
1091 
1092 	if (status & UHCI_USBSTS_USBINT) {
1093 		TRACE(("usb_uhci: transfer finished\n"));
1094 		acknowledge |= UHCI_USBSTS_USBINT;
1095 		result = B_INVOKE_SCHEDULER;
1096 		finishTransfers = true;
1097 	}
1098 
1099 	if (status & UHCI_USBSTS_ERRINT) {
1100 		TRACE(("usb_uhci: transfer error\n"));
1101 		acknowledge |= UHCI_USBSTS_ERRINT;
1102 		result = B_INVOKE_SCHEDULER;
1103 		finishTransfers = true;
1104 	}
1105 
1106 	if (status & UHCI_USBSTS_RESDET) {
1107 		TRACE(("usb_uhci: resume detected\n"));
1108 		acknowledge |= UHCI_USBSTS_RESDET;
1109 	}
1110 
1111 	if (status & UHCI_USBSTS_HOSTERR) {
1112 		TRACE(("usb_uhci: host system error\n"));
1113 		acknowledge |= UHCI_USBSTS_HOSTERR;
1114 	}
1115 
1116 	if (status & UHCI_USBSTS_HCPRERR) {
1117 		TRACE(("usb_uhci: process error\n"));
1118 		acknowledge |= UHCI_USBSTS_HCPRERR;
1119 	}
1120 
1121 	if (status & UHCI_USBSTS_HCHALT) {
1122 		TRACE(("usb_uhci: host controller halted\n"));
1123 		// ToDo: cancel all transfers and reset the host controller
1124 		// acknowledge not needed
1125 	}
1126 
1127 	if (acknowledge)
1128 		WriteReg16(UHCI_USBSTS, acknowledge);
1129 
1130 	release_spinlock(&lock);
1131 
1132 	if (finishTransfers)
1133 		release_sem_etc(fFinishTransfersSem, 1, B_DO_NOT_RESCHEDULE);
1134 
1135 	return result;
1136 }
1137 
1138 
1139 status_t
1140 UHCI::AddTo(Stack *stack)
1141 {
1142 #ifdef TRACE_USB
1143 	set_dprintf_enabled(true);
1144 	load_driver_symbols("uhci");
1145 #endif
1146 
1147 	if (!sPCIModule) {
1148 		status_t status = get_module(B_PCI_MODULE_NAME, (module_info **)&sPCIModule);
1149 		if (status < B_OK) {
1150 			TRACE_ERROR(("usb_uhci: AddTo(): getting pci module failed! 0x%08lx\n",
1151 				status));
1152 			return status;
1153 		}
1154 	}
1155 
1156 	TRACE(("usb_uhci: AddTo(): setting up hardware\n"));
1157 
1158 	bool found = false;
1159 	pci_info *item = new(std::nothrow) pci_info;
1160 	if (!item) {
1161 		sPCIModule = NULL;
1162 		put_module(B_PCI_MODULE_NAME);
1163 		return B_NO_MEMORY;
1164 	}
1165 
1166 	for (int32 i = 0; sPCIModule->get_nth_pci_info(i, item) >= B_OK; i++) {
1167 
1168 		if (item->class_base == PCI_serial_bus && item->class_sub == PCI_usb
1169 			&& item->class_api == PCI_usb_uhci) {
1170 			if (item->u.h0.interrupt_line == 0
1171 				|| item->u.h0.interrupt_line == 0xFF) {
1172 				TRACE_ERROR(("usb_uhci: AddTo(): found with invalid IRQ - check IRQ assignement\n"));
1173 				continue;
1174 			}
1175 
1176 			TRACE(("usb_uhci: AddTo(): found at IRQ %u\n", item->u.h0.interrupt_line));
1177 			UHCI *bus = new(std::nothrow) UHCI(item, stack);
1178 			if (!bus) {
1179 				delete item;
1180 				sPCIModule = NULL;
1181 				put_module(B_PCI_MODULE_NAME);
1182 				return B_NO_MEMORY;
1183 			}
1184 
1185 			if (bus->InitCheck() < B_OK) {
1186 				TRACE_ERROR(("usb_uhci: AddTo(): InitCheck() failed 0x%08lx\n", bus->InitCheck()));
1187 				delete bus;
1188 				continue;
1189 			}
1190 
1191 			// the bus took it away
1192 			item = new(std::nothrow) pci_info;
1193 
1194 			bus->Start();
1195 			stack->AddBusManager(bus);
1196 			found = true;
1197 		}
1198 	}
1199 
1200 	if (!found) {
1201 		TRACE_ERROR(("usb_uhci: no devices found\n"));
1202 		delete item;
1203 		sPCIModule = NULL;
1204 		put_module(B_PCI_MODULE_NAME);
1205 		return ENODEV;
1206 	}
1207 
1208 	delete item;
1209 	return B_OK;
1210 }
1211 
1212 
1213 status_t
1214 UHCI::CreateFilledTransfer(Transfer *transfer, uhci_td **_firstDescriptor,
1215 	uhci_qh **_transferQueue)
1216 {
1217 	Pipe *pipe = transfer->TransferPipe();
1218 	bool directionIn = (pipe->Direction() == Pipe::In);
1219 
1220 	uhci_td *firstDescriptor = NULL;
1221 	uhci_td *lastDescriptor = NULL;
1222 	status_t result = CreateDescriptorChain(pipe, &firstDescriptor,
1223 		&lastDescriptor, directionIn ? TD_TOKEN_IN : TD_TOKEN_OUT,
1224 		transfer->VectorLength());
1225 
1226 	if (result < B_OK)
1227 		return result;
1228 	if (!firstDescriptor || !lastDescriptor)
1229 		return B_NO_MEMORY;
1230 
1231 	lastDescriptor->status |= TD_CONTROL_IOC;
1232 	lastDescriptor->link_phy = TD_TERMINATE;
1233 	lastDescriptor->link_log = 0;
1234 
1235 	if (!directionIn) {
1236 		WriteDescriptorChain(firstDescriptor, transfer->Vector(),
1237 			transfer->VectorCount());
1238 	}
1239 
1240 	uhci_qh *transferQueue = CreateTransferQueue(firstDescriptor);
1241 	if (!transferQueue) {
1242 		FreeDescriptorChain(firstDescriptor);
1243 		return B_NO_MEMORY;
1244 	}
1245 
1246 	*_firstDescriptor = firstDescriptor;
1247 	*_transferQueue = transferQueue;
1248 	return B_OK;
1249 }
1250 
1251 
1252 uhci_qh *
1253 UHCI::CreateTransferQueue(uhci_td *descriptor)
1254 {
1255 	uhci_qh *queueHead;
1256 	void *physicalAddress;
1257 	if (fStack->AllocateChunk((void **)&queueHead,
1258 		&physicalAddress, sizeof(uhci_qh)) < B_OK)
1259 		return NULL;
1260 
1261 	queueHead->this_phy = (addr_t)physicalAddress;
1262 	queueHead->element_phy = descriptor->this_phy;
1263 	return queueHead;
1264 }
1265 
1266 
1267 void
1268 UHCI::FreeTransferQueue(uhci_qh *queueHead)
1269 {
1270 	if (!queueHead)
1271 		return;
1272 
1273 	fStack->FreeChunk(queueHead, (void *)queueHead->this_phy, sizeof(uhci_qh));
1274 }
1275 
1276 
1277 uhci_td *
1278 UHCI::CreateDescriptor(Pipe *pipe, uint8 direction, size_t bufferSize)
1279 {
1280 	uhci_td *result;
1281 	void *physicalAddress;
1282 
1283 	if (fStack->AllocateChunk((void **)&result, &physicalAddress,
1284 		sizeof(uhci_td)) < B_OK) {
1285 		TRACE_ERROR(("usb_uhci: failed to allocate a transfer descriptor\n"));
1286 		return NULL;
1287 	}
1288 
1289 	result->this_phy = (addr_t)physicalAddress;
1290 	result->status = TD_STATUS_ACTIVE | TD_CONTROL_3_ERRORS;
1291 	if (direction == TD_TOKEN_IN)
1292 		result->status |= TD_CONTROL_SPD;
1293 	if (pipe->Speed() == USB_SPEED_LOWSPEED)
1294 		result->status |= TD_CONTROL_LOWSPEED;
1295 
1296 	result->buffer_size = bufferSize;
1297 	if (bufferSize == 0)
1298 		result->token = TD_TOKEN_NULL_DATA;
1299 	else
1300 		result->token = (bufferSize - 1) << TD_TOKEN_MAXLEN_SHIFT;
1301 
1302 	result->token |= (pipe->EndpointAddress() << TD_TOKEN_ENDPTADDR_SHIFT)
1303 		| (pipe->DeviceAddress() << 8) | direction;
1304 
1305 	result->link_phy = 0;
1306 	result->link_log = NULL;
1307 	if (bufferSize <= 0) {
1308 		result->buffer_log = NULL;
1309 		result->buffer_phy = NULL;
1310 		return result;
1311 	}
1312 
1313 	if (fStack->AllocateChunk(&result->buffer_log, &result->buffer_phy,
1314 		bufferSize) < B_OK) {
1315 		TRACE_ERROR(("usb_uhci: unable to allocate space for the buffer\n"));
1316 		fStack->FreeChunk(result, (void *)result->this_phy, sizeof(uhci_td));
1317 		return NULL;
1318 	}
1319 
1320 	return result;
1321 }
1322 
1323 
1324 status_t
1325 UHCI::CreateDescriptorChain(Pipe *pipe, uhci_td **_firstDescriptor,
1326 	uhci_td **_lastDescriptor, uint8 direction, size_t bufferSize)
1327 {
1328 	size_t packetSize = pipe->MaxPacketSize();
1329 	int32 descriptorCount = (bufferSize + packetSize - 1) / packetSize;
1330 	if (descriptorCount == 0)
1331 		descriptorCount = 1;
1332 
1333 	bool dataToggle = pipe->DataToggle();
1334 	uhci_td *firstDescriptor = NULL;
1335 	uhci_td *lastDescriptor = *_firstDescriptor;
1336 	for (int32 i = 0; i < descriptorCount; i++) {
1337 		uhci_td *descriptor = CreateDescriptor(pipe, direction,
1338 			min_c(packetSize, bufferSize));
1339 
1340 		if (!descriptor) {
1341 			FreeDescriptorChain(firstDescriptor);
1342 			return B_NO_MEMORY;
1343 		}
1344 
1345 		if (dataToggle)
1346 			descriptor->token |= TD_TOKEN_DATA1;
1347 
1348 		// link to previous
1349 		if (lastDescriptor)
1350 			LinkDescriptors(lastDescriptor, descriptor);
1351 
1352 		dataToggle = !dataToggle;
1353 		bufferSize -= packetSize;
1354 		lastDescriptor = descriptor;
1355 		if (!firstDescriptor)
1356 			firstDescriptor = descriptor;
1357 	}
1358 
1359 	*_firstDescriptor = firstDescriptor;
1360 	*_lastDescriptor = lastDescriptor;
1361 	return B_OK;
1362 }
1363 
1364 
1365 void
1366 UHCI::FreeDescriptor(uhci_td *descriptor)
1367 {
1368 	if (!descriptor)
1369 		return;
1370 
1371 	if (descriptor->buffer_log) {
1372 		fStack->FreeChunk(descriptor->buffer_log,
1373 			(void *)descriptor->buffer_phy, descriptor->buffer_size);
1374 	}
1375 
1376 	fStack->FreeChunk(descriptor, (void *)descriptor->this_phy, sizeof(uhci_td));
1377 }
1378 
1379 
1380 void
1381 UHCI::FreeDescriptorChain(uhci_td *topDescriptor)
1382 {
1383 	uhci_td *current = topDescriptor;
1384 	uhci_td *next = NULL;
1385 
1386 	while (current) {
1387 		next = (uhci_td *)current->link_log;
1388 		FreeDescriptor(current);
1389 		current = next;
1390 	}
1391 }
1392 
1393 
1394 void
1395 UHCI::LinkDescriptors(uhci_td *first, uhci_td *second)
1396 {
1397 	first->link_phy = second->this_phy | TD_DEPTH_FIRST;
1398 	first->link_log = second;
1399 }
1400 
1401 
1402 size_t
1403 UHCI::WriteDescriptorChain(uhci_td *topDescriptor, iovec *vector,
1404 	size_t vectorCount)
1405 {
1406 	uhci_td *current = topDescriptor;
1407 	size_t actualLength = 0;
1408 	size_t vectorIndex = 0;
1409 	size_t vectorOffset = 0;
1410 	size_t bufferOffset = 0;
1411 
1412 	while (current) {
1413 		if (!current->buffer_log)
1414 			break;
1415 
1416 		while (true) {
1417 			size_t length = min_c(current->buffer_size - bufferOffset,
1418 				vector[vectorIndex].iov_len - vectorOffset);
1419 
1420 			TRACE(("usb_uhci: copying %ld bytes to bufferOffset %ld from vectorOffset %ld at index %ld of %ld\n", length, bufferOffset, vectorOffset, vectorIndex, vectorCount));
1421 			memcpy((uint8 *)current->buffer_log + bufferOffset,
1422 				(uint8 *)vector[vectorIndex].iov_base + vectorOffset, length);
1423 
1424 			actualLength += length;
1425 			vectorOffset += length;
1426 			bufferOffset += length;
1427 
1428 			if (vectorOffset >= vector[vectorIndex].iov_len) {
1429 				if (++vectorIndex >= vectorCount) {
1430 					TRACE(("usb_uhci: wrote descriptor chain (%ld bytes, no more vectors)\n", actualLength));
1431 					return actualLength;
1432 				}
1433 
1434 				vectorOffset = 0;
1435 			}
1436 
1437 			if (bufferOffset >= current->buffer_size) {
1438 				bufferOffset = 0;
1439 				break;
1440 			}
1441 		}
1442 
1443 		if (current->link_phy & TD_TERMINATE)
1444 			break;
1445 
1446 		current = (uhci_td *)current->link_log;
1447 	}
1448 
1449 	TRACE(("usb_uhci: wrote descriptor chain (%ld bytes)\n", actualLength));
1450 	return actualLength;
1451 }
1452 
1453 
1454 size_t
1455 UHCI::ReadDescriptorChain(uhci_td *topDescriptor, iovec *vector,
1456 	size_t vectorCount, uint8 *lastDataToggle)
1457 {
1458 	uint8 dataToggle = 0;
1459 	uhci_td *current = topDescriptor;
1460 	size_t actualLength = 0;
1461 	size_t vectorIndex = 0;
1462 	size_t vectorOffset = 0;
1463 	size_t bufferOffset = 0;
1464 
1465 	while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
1466 		if (!current->buffer_log)
1467 			break;
1468 
1469 		dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
1470 		size_t bufferSize = (current->status & TD_STATUS_ACTLEN_MASK) + 1;
1471 		if (bufferSize == TD_STATUS_ACTLEN_NULL + 1)
1472 			bufferSize = 0;
1473 
1474 		while (true) {
1475 			size_t length = min_c(bufferSize - bufferOffset,
1476 				vector[vectorIndex].iov_len - vectorOffset);
1477 
1478 			TRACE(("usb_uhci: copying %ld bytes to vectorOffset %ld from bufferOffset %ld at index %ld of %ld\n", length, vectorOffset, bufferOffset, vectorIndex, vectorCount));
1479 			memcpy((uint8 *)vector[vectorIndex].iov_base + vectorOffset,
1480 				(uint8 *)current->buffer_log + bufferOffset, length);
1481 
1482 			actualLength += length;
1483 			vectorOffset += length;
1484 			bufferOffset += length;
1485 
1486 			if (vectorOffset >= vector[vectorIndex].iov_len) {
1487 				if (++vectorIndex >= vectorCount) {
1488 					TRACE(("usb_uhci: read descriptor chain (%ld bytes, no more vectors)\n", actualLength));
1489 					if (lastDataToggle)
1490 						*lastDataToggle = dataToggle;
1491 					return actualLength;
1492 				}
1493 
1494 				vectorOffset = 0;
1495 			}
1496 
1497 			if (bufferOffset >= bufferSize) {
1498 				bufferOffset = 0;
1499 				break;
1500 			}
1501 		}
1502 
1503 		if (current->link_phy & TD_TERMINATE)
1504 			break;
1505 
1506 		current = (uhci_td *)current->link_log;
1507 	}
1508 
1509 	if (lastDataToggle)
1510 		*lastDataToggle = dataToggle;
1511 
1512 	TRACE(("usb_uhci: read descriptor chain (%ld bytes)\n", actualLength));
1513 	return actualLength;
1514 }
1515 
1516 
1517 size_t
1518 UHCI::ReadActualLength(uhci_td *topDescriptor, uint8 *lastDataToggle)
1519 {
1520 	size_t actualLength = 0;
1521 	uhci_td *current = topDescriptor;
1522 	uint8 dataToggle = 0;
1523 
1524 	while (current && (current->status & TD_STATUS_ACTIVE) == 0) {
1525 		size_t length = (current->status & TD_STATUS_ACTLEN_MASK) + 1;
1526 		if (length == TD_STATUS_ACTLEN_NULL + 1)
1527 			length = 0;
1528 
1529 		actualLength += length;
1530 		dataToggle = (current->token >> TD_TOKEN_DATA_TOGGLE_SHIFT) & 0x01;
1531 
1532 		if (current->link_phy & TD_TERMINATE)
1533 			break;
1534 
1535 		current = (uhci_td *)current->link_log;
1536 	}
1537 
1538 	if (lastDataToggle)
1539 		*lastDataToggle = dataToggle;
1540 
1541 	TRACE(("usb_uhci: read actual length (%ld bytes)\n", actualLength));
1542 	return actualLength;
1543 }
1544 
1545 
1546 inline void
1547 UHCI::WriteReg8(uint32 reg, uint8 value)
1548 {
1549 	sPCIModule->write_io_8(fRegisterBase + reg, value);
1550 }
1551 
1552 
1553 inline void
1554 UHCI::WriteReg16(uint32 reg, uint16 value)
1555 {
1556 	sPCIModule->write_io_16(fRegisterBase + reg, value);
1557 }
1558 
1559 
1560 inline void
1561 UHCI::WriteReg32(uint32 reg, uint32 value)
1562 {
1563 	sPCIModule->write_io_32(fRegisterBase + reg, value);
1564 }
1565 
1566 
1567 inline uint8
1568 UHCI::ReadReg8(uint32 reg)
1569 {
1570 	return sPCIModule->read_io_8(fRegisterBase + reg);
1571 }
1572 
1573 
1574 inline uint16
1575 UHCI::ReadReg16(uint32 reg)
1576 {
1577 	return sPCIModule->read_io_16(fRegisterBase + reg);
1578 }
1579 
1580 
1581 inline uint32
1582 UHCI::ReadReg32(uint32 reg)
1583 {
1584 	return sPCIModule->read_io_32(fRegisterBase + reg);
1585 }
1586