xref: /haiku/src/add-ons/kernel/bus_managers/usb/Stack.cpp (revision 652f187eee454506a61c85631eb5d8415f3e22d4)
1 /*
2  * Copyright 2003-2006, Haiku Inc. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Michael Lotz <mmlr@mlotz.ch>
7  *		Niels S. Reedijk
8  */
9 
10 #include <module.h>
11 #include <unistd.h>
12 #include <util/kernel_cpp.h>
13 #include "usb_p.h"
14 #include "PhysicalMemoryAllocator.h"
15 
16 #ifdef HAIKU_TARGET_PLATFORM_HAIKU
17 #include <fs/devfs.h>
18 #endif
19 
20 Stack::Stack()
21 	:	fExploreThread(-1),
22 		fFirstExploreDone(false),
23 		fStopThreads(false),
24 		fObjectIndex(1),
25 		fObjectMaxCount(1024),
26 		fObjectArray(NULL),
27 		fDriverList(NULL)
28 {
29 	TRACE(("USB Stack: stack init\n"));
30 
31 	if (benaphore_init(&fLock, "usb stack lock") < B_OK) {
32 		TRACE_ERROR(("USB Stack: failed to create benaphore lock\n"));
33 		return;
34 	}
35 
36 	size_t objectArraySize = fObjectMaxCount * sizeof(Object *);
37 	fObjectArray = (Object **)malloc(objectArraySize);
38 	memset(fObjectArray, 0, objectArraySize);
39 
40 	fAllocator = new(std::nothrow) PhysicalMemoryAllocator("USB Stack Allocator",
41 		8, B_PAGE_SIZE * 4, 64);
42 	if (!fAllocator || fAllocator->InitCheck() < B_OK) {
43 		TRACE_ERROR(("USB Stack: failed to allocate the allocator\n"));
44 		delete fAllocator;
45 		return;
46 	}
47 
48 	// Check for host controller modules
49 	void *moduleList = open_module_list("busses/usb");
50 	char moduleName[B_PATH_NAME_LENGTH];
51 	size_t bufferSize = sizeof(moduleName);
52 
53 	TRACE(("USB Stack: looking for host controller modules\n"));
54 	while(read_next_module_name(moduleList, moduleName, &bufferSize) == B_OK) {
55 		bufferSize = sizeof(moduleName);
56 		TRACE(("USB Stack: found module %s\n", moduleName));
57 
58 		host_controller_info *module = NULL;
59 		if (get_module(moduleName, (module_info **)&module) != B_OK)
60 			continue;
61 
62 		if (module->add_to(this) < B_OK)
63 			continue;
64 
65 		TRACE(("USB Stack: module %s successfully loaded\n", moduleName));
66 	}
67 
68 	close_module_list(moduleList);
69 
70 	if (fBusManagers.Count() == 0) {
71 		TRACE_ERROR(("USB Stack: no bus managers available\n"));
72 		return;
73 	}
74 
75 	fExploreThread = spawn_kernel_thread(ExploreThread, "usb explore",
76 		B_LOW_PRIORITY, this);
77 	resume_thread(fExploreThread);
78 }
79 
80 
81 Stack::~Stack()
82 {
83 	int32 result;
84 	fStopThreads = true;
85 	wait_for_thread(fExploreThread, &result);
86 
87 	Lock();
88 	benaphore_destroy(&fLock);
89 
90 	//Release the bus modules
91 	for (Vector<BusManager *>::Iterator i = fBusManagers.Begin();
92 		i != fBusManagers.End(); i++) {
93 		delete (*i);
94 	}
95 
96 	delete fAllocator;
97 }
98 
99 
100 status_t
101 Stack::InitCheck()
102 {
103 	if (fBusManagers.Count() == 0)
104 		return ENODEV;
105 
106 	return B_OK;
107 }
108 
109 
110 bool
111 Stack::Lock()
112 {
113 	return (benaphore_lock(&fLock) == B_OK);
114 }
115 
116 
117 void
118 Stack::Unlock()
119 {
120 	benaphore_unlock(&fLock);
121 }
122 
123 
124 usb_id
125 Stack::GetUSBID(Object *object)
126 {
127 	if (!Lock())
128 		return 0;
129 
130 	uint32 id = fObjectIndex;
131 	uint32 tries = fObjectMaxCount;
132 	while (tries-- > 0) {
133 		if (fObjectArray[id] == NULL) {
134 			fObjectIndex = (id + 1) % fObjectMaxCount;
135 			fObjectArray[id] = object;
136 			Unlock();
137 			return (usb_id)id;
138 		}
139 
140 		id = (id + 1) % fObjectMaxCount;
141 	}
142 
143 	TRACE_ERROR(("USB Stack: the stack did run out of usb_ids\n"));
144 	Unlock();
145 	return 0;
146 }
147 
148 
149 void
150 Stack::PutUSBID(usb_id id)
151 {
152 	if (!Lock())
153 		return;
154 
155 	if (id >= fObjectMaxCount) {
156 		TRACE_ERROR(("USB Stack: tried to put an invalid usb_id\n"));
157 		Unlock();
158 		return;
159 	}
160 
161 	fObjectArray[id] = NULL;
162 	Unlock();
163 }
164 
165 
166 Object *
167 Stack::GetObject(usb_id id)
168 {
169 	if (!Lock())
170 		return NULL;
171 
172 	if (id >= fObjectMaxCount) {
173 		TRACE_ERROR(("USB Stack: tried to get object with invalid usb_id\n"));
174 		Unlock();
175 		return NULL;
176 	}
177 
178 	Object *result = fObjectArray[id];
179 
180 	Unlock();
181 	return result;
182 }
183 
184 
185 int32
186 Stack::ExploreThread(void *data)
187 {
188 	Stack *stack = (Stack *)data;
189 
190 	while (!stack->fStopThreads) {
191 		for (int32 i = 0; i < stack->fBusManagers.Count(); i++) {
192 			Hub *rootHub = stack->fBusManagers.ElementAt(i)->GetRootHub();
193 			if (rootHub)
194 				rootHub->Explore();
195 		}
196 
197 		stack->fFirstExploreDone = true;
198 		snooze(USB_DELAY_HUB_EXPLORE);
199 	}
200 
201 	return B_OK;
202 }
203 
204 
205 void
206 Stack::AddBusManager(BusManager *busManager)
207 {
208 	fBusManagers.PushBack(busManager);
209 }
210 
211 
212 int32
213 Stack::IndexOfBusManager(BusManager *busManager)
214 {
215 	return fBusManagers.IndexOf(busManager);
216 }
217 
218 
219 status_t
220 Stack::AllocateChunk(void **logicalAddress, void **physicalAddress, size_t size)
221 {
222 	return fAllocator->Allocate(size, logicalAddress, physicalAddress);
223 }
224 
225 
226 status_t
227 Stack::FreeChunk(void *logicalAddress, void *physicalAddress, size_t size)
228 {
229 	return fAllocator->Deallocate(size, logicalAddress, physicalAddress);
230 }
231 
232 
233 area_id
234 Stack::AllocateArea(void **logicalAddress, void **physicalAddress, size_t size,
235 	const char *name)
236 {
237 	TRACE(("USB Stack: allocating %ld bytes for %s\n", size, name));
238 
239 	void *logAddress;
240 	size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
241 	area_id area = create_area(name, &logAddress, B_ANY_KERNEL_ADDRESS, size,
242 		B_FULL_LOCK | B_CONTIGUOUS, 0);
243 
244 	if (area < B_OK) {
245 		TRACE_ERROR(("USB Stack: couldn't allocate area %s\n", name));
246 		return B_ERROR;
247 	}
248 
249 	physical_entry physicalEntry;
250 	status_t result = get_memory_map(logAddress, size, &physicalEntry, 1);
251 	if (result < B_OK) {
252 		delete_area(area);
253 		TRACE_ERROR(("USB Stack: couldn't map area %s\n", name));
254 		return B_ERROR;
255 	}
256 
257 	memset(logAddress, 0, size);
258 	if (logicalAddress)
259 		*logicalAddress = logAddress;
260 
261 	if (physicalAddress)
262 		*physicalAddress = physicalEntry.address;
263 
264 	TRACE(("USB Stack: area = 0x%08lx, size = %ld, log = 0x%08lx, phy = 0x%08lx\n",
265 		area, size, logAddress, physicalEntry.address));
266 	return area;
267 }
268 
269 
270 void
271 Stack::NotifyDeviceChange(Device *device, bool added)
272 {
273 	TRACE(("USB Stack: device %s\n", added ? "added" : "removed"));
274 
275 	usb_driver_info *element = fDriverList;
276 	while (element) {
277 		status_t result = device->ReportDevice(element->support_descriptors,
278 			element->support_descriptor_count, &element->notify_hooks,
279 			&element->cookies, added);
280 
281 		if (result >= B_OK) {
282 			// the device is supported by this driver. it either got notified
283 			// already by the hooks or it is not loaded at this time. in any
284 			// case we will rescan the driver so it either is loaded and can
285 			// scan for supported devices or its publish_devices hook will be
286 			// called to expose new devices.
287 			const char *name = element->driver_name;
288 			if (element->republish_driver_name)
289 				name = element->republish_driver_name;
290 
291 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
292 			// the R5 way to republish a device in devfs
293 			int devFS = open("/dev", O_WRONLY);
294 			write(devFS, name, strlen(name));
295 			close(devFS);
296 #else
297 			// use the private devfs API under Haiku
298 			//devfs_rescan_driver(name);
299 #endif
300 		}
301 
302 		element = element->link;
303 	}
304 }
305 
306 
307 status_t
308 Stack::RegisterDriver(const char *driverName,
309 	const usb_support_descriptor *descriptors,
310 	size_t descriptorCount, const char *republishDriverName)
311 {
312 	TRACE(("USB Stack: register driver \"%s\"\n", driverName));
313 	if (!driverName)
314 		return B_BAD_VALUE;
315 
316 	if (!Lock())
317 		return B_ERROR;
318 
319 	usb_driver_info *element = fDriverList;
320 	while (element) {
321 		if (strcmp(element->driver_name, driverName) == 0) {
322 			// we already have an entry for this driver, just update it
323 			free((char *)element->republish_driver_name);
324 			element->republish_driver_name = strdup(republishDriverName);
325 
326 			free(element->support_descriptors);
327 			size_t descriptorsSize = descriptorCount * sizeof(usb_support_descriptor);
328 			element->support_descriptors = (usb_support_descriptor *)malloc(descriptorsSize);
329 			memcpy(element->support_descriptors, descriptors, descriptorsSize);
330 			element->support_descriptor_count = descriptorCount;
331 
332 			Unlock();
333 			return B_OK;
334 		}
335 
336 		element = element->link;
337 	}
338 
339 	// this is a new driver, add it to the driver list
340 	usb_driver_info *info = new(std::nothrow) usb_driver_info;
341 	if (!info) {
342 		Unlock();
343 		return B_NO_MEMORY;
344 	}
345 
346 	info->driver_name = strdup(driverName);
347 	info->republish_driver_name = strdup(republishDriverName);
348 
349 	size_t descriptorsSize = descriptorCount * sizeof(usb_support_descriptor);
350 	info->support_descriptors = (usb_support_descriptor *)malloc(descriptorsSize);
351 	memcpy(info->support_descriptors, descriptors, descriptorsSize);
352 	info->support_descriptor_count = descriptorCount;
353 
354 	info->notify_hooks.device_added = NULL;
355 	info->notify_hooks.device_removed = NULL;
356 	info->cookies = NULL;
357 	info->link = NULL;
358 
359 	if (fDriverList) {
360 		usb_driver_info *element = fDriverList;
361 		while (element->link)
362 			element = element->link;
363 
364 		element->link = info;
365 	} else
366 		fDriverList = info;
367 
368 	Unlock();
369 	return B_OK;
370 }
371 
372 
373 status_t
374 Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks)
375 {
376 	TRACE(("USB Stack: installing notify hooks for driver \"%s\"\n", driverName));
377 
378 	// wait for the first explore to complete
379 	// this ensures that we get all initial devices
380 	while (!fFirstExploreDone)
381 		snooze(1000);
382 
383 	usb_driver_info *element = fDriverList;
384 	while (element) {
385 		if (strcmp(element->driver_name, driverName) == 0) {
386 			// inform driver about any already present devices
387 			for (int32 i = 0; i < fBusManagers.Count(); i++) {
388 				Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub();
389 				if (rootHub) {
390 					// Report device will recurse down the whole tree
391 					rootHub->ReportDevice(element->support_descriptors,
392 						element->support_descriptor_count, hooks,
393 						&element->cookies, true);
394 				}
395 			}
396 
397 			element->notify_hooks.device_added = hooks->device_added;
398 			element->notify_hooks.device_removed = hooks->device_removed;
399 			return B_OK;
400 		}
401 
402 		element = element->link;
403 	}
404 
405 	return B_NAME_NOT_FOUND;
406 }
407 
408 
409 status_t
410 Stack::UninstallNotify(const char *driverName)
411 {
412 	TRACE(("USB Stack: uninstalling notify hooks for driver \"%s\"\n", driverName));
413 
414 	usb_driver_info *element = fDriverList;
415 	while (element) {
416 		if (strcmp(element->driver_name, driverName) == 0) {
417 			// trigger the device removed hook
418 			for (int32 i = 0; i < fBusManagers.Count(); i++) {
419 				Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub();
420 				if (rootHub)
421 					rootHub->ReportDevice(element->support_descriptors,
422 						element->support_descriptor_count,
423 						&element->notify_hooks, &element->cookies, false);
424 			}
425 
426 			element->notify_hooks.device_added = NULL;
427 			element->notify_hooks.device_removed = NULL;
428 			return B_OK;
429 		}
430 
431 		element = element->link;
432 	}
433 
434 	return B_NAME_NOT_FOUND;
435 }
436