xref: /haiku/src/add-ons/kernel/busses/usb/ohci.cpp (revision 0c93c0a807b27096abbfad677436afb7d1712d4a)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2005, Jan-Rixt Van Hoye
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //  explanation of this file:
23 //  -------------------------
24 //
25 //	This is the implementation of the OHCI module for the Haiku USB stack
26 //  It is bases on the hcir1_0a documentation that can be found on www.usb.org
27 //  Some parts are derive from source-files from openbsd, netbsd and linux.
28 //
29 //	------------------------------------------------------------------------
30 
31 //	---------------------------
32 //	OHCI::	Includes
33 //	---------------------------
34 #include <module.h>
35 #include <PCI.h>
36 #include <USB3.h>
37 #include <KernelExport.h>
38 #include <stdlib.h>
39 
40 //	---------------------------
41 //	OHCI::	Local includes
42 //	---------------------------
43 
44 #include "ohci.h"
45 #include "ohci_hardware.h"
46 #include "usb_p.h"
47 
48 //------------------------------------------------------
49 //	OHCI:: 	Reverse the bits in a value between 0 and 31
50 //			(Section 3.3.2)
51 //------------------------------------------------------
52 
53 static uint8 revbits[OHCI_NO_INTRS] =
54   { 0x00, 0x10, 0x08, 0x18, 0x04, 0x14, 0x0c, 0x1c,
55     0x02, 0x12, 0x0a, 0x1a, 0x06, 0x16, 0x0e, 0x1e,
56     0x01, 0x11, 0x09, 0x19, 0x05, 0x15, 0x0d, 0x1d,
57     0x03, 0x13, 0x0b, 0x1b, 0x07, 0x17, 0x0f, 0x1f };
58 
59 //------------------------------------------------------------------------
60 //	OHCI::	These are the OHCI operations that can be done.
61 //
62 //		parameters:
63 //					- op: operation
64 //------------------------------------------------------------------------
65 
66 static int32
67 ohci_std_ops( int32 op , ... )
68 {
69 	switch (op)
70 	{
71 		case B_MODULE_INIT:
72 			TRACE(("ohci_module: init the module\n"));
73 			return B_OK;
74 		case B_MODULE_UNINIT:
75 			TRACE(("ohci_module: uninit the module\n"));
76 			break;
77 		default:
78 			return EINVAL;
79 	}
80 	return B_OK;
81 }
82 
83 //------------------------------------------------------------------------
84 //	OHCI::	Give an reference of a stack instance to the OHCI module
85 //
86 //		parameters:
87 //					- &stack: reference to a stack instance form stack.cpp
88 //------------------------------------------------------------------------
89 
90 static status_t
91 ohci_add_to(Stack *stack)
92 {
93 	status_t status;
94 	pci_info *item;
95 	bool found = false;
96 	int i;
97 
98 #ifdef TRACE_USB
99 	set_dprintf_enabled(true);
100 	load_driver_symbols("ohci");
101 #endif
102 
103 	//
104 	// 	Try if the PCI module is loaded
105 	//
106 	if( ( status = get_module( B_PCI_MODULE_NAME, (module_info **)&( OHCI::pci_module ) ) ) != B_OK) {
107 		TRACE(("USB_ OHCI: init_hardware(): Get PCI module failed! %lu \n", status));
108 		return status;
109 	}
110 	TRACE(("usb_ohci init_hardware(): Setting up hardware\n"));
111 	item = new pci_info;
112 	for ( i = 0 ; OHCI::pci_module->get_nth_pci_info( i , item ) == B_OK ; i++ ) {
113 		if ( ( item->class_base == PCI_serial_bus ) && ( item->class_sub == PCI_usb )
114 			 && ( item->class_api  == PCI_usb_ohci ) )
115 		{
116 			if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF)) {
117 				TRACE(("USB OHCI: init_hardware(): found with invalid IRQ - check IRQ assignement\n"));
118 				continue;
119 			}
120 			TRACE(("USB OHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line));
121 			OHCI *bus = new(std::nothrow) OHCI(item, stack);
122 
123 			if (!bus) {
124 				delete item;
125 				OHCI::pci_module = NULL;
126 				put_module(B_PCI_MODULE_NAME);
127 				return B_NO_MEMORY;
128 			}
129 
130 			if (bus->InitCheck() != B_OK) {
131 				TRACE(("usb_ohci: bus failed to initialize...\n"));
132 				delete bus;
133 				continue;
134 			}
135 
136 			bus->Start();
137 			stack->AddBusManager( bus );
138 			found = true;
139 		}
140 	}
141 
142 	if (!found) {
143 		TRACE(("USB OHCI: init hardware(): no devices found\n"));
144 		free( item );
145 		put_module( B_PCI_MODULE_NAME );
146 		return ENODEV;
147 	}
148 	return B_OK; //Hardware found
149 }
150 
151 //------------------------------------------------------------------------
152 //	OHCI::	Host controller information
153 //
154 //		parameters:	none
155 //------------------------------------------------------------------------
156 
157 host_controller_info ohci_module = {
158 	{
159 		"busses/usb/ohci",
160 		0,						// No flag like B_KEEP_LOADED : the usb module does that
161 		ohci_std_ops
162 	},
163 	NULL ,
164 	ohci_add_to
165 };
166 
167 //------------------------------------------------------------------------
168 //	OHCI::	Module information
169 //
170 //		parameters:	none
171 //------------------------------------------------------------------------
172 
173 module_info *modules[] = {
174 	(module_info *) &ohci_module,
175 	NULL
176 };
177 
178 //------------------------------------------------------------------------
179 //	OHCI::	Constructor/Initialisation
180 //
181 //		parameters:
182 //					- info:		pointer to a pci information structure
183 //					- stack:	pointer to a stack instance
184 //------------------------------------------------------------------------
185 
186 OHCI::OHCI(pci_info *info, Stack *stack)
187 	:	BusManager(stack),
188 		fRegisterArea(-1),
189 		fHccaArea(-1),
190 		fDummyControl(0),
191 		fDummyBulk(0),
192 		fDummyIsochronous(0),
193 		fRootHub(0),
194 		fRootHubAddress(0),
195 		fNumPorts(0)
196 {
197 	fPcii = info;
198 	fStack = stack;
199 	int i;
200 	TRACE(("USB OHCI: constructing new BusManager\n"));
201 
202 	fInitOK = false;
203 
204 	for(i = 0; i < OHCI_NO_EDS; i++) //Clear the interrupt list
205 		fInterruptEndpoints[i] = 0;
206 
207 	// enable busmaster and memory mapped access
208 	uint16 cmd = OHCI::pci_module->read_pci_config(fPcii->bus, fPcii->device, fPcii->function, PCI_command, 2);
209 	cmd &= ~PCI_command_io;
210 	cmd |= PCI_command_master | PCI_command_memory;
211 	OHCI::pci_module->write_pci_config(fPcii->bus, fPcii->device, fPcii->function, PCI_command, 2, cmd );
212 
213 	//
214 	// 5.1.1.2 map the registers
215 	//
216 	addr_t registeroffset = pci_module->read_pci_config(info->bus,
217 		info->device, info->function, PCI_base_registers, 4);
218 	registeroffset &= PCI_address_memory_32_mask;
219 	TRACE(("OHCI: iospace offset: %lx\n" , registeroffset));
220 	fRegisterArea = map_physical_memory("OHCI base registers", (void *)registeroffset,
221 		B_PAGE_SIZE, B_ANY_KERNEL_BLOCK_ADDRESS, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA | B_READ_AREA | B_WRITE_AREA, (void **)&fRegisters);
222 	if (fRegisterArea < B_OK) {
223 		TRACE(("USB OHCI: error mapping the registers\n"));
224 		return;
225 	}
226 
227 	//	Get the revision of the controller
228 	uint32 rev = ReadReg(OHCI_REVISION) & 0xff;
229 
230 	//	Check the revision of the controller. The revision should be 10xh
231 	TRACE((" OHCI: Version %ld.%ld%s\n", OHCI_REV_HI(rev), OHCI_REV_LO(rev),OHCI_REV_LEGACY(rev) ? ", legacy support" : ""));
232 	if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0) {
233 		TRACE(("USB OHCI: Unsupported OHCI revision of the ohci device\n"));
234 		return;
235 	}
236 
237 	// Set up the Host Controller Communications Area
238 	void *hcca_phy;
239 	fHccaArea = fStack->AllocateArea((void**)&fHcca, &hcca_phy,
240 										B_PAGE_SIZE, "OHCI HCCA");
241 	if (fHccaArea < B_OK) {
242 		TRACE(("USB OHCI: Error allocating HCCA block\n"));
243 		return;
244 	}
245 	memset((void*)fHcca, 0, sizeof(ohci_hcca));
246 
247 	//
248 	// 5.1.1.3 Take control of the host controller
249 	//
250 	if (ReadReg(OHCI_CONTROL) & OHCI_IR) {
251 		TRACE(("USB OHCI: SMM is in control of the host controller\n"));
252 		WriteReg(OHCI_COMMAND_STATUS, OHCI_OCR);
253 		for (int i = 0; i < 100 && (ReadReg(OHCI_CONTROL) & OHCI_IR); i++)
254 			snooze(1000);
255 		if (ReadReg(OHCI_CONTROL) & OHCI_IR)
256 			TRACE(("USB OHCI: SMM doesn't respond... continueing anyway...\n"));
257 	} else if (!(ReadReg(OHCI_CONTROL) & OHCI_HCFS_RESET)) {
258 		TRACE(("USB OHCI: BIOS is in control of the host controller\n"));
259 		if (!(ReadReg(OHCI_CONTROL) & OHCI_HCFS_OPERATIONAL)) {
260 			WriteReg(OHCI_CONTROL, OHCI_HCFS_RESUME);
261 			snooze(USB_DELAY_BUS_RESET);
262 		}
263 	} else if (ReadReg(OHCI_CONTROL) & OHCI_HCFS_RESET) //Only if no BIOS/SMM control
264 		snooze(USB_DELAY_BUS_RESET);
265 
266 	//
267 	// 5.1.1.4 Set Up Host controller
268 	//
269 	// Dummy endpoints
270 	fDummyControl = AllocateEndpoint();
271 	if (!fDummyControl)
272 		return;
273 	fDummyBulk = AllocateEndpoint();
274 	if (!fDummyBulk)
275 		return;
276 	fDummyIsochronous = AllocateEndpoint();
277 	if (!fDummyIsochronous)
278 		return;
279 	//Create the interrupt tree
280 	//Algorhythm kindly borrowed from NetBSD code
281 	for(i = 0; i < OHCI_NO_EDS; i++) {
282 		fInterruptEndpoints[i] = AllocateEndpoint();
283 		if (!fInterruptEndpoints[i])
284 			return;
285 		if (i != 0)
286 			fInterruptEndpoints[i]->SetNext(fInterruptEndpoints[(i-1) / 2]);
287 		else
288 			fInterruptEndpoints[i]->SetNext(fDummyIsochronous);
289 	}
290 	for (i = 0; i < OHCI_NO_INTRS; i++)
291 		fHcca->hcca_interrupt_table[revbits[i]] =
292 			fInterruptEndpoints[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physicaladdress;
293 
294 	//Go to the hardware part of the initialisation
295 	uint32 frameinterval = ReadReg(OHCI_FM_INTERVAL);
296 
297 	WriteReg(OHCI_COMMAND_STATUS, OHCI_HCR);
298 	for (i = 0; i < 10; i++){
299 		snooze(10);				//Should be okay in one run: 10 microseconds for reset
300 		if (!(ReadReg(OHCI_COMMAND_STATUS) & OHCI_HCR))
301 			break;
302 	}
303 	if (ReadReg(OHCI_COMMAND_STATUS) & OHCI_HCR) {
304 		TRACE(("USB OHCI: Error resetting the host controller\n"));
305 		return;
306 	}
307 
308 	WriteReg(OHCI_FM_INTERVAL, frameinterval);
309 	//We now have 2 ms to finish the following sequence.
310 	//TODO: maybe add spinlock protection???
311 
312 	WriteReg(OHCI_CONTROL_HEAD_ED, (uint32)fDummyControl->physicaladdress);
313 	WriteReg(OHCI_BULK_HEAD_ED, (uint32)fDummyBulk->physicaladdress);
314 	WriteReg(OHCI_HCCA, (uint32)hcca_phy);
315 
316 	WriteReg(OHCI_INTERRUPT_DISABLE, OHCI_ALL_INTRS);
317 	WriteReg(OHCI_INTERRUPT_ENABLE, OHCI_NORMAL_INTRS);
318 
319 	//
320 	// 5.1.1.5 Begin Sending SOFs
321 	//
322 	uint32 control = ReadReg(OHCI_CONTROL);
323 	control &= ~(OHCI_CBSR_MASK | OHCI_LES | OHCI_HCFS_MASK | OHCI_IR);
324 	control |= OHCI_PLE | OHCI_IE | OHCI_CLE | OHCI_BLE |
325 		OHCI_RATIO_1_4 | OHCI_HCFS_OPERATIONAL;
326 	WriteReg(OHCI_CONTROL, control);
327 
328 	//The controller is now operational, end of 2ms block.
329 	uint32 interval = OHCI_GET_IVAL(frameinterval);
330 	WriteReg(OHCI_PERIODIC_START, OHCI_PERIODIC(interval));
331 
332 	//Work on some Roothub settings
333 	uint32 desca = ReadReg(OHCI_RH_DESCRIPTOR_A);
334 	WriteReg(OHCI_RH_DESCRIPTOR_A, desca | OHCI_NOCP); //FreeBSD source does this to avoid a chip bug
335 	//Enable power
336 	WriteReg(OHCI_RH_STATUS, OHCI_LPSC);
337 	snooze(5000); //Wait for power to stabilize (5ms)
338 	WriteReg(OHCI_RH_DESCRIPTOR_A, desca);
339 	snooze(5000); //Delay required by the AMD756 because else the # of ports might be misread
340 
341 	fInitOK = true;
342 }
343 
344 OHCI::~OHCI()
345 {
346 	if (fHccaArea > 0)
347 		delete_area(fHccaArea);
348 	if (fRegisterArea > 0)
349 		delete_area(fRegisterArea);
350 	if (fDummyControl)
351 		FreeEndpoint(fDummyControl);
352 	if (fDummyBulk)
353 		FreeEndpoint(fDummyBulk);
354 	if (fDummyIsochronous)
355 		FreeEndpoint(fDummyIsochronous);
356 	if (fRootHub)
357 		delete fRootHub;
358 	for (int i = 0; i < OHCI_NO_EDS; i++)
359 		if (fInterruptEndpoints[i])
360 			FreeEndpoint(fInterruptEndpoints[i]);
361 }
362 
363 status_t
364 OHCI::Start()
365 {
366 	if (InitCheck())
367 		return B_ERROR;
368 
369 	if (!(ReadReg(OHCI_CONTROL) & OHCI_HCFS_OPERATIONAL)) {
370 		TRACE(("USB OHCI::Start(): Controller not started. TODO: find out what happens.\n"));
371 		return B_ERROR;
372 	}
373 
374 	fRootHubAddress = AllocateAddress();
375 	fNumPorts = OHCI_GET_PORT_COUNT(ReadReg(OHCI_RH_DESCRIPTOR_A));
376 
377 	fRootHub = new(std::nothrow) OHCIRootHub(this, fRootHubAddress);
378 	if (!fRootHub) {
379 		TRACE_ERROR(("USB OHCI::Start(): no memory to allocate root hub\n"));
380 		return B_NO_MEMORY;
381 	}
382 
383 	if (fRootHub->InitCheck() < B_OK) {
384 		TRACE_ERROR(("USB OHCI::Start(): root hub failed init check\n"));
385 		return B_ERROR;
386 	}
387 
388 	SetRootHub(fRootHub);
389 	TRACE(("USB OHCI::Start(): Succesful start\n"));
390 	return B_OK;
391 }
392 
393 status_t OHCI::SubmitTransfer( Transfer *t )
394 {
395 	TRACE(("usb OHCI::SubmitTransfer: called for device %d\n", t->TransferPipe()->DeviceAddress()));
396 
397 	if (t->TransferPipe()->DeviceAddress() == fRootHubAddress)
398 		return fRootHub->ProcessTransfer(t, this);
399 
400 	return B_ERROR;
401 }
402 
403 status_t
404 OHCI::NotifyPipeChange(Pipe *pipe, usb_change change)
405 {
406 	if (InitCheck())
407 		return B_ERROR;
408 
409 	switch (change) {
410 	case USB_CHANGE_CREATED:
411 		return InsertEndpointForPipe(pipe);
412 	case USB_CHANGE_DESTROYED:
413 		// Do something
414 		return B_ERROR;
415 	case USB_CHANGE_PIPE_POLICY_CHANGED:
416 	default:
417 		break;
418 	}
419 	return B_ERROR; //We should never go here
420 }
421 
422 status_t
423 OHCI::GetPortStatus(uint8 index, usb_port_status *status)
424 {
425 	if (index > fNumPorts)
426 		return B_BAD_INDEX;
427 
428 	status->status = status->change = 0;
429 	uint32 portStatus = ReadReg(OHCI_RH_PORT_STATUS(index));
430 
431 	TRACE(("OHCIRootHub::GetPortStatus: Port %i Value 0x%lx\n", OHCI_RH_PORT_STATUS(index), portStatus));
432 
433 	// status
434 	if (portStatus & OHCI_PORTSTATUS_CCS)
435 		status->status |= PORT_STATUS_CONNECTION;
436 	if (portStatus & OHCI_PORTSTATUS_PES)
437 		status->status |= PORT_STATUS_ENABLE;
438 	if (portStatus & OHCI_PORTSTATUS_PRS)
439 		status->status |= PORT_STATUS_RESET;
440 	if (portStatus & OHCI_PORTSTATUS_LSDA)
441 		status->status |= PORT_STATUS_LOW_SPEED;
442 	if (portStatus & OHCI_PORTSTATUS_PSS)
443 		status->status |= PORT_STATUS_SUSPEND;
444 	if (portStatus & OHCI_PORTSTATUS_POCI)
445 		status->status |= PORT_STATUS_OVER_CURRENT;
446 	if (portStatus & OHCI_PORTSTATUS_PPS)
447 		status->status |= PORT_STATUS_POWER;
448 
449 
450 	// change
451 	if (portStatus & OHCI_PORTSTATUS_CSC)
452 		status->change |= PORT_STATUS_CONNECTION;
453 	if (portStatus & OHCI_PORTSTATUS_PESC)
454 		status->change |= PORT_STATUS_ENABLE;
455 	if (portStatus & OHCI_PORTSTATUS_PSSC)
456 		status->change |= PORT_STATUS_SUSPEND;
457 	if (portStatus & OHCI_PORTSTATUS_OCIC)
458 		status->change |= PORT_STATUS_OVER_CURRENT;
459 	if (portStatus & OHCI_PORTSTATUS_PRSC)
460 		status->change |= PORT_STATUS_RESET;
461 
462 	return B_OK;
463 }
464 
465 status_t
466 OHCI::SetPortFeature(uint8 index, uint16 feature)
467 {
468 	if (index > fNumPorts)
469 		return B_BAD_INDEX;
470 
471 	switch (feature) {
472 		case PORT_RESET:
473 			WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_PORTSTATUS_PRS);
474 			return B_OK;
475 
476 		case PORT_POWER:
477 			WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_PORTSTATUS_PPS);
478 			return B_OK;
479 	}
480 
481 	return B_BAD_VALUE;
482 }
483 
484 status_t
485 OHCI::ClearPortFeature(uint8 index, uint16 feature)
486 {
487 	if (index > fNumPorts)
488 		return B_BAD_INDEX;
489 
490 	switch (feature) {
491 		case C_PORT_RESET:
492 			WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_PORTSTATUS_CSC);
493 			return B_OK;
494 
495 		case C_PORT_CONNECTION:
496 			WriteReg(OHCI_RH_PORT_STATUS(index), OHCI_PORTSTATUS_CSC);
497 			return B_OK;
498 	}
499 
500 	return B_BAD_VALUE;
501 }
502 
503 Endpoint *
504 OHCI::AllocateEndpoint()
505 {
506 	//Allocate memory chunk
507 	Endpoint *endpoint = new(std::nothrow) Endpoint;
508 	void *phy;
509 	if (fStack->AllocateChunk((void **)&endpoint->ed, &phy, sizeof(ohci_endpoint_descriptor)) != B_OK) {
510 		TRACE(("OHCI::AllocateEndpoint(): Error Allocating Endpoint\n"));
511 		return 0;
512 	}
513 	endpoint->physicaladdress = (addr_t)phy;
514 
515 	//Initialize the physical part
516 	memset((void *)endpoint->ed, 0, sizeof(ohci_endpoint_descriptor));
517 	endpoint->ed->flags = OHCI_ENDPOINT_SKIP;
518 
519 	//Add a NULL list by creating one TransferDescriptor
520 	TransferDescriptor *trans = new(std::nothrow) TransferDescriptor;
521 	endpoint->head = endpoint->tail = trans;
522 	endpoint->ed->headp = endpoint->ed->tailp = trans->physicaladdress;
523 
524 	return endpoint;
525 }
526 
527 void
528 OHCI::FreeEndpoint(Endpoint *end)
529 {
530 	fStack->FreeChunk((void *)end->ed, (void *) end->physicaladdress, sizeof(ohci_endpoint_descriptor));
531 	delete end;
532 }
533 
534 TransferDescriptor *
535 OHCI::AllocateTransfer()
536 {
537 	TransferDescriptor *transfer = new TransferDescriptor;
538 	void *phy;
539 	if (fStack->AllocateChunk((void **)&transfer->td, &phy, sizeof(ohci_transfer_descriptor)) != B_OK) {
540 		TRACE(("OHCI::AllocateTransfer(): Error Allocating Transfer\n"));
541 		return 0;
542 	}
543 	transfer->physicaladdress = (addr_t)phy;
544 	memset((void *)transfer->td, 0, sizeof(ohci_transfer_descriptor));
545 	return transfer;
546 }
547 
548 void
549 OHCI::FreeTransfer(TransferDescriptor *trans)
550 {
551 	fStack->FreeChunk((void *)trans->td, (void *) trans->physicaladdress, sizeof(ohci_transfer_descriptor));
552 	delete trans;
553 }
554 
555 status_t
556 OHCI::InsertEndpointForPipe(Pipe *p)
557 {
558 	TRACE(("OHCI: Inserting Endpoint for device %u function %u\n", p->DeviceAddress(), p->EndpointAddress()));
559 
560 	if (InitCheck())
561 		return B_ERROR;
562 
563 	Endpoint *endpoint = AllocateEndpoint();
564 	if (!endpoint)
565 		return B_NO_MEMORY;
566 
567 	//Set up properties of the endpoint
568 	//TODO: does this need its own utility function?
569 	{
570 		uint32 properties = 0;
571 
572 		//Set the device address
573 		properties |= OHCI_ENDPOINT_SET_FA(p->DeviceAddress());
574 
575 		//Set the endpoint number
576 		properties |= OHCI_ENDPOINT_SET_EN(p->EndpointAddress());
577 
578 		//Set the direction
579 		switch (p->Direction()) {
580 		case Pipe::In:
581 			properties |= OHCI_ENDPOINT_DIR_IN;
582 			break;
583 		case Pipe::Out:
584 			properties |= OHCI_ENDPOINT_DIR_OUT;
585 			break;
586 		case Pipe::Default:
587 			properties |= OHCI_ENDPOINT_DIR_TD;
588 			break;
589 		default:
590 			//TODO: error
591 			break;
592 		}
593 
594 		//Set the speed
595 		switch (p->Speed()) {
596 		case USB_SPEED_LOWSPEED:
597 			//the bit is 0
598 			break;
599 		case USB_SPEED_FULLSPEED:
600 			properties |= OHCI_ENDPOINT_SPEED;
601 			break;
602 		case USB_SPEED_HIGHSPEED:
603 		default:
604 			//TODO: error
605 			break;
606 		}
607 
608 		//Assign the format. Isochronous endpoints require this switch
609 		if (p->Type() & USB_OBJECT_ISO_PIPE)
610 			properties |= OHCI_ENDPOINT_FORMAT_ISO;
611 
612 		//Set the maximum packet size
613 		properties |= OHCI_ENDPOINT_SET_MAXP(p->MaxPacketSize());
614 
615 		endpoint->ed->flags = properties;
616 	}
617 
618 	//Check which list we need to add the endpoint in
619 	Endpoint *listhead;
620 	if (p->Type() & USB_OBJECT_CONTROL_PIPE)
621 		listhead = fDummyControl;
622 	else if (p->Type() & USB_OBJECT_BULK_PIPE)
623 		listhead = fDummyBulk;
624 	else if (p->Type() & USB_OBJECT_ISO_PIPE)
625 		listhead = fDummyIsochronous;
626 	else {
627 		FreeEndpoint(endpoint);
628 		return B_ERROR;
629 	}
630 
631 	//Add the endpoint to the queues
632 	if ((p->Type() & USB_OBJECT_ISO_PIPE) == 0) {
633 		//Link the endpoint into the head of the list
634 		endpoint->SetNext(listhead->next);
635 		listhead->SetNext(endpoint);
636 	} else {
637 		//Link the endpoint into the tail of the list
638 		Endpoint *tail = listhead;
639 		while (tail->next != 0)
640 			tail = tail->next;
641 		tail->SetNext(endpoint);
642 	}
643 
644 	return B_OK;
645 }
646 
647 pci_module_info *OHCI::pci_module = 0;
648 
649 void
650 OHCI::WriteReg(uint32 reg, uint32 value)
651 {
652 	*(volatile uint32 *)(fRegisters + reg) = value;
653 }
654 
655 uint32
656 OHCI::ReadReg(uint32 reg)
657 {
658 	return *(volatile uint32 *)(fRegisters + reg);
659 }
660