xref: /haiku/src/add-ons/kernel/bus_managers/usb/BusManager.cpp (revision 67bce78b48ed6d01b5a8eef89f5694c372b7e0a1)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2003, 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 	while (true )
34 	{
35 		//Go to the hubs
36 		roothub->Explore();
37 		snooze(10000); //Wait one second before continueing
38 	}
39 	return B_OK;
40 }
41 
42 
43 BusManager::BusManager( host_controller_info *info )
44 {
45 	hcpointer = info;
46 	m_initok = false;
47 	m_roothub = 0;
48 
49 	// Set up the semaphore
50 	m_lock = create_sem( 1 , "buslock" );
51 	if( m_lock < B_OK )
52 		return;
53 	set_sem_owner( B_SYSTEM_TEAM , m_lock );
54 
55 	// Clear the device map
56 	memset( &m_devicemap , false , 128 );
57 
58 	// Set up the new root hub
59 	AllocateNewDevice( 0 );
60 
61 	if( m_roothub == 0 )
62 		return;
63 
64 	// Start the 'explore thread'
65 	m_explore_thread = spawn_kernel_thread( usb_explore_thread , "usb_busmanager_explore" ,
66 	                     B_LOW_PRIORITY , (void *)m_roothub );
67 	resume_thread( m_explore_thread );
68 
69 	m_initok = true;
70 }
71 
72 BusManager::~BusManager()
73 {
74 	put_module( hcpointer->info.name );
75 }
76 
77 status_t BusManager::InitCheck()
78 {
79 	if ( m_initok == true )
80 		return B_OK;
81 	else
82 		return B_ERROR;
83 }
84 
85 Device * BusManager::AllocateNewDevice( Device *parent )
86 {
87 	int8 devicenum;
88 	status_t retval;
89 	usb_device_descriptor device_descriptor;
90 
91 	//1. Check if there is a free entry in the device map (for the device number)
92 	devicenum = AllocateAddress();
93 	if ( devicenum < 0 )
94 	{
95 		dprintf( "usb Busmanager [new device]: could not get a new address\n" );
96 		return 0;
97 	}
98 
99 	//2. Set the address of the device USB 1.1 spec p202 (bepdf)
100 	retval = SendRequest( 0 ,
101 				 USB_REQTYPE_DEVICE_OUT | USB_REQTYPE_STANDARD , //host->device
102 	             USB_REQUEST_SET_ADDRESS , 						//request
103 	             devicenum ,									//value
104 	             0 ,											//index
105 	             0 ,											//length
106 	             NULL ,											//data
107 	             0 ,											//data_len
108 	             0 );											//actual len
109 
110 	if ( retval < B_OK )
111 	{
112 		dprintf( "usb busmanager [new device]: error with commmunicating the right address\n" );
113 		return 0;
114 	}
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 	SendRequest( 0 ,
124 	             USB_REQTYPE_DEVICE_IN | USB_REQTYPE_STANDARD , //Type
125 	             USB_REQUEST_GET_DESCRIPTOR ,					//Request
126 	             ( USB_DESCRIPTOR_DEVICE << 8 ),				//Value
127 	             0 ,											//Index
128 	             8 ,											//Length
129 	             (void *)&device_descriptor ,					//Buffer
130 	             8 ,											//Bufferlength
131 	             &actual_length );								//length
132 
133 	if ( actual_length != 8 )
134 	{
135 		dprintf( "usb busmanager [new device]: error while getting the device descriptor\n" );
136 		return 0;
137 	}
138 
139 	//4. Create a new instant based on the type (Hub or Device);
140 	if ( device_descriptor.device_class == 0x09 )
141 	{
142 		dprintf( "usb Busmanager [new device]: New hub\n" );
143 		Device *ret = new Hub( this , parent , device_descriptor , devicenum );
144 		if ( parent == 0 ) //root hub!!
145 			m_roothub = ret;
146 		return ret;
147 	}
148 
149 	dprintf( "usb Busmanager [new device]: New normal device\n" );
150 	return new Device( this , parent , device_descriptor , devicenum );
151 }
152 
153 int8 BusManager::AllocateAddress()
154 {
155 	acquire_sem_etc( m_lock , 1 , B_CAN_INTERRUPT , 0 );
156 	int8 devicenum = -1;
157 	for( int i = 0 ; i < 128 ; i++ )
158 	{
159 		if ( m_devicemap[i] == false )
160 		{
161 			devicenum = i;
162 			m_devicemap[i] = true;
163 			break;
164 		}
165 	}
166 	release_sem( m_lock );
167 	return devicenum;
168 }
169 
170 status_t BusManager::SendRequest( Device * dev , uint8 request_type , uint8 request , uint16 value ,
171 	                  uint16 index , uint16 length , void *data ,
172 	                  size_t data_len , size_t *actual_len )
173 {
174 	//todo: het moet speciaal soort geheugen worden
175 	usb_request_data *req = (usb_request_data *)malloc( sizeof( usb_request_data) );
176 
177 	req->RequestType = request_type;
178 	req->Request = request;
179 	req->Value = value;
180 	req->Index = index;
181 	req->Length = length;
182 
183 	//Nicen up the second argument: the default pipe
184 	//1) set up the pipe stuff a little nicer
185 	//2) don't assume it's a low speed device :-(
186 	return SendControlMessage( dev , ( 2 << 30 | 1 << 26 ) , req ,
187 	                                   data , data_len , actual_len , 3 * 1000 * 1000 );
188 }
189 
190 status_t BusManager::SendControlMessage( Device *dev , uint16 pipe ,
191 	                             usb_request_data *command , void *data ,
192 	                             size_t data_length , size_t *actual_length ,
193 	                             bigtime_t timeout )
194 {
195 	// this method should build an usb packet (new class) with the needed data
196 	Packet packet;
197 
198 	packet.SetPipe( pipe );
199 	packet.SetRequestData( (uint8 *)command );
200 	packet.SetBuffer( (uint8 *)data );
201 	packet.SetBufferLength( data_length );
202 	packet.SetActualLength( actual_length );
203 	packet.SetAddress( 0 );
204 
205 	status_t retval = hcpointer->SubmitPacket( packet.GetData() );
206 	return retval;
207 }
208 
209