xref: /haiku/src/add-ons/kernel/bus_managers/usb/Stack.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
1 /*
2  * Copyright 2003-2008, 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 
11 #include <module.h>
12 #include <unistd.h>
13 #include <util/kernel_cpp.h>
14 #include "usb_private.h"
15 #include "PhysicalMemoryAllocator.h"
16 
17 #include <fs/devfs.h>
18 
19 
20 Stack::Stack()
21 	:	fExploreThread(-1),
22 		fFirstExploreDone(false),
23 		fStopThreads(false),
24 		fAllocator(NULL),
25 		fObjectIndex(1),
26 		fObjectMaxCount(1024),
27 		fObjectArray(NULL),
28 		fDriverList(NULL)
29 {
30 	TRACE("stack init\n");
31 
32 	mutex_init(&fStackLock, "usb stack lock");
33 	mutex_init(&fExploreLock, "usb explore lock");
34 
35 	size_t objectArraySize = fObjectMaxCount * sizeof(Object *);
36 	fObjectArray = (Object **)malloc(objectArraySize);
37 	if (fObjectArray == NULL) {
38 		TRACE_ERROR("failed to allocate object array\n");
39 		return;
40 	}
41 
42 	memset(fObjectArray, 0, objectArraySize);
43 
44 	fAllocator = new(std::nothrow) PhysicalMemoryAllocator("USB Stack Allocator",
45 		8, B_PAGE_SIZE * 32, 64);
46 	if (!fAllocator || fAllocator->InitCheck() < B_OK) {
47 		TRACE_ERROR("failed to allocate the allocator\n");
48 		delete fAllocator;
49 		fAllocator = NULL;
50 		return;
51 	}
52 
53 	// Check for host controller modules.
54 	//
55 	// While using a fixed list of names is inflexible, it allows us to control
56 	// the order in which we try modules. There are controllers/BIOSes that
57 	// require UHCI/OHCI to be initialized before EHCI or otherwise they
58 	// refuse to publish any high-speed devices.
59 	//
60 	// On other systems, the ordering is probably ensured because the EHCI
61 	// controller is required to have a higher PCI function number than the
62 	// companion host controllers (per the EHCI specs) and it would therefore
63 	// be enumerated as the last item. As this does not apply to us, we have to
64 	// ensure ordering using another method.
65 	//
66 	// Furthermore, on some systems, there can be ports shared between
67 	// EHCI and XHCI, defaulting to EHCI. The XHCI module will switch these
68 	// ports before the EHCI module discovers them.
69 	const char *moduleNames[] = {
70 		"busses/usb/xhci",
71 		"busses/usb/uhci",
72 		"busses/usb/ohci",
73 		"busses/usb/ehci",
74 		NULL
75 	};
76 
77 	TRACE("looking for host controller modules\n");
78 	for (uint32 i = 0; moduleNames[i]; i++) {
79 		TRACE("looking for module %s\n", moduleNames[i]);
80 
81 		usb_host_controller_info *module = NULL;
82 		if (get_module(moduleNames[i], (module_info **)&module) != B_OK)
83 			continue;
84 
85 		TRACE("adding module %s\n", moduleNames[i]);
86 		if (module->add_to(this) < B_OK) {
87 			put_module(moduleNames[i]);
88 			continue;
89 		}
90 
91 		TRACE("module %s successfully loaded\n", moduleNames[i]);
92 	}
93 
94 	if (fBusManagers.Count() == 0) {
95 		TRACE_ERROR("no bus managers available\n");
96 		return;
97 	}
98 
99 	fExploreThread = spawn_kernel_thread(ExploreThread, "usb explore",
100 		B_LOW_PRIORITY, this);
101 	resume_thread(fExploreThread);
102 
103 	// wait for the first explore to complete. this ensures that a driver that
104 	// is opening the module does not get rescanned while or before installing
105 	// its hooks.
106 	while (!fFirstExploreDone)
107 		snooze(10000);
108 }
109 
110 
111 Stack::~Stack()
112 {
113 	int32 result;
114 	fStopThreads = true;
115 	wait_for_thread(fExploreThread, &result);
116 
117 	mutex_lock(&fStackLock);
118 	mutex_destroy(&fStackLock);
119 	mutex_lock(&fExploreLock);
120 	mutex_destroy(&fExploreLock);
121 
122 	// Release the bus modules
123 	for (Vector<BusManager *>::Iterator i = fBusManagers.Begin();
124 		i != fBusManagers.End(); i++) {
125 		delete (*i);
126 	}
127 
128 	delete fAllocator;
129 	free(fObjectArray);
130 }
131 
132 
133 status_t
134 Stack::InitCheck()
135 {
136 	if (fBusManagers.Count() == 0)
137 		return ENODEV;
138 	return B_OK;
139 }
140 
141 
142 bool
143 Stack::Lock()
144 {
145 	return (mutex_lock(&fStackLock) == B_OK);
146 }
147 
148 
149 void
150 Stack::Unlock()
151 {
152 	mutex_unlock(&fStackLock);
153 }
154 
155 
156 usb_id
157 Stack::GetUSBID(Object *object)
158 {
159 	if (!Lock())
160 		return fObjectMaxCount;
161 
162 	uint32 id = fObjectIndex;
163 	uint32 tries = fObjectMaxCount;
164 	while (tries-- > 0) {
165 		if (fObjectArray[id] == NULL) {
166 			fObjectIndex = (id + 1) % fObjectMaxCount;
167 			fObjectArray[id] = object;
168 			Unlock();
169 			return (usb_id)id;
170 		}
171 
172 		id = (id + 1) % fObjectMaxCount;
173 	}
174 
175 	TRACE_ERROR("the stack has run out of usb_ids\n");
176 	Unlock();
177 	return 0;
178 }
179 
180 
181 void
182 Stack::PutUSBID(Object *object)
183 {
184 	if (!Lock())
185 		return;
186 
187 	usb_id id = object->USBID();
188 	if (id >= fObjectMaxCount) {
189 		TRACE_ERROR("tried to put an invalid usb_id\n");
190 		Unlock();
191 		return;
192 	}
193 	if (fObjectArray[id] != object) {
194 		TRACE_ERROR("tried to put an object with incorrect usb_id\n");
195 		Unlock();
196 		return;
197 	}
198 
199 	fObjectArray[id] = NULL;
200 
201 #if KDEBUG
202 	// Validate that no children of this object are still in the stack.
203 	for (usb_id i = 0; i < fObjectMaxCount; i++) {
204 		if (fObjectArray[i] == NULL)
205 			continue;
206 
207 		ASSERT_PRINT(fObjectArray[i]->Parent() != object,
208 			"%s", fObjectArray[i]->TypeName());
209 	}
210 #endif
211 
212 	Unlock();
213 }
214 
215 
216 Object *
217 Stack::GetObject(usb_id id)
218 {
219 	if (!Lock())
220 		return NULL;
221 
222 	if (id >= fObjectMaxCount) {
223 		TRACE_ERROR("tried to get object with invalid usb_id\n");
224 		Unlock();
225 		return NULL;
226 	}
227 
228 	Object *result = fObjectArray[id];
229 
230 	if (result != NULL)
231 		result->SetBusy(true);
232 
233 	Unlock();
234 	return result;
235 }
236 
237 
238 Object *
239 Stack::GetObjectNoLock(usb_id id) const
240 {
241 	ASSERT(debug_debugger_running());
242 	if (id >= fObjectMaxCount)
243 		return NULL;
244 	return fObjectArray[id];
245 }
246 
247 
248 int32
249 Stack::ExploreThread(void *data)
250 {
251 	Stack *stack = (Stack *)data;
252 
253 	while (!stack->fStopThreads) {
254 		if (mutex_lock(&stack->fExploreLock) != B_OK)
255 			break;
256 
257 		rescan_item *rescanList = NULL;
258 		change_item *changeItem = NULL;
259 		for (int32 i = 0; i < stack->fBusManagers.Count(); i++) {
260 			Hub *rootHub = stack->fBusManagers.ElementAt(i)->GetRootHub();
261 			if (rootHub)
262 				rootHub->Explore(&changeItem);
263 		}
264 
265 		while (changeItem) {
266 			stack->NotifyDeviceChange(changeItem->device, &rescanList, changeItem->added);
267 			if (!changeItem->added) {
268 				// everyone possibly holding a reference is now notified so we
269 				// can delete the device
270 				changeItem->device->GetBusManager()->FreeDevice(changeItem->device);
271 			}
272 
273 			change_item *next = changeItem->link;
274 			delete changeItem;
275 			changeItem = next;
276 		}
277 
278 		stack->fFirstExploreDone = true;
279 		mutex_unlock(&stack->fExploreLock);
280 		stack->RescanDrivers(rescanList);
281 		snooze(USB_DELAY_HUB_EXPLORE);
282 	}
283 
284 	return B_OK;
285 }
286 
287 
288 void
289 Stack::AddBusManager(BusManager *busManager)
290 {
291 	fBusManagers.PushBack(busManager);
292 }
293 
294 
295 int32
296 Stack::IndexOfBusManager(BusManager *busManager)
297 {
298 	return fBusManagers.IndexOf(busManager);
299 }
300 
301 
302 BusManager *
303 Stack::BusManagerAt(int32 index) const
304 {
305 	return fBusManagers.ElementAt(index);
306 }
307 
308 
309 status_t
310 Stack::AllocateChunk(void **logicalAddress, phys_addr_t *physicalAddress,
311 	size_t size)
312 {
313 	return fAllocator->Allocate(size, logicalAddress, physicalAddress);
314 }
315 
316 
317 status_t
318 Stack::FreeChunk(void *logicalAddress, phys_addr_t physicalAddress,
319 	size_t size)
320 {
321 	return fAllocator->Deallocate(size, logicalAddress, physicalAddress);
322 }
323 
324 
325 area_id
326 Stack::AllocateArea(void **logicalAddress, phys_addr_t *physicalAddress, size_t size,
327 	const char *name)
328 {
329 	TRACE("allocating %ld bytes for %s\n", size, name);
330 
331 	void *logAddress;
332 	size = (size + B_PAGE_SIZE - 1) & ~(B_PAGE_SIZE - 1);
333 	area_id area = create_area(name, &logAddress, B_ANY_KERNEL_ADDRESS, size,
334 		B_32_BIT_CONTIGUOUS, 0);
335 		// TODO: Use B_CONTIGUOUS when the TODOs regarding 64 bit physical
336 		// addresses are fixed (if possible).
337 
338 	if (area < B_OK) {
339 		TRACE_ERROR("couldn't allocate area %s\n", name);
340 		return B_ERROR;
341 	}
342 
343 	physical_entry physicalEntry;
344 	status_t result = get_memory_map(logAddress, size, &physicalEntry, 1);
345 	if (result < B_OK) {
346 		delete_area(area);
347 		TRACE_ERROR("couldn't map area %s\n", name);
348 		return B_ERROR;
349 	}
350 
351 	memset(logAddress, 0, size);
352 	if (logicalAddress)
353 		*logicalAddress = logAddress;
354 
355 	if (physicalAddress)
356 		*physicalAddress = (phys_addr_t)physicalEntry.address;
357 
358 	TRACE("area = %" B_PRId32 ", size = %" B_PRIuSIZE ", log = %p, phy = %#"
359 		B_PRIxPHYSADDR "\n", area, size, logAddress, physicalEntry.address);
360 	return area;
361 }
362 
363 
364 void
365 Stack::NotifyDeviceChange(Device *device, rescan_item **rescanList, bool added)
366 {
367 	TRACE("device %s\n", added ? "added" : "removed");
368 
369 	usb_driver_info *element = fDriverList;
370 	while (element) {
371 		status_t result = device->ReportDevice(element->support_descriptors,
372 			element->support_descriptor_count, &element->notify_hooks,
373 			&element->cookies, added, false);
374 
375 		if (result >= B_OK) {
376 			const char *driverName = element->driver_name;
377 			if (element->republish_driver_name)
378 				driverName = element->republish_driver_name;
379 
380 			bool already = false;
381 			rescan_item *rescanItem = *rescanList;
382 			while (rescanItem) {
383 				if (strcmp(rescanItem->name, driverName) == 0) {
384 					// this driver is going to be rescanned already
385 					already = true;
386 					break;
387 				}
388 				rescanItem = rescanItem->link;
389 			}
390 
391 			if (!already) {
392 				rescanItem = new(std::nothrow) rescan_item;
393 				if (!rescanItem)
394 					return;
395 
396 				rescanItem->name = driverName;
397 				rescanItem->link = *rescanList;
398 				*rescanList = rescanItem;
399 			}
400 		}
401 
402 		element = element->link;
403 	}
404 }
405 
406 
407 void
408 Stack::RescanDrivers(rescan_item *rescanItem)
409 {
410 	while (rescanItem) {
411 		// the device is supported by this driver. it either got notified
412 		// already by the hooks or it is not loaded at this time. in any
413 		// case we will rescan the driver so it either is loaded and can
414 		// scan for supported devices or its publish_devices hook will be
415 		// called to expose changed devices.
416 
417 		// use the private devfs API to republish a device
418 		devfs_rescan_driver(rescanItem->name);
419 
420 		rescan_item *next = rescanItem->link;
421 		delete rescanItem;
422 		rescanItem = next;
423 	}
424 }
425 
426 
427 status_t
428 Stack::RegisterDriver(const char *driverName,
429 	const usb_support_descriptor *descriptors,
430 	size_t descriptorCount, const char *republishDriverName)
431 {
432 	TRACE("register driver \"%s\"\n", driverName);
433 	if (!driverName)
434 		return B_BAD_VALUE;
435 
436 	if (!Lock())
437 		return B_ERROR;
438 
439 	usb_driver_info *element = fDriverList;
440 	while (element) {
441 		if (strcmp(element->driver_name, driverName) == 0) {
442 			// we already have an entry for this driver, just update it
443 			free((char *)element->republish_driver_name);
444 			element->republish_driver_name = strdup(republishDriverName);
445 
446 			free(element->support_descriptors);
447 			size_t descriptorsSize = descriptorCount * sizeof(usb_support_descriptor);
448 			element->support_descriptors = (usb_support_descriptor *)malloc(descriptorsSize);
449 			memcpy(element->support_descriptors, descriptors, descriptorsSize);
450 			element->support_descriptor_count = descriptorCount;
451 
452 			Unlock();
453 			return B_OK;
454 		}
455 
456 		element = element->link;
457 	}
458 
459 	// this is a new driver, add it to the driver list
460 	usb_driver_info *info = new(std::nothrow) usb_driver_info;
461 	if (!info) {
462 		Unlock();
463 		return B_NO_MEMORY;
464 	}
465 
466 	info->driver_name = strdup(driverName);
467 	info->republish_driver_name = strdup(republishDriverName);
468 
469 	size_t descriptorsSize = descriptorCount * sizeof(usb_support_descriptor);
470 	info->support_descriptors = (usb_support_descriptor *)malloc(descriptorsSize);
471 	memcpy(info->support_descriptors, descriptors, descriptorsSize);
472 	info->support_descriptor_count = descriptorCount;
473 
474 	info->notify_hooks.device_added = NULL;
475 	info->notify_hooks.device_removed = NULL;
476 	info->cookies = NULL;
477 	info->link = NULL;
478 
479 	if (fDriverList) {
480 		usb_driver_info *element = fDriverList;
481 		while (element->link)
482 			element = element->link;
483 
484 		element->link = info;
485 	} else
486 		fDriverList = info;
487 
488 	Unlock();
489 	return B_OK;
490 }
491 
492 
493 status_t
494 Stack::InstallNotify(const char *driverName, const usb_notify_hooks *hooks)
495 {
496 	TRACE("installing notify hooks for driver \"%s\"\n", driverName);
497 
498 	usb_driver_info *element = fDriverList;
499 	while (element) {
500 		if (strcmp(element->driver_name, driverName) == 0) {
501 			if (mutex_lock(&fExploreLock) != B_OK)
502 				return B_ERROR;
503 
504 			// inform driver about any already present devices
505 			for (int32 i = 0; i < fBusManagers.Count(); i++) {
506 				Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub();
507 				if (rootHub) {
508 					// Report device will recurse down the whole tree
509 					rootHub->ReportDevice(element->support_descriptors,
510 						element->support_descriptor_count, hooks,
511 						&element->cookies, true, true);
512 				}
513 			}
514 
515 			element->notify_hooks.device_added = hooks->device_added;
516 			element->notify_hooks.device_removed = hooks->device_removed;
517 			mutex_unlock(&fExploreLock);
518 			return B_OK;
519 		}
520 
521 		element = element->link;
522 	}
523 
524 	return B_NAME_NOT_FOUND;
525 }
526 
527 
528 status_t
529 Stack::UninstallNotify(const char *driverName)
530 {
531 	TRACE("uninstalling notify hooks for driver \"%s\"\n", driverName);
532 
533 	usb_driver_info *element = fDriverList;
534 	while (element) {
535 		if (strcmp(element->driver_name, driverName) == 0) {
536 			if (mutex_lock(&fExploreLock) != B_OK)
537 				return B_ERROR;
538 
539 			// trigger the device removed hook
540 			for (int32 i = 0; i < fBusManagers.Count(); i++) {
541 				Hub *rootHub = fBusManagers.ElementAt(i)->GetRootHub();
542 				if (rootHub)
543 					rootHub->ReportDevice(element->support_descriptors,
544 						element->support_descriptor_count,
545 						&element->notify_hooks, &element->cookies, false, true);
546 			}
547 
548 			element->notify_hooks.device_added = NULL;
549 			element->notify_hooks.device_removed = NULL;
550 			mutex_unlock(&fExploreLock);
551 			return B_OK;
552 		}
553 
554 		element = element->link;
555 	}
556 
557 	return B_NAME_NOT_FOUND;
558 }
559