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