xref: /haiku/src/add-ons/kernel/bus_managers/usb/BusManager.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2003-2004, Niels S. Reedijk
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 #include "usb_p.h"
23 
24 
25 /* +++++++++
26 This is the 'main' function of the explore thread, which keeps track of
27 the hub statuses.
28 +++++++++ */
29 int32 usb_explore_thread( void *data )
30 {
31 	Hub *roothub = (Hub *)data;
32 
33 	if ( roothub == 0 )
34 		return B_ERROR;
35 
36 	while ( true )
37 	{
38 		//Go to the hubs
39 		roothub->Explore();
40 		snooze(1000000); //Wait one second before continueing
41 	}
42 	return B_OK;
43 }
44 
45 
46 BusManager::BusManager()
47 {
48 	m_initok = false;
49 	m_roothub = 0;
50 
51 	// Set up the semaphore
52 	m_lock = create_sem( 1 , "buslock" );
53 	if( m_lock < B_OK )
54 		return;
55 	set_sem_owner( B_SYSTEM_TEAM , m_lock );
56 
57 	// Clear the device map
58 	memset( &m_devicemap , 0 , 128 );
59 
60 	// Set up the default pipes
61 	m_defaultPipe = new ControlPipe( this , 0 , Pipe::Default , Pipe::NormalSpeed , 0 );
62 	m_defaultLowSpeedPipe = new ControlPipe( this , 0 , Pipe::Default , Pipe::LowSpeed , 0 );
63 
64 	// Clear the 'explore thread'
65 	m_explore_thread = 0;
66 
67 	m_initok = true;
68 }
69 
70 BusManager::~BusManager()
71 {
72 }
73 
74 status_t BusManager::InitCheck()
75 {
76 	if ( m_initok == true )
77 		return B_OK;
78 	else
79 		return B_ERROR;
80 }
81 
82 Device * BusManager::AllocateNewDevice( Device *parent , bool lowspeed )
83 {
84 	int8 devicenum;
85 	status_t retval;
86 	usb_device_descriptor device_descriptor;
87 
88 	//1. Check if there is a free entry in the device map (for the device number)
89 	devicenum = AllocateAddress();
90 	if ( devicenum < 0 )
91 	{
92 		dprintf( "usb Busmanager [new device]: could not get a new address\n" );
93 		return 0;
94 	}
95 
96 
97 	//2. Set the address of the device USB 1.1 spec p202 (bepdf)
98 	retval = m_defaultPipe->SendRequest( USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD , //host->device
99 	             USB_REQUEST_SET_ADDRESS , 						//request
100 	             devicenum ,									//value
101 	             0 ,											//index
102 	             0 ,											//length
103 	             NULL ,											//data
104 	             0 ,											//data_len
105 	             0 );											//actual len
106 
107 	if ( retval < B_OK )
108 	{
109 		dprintf( "usb busmanager [new device]: error with commmunicating the right address\n" );
110 		return 0;
111 	}
112 
113 	//Create a temporary pipe
114 	ControlPipe pipe( this , devicenum , Pipe::Default , Pipe::LowSpeed , 0 );
115 
116 	//3. Get the device descriptor
117 	// Just retrieve the first 8 bytes of the descriptor -> minimum supported
118 	// size of any device, plus it is enough, because the device type is in
119 	// there too
120 
121 	size_t actual_length;
122 
123 	pipe.SendRequest( USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD , //Type
124 	             USB_REQUEST_GET_DESCRIPTOR ,					//Request
125 	             ( USB_DESCRIPTOR_DEVICE << 8 ),				//Value
126 	             0 ,											//Index
127 	             8 ,											//Length
128 	             (void *)&device_descriptor ,					//Buffer
129 	             8 ,											//Bufferlength
130 	             &actual_length );								//length
131 
132 	if ( actual_length != 8 )
133 	{
134 		dprintf( "usb busmanager [new device]: error while getting the device descriptor\n" );
135 		return 0;
136 	}
137 
138 	//4. Create a new instant based on the type (Hub or Device);
139 	if ( device_descriptor.device_class == 0x09 )
140 	{
141 		dprintf( "usb Busmanager [new device]: New hub\n" );
142 		Device *ret = new Hub( this , parent , device_descriptor , devicenum , lowspeed );
143 		if ( parent == 0 ) //root hub!!
144 			m_roothub = ret;
145 		return 0;
146 	}
147 
148 	dprintf( "usb Busmanager [new device]: New normal device\n" );
149 	return new Device( this , parent , device_descriptor , devicenum , lowspeed);
150 }
151 
152 int8 BusManager::AllocateAddress()
153 {
154 	acquire_sem_etc( m_lock , 1 , B_CAN_INTERRUPT , 0 );
155 	int8 devicenum = -1;
156 	for( int i = 1 ; i < 128 ; i++ )
157 	{
158 		if ( m_devicemap[i] == false )
159 		{
160 			devicenum = i;
161 			m_devicemap[i] = true;
162 			break;
163 		}
164 	}
165 	release_sem( m_lock );
166 	return devicenum;
167 }
168 
169 status_t BusManager::Start()
170 {
171 	dprintf( "USB: BusManager::Start()\n" );
172 	if ( InitCheck() != B_OK )
173 		return InitCheck();
174 
175 	if ( m_explore_thread == 0 )
176 		m_explore_thread = spawn_kernel_thread( usb_explore_thread , "usb_busmanager_explore" ,
177 	                     B_LOW_PRIORITY , (void *)m_roothub );
178 
179 	// Start the 'explore thread'
180 	return resume_thread( m_explore_thread );
181 }
182 
183 status_t BusManager::SubmitTransfer( Transfer *t )
184 {
185 	return B_ERROR;
186 };
187