xref: /haiku/src/add-ons/kernel/bus_managers/usb/Stack.cpp (revision 2f470aec1c92ce6917b8a903e343795dc77af41f)
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 	// wait for the first explore to complete
80 	// this ensures that we get all initial devices under InstallNotify
81 	while (!fFirstExploreDone)
82 		snooze(1000);
83 }
84 
85 
86 Stack::~Stack()
87 {
88 	int32 result;
89 	fStopThreads = true;
90 	wait_for_thread(fExploreThread, &result);
91 
92 	Lock();
93 	benaphore_destroy(&fLock);
94 
95 	//Release the bus modules
96 	for (Vector<BusManager *>::Iterator i = fBusManagers.Begin();
97 		i != fBusManagers.End(); i++) {
98 		delete (*i);
99 	}
100 
101 	delete fAllocator;
102 }
103 
104 
105 status_t
106 Stack::InitCheck()
107 {
108 	if (fBusManagers.Count() == 0)
109 		return ENODEV;
110 
111 	return B_OK;
112 }
113 
114 
115 bool
116 Stack::Lock()
117 {
118 	return (benaphore_lock(&fLock) == B_OK);
119 }
120 
121 
122 void
123 Stack::Unlock()
124 {
125 	benaphore_unlock(&fLock);
126 }
127 
128 
129 usb_id
130 Stack::GetUSBID(Object *object)
131 {
132 	if (!Lock())
133 		return 0;
134 
135 	uint32 id = fObjectIndex;
136 	uint32 tries = fObjectMaxCount;
137 	while (tries-- > 0) {
138 		if (fObjectArray[id] == NULL) {
139 			fObjectIndex = (id + 1) % fObjectMaxCount;
140 			fObjectArray[id] = object;
141 			Unlock();
142 			return (usb_id)id;
143 		}
144 
145 		id = (id + 1) % fObjectMaxCount;
146 	}
147 
148 	TRACE_ERROR(("USB Stack: the stack did run out of usb_ids\n"));
149 	Unlock();
150 	return 0;
151 }
152 
153 
154 void
155 Stack::PutUSBID(usb_id id)
156 {
157 	if (!Lock())
158 		return;
159 
160 	if (id >= fObjectMaxCount) {
161 		TRACE_ERROR(("USB Stack: tried to put an invalid usb_id\n"));
162 		Unlock();
163 		return;
164 	}
165 
166 	fObjectArray[id] = NULL;
167 	Unlock();
168 }
169 
170 
171 Object *
172 Stack::GetObject(usb_id id)
173 {
174 	if (!Lock())
175 		return NULL;
176 
177 	if (id >= fObjectMaxCount) {
178 		TRACE_ERROR(("USB Stack: tried to get object with invalid usb_id\n"));
179 		Unlock();
180 		return NULL;
181 	}
182 
183 	Object *result = fObjectArray[id];
184 
185 	Unlock();
186 	return result;
187 }
188 
189 
190 int32
191 Stack::ExploreThread(void *data)
192 {
193 	Stack *stack = (Stack *)data;
194 
195 	while (!stack->fStopThreads) {
196 		for (int32 i = 0; i < stack->fBusManagers.Count(); i++) {
197 			Hub *rootHub = stack->fBusManagers.ElementAt(i)->GetRootHub();
198 			if (rootHub)
199 				rootHub->Explore();
200 		}
201 
202 		stack->fFirstExploreDone = true;
203 		snooze(USB_DELAY_HUB_EXPLORE);
204 	}
205 
206 	return B_OK;
207 }
208 
209 
210 void
211 Stack::AddBusManager(BusManager *busManager)
212 {
213 	fBusManagers.PushBack(busManager);
214 }
215 
216 
217 int32
218 Stack::IndexOfBusManager(BusManager *busManager)
219 {
220 	return fBusManagers.IndexOf(busManager);
221 }
222 
223 
224 status_t
225 Stack::AllocateChunk(void **logicalAddress, void **physicalAddress, size_t size)
226 {
227 	return fAllocator->Allocate(size, logicalAddress, physicalAddress);
228 }
229 
230 
231 status_t
232 Stack::FreeChunk(void *logicalAddress, void *physicalAddress, size_t size)
233 {
234 	return fAllocator->Deallocate(size, logicalAddress, physicalAddress);
235 }
236 
237 
238 area_id
239 Stack::AllocateArea(void **logicalAddress, void **physicalAddress, size_t size,
240 	const char *name)
241 {
242 	TRACE(("USB Stack: allocating %ld bytes for %s\n", size, name));
243 
244 	void *logAddress;
245 	size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
246 	area_id area = create_area(name, &logAddress, B_ANY_KERNEL_ADDRESS, size,
247 		B_FULL_LOCK | B_CONTIGUOUS, 0);
248 
249 	if (area < B_OK) {
250 		TRACE_ERROR(("USB Stack: couldn't allocate area %s\n", name));
251 		return B_ERROR;
252 	}
253 
254 	physical_entry physicalEntry;
255 	status_t result = get_memory_map(logAddress, size, &physicalEntry, 1);
256 	if (result < B_OK) {
257 		delete_area(area);
258 		TRACE_ERROR(("USB Stack: couldn't map area %s\n", name));
259 		return B_ERROR;
260 	}
261 
262 	memset(logAddress, 0, size);
263 	if (logicalAddress)
264 		*logicalAddress = logAddress;
265 
266 	if (physicalAddress)
267 		*physicalAddress = physicalEntry.address;
268 
269 	TRACE(("USB Stack: area = 0x%08lx, size = %ld, log = 0x%08lx, phy = 0x%08lx\n",
270 		area, size, logAddress, physicalEntry.address));
271 	return area;
272 }
273 
274 
275 void
276 Stack::NotifyDeviceChange(Device *device, bool added)
277 {
278 	TRACE(("USB Stack: device %s\n", added ? "added" : "removed"));
279 
280 	usb_driver_info *element = fDriverList;
281 	while (element) {
282 		status_t result = device->ReportDevice(element->support_descriptors,
283 			element->support_descriptor_count, &element->notify_hooks,
284 			&element->cookies, added);
285 
286 		if (result >= B_OK) {
287 			// the device is supported by this driver. it either got notified
288 			// already by the hooks or it is not loaded at this time. in any
289 			// case we will rescan the driver so it either is loaded and can
290 			// scan for supported devices or its publish_devices hook will be
291 			// called to expose new devices.
292 			const char *name = element->driver_name;
293 			if (element->republish_driver_name)
294 				name = element->republish_driver_name;
295 
296 #ifndef HAIKU_TARGET_PLATFORM_HAIKU
297 			// the R5 way to republish a device in devfs
298 			int devFS = open("/dev", O_WRONLY);
299 			write(devFS, name, strlen(name));
300 			close(devFS);
301 #else
302 			// use the private devfs API under Haiku
303 			//devfs_rescan_driver(name);
304 #endif
305 		}
306 
307 		element = element->link;
308 	}
309 }
310 
311 
312 status_t
313 Stack::RegisterDriver(const char *driverName,
314 	const usb_support_descriptor *descriptors,
315 	size_t descriptorCount, const char *republishDriverName)
316 {
317 	TRACE(("USB Stack: register driver \"%s\"\n", driverName));
318 	if (!driverName)
319 		return B_BAD_VALUE;
320 
321 	if (!Lock())
322 		return B_ERROR;
323 
324 	usb_driver_info *element = fDriverList;
325 	while (element) {
326 		if (strcmp(element->driver_name, driverName) == 0) {
327 			// we already have an entry for this driver, just update it
328 			free((char *)element->republish_driver_name);
329 			element->republish_driver_name = strdup(republishDriverName);
330 
331 			free(element->support_descriptors);
332 			size_t descriptorsSize = descriptorCount * sizeof(usb_support_descriptor);
333 			element->support_descriptors = (usb_support_descriptor *)malloc(descriptorsSize);
334 			memcpy(element->support_descriptors, descriptors, descriptorsSize);
335 			element->support_descriptor_count = descriptorCount;
336 
337 			Unlock();
338 			return B_OK;
339 		}
340 
341 		element = element->link;
342 	}
343 
344 	// this is a new driver, add it to the driver list
345 	usb_driver_info *info = new(std::nothrow) usb_driver_info;
346 	if (!info) {
347 		Unlock();
348 		return B_NO_MEMORY;
349 	}
350 
351 	info->driver_name = strdup(driverName);
352 	info->republish_driver_name = strdup(republishDriverName);
353 
354 	size_t descriptorsSize = descriptorCount * sizeof(usb_support_descriptor);
355 	info->support_descriptors = (usb_support_descriptor *)malloc(descriptorsSize);
356 	memcpy(info->support_descriptors, descriptors, descriptorsSize);
357 	info->support_descriptor_count = descriptorCount;
358 
359 	info->notify_hooks.device_added = NULL;
360 	info->notify_hooks.device_removed = NULL;
361 	info->cookies = NULL;
362 	info->link = NULL;
363 
364 	if (fDriverList) {
365 		usb_driver_info *element = fDriverList;
366 		while (element->link)
367 			element = element->link;
368 
369 		element->link = info;
370 	} else
371 		fDriverList = info;
372 
373 	Unlock();
374 	return B_OK;
375 }
376 
377 
378 status_t
379 Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks)
380 {
381 	TRACE(("USB Stack: installing notify hooks for driver \"%s\"\n", driverName));
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