xref: /haiku/src/tests/system/kernel/device_manager/playground/device_manager.cpp (revision 548c508ff7032b9da455319ec37ffc242d3a43fe)
1 /*
2  * Copyright 2008, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include "device_manager.h"
8 
9 #include <new>
10 #include <set>
11 #include <stdio.h>
12 #include <stdlib.h>
13 #include <string.h>
14 
15 #include <KernelExport.h>
16 #include <Locker.h>
17 #include <module.h>
18 #include <PCI.h>
19 
20 #include <fs/KPath.h>
21 #include <util/AutoLock.h>
22 #include <util/DoublyLinkedList.h>
23 #include <util/Stack.h>
24 
25 
26 #define TRACE(a) dprintf a
27 
28 #define DEVICE_MANAGER_ROOT_NAME "system/devices_root/driver_v1"
29 
30 extern struct device_module_info gDeviceModuleInfo;
31 extern struct driver_module_info gDriverModuleInfo;
32 extern struct device_module_info gGenericVideoDeviceModuleInfo;
33 extern struct driver_module_info gGenericVideoDriverModuleInfo;
34 extern struct device_module_info gSpecificVideoDeviceModuleInfo;
35 extern struct driver_module_info gSpecificVideoDriverModuleInfo;
36 extern struct driver_module_info gBusModuleInfo;
37 extern struct driver_module_info gBusDriverModuleInfo;
38 
39 extern "C" status_t _add_builtin_module(module_info *info);
40 extern "C" status_t _get_builtin_dependencies(void);
41 extern bool gDebugOutputEnabled;
42 	// from libkernelland_emu.so
43 
44 status_t dm_get_attr_uint8(const device_node* node, const char* name,
45 	uint8* _value, bool recursive);
46 status_t dm_get_attr_uint16(const device_node* node, const char* name,
47 	uint16* _value, bool recursive);
48 status_t dm_get_attr_uint32(const device_node* node, const char* name,
49 	uint32* _value, bool recursive);
50 status_t dm_get_attr_string(const device_node* node, const char* name,
51 	const char** _value, bool recursive);
52 
53 
54 struct device_attr_private : device_attr,
55 		DoublyLinkedListLinkImpl<device_attr_private> {
56 						device_attr_private();
57 						device_attr_private(const device_attr& attr);
58 						~device_attr_private();
59 
60 			status_t	InitCheck();
61 			status_t	CopyFrom(const device_attr& attr);
62 
63 	static	int			Compare(const device_attr* attrA,
64 							const device_attr *attrB);
65 
66 private:
67 			void		_Unset();
68 };
69 
70 typedef DoublyLinkedList<device_attr_private> AttributeList;
71 
72 
73 // I/O resource
74 typedef struct io_resource_info {
75 	struct io_resource_info *prev, *next;
76 	device_node*		owner;			// associated node; NULL for temporary allocation
77 	io_resource			resource;		// info about actual resource
78 } io_resource_info;
79 
80 
81 // a structure to put nodes into lists
82 struct node_entry {
83 	struct list_link	link;
84 	device_node*		node;
85 };
86 
87 typedef DoublyLinkedList<device_node> NodeList;
88 
89 struct device_node : DoublyLinkedListLinkImpl<device_node> {
90 							device_node(const char *moduleName,
91 								const device_attr *attrs,
92 								const io_resource *resources);
93 							~device_node();
94 
95 			status_t		InitCheck();
96 
97 			const char*		ModuleName() const { return fModuleName; }
98 			device_node*	Parent() const { return fParent; }
99 			AttributeList&	Attributes() { return fAttributes; }
100 			const AttributeList& Attributes() const { return fAttributes; }
101 
102 			status_t		InitDriver();
103 			bool			UninitDriver();
104 
105 			// The following two are only valid, if the node's driver is
106 			// initialized
107 			driver_module_info* DriverModule() const { return fDriver; }
108 			void*			DriverData() const { return fDriverData; }
109 
110 			void			AddChild(device_node *node);
111 			void			RemoveChild(device_node *node);
112 			const NodeList&	Children() const { return fChildren; }
113 			void			UninitUnusedChildren();
114 
115 			status_t		Register();
116 			status_t		Probe(const char* devicePath);
117 			bool			IsRegistered() const { return fRegistered; }
118 			bool			IsInitialized() const { return fInitialized > 0; }
119 
120 			void			Acquire();
121 			bool			Release();
122 
123 			int				CompareTo(const device_attr* attributes) const;
124 			device_node*	FindChild(const device_attr* attributes) const;
125 
126 			void			Dump(int32 level = 0);
127 
128 private:
129 			status_t		_RegisterFixed(uint32& registered);
130 			bool			_AlwaysRegisterDynamic();
131 			status_t		_AddPath(Stack<KPath*>& stack, const char* path,
132 								const char* subPath = NULL);
133 			status_t		_GetNextDriverPath(void*& cookie, KPath& _path);
134 			status_t		_GetNextDriver(void* list,
135 								driver_module_info*& driver);
136 			status_t		_FindBestDriver(const char* path,
137 								driver_module_info*& bestDriver,
138 								float& bestSupport);
139 			status_t		_RegisterPath(const char* path);
140 			status_t		_RegisterDynamic();
141 			status_t		_RemoveChildren();
142 			bool			_UninitUnusedChildren();
143 
144 	device_node*			fParent;
145 	NodeList				fChildren;
146 	int32					fRefCount;
147 	int32					fInitialized;
148 	bool					fRegistered;
149 	uint32					fFlags;
150 
151 	const char*				fModuleName;
152 	driver_module_info*		fDriver;
153 	void*					fDriverData;
154 
155 	AttributeList			fAttributes;
156 };
157 
158 enum node_flags {
159 	NODE_FLAG_REMOVE_ON_UNINIT	= 0x01
160 };
161 
162 device_manager_info *gDeviceManager;
163 
164 static device_node *sRootNode;
165 static recursive_lock sLock;
166 
167 
168 //	#pragma mark - device_attr
169 
170 
171 device_attr_private::device_attr_private()
172 {
173 	name = NULL;
174 	type = 0;
175 	value.raw.data = NULL;
176 	value.raw.length = 0;
177 }
178 
179 
180 device_attr_private::device_attr_private(const device_attr& attr)
181 {
182 	CopyFrom(attr);
183 }
184 
185 
186 device_attr_private::~device_attr_private()
187 {
188 	_Unset();
189 }
190 
191 
192 status_t
193 device_attr_private::InitCheck()
194 {
195 	return name != NULL ? B_OK : B_NO_INIT;
196 }
197 
198 
199 status_t
200 device_attr_private::CopyFrom(const device_attr& attr)
201 {
202 	name = strdup(attr.name);
203 	if (name == NULL)
204 		return B_NO_MEMORY;
205 
206 	type = attr.type;
207 
208 	switch (type) {
209 		case B_UINT8_TYPE:
210 		case B_UINT16_TYPE:
211 		case B_UINT32_TYPE:
212 		case B_UINT64_TYPE:
213 			value.ui64 = attr.value.ui64;
214 			break;
215 
216 		case B_STRING_TYPE:
217 			if (attr.value.string != NULL) {
218 				value.string = strdup(attr.value.string);
219 				if (value.string == NULL) {
220 					_Unset();
221 					return B_NO_MEMORY;
222 				}
223 			} else
224 				value.string = NULL;
225 			break;
226 
227 		case B_RAW_TYPE:
228 			value.raw.data = malloc(attr.value.raw.length);
229 			if (value.raw.data == NULL) {
230 				_Unset();
231 				return B_NO_MEMORY;
232 			}
233 
234 			value.raw.length = attr.value.raw.length;
235 			memcpy((void*)value.raw.data, attr.value.raw.data,
236 				attr.value.raw.length);
237 			break;
238 
239 		default:
240 			return B_BAD_VALUE;
241 	}
242 
243 	return B_OK;
244 }
245 
246 
247 void
248 device_attr_private::_Unset()
249 {
250 	if (type == B_STRING_TYPE)
251 		free((char*)value.string);
252 	else if (type == B_RAW_TYPE)
253 		free((void*)value.raw.data);
254 
255 	free((char*)name);
256 
257 	name = NULL;
258 	value.raw.data = NULL;
259 	value.raw.length = 0;
260 }
261 
262 
263 /*static*/ int
264 device_attr_private::Compare(const device_attr* attrA, const device_attr *attrB)
265 {
266 	if (attrA->type != attrB->type)
267 		return -1;
268 
269 	switch (attrA->type) {
270 		case B_UINT8_TYPE:
271 			return (int)attrA->value.ui8 - (int)attrB->value.ui8;
272 
273 		case B_UINT16_TYPE:
274 			return (int)attrA->value.ui16 - (int)attrB->value.ui16;
275 
276 		case B_UINT32_TYPE:
277 			if (attrA->value.ui32 > attrB->value.ui32)
278 				return 1;
279 			if (attrA->value.ui32 < attrB->value.ui32)
280 				return -1;
281 			return 0;
282 
283 		case B_UINT64_TYPE:
284 			if (attrA->value.ui64 > attrB->value.ui64)
285 				return 1;
286 			if (attrA->value.ui64 < attrB->value.ui64)
287 				return -1;
288 			return 0;
289 
290 		case B_STRING_TYPE:
291 			return strcmp(attrA->value.string, attrB->value.string);
292 
293 		case B_RAW_TYPE:
294 			if (attrA->value.raw.length != attrB->value.raw.length)
295 				return -1;
296 
297 			return memcmp(attrA->value.raw.data, attrB->value.raw.data,
298 				attrA->value.raw.length);
299 	}
300 
301 	return -1;
302 }
303 
304 
305 //	#pragma mark -
306 
307 
308 device_attr_private*
309 dm_find_attr(const device_node* node, const char* name, bool recursive,
310 	type_code type)
311 {
312 	do {
313 		AttributeList::ConstIterator iterator
314 			= node->Attributes().GetIterator();
315 
316 		while (iterator.HasNext()) {
317 			device_attr_private* attr = iterator.Next();
318 
319 			if (type != B_ANY_TYPE && attr->type != type)
320 				continue;
321 
322 			if (!strcmp(attr->name, name))
323 				return attr;
324 		}
325 
326 		node = node->Parent();
327 	} while (node != NULL && recursive);
328 
329 	return NULL;
330 }
331 
332 
333 static void
334 put_level(int32 level)
335 {
336 	while (level-- > 0)
337 		dprintf("   ");
338 }
339 
340 
341 static void
342 dump_attribute(device_attr* attr, int32 level)
343 {
344 	if (attr == NULL)
345 		return;
346 
347 	put_level(level + 2);
348 	dprintf("\"%s\" : ", attr->name);
349 	switch (attr->type) {
350 		case B_STRING_TYPE:
351 			dprintf("string : \"%s\"", attr->value.string);
352 			break;
353 		case B_INT8_TYPE:
354 		case B_UINT8_TYPE:
355 			dprintf("uint8 : %u (%#x)", attr->value.ui8, attr->value.ui8);
356 			break;
357 		case B_INT16_TYPE:
358 		case B_UINT16_TYPE:
359 			dprintf("uint16 : %u (%#x)", attr->value.ui16, attr->value.ui16);
360 			break;
361 		case B_INT32_TYPE:
362 		case B_UINT32_TYPE:
363 			dprintf("uint32 : %lu (%#lx)", attr->value.ui32, attr->value.ui32);
364 			break;
365 		case B_INT64_TYPE:
366 		case B_UINT64_TYPE:
367 			dprintf("uint64 : %Lu (%#Lx)", attr->value.ui64, attr->value.ui64);
368 			break;
369 		default:
370 			dprintf("raw data");
371 	}
372 	dprintf("\n");
373 }
374 
375 
376 static void
377 uninit_unused()
378 {
379 	RecursiveLocker _(sLock);
380 	sRootNode->UninitUnusedChildren();
381 }
382 
383 
384 static status_t
385 probe_path(const char* path)
386 {
387 	RecursiveLocker _(sLock);
388 	return sRootNode->Probe(path);
389 }
390 
391 
392 //	#pragma mark - device_node
393 
394 
395 /*!	Allocate device node info structure;
396 	initially, ref_count is one to make sure node won't get destroyed by mistake
397 */
398 device_node::device_node(const char* moduleName, const device_attr* attrs,
399 	const io_resource* resources)
400 {
401 	fModuleName = strdup(moduleName);
402 	if (fModuleName == NULL)
403 		return;
404 
405 	fParent = NULL;
406 	fRefCount = 1;
407 	fInitialized = 0;
408 	fRegistered = false;
409 	fDriver = NULL;
410 	fDriverData = NULL;
411 
412 	// copy attributes
413 
414 	while (attrs != NULL && attrs->name != NULL) {
415 		device_attr_private* attr
416 			= new(std::nothrow) device_attr_private(*attrs);
417 		if (attr == NULL)
418 			break;
419 
420 		fAttributes.Add(attr);
421 		attrs++;
422 	}
423 }
424 
425 
426 device_node::~device_node()
427 {
428 	TRACE(("delete node %p\n", this));
429 
430 	// Delete children
431 	NodeList::Iterator nodeIterator = fChildren.GetIterator();
432 	while (nodeIterator.HasNext()) {
433 		device_node* child = nodeIterator.Next();
434 		nodeIterator.Remove();
435 		delete child;
436 	}
437 
438 	// Delete attributes
439 	AttributeList::Iterator attrIterator = fAttributes.GetIterator();
440 	while (attrIterator.HasNext()) {
441 		device_attr_private* attr = attrIterator.Next();
442 		attrIterator.Remove();
443 		delete attr;
444 	}
445 
446 	free((char*)fModuleName);
447 }
448 
449 
450 status_t
451 device_node::InitCheck()
452 {
453 	return fModuleName != NULL ? B_OK : B_NO_MEMORY;
454 }
455 
456 
457 status_t
458 device_node::InitDriver()
459 {
460 	if (fInitialized++ > 0) {
461 		if (Parent() != NULL) {
462 			Parent()->InitDriver();
463 				// acquire another reference to our parent as well
464 		}
465 		Acquire();
466 		return B_OK;
467 	}
468 
469 	status_t status = get_module(ModuleName(), (module_info**)&fDriver);
470 	if (status == B_OK && Parent() != NULL) {
471 		// our parent always have to be initialized
472 		status = Parent()->InitDriver();
473 	}
474 	if (status < B_OK) {
475 		fInitialized--;
476 		return status;
477 	}
478 
479 	if (fDriver->init_driver != NULL)
480 		status = fDriver->init_driver(this, &fDriverData);
481 
482 	if (status < B_OK) {
483 		fInitialized--;
484 
485 		put_module(ModuleName());
486 		fDriver = NULL;
487 		fDriverData = NULL;
488 		return status;
489 	}
490 
491 	Acquire();
492 	return B_OK;
493 }
494 
495 
496 bool
497 device_node::UninitDriver()
498 {
499 	if (fInitialized-- > 1) {
500 		Release();
501 		return false;
502 	}
503 	TRACE(("uninit driver for node %p\n", this));
504 
505 	if (fDriver->uninit_driver != NULL)
506 		fDriver->uninit_driver(this);
507 
508 	fDriver = NULL;
509 	fDriverData = NULL;
510 
511 	put_module(ModuleName());
512 
513 	Release();
514 	if (Parent() != NULL)
515 		Parent()->UninitDriver();
516 
517 	if ((fFlags & NODE_FLAG_REMOVE_ON_UNINIT) != 0)
518 		Release();
519 
520 	return true;
521 }
522 
523 
524 void
525 device_node::AddChild(device_node* node)
526 {
527 	// we must not be destroyed	as long as we have children
528 	Acquire();
529 	node->fParent = this;
530 	fChildren.Add(node);
531 }
532 
533 
534 void
535 device_node::RemoveChild(device_node* node)
536 {
537 	node->fParent = NULL;
538 	fChildren.Remove(node);
539 	Release();
540 }
541 
542 
543 status_t
544 device_node::Register()
545 {
546 	uint32 registered;
547 	status_t status = _RegisterFixed(registered);
548 	if (status != B_OK)
549 		return status;
550 	if (registered > 0) {
551 		fRegistered = true;
552 		return B_OK;
553 	}
554 
555 	// Register the children the driver wants
556 
557 	if (DriverModule()->register_child_devices != NULL) {
558 		status = DriverModule()->register_child_devices(this);
559 		if (status != B_OK)
560 			return status;
561 
562 		if (!fChildren.IsEmpty()) {
563 			fRegistered = true;
564 			return B_OK;
565 		}
566 	}
567 
568 	// Register all possible child device nodes
569 
570 	status = _RegisterDynamic();
571 	if (status == B_OK)
572 		fRegistered = true;
573 
574 	return status;
575 }
576 
577 
578 /*!	Registers any children that are identified via the B_DRIVER_FIXED_CHILD
579 	attribute.
580 	If any of these children cannot be registered, this call will fail (we
581 	don't remove already registered children in this case).
582 */
583 status_t
584 device_node::_RegisterFixed(uint32& registered)
585 {
586 	AttributeList::Iterator iterator = fAttributes.GetIterator();
587 	registered = 0;
588 
589 	while (iterator.HasNext()) {
590 		device_attr_private* attr = iterator.Next();
591 		if (strcmp(attr->name, B_DEVICE_FIXED_CHILD))
592 			continue;
593 
594 		driver_module_info* driver;
595 		status_t status = get_module(attr->value.string,
596 			(module_info**)&driver);
597 		if (status != B_OK)
598 			return status;
599 
600 		if (driver->register_device != NULL) {
601 			status = driver->register_device(this);
602 			if (status == B_OK)
603 				registered++;
604 		}
605 
606 		put_module(attr->value.string);
607 
608 		if (status != B_OK)
609 			return status;
610 	}
611 
612 	return B_OK;
613 }
614 
615 
616 status_t
617 device_node::_AddPath(Stack<KPath*>& stack, const char* basePath,
618 	const char* subPath)
619 {
620 	KPath* path = new(std::nothrow) KPath;
621 	if (path == NULL)
622 		return B_NO_MEMORY;
623 
624 	status_t status = path->SetTo(basePath);
625 	if (status == B_OK && subPath != NULL && subPath[0])
626 		status = path->Append(subPath);
627 	if (status == B_OK)
628 		status = stack.Push(path);
629 
630 	if (status != B_OK)
631 		delete path;
632 
633 	return status;
634 }
635 
636 
637 status_t
638 device_node::_GetNextDriverPath(void*& cookie, KPath& _path)
639 {
640 	Stack<KPath*>* stack = NULL;
641 
642 	if (cookie == NULL) {
643 		// find all paths and add them
644 		stack = new(std::nothrow) Stack<KPath*>();
645 		if (stack == NULL)
646 			return B_NO_MEMORY;
647 
648 		StackDeleter<KPath*> stackDeleter(stack);
649 		uint16 type = 0;
650 		uint16 subType = 0;
651 		uint16 interface = 0;
652 		dm_get_attr_uint16(this, B_DEVICE_TYPE, &type, false);
653 		dm_get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false);
654 		dm_get_attr_uint16(this, B_DEVICE_INTERFACE, &interface, false);
655 
656 		// TODO: maybe make this extendible via settings file?
657 		switch (type) {
658 			case PCI_mass_storage:
659 				switch (subType) {
660 					case PCI_scsi:
661 						_AddPath(*stack, "busses", "scsi");
662 						break;
663 					case PCI_ide:
664 						_AddPath(*stack, "busses", "ide");
665 						break;
666 					case PCI_sata:
667 						_AddPath(*stack, "busses", "sata");
668 						break;
669 					default:
670 						_AddPath(*stack, "busses", "disk");
671 						break;
672 				}
673 				break;
674 			case PCI_serial_bus:
675 				switch (subType) {
676 					case PCI_firewire:
677 						_AddPath(*stack, "busses", "firewire");
678 						break;
679 					case PCI_usb:
680 						_AddPath(*stack, "busses", "usb");
681 						break;
682 					default:
683 						_AddPath(*stack, "busses");
684 						break;
685 				}
686 				break;
687 			case PCI_network:
688 				_AddPath(*stack, "drivers", "net");
689 				break;
690 			case PCI_display:
691 				_AddPath(*stack, "drivers", "graphics");
692 				break;
693 			case PCI_multimedia:
694 				switch (subType) {
695 					case PCI_audio:
696 					case PCI_hd_audio:
697 						_AddPath(*stack, "drivers", "audio");
698 						break;
699 					case PCI_video:
700 						_AddPath(*stack, "drivers", "video");
701 						break;
702 					default:
703 						_AddPath(*stack, "drivers");
704 						break;
705 				}
706 				break;
707 			default:
708 				if (sRootNode == this) {
709 					_AddPath(*stack, "busses/pci");
710 					_AddPath(*stack, "bus_managers");
711 				} else
712 					_AddPath(*stack, "drivers");
713 				break;
714 		}
715 
716 		stackDeleter.Detach();
717 
718 		cookie = (void*)stack;
719 	} else
720 		stack = static_cast<Stack<KPath*>*>(cookie);
721 
722 	KPath* path;
723 	if (stack->Pop(&path)) {
724 		_path.Adopt(*path);
725 		delete path;
726 		return B_OK;
727 	}
728 
729 	delete stack;
730 	return B_ENTRY_NOT_FOUND;
731 }
732 
733 
734 status_t
735 device_node::_GetNextDriver(void* list, driver_module_info*& driver)
736 {
737 	while (true) {
738 		char name[B_FILE_NAME_LENGTH];
739 		size_t nameLength = sizeof(name);
740 
741 		status_t status = read_next_module_name(list, name, &nameLength);
742 		if (status != B_OK)
743 			return status;
744 
745 		if (!strcmp(fModuleName, name))
746 			continue;
747 
748 		if (get_module(name, (module_info**)&driver) != B_OK)
749 			continue;
750 
751 		if (driver->supports_device == NULL
752 			|| driver->register_device == NULL) {
753 			put_module(name);
754 			continue;
755 		}
756 
757 		return B_OK;
758 	}
759 }
760 
761 
762 status_t
763 device_node::_FindBestDriver(const char* path, driver_module_info*& bestDriver,
764 	float& bestSupport)
765 {
766 	if (bestDriver == NULL)
767 		bestSupport = 0.0f;
768 
769 	void* list = open_module_list_etc(path, "driver_v1");
770 	driver_module_info* driver;
771 	while (_GetNextDriver(list, driver) == B_OK) {
772 		float support = driver->supports_device(this);
773 		if (support > bestSupport) {
774 			if (bestDriver != NULL)
775 				put_module(bestDriver->info.name);
776 
777 			bestDriver = driver;
778 			bestSupport = support;
779 			continue;
780 				// keep reference to best module around
781 		}
782 
783 		put_module(driver->info.name);
784 	}
785 	close_module_list(list);
786 
787 	return bestDriver != NULL ? B_OK : B_ENTRY_NOT_FOUND;
788 }
789 
790 
791 status_t
792 device_node::_RegisterPath(const char* path)
793 {
794 	void* list = open_module_list_etc(path, "driver_v1");
795 	driver_module_info* driver;
796 	uint32 count = 0;
797 
798 	while (_GetNextDriver(list, driver) == B_OK) {
799 		float support = driver->supports_device(this);
800 		if (support > 0.0) {
801 			TRACE(("  register module \"%s\", support %f\n", driver->info.name,
802 				support));
803 			if (driver->register_device(this) == B_OK)
804 				count++;
805 		}
806 
807 		put_module(driver->info.name);
808 	}
809 	close_module_list(list);
810 
811 	return count > 0 ? B_OK : B_ENTRY_NOT_FOUND;
812 }
813 
814 
815 bool
816 device_node::_AlwaysRegisterDynamic()
817 {
818 	uint16 type = 0;
819 	uint16 subType = 0;
820 	dm_get_attr_uint16(this, B_DEVICE_TYPE, &type, false);
821 	dm_get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false);
822 
823 	return type == PCI_serial_bus || type == PCI_bridge;
824 		// TODO: we may want to be a bit more specific in the future
825 }
826 
827 
828 status_t
829 device_node::_RegisterDynamic()
830 {
831 	uint32 findFlags = 0;
832 	dm_get_attr_uint32(this, B_DEVICE_FIND_CHILD_FLAGS, &findFlags, false);
833 
834 	// If this is our initial registration, we honour the B_FIND_CHILD_ON_DEMAND
835 	// requirements
836 	if (!fRegistered && (findFlags & B_FIND_CHILD_ON_DEMAND) != 0
837 		&& !_AlwaysRegisterDynamic())
838 		return B_OK;
839 
840 	KPath path;
841 
842 	if ((findFlags & B_FIND_MULTIPLE_CHILDREN) == 0) {
843 		// find the one driver
844 		driver_module_info* bestDriver = NULL;
845 		float bestSupport = 0.0;
846 		void* cookie = NULL;
847 
848 		while (_GetNextDriverPath(cookie, path) == B_OK) {
849 			_FindBestDriver(path.Path(), bestDriver, bestSupport);
850 		}
851 
852 		if (bestDriver != NULL) {
853 			TRACE(("  register best module \"%s\", support %f\n",
854 				bestDriver->info.name, bestSupport));
855 			bestDriver->register_device(this);
856 			put_module(bestDriver->info.name);
857 		}
858 	} else {
859 		// register all drivers that match
860 		void* cookie = NULL;
861 		while (_GetNextDriverPath(cookie, path) == B_OK) {
862 			_RegisterPath(path.Path());
863 		}
864 	}
865 
866 	return B_OK;
867 }
868 
869 
870 status_t
871 device_node::_RemoveChildren()
872 {
873 	NodeList::Iterator iterator = fChildren.GetIterator();
874 	while (iterator.HasNext()) {
875 		device_node* child = iterator.Next();
876 
877 		if (!child->IsInitialized()) {
878 			// this child is not used currently, and can be removed safely
879 			iterator.Remove();
880 			child->fParent = NULL;
881 			delete child;
882 			if (Release())
883 				panic("died early");
884 		} else
885 			child->fFlags |= NODE_FLAG_REMOVE_ON_UNINIT;
886 	}
887 
888 	return fChildren.IsEmpty() ? B_OK : B_BUSY;
889 }
890 
891 
892 status_t
893 device_node::Probe(const char* devicePath)
894 {
895 	status_t status = InitDriver();
896 	if (status < B_OK)
897 		return status;
898 
899 	MethodDeleter<device_node, bool> uninit(this, &device_node::UninitDriver);
900 
901 	uint16 type = 0;
902 	uint16 subType = 0;
903 	if (dm_get_attr_uint16(this, B_DEVICE_TYPE, &type, false) == B_OK
904 		&& dm_get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false)
905 			== B_OK) {
906 		// Check if this node matches the device path
907 		// TODO: maybe make this extendible via settings file?
908 		bool matches = false;
909 		if (!strcmp(devicePath, "disk")) {
910 			matches = type == PCI_mass_storage;
911 		} else if (!strcmp(devicePath, "audio")) {
912 			matches = type == PCI_multimedia
913 				&& (subType == PCI_audio || subType == PCI_hd_audio);
914 		} else if (!strcmp(devicePath, "net")) {
915 			matches = type == PCI_network;
916 		} else if (!strcmp(devicePath, "graphics")) {
917 			matches = type == PCI_display;
918 		} else if (!strcmp(devicePath, "video")) {
919 			matches = type == PCI_multimedia && subType == PCI_video;
920 		}
921 
922 		if (matches) {
923 			if (!fChildren.IsEmpty()) {
924 				// We already have a driver that claims this node.
925 				// Try to remove uninitialized children, so that this node
926 				// can be re-evaluated
927 				// TODO: try first if there is a better child!
928 				// TODO: publish both devices, make new one busy as long
929 				// as the old one is in use!
930 				if (_RemoveChildren() != B_OK)
931 					return B_OK;
932 			}
933 			return _RegisterDynamic();
934 		}
935 
936 		return B_OK;
937 	}
938 
939 	NodeList::Iterator iterator = fChildren.GetIterator();
940 	while (iterator.HasNext()) {
941 		device_node* child = iterator.Next();
942 
943 		status = child->Probe(devicePath);
944 		if (status != B_OK)
945 			return status;
946 	}
947 
948 	return B_OK;
949 }
950 
951 
952 bool
953 device_node::_UninitUnusedChildren()
954 {
955 	// First, we need to go to the leaf, and go back from there
956 
957 	bool uninit = true;
958 
959 	NodeList::Iterator iterator = fChildren.GetIterator();
960 
961 	while (iterator.HasNext()) {
962 		device_node* child = iterator.Next();
963 
964 		if (!child->_UninitUnusedChildren())
965 			uninit = false;
966 	}
967 
968 	// Not all of our children could be uninitialized
969 	if (!uninit)
970 		return false;
971 
972 	if (!IsInitialized())
973 		return true;
974 
975 	if ((DriverModule()->info.flags & B_KEEP_LOADED) != 0) {
976 		// We must not get unloaded
977 		return false;
978 	}
979 
980 	return UninitDriver();
981 }
982 
983 
984 void
985 device_node::UninitUnusedChildren()
986 {
987 	_UninitUnusedChildren();
988 }
989 
990 
991 void
992 device_node::Acquire()
993 {
994 	atomic_add(&fRefCount, 1);
995 }
996 
997 
998 bool
999 device_node::Release()
1000 {
1001 	if (atomic_add(&fRefCount, -1) > 1)
1002 		return false;
1003 
1004 	if (Parent() != NULL)
1005 		Parent()->RemoveChild(this);
1006 	delete this;
1007 	return true;
1008 }
1009 
1010 
1011 int
1012 device_node::CompareTo(const device_attr* attributes) const
1013 {
1014 	if (attributes == NULL)
1015 		return -1;
1016 
1017 	for (; attributes->name != NULL; attributes++) {
1018 		// find corresponding attribute
1019 		AttributeList::ConstIterator iterator = Attributes().GetIterator();
1020 		device_attr_private* attr = NULL;
1021 		while (iterator.HasNext()) {
1022 			attr = iterator.Next();
1023 
1024 			if (!strcmp(attr->name, attributes->name))
1025 				break;
1026 		}
1027 		if (!iterator.HasNext())
1028 			return -1;
1029 
1030 		int compare = device_attr_private::Compare(attr, attributes);
1031 		if (compare != 0)
1032 			return compare;
1033 	}
1034 
1035 	return 0;
1036 }
1037 
1038 
1039 device_node*
1040 device_node::FindChild(const device_attr* attributes) const
1041 {
1042 	if (attributes == NULL)
1043 		return NULL;
1044 
1045 	NodeList::ConstIterator iterator = Children().GetIterator();
1046 	while (iterator.HasNext()) {
1047 		device_node* child = iterator.Next();
1048 
1049 		if (!child->CompareTo(attributes))
1050 			return child;
1051 	}
1052 
1053 	return NULL;
1054 }
1055 
1056 
1057 void
1058 device_node::Dump(int32 level = 0)
1059 {
1060 	put_level(level);
1061 	dprintf("(%ld) @%p \"%s\" (ref %ld, init %ld)\n", level, this, ModuleName(),
1062 		fRefCount, fInitialized);
1063 
1064 	AttributeList::Iterator attribute = Attributes().GetIterator();
1065 	while (attribute.HasNext()) {
1066 		dump_attribute(attribute.Next(), level);
1067 	}
1068 
1069 	NodeList::ConstIterator iterator = Children().GetIterator();
1070 	while (iterator.HasNext()) {
1071 		iterator.Next()->Dump(level + 1);
1072 	}
1073 }
1074 
1075 
1076 //	#pragma mark - Device Manager module API
1077 
1078 
1079 static status_t
1080 rescan_device(device_node* node)
1081 {
1082 	return B_ERROR;
1083 }
1084 
1085 
1086 static status_t
1087 register_device(device_node* parent, const char* moduleName,
1088 	const device_attr* attrs, const io_resource* ioResources,
1089 	device_node** _node)
1090 {
1091 	if ((parent == NULL && sRootNode != NULL) || moduleName == NULL)
1092 		return B_BAD_VALUE;
1093 
1094 	if (parent != NULL && parent->FindChild(attrs) != NULL) {
1095 		// A node like this one already exists for this parent
1096 		return B_NAME_IN_USE;
1097 	}
1098 
1099 	// TODO: handle I/O resources!
1100 
1101 	device_node *newNode = new(std::nothrow) device_node(moduleName, attrs,
1102 		ioResources);
1103 	if (newNode == NULL)
1104 		return B_NO_MEMORY;
1105 
1106 	TRACE(("%p: register device \"%s\", parent %p\n", newNode, moduleName,
1107 		parent));
1108 
1109 	RecursiveLocker _(sLock);
1110 
1111 	status_t status = newNode->InitCheck();
1112 	if (status != B_OK)
1113 		goto err1;
1114 
1115 	// make it public
1116 	if (parent != NULL)
1117 		parent->AddChild(newNode);
1118 	else
1119 		sRootNode = newNode;
1120 
1121 	status = newNode->InitDriver();
1122 	if (status != B_OK)
1123 		goto err1;
1124 
1125 #if 0
1126 	// The following is done to reduce the stack usage of deeply nested
1127 	// child device nodes.
1128 	// There is no other need to delay the complete registration process
1129 	// the way done here. This approach is also slightly different as
1130 	// the registration might fail later than it used in case of errors.
1131 
1132 	if (!parent->IsRegistered()) {
1133 		// The parent has not been registered completely yet - child
1134 		// registration is deferred to the parent registration
1135 		return B_OK;
1136 	}
1137 #endif
1138 
1139 	status = newNode->Register();
1140 	if (status < B_OK) {
1141 		parent->RemoveChild(newNode);
1142 		goto err1;
1143 	}
1144 
1145 	if (_node)
1146 		*_node = newNode;
1147 
1148 	return B_OK;
1149 
1150 err1:
1151 	delete newNode;
1152 	return status;
1153 }
1154 
1155 
1156 static status_t
1157 unregister_device(device_node* node)
1158 {
1159 	return B_ERROR;
1160 }
1161 
1162 
1163 static status_t
1164 get_driver(device_node* node, driver_module_info** _module, void** _data)
1165 {
1166 	if (node->DriverModule() == NULL)
1167 		return B_NO_INIT;
1168 
1169 	if (_module != NULL)
1170 		*_module = node->DriverModule();
1171 	if (_data != NULL)
1172 		*_data = node->DriverData();
1173 
1174 	return B_OK;
1175 }
1176 
1177 
1178 static device_node*
1179 get_device_root(void)
1180 {
1181 	if (sRootNode != NULL)
1182 		sRootNode->Acquire();
1183 
1184 	return sRootNode;
1185 }
1186 
1187 
1188 static status_t
1189 get_next_child_device(device_node* parent, device_node* _node,
1190 	const device_attr* attrs)
1191 {
1192 	return B_ERROR;
1193 }
1194 
1195 
1196 static device_node*
1197 get_parent(device_node* node)
1198 {
1199 	if (node == NULL)
1200 		return NULL;
1201 
1202 	RecursiveLocker _(sLock);
1203 
1204 	device_node* parent = node->Parent();
1205 	parent->Acquire();
1206 
1207 	return parent;
1208 }
1209 
1210 
1211 static void
1212 put_device_node(device_node* node)
1213 {
1214 	RecursiveLocker _(sLock);
1215 	node->Release();
1216 }
1217 
1218 
1219 status_t
1220 dm_get_attr_uint8(const device_node* node, const char* name, uint8* _value,
1221 	bool recursive)
1222 {
1223 	if (node == NULL || name == NULL || _value == NULL)
1224 		return B_BAD_VALUE;
1225 
1226 	device_attr_private* attr = dm_find_attr(node, name, recursive,
1227 		B_UINT8_TYPE);
1228 	if (attr == NULL)
1229 		return B_NAME_NOT_FOUND;
1230 
1231 	*_value = attr->value.ui8;
1232 	return B_OK;
1233 }
1234 
1235 
1236 status_t
1237 dm_get_attr_uint16(const device_node* node, const char* name, uint16* _value,
1238 	bool recursive)
1239 {
1240 	if (node == NULL || name == NULL || _value == NULL)
1241 		return B_BAD_VALUE;
1242 
1243 	device_attr_private* attr = dm_find_attr(node, name, recursive,
1244 		B_UINT16_TYPE);
1245 	if (attr == NULL)
1246 		return B_NAME_NOT_FOUND;
1247 
1248 	*_value = attr->value.ui16;
1249 	return B_OK;
1250 }
1251 
1252 
1253 status_t
1254 dm_get_attr_uint32(const device_node* node, const char* name, uint32* _value,
1255 	bool recursive)
1256 {
1257 	if (node == NULL || name == NULL || _value == NULL)
1258 		return B_BAD_VALUE;
1259 
1260 	device_attr_private* attr = dm_find_attr(node, name, recursive,
1261 		B_UINT32_TYPE);
1262 	if (attr == NULL)
1263 		return B_NAME_NOT_FOUND;
1264 
1265 	*_value = attr->value.ui32;
1266 	return B_OK;
1267 }
1268 
1269 
1270 status_t
1271 dm_get_attr_uint64(const device_node* node, const char* name,
1272 	uint64* _value, bool recursive)
1273 {
1274 	if (node == NULL || name == NULL || _value == NULL)
1275 		return B_BAD_VALUE;
1276 
1277 	device_attr_private* attr = dm_find_attr(node, name, recursive,
1278 		B_UINT64_TYPE);
1279 	if (attr == NULL)
1280 		return B_NAME_NOT_FOUND;
1281 
1282 	*_value = attr->value.ui64;
1283 	return B_OK;
1284 }
1285 
1286 
1287 status_t
1288 dm_get_attr_string(const device_node* node, const char* name,
1289 	const char** _value, bool recursive)
1290 {
1291 	if (node == NULL || name == NULL || _value == NULL)
1292 		return B_BAD_VALUE;
1293 
1294 	device_attr_private* attr = dm_find_attr(node, name, recursive,
1295 		B_STRING_TYPE);
1296 	if (attr == NULL)
1297 		return B_NAME_NOT_FOUND;
1298 
1299 	*_value = attr->value.string;
1300 	return B_OK;
1301 }
1302 
1303 
1304 status_t
1305 dm_get_attr_raw(const device_node* node, const char* name, const void** _data,
1306 	size_t* _length, bool recursive)
1307 {
1308 	if (node == NULL || name == NULL || (_data == NULL && _length == NULL))
1309 		return B_BAD_VALUE;
1310 
1311 	device_attr_private* attr = dm_find_attr(node, name, recursive, B_RAW_TYPE);
1312 	if (attr == NULL)
1313 		return B_NAME_NOT_FOUND;
1314 
1315 	if (_data != NULL)
1316 		*_data = attr->value.raw.data;
1317 	if (_length != NULL)
1318 		*_length = attr->value.raw.length;
1319 	return B_OK;
1320 }
1321 
1322 
1323 status_t
1324 dm_get_next_attr(device_node* node, device_attr** _attr)
1325 {
1326 	if (node == NULL)
1327 		return B_BAD_VALUE;
1328 
1329 	device_attr_private* next;
1330 	device_attr_private* attr = *(device_attr_private**)_attr;
1331 
1332 	if (attr != NULL) {
1333 		// next attribute
1334 		next = attr->GetDoublyLinkedListLink()->next;
1335 	} else {
1336 		// first attribute
1337 		next = node->Attributes().First();
1338 	}
1339 
1340 	*_attr = next;
1341 
1342 	return next ? B_OK : B_ENTRY_NOT_FOUND;
1343 }
1344 
1345 
1346 static struct device_manager_info sDeviceManagerModule = {
1347 	{
1348 		B_DEVICE_MANAGER_MODULE_NAME,
1349 		0,
1350 		NULL
1351 	},
1352 
1353 	// device nodes
1354 	rescan_device,
1355 	register_device,
1356 	unregister_device,
1357 	get_driver,
1358 	get_device_root,
1359 	get_next_child_device,
1360 	get_parent,
1361 	put_device_node,
1362 
1363 	// attributes
1364 	dm_get_attr_uint8,
1365 	dm_get_attr_uint16,
1366 	dm_get_attr_uint32,
1367 	dm_get_attr_uint64,
1368 	dm_get_attr_string,
1369 	dm_get_attr_raw,
1370 	dm_get_next_attr,
1371 };
1372 
1373 
1374 //	#pragma mark - root node
1375 
1376 
1377 void
1378 dm_init_root_node(void)
1379 {
1380 	device_attr attrs[] = {
1381 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Devices Root"}},
1382 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "root"}},
1383 		{B_DEVICE_FIND_CHILD_FLAGS, B_UINT32_TYPE,
1384 			{ui32: B_FIND_MULTIPLE_CHILDREN}},
1385 		{NULL}
1386 	};
1387 
1388 	if (register_device(NULL, DEVICE_MANAGER_ROOT_NAME, attrs, NULL, NULL)
1389 			!= B_OK) {
1390 		dprintf("Cannot register Devices Root Node\n");
1391 	}
1392 }
1393 
1394 
1395 static driver_module_info sDeviceRootModule = {
1396 	{
1397 		DEVICE_MANAGER_ROOT_NAME,
1398 		0,
1399 		NULL,
1400 	},
1401 	NULL
1402 };
1403 
1404 
1405 //	#pragma mark -
1406 
1407 
1408 int
1409 main(int argc, char** argv)
1410 {
1411 	_add_builtin_module((module_info*)&sDeviceManagerModule);
1412 	_add_builtin_module((module_info*)&sDeviceRootModule);
1413 
1414 	// bus
1415 	_add_builtin_module((module_info*)&gBusModuleInfo);
1416 	_add_builtin_module((module_info*)&gBusDriverModuleInfo);
1417 
1418 	// sample driver
1419 	_add_builtin_module((module_info*)&gDriverModuleInfo);
1420 	_add_builtin_module((module_info*)&gDeviceModuleInfo);
1421 
1422 	// generic video driver
1423 	_add_builtin_module((module_info*)&gGenericVideoDriverModuleInfo);
1424 	_add_builtin_module((module_info*)&gGenericVideoDeviceModuleInfo);
1425 
1426 	gDeviceManager = &sDeviceManagerModule;
1427 
1428 	status_t status = _get_builtin_dependencies();
1429 	if (status < B_OK) {
1430 		fprintf(stderr, "device_manager: Could not initialize modules: %s\n",
1431 			strerror(status));
1432 		return 1;
1433 	}
1434 
1435 	recursive_lock_init(&sLock, "device manager");
1436 
1437 	dm_init_root_node();
1438 	sRootNode->Dump();
1439 
1440 	probe_path("net");
1441 	probe_path("graphics");
1442 	// TODO: opened devices need to keep a "initialized" reference of the
1443 	// device_node
1444 
1445 	sRootNode->Dump();
1446 	uninit_unused();
1447 
1448 	// add specific video driver - ie. simulate installing it
1449 	_add_builtin_module((module_info*)&gSpecificVideoDriverModuleInfo);
1450 	_add_builtin_module((module_info*)&gSpecificVideoDeviceModuleInfo);
1451 	probe_path("graphics");
1452 
1453 	uninit_unused();
1454 
1455 	recursive_lock_destroy(&sLock);
1456 	return 0;
1457 }
1458