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