xref: /haiku/src/add-ons/kernel/bus_managers/usb/Stack.cpp (revision 93aeb8c3bc3f13cb1f282e3e749258a23790d947)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2003-2004, Niels S. Reedijk
3 //
4 //  AllocArea implementation (c) 2002 Marcus Overhagen <marcus@overhagen.de>
5 //
6 //	Permission is hereby granted, free of charge, to any person obtaining a
7 //	copy of this software and associated documentation files (the "Software"),
8 //	to deal in the Software without restriction, including without limitation
9 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 //	and/or sell copies of the Software, and to permit persons to whom the
11 //	Software is furnished to do so, subject to the following conditions:
12 //
13 //	The above copyright notice and this permission notice shall be included in
14 //	all copies or substantial portions of the Software.
15 //
16 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 //	DEALINGS IN THE SOFTWARE.
23 
24 #include <module.h>
25 #include <util/kernel_cpp.h>
26 
27 #include "usb_p.h"
28 
29 Stack::Stack()
30 {
31 	//Init the master lock
32 	m_master = create_sem( 1 , "usb master lock" );
33 	set_sem_owner( m_master , B_SYSTEM_TEAM );
34 
35 	//Create the data lock
36 	m_datalock = create_sem( 1 , "usb data lock" );
37 	set_sem_owner( m_datalock , B_SYSTEM_TEAM );
38 
39 	//Set the global "data" variable to this
40 	data = this;
41 
42 	//Initialise the memory chunks: create 8, 16 and 32 byte-heaps
43 	//NOTE: This is probably the most ugly code you will see in the
44 	//whole stack. Unfortunately this is needed because of the fact
45 	//that the compiler doesn't like us to apply pointer arithmethic
46 	//to (void *) pointers.
47 
48 	// 8-byte heap
49 	m_areafreecount[0] = 0;
50 	m_areas[0] = AllocateArea( &m_logical[0] , &m_physical[0] , B_PAGE_SIZE ,
51 	                        "8-byte chunk area" );
52 	if ( m_areas[0] < B_OK )
53 	{
54 		dprintf( "USB: 8-byte chunk area failed to initialise\n" );
55 		return;
56 	}
57 
58 	m_8_listhead = (addr_t)m_logical[0];
59 
60 	for ( int i = 0 ; i < B_PAGE_SIZE/8 ; i++ )
61 	{
62 		memory_chunk *chunk = (memory_chunk *)((addr_t)m_logical[0] + 8 * i);
63 		chunk->physical = (addr_t)m_physical[0] + 8 * i;
64 		if ( i != B_PAGE_SIZE / 8 - 1 )
65 			chunk->next_item = (addr_t)m_logical[0] + 8 * ( i + 1 );
66 		else
67 			chunk->next_item = NULL;
68 	}
69 
70 	// 16-byte heap
71 	m_areafreecount[1] = 0;
72 	m_areas[1] = AllocateArea( &m_logical[1] , &m_physical[1] , B_PAGE_SIZE ,
73 	                        "16-byte chunk area" );
74 	if ( m_areas[1] < B_OK )
75 	{
76 		dprintf( "USB: 16-byte chunk area failed to initialise\n" );
77 		return;
78 	}
79 
80 	m_16_listhead = (addr_t)m_logical[1];
81 
82 	for ( int i = 0 ; i < B_PAGE_SIZE/16 ; i++ )
83 	{
84 		memory_chunk *chunk = (memory_chunk *)((addr_t)m_logical[1] + 16 * i);
85 		chunk->physical = (addr_t)m_physical[1] + 16 * i;
86 		if ( i != B_PAGE_SIZE / 16 - 1 )
87 			chunk->next_item = (addr_t)m_logical[1] + 16 * ( i + 1 );
88 		else
89 			chunk->next_item = NULL;
90 	}
91 
92 	// 32-byte heap
93 	m_areafreecount[2] = 0;
94 	m_areas[2] = AllocateArea( &m_logical[2] , &m_physical[2] , B_PAGE_SIZE ,
95 	                        "32-byte chunk area" );
96 	if ( m_areas[2] < B_OK )
97 	{
98 		dprintf( "USB: 32-byte chunk area failed to initialise\n" );
99 		return;
100 	}
101 
102 	m_32_listhead = (addr_t)m_logical[2];
103 
104 	for ( int i = 0 ; i < B_PAGE_SIZE/32 ; i++ )
105 	{
106 		memory_chunk *chunk = (memory_chunk *)((addr_t)m_logical[2] + 32 * i);
107 		chunk->physical = (addr_t)m_physical[2] + 32 * i;
108 		if ( i != B_PAGE_SIZE / 32 - 1 )
109 			chunk->next_item = (addr_t)m_logical[2] + 32 * ( i + 1 );
110 		else
111 			chunk->next_item = NULL;
112 	}
113 
114 
115 	//Check for host controller modules
116 	void *list = open_module_list( "busses/usb" );
117 	char modulename[B_PATH_NAME_LENGTH];
118 	size_t buffersize = sizeof(modulename);
119 	dprintf( "USB: Looking for host controller modules\n" );
120 	while( read_next_module_name( list , modulename , &buffersize ) == B_OK )
121 	{
122 		dprintf( "USB: Found module %s\n" , modulename );
123 		host_controller_info *module = 0;
124 		if ( get_module( modulename , (module_info **)&module ) != B_OK )
125 			continue;
126 		if ( module->add_to( *this) != B_OK )
127 			continue;
128 		dprintf( "USB: module %s successfully loaded\n" , modulename );
129 	}
130 
131 	if( m_busmodules.Count() == 0 )
132 		return;
133 }
134 
135 Stack::~Stack()
136 {
137 	//Release the bus modules
138 	for( Vector<BusManager *>::Iterator i = m_busmodules.Begin() ; i != m_busmodules.End() ; i++ )
139 		delete (*i);
140 	delete_area( m_areas[0] );
141 	delete_area( m_areas[1] );
142 	delete_area( m_areas[2] );
143 }
144 
145 
146 status_t Stack::InitCheck()
147 {
148 	if ( m_busmodules.Count() == 0 )
149 		return ENODEV;
150 	return B_OK;
151 }
152 
153 void Stack::Lock()
154 {
155 	acquire_sem( m_master );
156 }
157 
158 void Stack::Unlock()
159 {
160 	release_sem( m_master );
161 }
162 
163 void Stack::AddBusManager( BusManager *bus )
164 {
165 	m_busmodules.PushBack( bus );
166 }
167 
168 
169 status_t Stack::AllocateChunk( void **log , void **phy , uint8 size )
170 {
171 	Lock();
172 
173 	addr_t listhead;
174 	if ( size <= 8 )
175 		listhead = m_8_listhead;
176 	else if ( size <= 16 )
177 		listhead = m_16_listhead;
178 	else if ( size <= 32 )
179 		listhead = m_32_listhead;
180 	else
181 	{
182 		dprintf ( "USB Stack: Chunk size %i to big\n" , size );
183 		Unlock();
184 		return B_ERROR;
185 	}
186 
187 	if ( listhead == NULL )
188 	{
189 		Unlock();
190 		dprintf( "USB Stack: Out of memory on this list\n" );
191 		return B_ERROR;
192 	}
193 
194 	dprintf( "USB Stack::Allocate() listhead: %l\n" , listhead );
195 
196 	memory_chunk *chunk = (memory_chunk *)listhead;
197 	*log = (void *)listhead;
198 	*phy = (void *)(chunk->physical);
199 	if ( chunk->next_item == NULL )
200 		//TODO: allocate more memory
201 		listhead = NULL;
202 	else
203 		listhead = chunk->next_item;
204 
205 	//Update our listhead pointers
206 	if ( size <= 8 )
207 		m_8_listhead = listhead;
208 	else if ( size <= 16 )
209 		m_16_listhead = listhead;
210 	else if ( size <= 32 )
211 		m_32_listhead = listhead;
212 
213 	Unlock();
214 	dprintf( "USB Stack: allocated a new chunk with size %u\n" , size );
215 	return B_OK;
216 }
217 
218 status_t Stack::FreeChunk( void *log , void *phy , uint8 size )
219 {
220 	Lock();
221 	addr_t listhead;
222 	if ( size <= 8 )
223 		listhead = m_8_listhead;
224 	else if ( size <= 16 )
225 		listhead = m_16_listhead;
226 	else if ( size <= 32 )
227 		listhead = m_32_listhead;
228 	else
229 	{
230 		dprintf ( "USB Stack: Chunk size %i invalid\n" , size );
231 		Unlock();
232 		return B_ERROR;
233 	}
234 
235 	memory_chunk *chunk = (memory_chunk *)log;
236 
237 	chunk->next_item = listhead;
238 	chunk->physical = (addr_t)phy;
239 
240 	if ( size <= 8 )
241 		m_8_listhead = (addr_t)log;
242 	else if ( size <= 16 )
243 		m_16_listhead = (addr_t)log;
244 	else if ( size <= 32 )
245 		m_32_listhead = (addr_t)log;
246 
247 	Unlock();
248 	return B_OK;
249 }
250 
251 area_id Stack::AllocateArea( void **log , void **phy , size_t size , const char *name )
252 {
253 	physical_entry pe;
254 	void * logadr;
255 	area_id areaid;
256 	status_t rv;
257 
258 	dprintf("allocating %ld bytes for %s\n",size,name);
259 
260 	size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
261 	areaid = create_area(name, &logadr, B_ANY_KERNEL_ADDRESS,size,B_FULL_LOCK | B_CONTIGUOUS, 0 );
262 	if (areaid < B_OK) {
263 		dprintf("couldn't allocate area %s\n",name);
264 		return B_ERROR;
265 	}
266 	rv = get_memory_map(logadr,size,&pe,1);
267 	if (rv < B_OK) {
268 		delete_area(areaid);
269 		dprintf("couldn't map %s\n",name);
270 		return B_ERROR;
271 	}
272 	memset(logadr,0,size);
273 	if (log)
274 		*log = logadr;
275 	if (phy)
276 		*phy = pe.address;
277 	dprintf("area = %ld, size = %ld, log = %#08lX, phy = %#08lX\n",areaid,size,(uint32)logadr,(uint32)(pe.address));
278 	return areaid;
279 }
280 
281 Stack *data = 0;
282