xref: /haiku/src/add-ons/kernel/bus_managers/usb/Stack.cpp (revision 1d9d47fc72028bb71b5f232a877231e59cfe2438)
1 /*
2  * Copyright 2003-2006, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Niels S. Reedijk
7  */
8 
9 #include <module.h>
10 #include <util/kernel_cpp.h>
11 #include "usb_p.h"
12 
13 
14 #define TRACE_STACK
15 #ifdef TRACE_STACK
16 #define TRACE(x)	dprintf x
17 #else
18 #define TRACE(x)	/* nothing */
19 #endif
20 
21 
22 Stack::Stack()
23 {
24 	TRACE(("usb stack: stack init\n"));
25 
26 	// Create the master lock
27 	fMasterLock = create_sem(1, "usb master lock");
28 	set_sem_owner(fMasterLock, B_SYSTEM_TEAM);
29 
30 	// Create the data lock
31 	fDataLock = create_sem(1, "usb data lock");
32 	set_sem_owner(fDataLock, B_SYSTEM_TEAM);
33 
34 	// Set the global "data" variable to this
35 	usb_stack = this;
36 
37 	// Initialise the memory chunks: create 8, 16 and 32 byte-heaps
38 	// NOTE: This is probably the most ugly code you will see in the
39 	// whole stack. Unfortunately this is needed because of the fact
40 	// that the compiler doesn't like us to apply pointer arithmethic
41 	// to (void *) pointers.
42 
43 	// 8-byte heap
44 	fAreaFreeCount[0] = 0;
45 	fAreas[0] = AllocateArea(&fLogical[0], &fPhysical[0], B_PAGE_SIZE,
46 		"8-byte chunk area");
47 
48 	if (fAreas[0] < B_OK) {
49 		TRACE(("usb stack: 8-byte chunk area failed to initialise\n"));
50 		return;
51 	}
52 
53 	fListhead8 = (addr_t)fLogical[0];
54 	for (int32 i = 0; i < B_PAGE_SIZE / 8; i++) {
55 		memory_chunk *chunk = (memory_chunk *)((addr_t)fLogical[0] + 8 * i);
56 		chunk->physical = (addr_t)fPhysical[0] + 8 * i;
57 
58 		if (i < B_PAGE_SIZE / 8 - 1)
59 			chunk->next_item = (addr_t)fLogical[0] + 8 * (i + 1);
60 		else
61 			chunk->next_item = NULL;
62 	}
63 
64 	// 16-byte heap
65 	fAreaFreeCount[1] = 0;
66 	fAreas[1] = AllocateArea(&fLogical[1], &fPhysical[1], B_PAGE_SIZE,
67 		"16-byte chunk area");
68 
69 	if (fAreas[1] < B_OK) {
70 		TRACE(("usb stack: 16-byte chunk area failed to initialise\n"));
71 		return;
72 	}
73 
74 	fListhead16 = (addr_t)fLogical[1];
75 	for (int32 i = 0; i < B_PAGE_SIZE / 16; i++) {
76 		memory_chunk *chunk = (memory_chunk *)((addr_t)fLogical[1] + 16 * i);
77 		chunk->physical = (addr_t)fPhysical[1] + 16 * i;
78 
79 		if (i < B_PAGE_SIZE / 16 - 1)
80 			chunk->next_item = (addr_t)fLogical[1] + 16 * (i + 1);
81 		else
82 			chunk->next_item = NULL;
83 	}
84 
85 	// 32-byte heap
86 	fAreaFreeCount[2] = 0;
87 	fAreas[2] = AllocateArea(&fLogical[2], &fPhysical[2], B_PAGE_SIZE,
88 		"32-byte chunk area");
89 
90 	if (fAreas[2] < B_OK) {
91 		TRACE(("usb stack: 32-byte chunk area failed to initialise\n"));
92 		return;
93 	}
94 
95 	fListhead32 = (addr_t)fLogical[2];
96 	for (int32 i = 0; i < B_PAGE_SIZE / 32; i++) {
97 		memory_chunk *chunk = (memory_chunk *)((addr_t)fLogical[2] + 32 * i);
98 		chunk->physical = (addr_t)fPhysical[2] + 32 * i;
99 
100 		if (i < B_PAGE_SIZE / 32 - 1)
101 			chunk->next_item = (addr_t)fLogical[2] + 32 * (i + 1);
102 		else
103 			chunk->next_item = NULL;
104 	}
105 
106 	// Check for host controller modules
107 	void *moduleList = open_module_list("busses/usb");
108 	char moduleName[B_PATH_NAME_LENGTH];
109 	size_t bufferSize = sizeof(moduleName);
110 
111 	TRACE(("usb stack: Looking for host controller modules\n"));
112 	while(read_next_module_name(moduleList, moduleName, &bufferSize) == B_OK) {
113 		bufferSize = sizeof(moduleName);
114 		TRACE(("usb stack: Found module %s\n", moduleName));
115 
116 		host_controller_info *module = NULL;
117 		if (get_module(moduleName, (module_info **)&module) != B_OK)
118 			continue;
119 
120 		if (module->add_to(*this) != B_OK)
121 			continue;
122 
123 		TRACE(("usb stack: module %s successfully loaded\n", moduleName));
124 	}
125 
126 	if (fBusManagers.Count() == 0)
127 		return;
128 }
129 
130 
131 Stack::~Stack()
132 {
133 	//Release the bus modules
134 	for (Vector<BusManager *>::Iterator i = fBusManagers.Begin();
135 		i != fBusManagers.End(); i++) {
136 		delete (*i);
137 	}
138 
139 	delete_area(fAreas[0]);
140 	delete_area(fAreas[1]);
141 	delete_area(fAreas[2]);
142 }
143 
144 
145 status_t
146 Stack::InitCheck()
147 {
148 	if (fBusManagers.Count() == 0)
149 		return ENODEV;
150 
151 	return B_OK;
152 }
153 
154 
155 void
156 Stack::Lock()
157 {
158 	acquire_sem(fMasterLock);
159 }
160 
161 
162 void
163 Stack::Unlock()
164 {
165 	release_sem(fMasterLock);
166 }
167 
168 
169 void
170 Stack::AddBusManager(BusManager *busManager)
171 {
172 	fBusManagers.PushBack(busManager);
173 }
174 
175 
176 status_t
177 Stack::AllocateChunk(void **logicalAddress, void **physicalAddress, uint8 size)
178 {
179 	Lock();
180 
181 	addr_t listhead;
182 	if (size <= 8)
183 		listhead = fListhead8;
184 	else if (size <= 16)
185 		listhead = fListhead16;
186 	else if (size <= 32)
187 		listhead = fListhead32;
188 	else {
189 		TRACE(("usb stack: Chunk size %d to big\n", size));
190 		Unlock();
191 		return B_ERROR;
192 	}
193 
194 	if (listhead == NULL) {
195 		TRACE(("usb stack: Out of memory on this list\n"));
196 		Unlock();
197 		return B_ERROR;
198 	}
199 
200 	//TRACE(("usb stack: Stack::Allocate() listhead: 0x%08x\n", listhead));
201 	memory_chunk *chunk = (memory_chunk *)listhead;
202 	*logicalAddress = (void *)listhead;
203 	*physicalAddress = (void *)chunk->physical;
204 	if (chunk->next_item == NULL) {
205 		//TODO: allocate more memory
206 		listhead = NULL;
207 	} else {
208 		listhead = chunk->next_item;
209 	}
210 
211 	// Update our listhead pointers
212 	if (size <= 8)
213 		fListhead8 = listhead;
214 	else if (size <= 16)
215 		fListhead16 = listhead;
216 	else if (size <= 32)
217 		fListhead32 = listhead;
218 
219 	Unlock();
220 	//TRACE(("usb stack: allocated a new chunk with size %u\n", size));
221 	return B_OK;
222 }
223 
224 
225 status_t
226 Stack::FreeChunk(void *logicalAddress, void *physicalAddress, uint8 size)
227 {
228 	Lock();
229 
230 	addr_t listhead;
231 	if (size <= 8)
232 		listhead = fListhead8;
233 	else if (size <= 16)
234 		listhead = fListhead16;
235 	else if (size <= 32)
236 		listhead = fListhead32;
237 	else {
238 		TRACE(("usb stack: Chunk size %d invalid\n", size));
239 		Unlock();
240 		return B_ERROR;
241 	}
242 
243 	memory_chunk *chunk = (memory_chunk *)logicalAddress;
244 	chunk->next_item = listhead;
245 	chunk->physical = (addr_t)physicalAddress;
246 
247 	if (size <= 8)
248 		fListhead8 = (addr_t)logicalAddress;
249 	else if (size <= 16)
250 		fListhead16 = (addr_t)logicalAddress;
251 	else if (size <= 32)
252 		fListhead32 = (addr_t)logicalAddress;
253 
254 	Unlock();
255 	return B_OK;
256 }
257 
258 
259 area_id
260 Stack::AllocateArea(void **logicalAddress, void **physicalAddress, size_t size,
261 	const char *name)
262 {
263 	TRACE(("usb stack: allocating %ld bytes for %s\n", size, name));
264 
265 	void *logAddress;
266 	size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
267 	area_id area = create_area(name, &logAddress, B_ANY_KERNEL_ADDRESS, size,
268 		B_FULL_LOCK | B_CONTIGUOUS, 0);
269 
270 	if (area < B_OK) {
271 		TRACE(("usb stack: couldn't allocate area %s\n", name));
272 		return B_ERROR;
273 	}
274 
275 	physical_entry physicalEntry;
276 	status_t result = get_memory_map(logAddress, size, &physicalEntry, 1);
277 	if (result < B_OK) {
278 		delete_area(area);
279 		TRACE(("usb stack: couldn't map area %s\n", name));
280 		return B_ERROR;
281 	}
282 
283 	memset(logAddress, 0, size);
284 	if (logicalAddress)
285 		*logicalAddress = logAddress;
286 
287 	if (physicalAddress)
288 		*physicalAddress = physicalEntry.address;
289 
290 	TRACE(("usb stack: area = 0x%08x, size = %ld, log = 0x%08x, phy = 0x%08x\n",
291 		area, size, logAddress, physicalEntry.address));
292 	return area;
293 }
294 
295 
296 Stack *usb_stack = NULL;
297