xref: /haiku/src/add-ons/kernel/busses/usb/ohci.cpp (revision d3d8b26997fac34a84981e6d2b649521de2cc45a)
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 <USB.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 bool
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 OHCI_DEBUG
99 	set_dprintf_enabled( true );
100 	load_driver_symbols( "ohci" );
101 	#endif
102 	//
103 	// 	Try if the PCI module is loaded
104 	//
105 	if( ( status = get_module( B_PCI_MODULE_NAME, (module_info **)&( OHCI::pci_module ) ) ) != B_OK)
106 	{
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 	//
112 	// 	TODO: in the future we might want to support multiple host controllers.
113 	//
114 	item = new pci_info;
115 	for ( i = 0 ; OHCI::pci_module->get_nth_pci_info( i , item ) == B_OK ; i++ )
116 	{
117 		//
118 		//	class_base = 0C (serial bus) class_sub = 03 (usb) prog_int: 10 (OHCI)
119 		//
120 		if ( ( item->class_base == 0x0C ) && ( item->class_sub == 0x03 ) &&
121 			 ( item->class_api  == 0x10 ) )
122 		{
123 			if ((item->u.h0.interrupt_line == 0) || (item->u.h0.interrupt_line == 0xFF))
124 			{
125 				TRACE( "USB OHCI: init_hardware(): found with invalid IRQ - check IRQ assignement\n");
126 				continue;
127 			}
128 			TRACE("USB OHCI: init_hardware(): found at IRQ %u \n", item->u.h0.interrupt_line);
129 			OHCI *bus = new OHCI( item , &stack );
130 			if ( bus->InitCheck() != B_OK )
131 			{
132 				delete bus;
133 				break;
134 			}
135 
136 			stack.AddBusManager( bus );
137 			bus->Start();
138 			found = true;
139 			break;
140 		}
141 	}
142 
143 	if ( found == false )
144 	{
145 		TRACE( "USB OHCI: init hardware(): no devices found\n" );
146 		free( item );
147 		put_module( B_PCI_MODULE_NAME );
148 		return ENODEV;
149 	}
150 	return B_OK; //Hardware found
151 }
152 
153 //------------------------------------------------------------------------
154 //	OHCI::	Host controller information
155 //
156 //		parameters:	none
157 //------------------------------------------------------------------------
158 
159 host_controller_info ohci_module = {
160 	{
161 		"busses/usb/ohci/jixt",
162 		NULL,						// No flag like B_KEEP_LOADED : the usb module does that
163 		ohci_std_ops
164 	},
165 	NULL ,
166 	ohci_add_to
167 };
168 
169 //------------------------------------------------------------------------
170 //	OHCI::	Module information
171 //
172 //		parameters:	none
173 //------------------------------------------------------------------------
174 
175 module_info *modules[] =
176 {
177 	(module_info *) &ohci_module,
178 	NULL
179 };
180 
181 //------------------------------------------------------------------------
182 //	OHCI::	Constructor/Initialisation
183 //
184 //		parameters:
185 //					- info:		pointer to a pci information structure
186 //					- stack:	pointer to a stack instance
187 //------------------------------------------------------------------------
188 
189 OHCI::OHCI( pci_info *info , Stack *stack )
190 {
191 	m_pcii = info;
192 	m_stack = stack;
193 	uint32 rev=0;
194 	int i;
195 	hcd_soft_endpoint *sed, *psed;
196 	dprintf( "OHCI: constructing new BusManager\n" );
197 	m_opreg_base = OHCI::pci_module->read_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, 0x20, 4);
198 	m_opreg_base &= PCI_address_io_mask;
199 	TRACE( "OHCI: iospace offset: %lx\n" , m_opreg_base );
200 	m_roothub_base = 255; //Invalidate the Root Hub address
201 	{
202 		// enable pci address access
203 		unsigned char cmd;
204 		cmd = OHCI::pci_module->read_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_command, 2);
205 		cmd = cmd | PCI_command_io | PCI_command_master | PCI_command_memory;
206 		OHCI::pci_module->write_pci_config(m_pcii->bus, m_pcii->device, m_pcii->function, PCI_command, 2, cmd );
207 	}
208 
209 	//	Get the revision of the controller
210 
211 	OHCI::pci_module->read_io_16( m_opreg_base + OHCI_REVISION );
212 
213 	//	Check the revision of the controller. The revision should be 10xh
214 
215 	dprintf(" OHCI: Version %ld.%ld%s\n", OHCI_REV_HI(rev), OHCI_REV_LO(rev),OHCI_REV_LEGACY(rev) ? ", legacy support" : "");
216 
217 	if (OHCI_REV_HI(rev) != 1 || OHCI_REV_LO(rev) != 0)
218 	{
219 		dprintf("OHCI: Unsupported OHCI revision of the ohci device\n");
220 		return;
221 	}
222 	//	Set the revision of the controller
223 	m_revision = rev;
224 	//	Set the product description of the controller
225 	m_product_descr = "Open Host Controller Interface";
226 	//	Initialize the transfer descriptors and the interupt transfer descriptors
227 	//
228 			/*		+++++++++++++++++++		*/
229 	//
230 	//	Allocate the HCCA area.
231 	void *phy;
232 	m_hcca_area = stack->AllocateArea( (void **)&(hcca) , &(phy) ,OHCI_HCCA_SIZE , "ohci hcca area" );
233 	m_hcca_base = reinterpret_cast<addr_t>(phy);
234 
235 	//	Allocate dummy Endpoint Descriptor that starts the control list.
236 	ed_control_tail = ohci_alloc_soft_endpoint();
237 	ed_control_tail->ed.ed_flags |= OHCI_ED_SKIP;
238 
239 	//	Allocate dummy Endpoint Descriptor that starts the bulk list.
240 	ed_bulk_tail = ohci_alloc_soft_endpoint();
241 	ed_bulk_tail->ed.ed_flags |= OHCI_ED_SKIP;
242 
243 	// Allocate dummy Endpoint Descriptor that starts the isochronous list.
244 	ed_isoch_tail = ohci_alloc_soft_endpoint();
245 	ed_isoch_tail->ed.ed_flags |= OHCI_ED_SKIP;
246 
247 	// Allocate all the dummy Endpoint Desriptors that make up the interrupt tree.
248 	for (i = 0; i < OHCI_NO_EDS; i++)
249 	{
250 		sed = ohci_alloc_soft_endpoint();
251 		if (sed == NULL)
252 		{
253 			return;
254 		}
255 		/* All ED fields are set to 0. */
256 		sc_eds[i] = sed;
257 		sed->ed.ed_flags |= OHCI_ED_SKIP;
258 		if (i != 0)
259 			psed = sc_eds[(i-1) / 2];
260 		else
261 			psed= ed_isoch_tail;
262 		sed->next = psed;
263 		sed->ed.ed_nexted = psed->physaddr;
264 	}
265 
266 	// Fill HCCA interrupt table.  The bit reversal is to get
267 	// the tree set up properly to spread the interrupts.
268 	for (i = 0; i < OHCI_NO_INTRS; i++)
269 		hcca->hcca_interrupt_table[revbits[i]] = sc_eds[OHCI_NO_EDS-OHCI_NO_INTRS+i]->physaddr;
270 
271 	//	Determine in what context we are running.
272 	uint32 ctrlmsg,statusmsg;
273 	ctrlmsg = OHCI::pci_module->read_io_16( m_opreg_base + OHCI_CONTROL);
274 	if (ctrlmsg & OHCI_IR)
275 	{
276 		/// SMM active, request change
277 		dprintf(("OHCI: SMM active, request owner change\n"));
278 		statusmsg = OHCI::pci_module->read_io_16( m_opreg_base + OHCI_COMMAND_STATUS);
279 		OHCI::pci_module->write_io_16( m_opreg_base + OHCI_COMMAND_STATUS,statusmsg | OHCI_OCR);
280 		for (i = 0; i < 100 && (ctrlmsg & OHCI_IR); i++)
281 		{
282 			snooze(100);
283 			ctrlmsg = OHCI::pci_module->read_io_16( m_opreg_base + OHCI_CONTROL);
284 		}
285 		if ((ctrlmsg & OHCI_IR) == 0)
286 		{
287 			dprintf("OHCI: SMM does not respond, resetting\n");
288 			OHCI::pci_module->write_io_16( m_opreg_base + OHCI_CONTROL,OHCI_HCFS_RESET);
289 			goto reset;
290 		}
291 	// Don't bother trying to reuse the BIOS init, we'll reset it anyway.
292 	}
293 	else if ((ctrlmsg & OHCI_HCFS_MASK) != OHCI_HCFS_RESET)
294 	{
295 		// BIOS started controller
296 		dprintf("OHCI: BIOS active\n");
297 		if ((ctrlmsg & OHCI_HCFS_MASK) != OHCI_HCFS_OPERATIONAL)
298 		{
299 			OHCI::pci_module->write_io_16( m_opreg_base + OHCI_CONTROL,OHCI_HCFS_OPERATIONAL);
300 			snooze(250000);
301 		}
302 	}
303 	else
304 	{
305 		dprintf("OHCI: cold started\n");
306 	reset:
307 		// Controller was cold started.
308 		snooze(100000);
309 	}
310 
311 	//	This reset should not be necessary according to the OHCI spec, but
312 	//	without it some controllers do not start.
313 	//
314 			/*		+++++++++++++++++++		*/
315 	//
316 	//	We now own the host controller and the bus has been reset.
317 	//
318 			/*		+++++++++++++++++++		*/
319 	//
320 	// Reset the Host Controller
321 	//
322 			/*		+++++++++++++++++++		*/
323 	//
324 	//	Nominal time for a reset is 10 us.
325 	//
326 			/*		+++++++++++++++++++		*/
327 	//
328 	//	The controller is now in SUSPEND state, we have 2ms to finish.
329 	//
330 	//	Set up the Host Controler registers.
331 	//
332 			/*		+++++++++++++++++++		*/
333 	//
334 	//	Disable all interrupts and then switch on all desired interrupts.
335 	//
336 			/*		+++++++++++++++++++		*/
337 	//
338 	//	Switch on desired functional features.
339 	//
340 			/*		+++++++++++++++++++		*/
341 	//
342 	//	And finally start it!
343 	//
344 			/*		+++++++++++++++++++		*/
345 	//
346 	//	The controller is now OPERATIONAL.  Set a some final
347 	//	registers that should be set earlier, but that the
348 	//	controller ignores when in the SUSPEND state.
349 	//
350 			/*		+++++++++++++++++++		*/
351 	//
352 	// Fiddle the No OverCurrent Protection bit to avoid chip bug.
353 	//
354 			/*		+++++++++++++++++++		*/
355 	//
356 	// The AMD756 requires a delay before re-reading the register,
357 	// otherwise it will occasionally report 0 ports.
358 	//
359 			/*		+++++++++++++++++++		*/
360 	//
361 	// Set up the bus structure
362 	//
363 			/*		+++++++++++++++++++		*/
364 	//return B_OK;
365 }
366 
367 hcd_soft_endpoint * OHCI::ohci_alloc_soft_endpoint()
368 {
369 	hcd_soft_endpoint *sed;
370 	int i;
371 	void *phy;
372 	if (sc_freeeds == NULL)
373 	{
374 		dprintf("OHCI: ohci_alloc_soft_endpoint(): allocating chunk\n");
375 		for(i = 0; i < OHCI_SED_CHUNK; i++)
376 		{
377 			if(m_stack->AllocateChunk( (void **)&(sed) ,&phy , OHCI_ED_ALIGN )!= B_OK)
378 			{
379 				dprintf( "USB OHCI: ohci_alloc_soft_endpoint(): failed allocation of skeleton qh %i, aborting\n",  i );
380 				return (0);
381 			}
382 			// chunk has been allocated
383 			sed->physaddr = reinterpret_cast<addr_t>(phy);
384 			sed->next = sc_freeeds;
385 			sc_freeeds = sed;
386 		}
387 	}
388 	sed = sc_freeeds;
389 	sc_freeeds = sed->next;
390 	memset(&sed->ed, 0, sizeof(hc_endpoint_descriptor));
391 	sed->next = 0;
392 	return (sed);
393 }
394 
395 //------------------------------------------------------------------------
396 //	OHCI::	Submit a transfer
397 //
398 //		parameters:
399 //					- t: pointer to a transfer instance
400 //------------------------------------------------------------------------
401 
402 status_t OHCI::SubmitTransfer( Transfer *t )
403 {
404 	return B_OK;
405 }
406 pci_module_info *OHCI::pci_module = 0;
407