xref: /haiku/src/tests/system/kernel/device_manager/playground/device_manager.cpp (revision cc6e7cb3477cdb34c23be8ce246203d2b7f002de)
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 <util/AutoLock.h>
10 #include <util/DoublyLinkedList.h>
11 
12 #include <KernelExport.h>
13 #include <module.h>
14 #include <Locker.h>
15 
16 #include <new>
17 #include <set>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 
22 
23 #define TRACE(a) dprintf a
24 
25 #define DEVICE_MANAGER_ROOT_NAME "system/devices_root/driver_v1"
26 
27 extern struct device_module_info gDeviceModuleInfo;
28 extern struct driver_module_info gDriverModuleInfo;
29 extern struct driver_module_info gBusModuleInfo;
30 extern struct driver_module_info gBusDriverModuleInfo;
31 
32 extern "C" status_t _add_builtin_module(module_info *info);
33 extern "C" status_t _get_builtin_dependencies(void);
34 extern bool gDebugOutputEnabled;
35 	// from libkernelland_emu.so
36 
37 status_t dm_get_attr_uint8(const device_node* node, const char* name, uint8* _value,
38 	bool recursive);
39 status_t dm_get_attr_uint32(device_node* node, const char* name, uint32* _value,
40 	bool recursive);
41 status_t dm_get_attr_string(device_node* node, const char* name,
42 	const char** _value, bool recursive);
43 
44 
45 struct device_attr_private : device_attr,
46 		DoublyLinkedListLinkImpl<device_attr_private> {
47 						device_attr_private();
48 						device_attr_private(const device_attr& attr);
49 						~device_attr_private();
50 
51 			status_t	InitCheck();
52 			status_t	CopyFrom(const device_attr& attr);
53 
54 	static	int			Compare(const device_attr* attrA,
55 							const device_attr *attrB);
56 
57 private:
58 			void		_Unset();
59 };
60 
61 typedef DoublyLinkedList<device_attr_private> AttributeList;
62 
63 
64 // I/O resource
65 typedef struct io_resource_info {
66 	struct io_resource_info *prev, *next;
67 	device_node*		owner;			// associated node; NULL for temporary allocation
68 	io_resource			resource;		// info about actual resource
69 } io_resource_info;
70 
71 
72 // a structure to put nodes into lists
73 struct node_entry {
74 	struct list_link	link;
75 	device_node*		node;
76 };
77 
78 typedef DoublyLinkedList<device_node> NodeList;
79 
80 struct device_node : DoublyLinkedListLinkImpl<device_node> {
81 							device_node(const char *moduleName,
82 								const device_attr *attrs,
83 								const io_resource *resources);
84 							~device_node();
85 
86 			status_t		InitCheck();
87 
88 			const char*		ModuleName() const { return fModuleName; }
89 			device_node*	Parent() const { return fParent; }
90 			AttributeList&	Attributes() { return fAttributes; }
91 			const AttributeList& Attributes() const { return fAttributes; }
92 
93 			status_t		InitDriver();
94 			void			UninitDriver();
95 
96 			// The following two are only valid, if the node's driver is
97 			// initialized
98 			driver_module_info* DriverModule() const { return fDriver; }
99 			void*			DriverData() const { return fDriverData; }
100 
101 			void			AddChild(device_node *node);
102 			void			RemoveChild(device_node *node);
103 			const NodeList&	Children() const { return fChildren; }
104 
105 			status_t		Register();
106 			bool			IsRegistered() const { return fRegistered; }
107 
108 private:
109 			status_t		_RegisterFixed(uint32& registered);
110 			status_t		_RegisterDynamic();
111 			bool			_IsBus() const;
112 
113 	device_node*			fParent;
114 	NodeList				fChildren;
115 	int32					fRefCount;
116 	int32					fInitialized;
117 	bool					fRegistered;
118 
119 	const char*				fModuleName;
120 	driver_module_info*		fDriver;
121 	void*					fDriverData;
122 
123 	AttributeList			fAttributes;
124 };
125 
126 
127 device_manager_info *gDeviceManager;
128 
129 static device_node *sRootNode;
130 
131 
132 device_attr_private::device_attr_private()
133 {
134 	name = NULL;
135 	type = 0;
136 	value.raw.data = NULL;
137 	value.raw.length = 0;
138 }
139 
140 
141 device_attr_private::device_attr_private(const device_attr& attr)
142 {
143 	CopyFrom(attr);
144 }
145 
146 
147 device_attr_private::~device_attr_private()
148 {
149 	_Unset();
150 }
151 
152 
153 status_t
154 device_attr_private::InitCheck()
155 {
156 	return name != NULL ? B_OK : B_NO_INIT;
157 }
158 
159 
160 status_t
161 device_attr_private::CopyFrom(const device_attr& attr)
162 {
163 	name = strdup(attr.name);
164 	if (name == NULL)
165 		return B_NO_MEMORY;
166 
167 	type = attr.type;
168 
169 	switch (type) {
170 		case B_UINT8_TYPE:
171 		case B_UINT16_TYPE:
172 		case B_UINT32_TYPE:
173 		case B_UINT64_TYPE:
174 			value.ui64 = attr.value.ui64;
175 			break;
176 
177 		case B_STRING_TYPE:
178 			if (attr.value.string != NULL) {
179 				value.string = strdup(attr.value.string);
180 				if (value.string == NULL) {
181 					_Unset();
182 					return B_NO_MEMORY;
183 				}
184 			} else
185 				value.string = NULL;
186 			break;
187 
188 		case B_RAW_TYPE:
189 			value.raw.data = malloc(attr.value.raw.length);
190 			if (value.raw.data == NULL) {
191 				_Unset();
192 				return B_NO_MEMORY;
193 			}
194 
195 			value.raw.length = attr.value.raw.length;
196 			memcpy((void*)value.raw.data, attr.value.raw.data,
197 				attr.value.raw.length);
198 			break;
199 
200 		default:
201 			return B_BAD_VALUE;
202 	}
203 
204 	return B_OK;
205 }
206 
207 
208 void
209 device_attr_private::_Unset()
210 {
211 	if (type == B_STRING_TYPE)
212 		free((char*)value.string);
213 	else if (type == B_RAW_TYPE)
214 		free((void*)value.raw.data);
215 
216 	free((char*)name);
217 
218 	name = NULL;
219 	value.raw.data = NULL;
220 	value.raw.length = 0;
221 }
222 
223 
224 /*static*/ int
225 device_attr_private::Compare(const device_attr* attrA, const device_attr *attrB)
226 {
227 	if (attrA->type != attrB->type)
228 		return -1;
229 
230 	switch (attrA->type) {
231 		case B_UINT8_TYPE:
232 			return (int)attrA->value.ui8 - (int)attrB->value.ui8;
233 
234 		case B_UINT16_TYPE:
235 			return (int)attrA->value.ui16 - (int)attrB->value.ui16;
236 
237 		case B_UINT32_TYPE:
238 			if (attrA->value.ui32 > attrB->value.ui32)
239 				return 1;
240 			if (attrA->value.ui32 < attrB->value.ui32)
241 				return -1;
242 			return 0;
243 
244 		case B_UINT64_TYPE:
245 			if (attrA->value.ui64 > attrB->value.ui64)
246 				return 1;
247 			if (attrA->value.ui64 < attrB->value.ui64)
248 				return -1;
249 			return 0;
250 
251 		case B_STRING_TYPE:
252 			return strcmp(attrA->value.string, attrB->value.string);
253 
254 		case B_RAW_TYPE:
255 			if (attrA->value.raw.length != attrB->value.raw.length)
256 				return -1;
257 
258 			return memcmp(attrA->value.raw.data, attrB->value.raw.data,
259 				attrA->value.raw.length);
260 	}
261 
262 	return -1;
263 }
264 
265 
266 //	#pragma mark -
267 
268 
269 device_attr_private*
270 dm_find_attr(const device_node* node, const char* name, bool recursive,
271 	type_code type)
272 {
273 	do {
274 		AttributeList::ConstIterator iterator
275 			= node->Attributes().GetIterator();
276 
277 		while (iterator.HasNext()) {
278 			device_attr_private* attr = iterator.Next();
279 
280 			if (type != B_ANY_TYPE && attr->type != type)
281 				continue;
282 
283 			if (!strcmp(attr->name, name))
284 				return attr;
285 		}
286 
287 		node = node->Parent();
288 	} while (node != NULL && recursive);
289 
290 	return NULL;
291 }
292 
293 
294 static void
295 put_level(int32 level)
296 {
297 	while (level-- > 0)
298 		dprintf("   ");
299 }
300 
301 
302 static void
303 dump_attribute(device_attr* attr, int32 level)
304 {
305 	if (attr == NULL)
306 		return;
307 
308 	put_level(level + 2);
309 	dprintf("\"%s\" : ", attr->name);
310 	switch (attr->type) {
311 		case B_STRING_TYPE:
312 			dprintf("string : \"%s\"", attr->value.string);
313 			break;
314 		case B_INT8_TYPE:
315 		case B_UINT8_TYPE:
316 			dprintf("uint8 : %u (%#x)", attr->value.ui8, attr->value.ui8);
317 			break;
318 		case B_INT16_TYPE:
319 		case B_UINT16_TYPE:
320 			dprintf("uint16 : %u (%#x)", attr->value.ui16, attr->value.ui16);
321 			break;
322 		case B_INT32_TYPE:
323 		case B_UINT32_TYPE:
324 			dprintf("uint32 : %lu (%#lx)", attr->value.ui32, attr->value.ui32);
325 			break;
326 		case B_INT64_TYPE:
327 		case B_UINT64_TYPE:
328 			dprintf("uint64 : %Lu (%#Lx)", attr->value.ui64, attr->value.ui64);
329 			break;
330 		default:
331 			dprintf("raw data");
332 	}
333 	dprintf("\n");
334 }
335 
336 
337 void
338 dm_dump_node(device_node* node, int32 level)
339 {
340 	if (node == NULL)
341 		return;
342 
343 	put_level(level);
344 	dprintf("(%ld) @%p \"%s\"\n", level, node, node->ModuleName());
345 
346 	AttributeList::Iterator attribute = node->Attributes().GetIterator();
347 	while (attribute.HasNext()) {
348 		dump_attribute(attribute.Next(), level);
349 	}
350 
351 	NodeList::ConstIterator iterator = node->Children().GetIterator();
352 	while (iterator.HasNext()) {
353 		dm_dump_node(iterator.Next(), level + 1);
354 	}
355 }
356 
357 
358 //	#pragma mark -
359 
360 
361 /*!	Allocate device node info structure;
362 	initially, ref_count is one to make sure node won't get destroyed by mistake
363 */
364 device_node::device_node(const char* moduleName, const device_attr* attrs,
365 	const io_resource* resources)
366 {
367 	fModuleName = strdup(moduleName);
368 	if (fModuleName == NULL)
369 		return;
370 
371 	fParent = NULL;
372 	fRefCount = 1;
373 	fInitialized = 0;
374 	fRegistered = false;
375 	fDriver = NULL;
376 	fDriverData = NULL;
377 
378 	// copy attributes
379 
380 	while (attrs != NULL && attrs->name != NULL) {
381 		device_attr_private* attr
382 			= new(std::nothrow) device_attr_private(*attrs);
383 		if (attr == NULL)
384 			break;
385 
386 		fAttributes.Add(attr);
387 		attrs++;
388 	}
389 }
390 
391 
392 device_node::~device_node()
393 {
394 	AttributeList::Iterator iterator = fAttributes.GetIterator();
395 	while (iterator.HasNext()) {
396 		device_attr_private* attr = iterator.Next();
397 		iterator.Remove();
398 		delete attr;
399 	}
400 	free((char*)fModuleName);
401 }
402 
403 
404 status_t
405 device_node::InitCheck()
406 {
407 	return fModuleName != NULL ? B_OK : B_NO_MEMORY;
408 }
409 
410 
411 status_t
412 device_node::InitDriver()
413 {
414 	if (fInitialized++ > 0)
415 		return B_OK;
416 
417 	status_t status = get_module(ModuleName(), (module_info**)&fDriver);
418 	if (status < B_OK) {
419 		fInitialized--;
420 		return status;
421 	}
422 
423 	if (fDriver->init_driver != NULL)
424 		status = fDriver->init_driver(this, &fDriverData);
425 	if (status < B_OK) {
426 		fInitialized--;
427 		put_module(ModuleName());
428 		return status;
429 	}
430 
431 	return B_OK;
432 }
433 
434 
435 void
436 device_node::UninitDriver()
437 {
438 	if (fInitialized-- > 1)
439 		return;
440 
441 	if (fDriver->uninit_driver != NULL)
442 		fDriver->uninit_driver(this);
443 	fDriverData = NULL;
444 
445 	put_module(ModuleName());
446 }
447 
448 
449 void
450 device_node::AddChild(device_node* node)
451 {
452 	// we must not be destroyed	as long as we have children
453 	fRefCount++;
454 	node->fParent = this;
455 	fChildren.Add(node);
456 }
457 
458 
459 void
460 device_node::RemoveChild(device_node* node)
461 {
462 	fRefCount--;
463 		// TODO: we may need to destruct ourselves here!
464 	node->fParent = NULL;
465 	fChildren.Remove(node);
466 }
467 
468 
469 status_t
470 device_node::Register()
471 {
472 	uint32 registered;
473 	status_t status = _RegisterFixed(registered);
474 	if (status != B_OK)
475 		return status;
476 	if (registered > 0) {
477 		fRegistered = true;
478 		return B_OK;
479 	}
480 
481 	// Register the children the driver wants
482 
483 	if (DriverModule()->register_child_devices != NULL) {
484 		status = DriverModule()->register_child_devices(this);
485 		if (status != B_OK)
486 			return status;
487 
488 		if (!fChildren.IsEmpty())
489 			return B_OK;
490 	}
491 
492 	// Register all possible child device nodes
493 
494 	uint32 findFlags = 0;
495 	dm_get_attr_uint32(this, B_DRIVER_FIND_CHILD_FLAGS, &findFlags, false);
496 
497 	if ((findFlags & B_FIND_CHILD_ON_DEMAND) != 0)
498 		return B_OK;
499 
500 	return _RegisterDynamic();
501 }
502 
503 
504 bool
505 device_node::_IsBus() const
506 {
507 	uint8 isBus;
508 	if (dm_get_attr_uint8(this, B_DRIVER_IS_BUS, &isBus, false) != B_OK)
509 		return false;
510 
511 	return isBus;
512 }
513 
514 
515 /*!	Registers any children that are identified via the B_DRIVER_FIXED_CHILD
516 	attribute.
517 	If any of these children cannot be registered, this call will fail (we
518 	don't remove already registered children in this case).
519 */
520 status_t
521 device_node::_RegisterFixed(uint32& registered)
522 {
523 	AttributeList::Iterator iterator = fAttributes.GetIterator();
524 	registered = 0;
525 
526 	while (iterator.HasNext()) {
527 		device_attr_private* attr = iterator.Next();
528 		if (strcmp(attr->name, B_DRIVER_FIXED_CHILD))
529 			continue;
530 
531 		driver_module_info* driver;
532 		status_t status = get_module(attr->value.string,
533 			(module_info**)&driver);
534 		if (status != B_OK)
535 			return status;
536 
537 		if (driver->register_device != NULL) {
538 			status = driver->register_device(this);
539 			if (status == B_OK)
540 				registered++;
541 		}
542 
543 		put_module(attr->value.string);
544 
545 		if (status != B_OK)
546 			return status;
547 	}
548 
549 	return B_OK;
550 }
551 
552 
553 status_t
554 device_node::_RegisterDynamic()
555 {
556 	uint32 findFlags;
557 	if (dm_get_attr_uint32(this, B_DRIVER_FIND_CHILD_FLAGS, &findFlags, false)
558 			!= B_OK)
559 		findFlags = 0;
560 
561 	driver_module_info* bestDriver = NULL;
562 	float best = 0.0;
563 
564 	char path[64];
565 	if (!_IsBus()) {
566 		strlcpy(path, "drivers", sizeof(path));
567 
568 		const char *type;
569 		if (dm_get_attr_string(this, B_DRIVER_DEVICE_TYPE, &type, false)
570 				== B_OK) {
571 			strlcat(path, "/", sizeof(path));
572 			strlcat(path, type, sizeof(path));
573 		}
574 	} else {
575 		// TODO: we might want to allow bus* specifiers as well, ie.
576 		// busses/usb
577 		strlcpy(path, "bus", sizeof(path));
578 	}
579 
580 	void* list = open_module_list_etc(path, "driver_v1");
581 	while (true) {
582 		char name[B_FILE_NAME_LENGTH];
583 		size_t nameLength = sizeof(name);
584 
585 		if (read_next_module_name(list, name, &nameLength) != B_OK)
586 			break;
587 
588 		if (!strcmp(fModuleName, name))
589 			continue;
590 
591 		driver_module_info* driver;
592 		if (get_module(name, (module_info**)&driver) != B_OK)
593 			continue;
594 
595 		if (driver->supports_device != NULL
596 			&& driver->register_device != NULL) {
597 			float support = driver->supports_device(this);
598 
599 			if ((findFlags & B_FIND_MULTIPLE_CHILDREN) == 0) {
600 				if (support > best) {
601 					if (bestDriver != NULL)
602 						put_module(bestDriver->info.name);
603 
604 					bestDriver = driver;
605 					best = support;
606 					continue;
607 						// keep reference to best module around
608 				}
609 			} else if (support > 0.0) {
610 printf("  register module \"%s\", support %f\n", name, support);
611 				driver->register_device(this);
612 			}
613 		}
614 
615 		put_module(name);
616 	}
617 	close_module_list(list);
618 
619 	if (bestDriver != NULL) {
620 printf("  register best module \"%s\", support %f\n", bestDriver->info.name, best);
621 		bestDriver->register_device(this);
622 		put_module(bestDriver->info.name);
623 	}
624 
625 	return B_OK;
626 }
627 
628 
629 //	#pragma mark -
630 
631 
632 //	#pragma mark - Device Manager module API
633 
634 
635 static status_t
636 rescan_device(device_node* node)
637 {
638 	return B_ERROR;
639 }
640 
641 
642 static status_t
643 register_device(device_node* parent, const char* moduleName,
644 	const device_attr* attrs, const io_resource* ioResources,
645 	device_node** _node)
646 {
647 	if ((parent == NULL && sRootNode != NULL) || moduleName == NULL)
648 		return B_BAD_VALUE;
649 
650 	// TODO: handle I/O resources!
651 
652 	device_node *newNode = new(std::nothrow) device_node(moduleName, attrs,
653 		ioResources);
654 	if (newNode == NULL)
655 		return B_NO_MEMORY;
656 
657 	TRACE(("%p: register device \"%s\", parent %p\n", newNode, moduleName,
658 		parent));
659 
660 	status_t status = newNode->InitCheck();
661 	if (status != B_OK)
662 		goto err1;
663 
664 	status = newNode->InitDriver();
665 	if (status != B_OK)
666 		goto err1;
667 
668 	// make it public
669 	if (parent != NULL)
670 		parent->AddChild(newNode);
671 	else
672 		sRootNode = newNode;
673 
674 #if 0
675 	// The following is done to reduce the stack usage of deeply nested
676 	// child device nodes.
677 	// There is no other need to delay the complete registration process
678 	// the way done here. This approach is also slightly different as
679 	// the registration might fail later than it used in case of errors.
680 
681 	if (!parent->IsRegistered()) {
682 		// The parent has not been registered completely yet - child
683 		// registration is deferred to the parent registration
684 		return B_OK;
685 	}
686 #endif
687 
688 	status = newNode->Register();
689 	if (status < B_OK) {
690 		parent->RemoveChild(newNode);
691 		goto err1;
692 	}
693 
694 	if (_node)
695 		*_node = newNode;
696 
697 	return B_OK;
698 
699 err1:
700 	delete newNode;
701 	return status;
702 }
703 
704 
705 static status_t
706 unregister_device(device_node* node)
707 {
708 	return B_ERROR;
709 }
710 
711 
712 static driver_module_info*
713 driver_module(device_node* node)
714 {
715 	return node->DriverModule();
716 }
717 
718 
719 static void*
720 driver_data(device_node* node)
721 {
722 	return node->DriverData();
723 }
724 
725 
726 static device_node*
727 device_root(void)
728 {
729 	return sRootNode;
730 }
731 
732 
733 static status_t
734 get_next_child_device(device_node* parent, device_node* _node,
735 	const device_attr* attrs)
736 {
737 	return B_ERROR;
738 }
739 
740 
741 static device_node*
742 get_parent(device_node* node)
743 {
744 	return NULL;
745 }
746 
747 
748 static void
749 put_device_node(device_node* node)
750 {
751 }
752 
753 
754 status_t
755 dm_get_attr_uint8(const device_node* node, const char* name, uint8* _value,
756 	bool recursive)
757 {
758 	if (node == NULL || name == NULL || _value == NULL)
759 		return B_BAD_VALUE;
760 
761 	device_attr_private* attr = dm_find_attr(node, name, recursive,
762 		B_UINT8_TYPE);
763 	if (attr == NULL)
764 		return B_NAME_NOT_FOUND;
765 
766 	*_value = attr->value.ui8;
767 	return B_OK;
768 }
769 
770 
771 status_t
772 dm_get_attr_uint16(device_node* node, const char* name, uint16* _value,
773 	bool recursive)
774 {
775 	if (node == NULL || name == NULL || _value == NULL)
776 		return B_BAD_VALUE;
777 
778 	device_attr_private* attr = dm_find_attr(node, name, recursive,
779 		B_UINT16_TYPE);
780 	if (attr == NULL)
781 		return B_NAME_NOT_FOUND;
782 
783 	*_value = attr->value.ui16;
784 	return B_OK;
785 }
786 
787 
788 status_t
789 dm_get_attr_uint32(device_node* node, const char* name, uint32* _value,
790 	bool recursive)
791 {
792 	if (node == NULL || name == NULL || _value == NULL)
793 		return B_BAD_VALUE;
794 
795 	device_attr_private* attr = dm_find_attr(node, name, recursive,
796 		B_UINT32_TYPE);
797 	if (attr == NULL)
798 		return B_NAME_NOT_FOUND;
799 
800 	*_value = attr->value.ui32;
801 	return B_OK;
802 }
803 
804 
805 status_t
806 dm_get_attr_uint64(device_node* node, const char* name,
807 	uint64* _value, bool recursive)
808 {
809 	if (node == NULL || name == NULL || _value == NULL)
810 		return B_BAD_VALUE;
811 
812 	device_attr_private* attr = dm_find_attr(node, name, recursive,
813 		B_UINT64_TYPE);
814 	if (attr == NULL)
815 		return B_NAME_NOT_FOUND;
816 
817 	*_value = attr->value.ui64;
818 	return B_OK;
819 }
820 
821 
822 status_t
823 dm_get_attr_string(device_node* node, const char* name, const char** _value,
824 	bool recursive)
825 {
826 	if (node == NULL || name == NULL || _value == NULL)
827 		return B_BAD_VALUE;
828 
829 	device_attr_private* attr = dm_find_attr(node, name, recursive,
830 		B_STRING_TYPE);
831 	if (attr == NULL)
832 		return B_NAME_NOT_FOUND;
833 
834 	*_value = attr->value.string;
835 	return B_OK;
836 }
837 
838 
839 status_t
840 dm_get_attr_raw(device_node* node, const char* name, const void** _data,
841 	size_t* _length, bool recursive)
842 {
843 	if (node == NULL || name == NULL || (_data == NULL && _length == NULL))
844 		return B_BAD_VALUE;
845 
846 	device_attr_private* attr = dm_find_attr(node, name, recursive, B_RAW_TYPE);
847 	if (attr == NULL)
848 		return B_NAME_NOT_FOUND;
849 
850 	if (_data != NULL)
851 		*_data = attr->value.raw.data;
852 	if (_length != NULL)
853 		*_length = attr->value.raw.length;
854 	return B_OK;
855 }
856 
857 
858 status_t
859 dm_get_next_attr(device_node* node, device_attr** _attr)
860 {
861 	if (node == NULL)
862 		return B_BAD_VALUE;
863 
864 	device_attr_private* next;
865 	device_attr_private* attr = *(device_attr_private**)_attr;
866 
867 	if (attr != NULL) {
868 		// next attribute
869 		next = attr->GetDoublyLinkedListLink()->next;
870 	} else {
871 		// first attribute
872 		next = node->Attributes().First();
873 	}
874 
875 	*_attr = next;
876 
877 	return next ? B_OK : B_ENTRY_NOT_FOUND;
878 }
879 
880 
881 static struct device_manager_info sDeviceManagerModule = {
882 	{
883 		B_DEVICE_MANAGER_MODULE_NAME,
884 		0,
885 		NULL
886 	},
887 
888 	// device nodes
889 	rescan_device,
890 	register_device,
891 	unregister_device,
892 	driver_module,
893 	driver_data,
894 	device_root,
895 	get_next_child_device,
896 	get_parent,
897 	put_device_node,
898 
899 	// attributes
900 	dm_get_attr_uint8,
901 	dm_get_attr_uint16,
902 	dm_get_attr_uint32,
903 	dm_get_attr_uint64,
904 	dm_get_attr_string,
905 	dm_get_attr_raw,
906 	dm_get_next_attr,
907 };
908 
909 
910 //	#pragma mark - root node
911 
912 
913 void
914 dm_init_root_node(void)
915 {
916 	device_attr attrs[] = {
917 		{B_DRIVER_PRETTY_NAME, B_STRING_TYPE, {string: "Devices Root"}},
918 		{B_DRIVER_IS_BUS, B_UINT8_TYPE, {ui8: true}},
919 		{B_DRIVER_BUS, B_STRING_TYPE, {string: "root"}},
920 		{B_DRIVER_FIND_CHILD_FLAGS, B_UINT32_TYPE,
921 			{ui32: B_FIND_MULTIPLE_CHILDREN}},
922 		{NULL}
923 	};
924 
925 	if (register_device(NULL, DEVICE_MANAGER_ROOT_NAME, attrs, NULL, NULL)
926 			!= B_OK) {
927 		dprintf("Cannot register Devices Root Node\n");
928 	}
929 }
930 
931 
932 static driver_module_info sDeviceRootModule = {
933 	{
934 		DEVICE_MANAGER_ROOT_NAME,
935 		0,
936 		NULL,
937 	},
938 	NULL
939 };
940 
941 
942 //	#pragma mark -
943 
944 
945 int
946 main(int argc, char** argv)
947 {
948 	_add_builtin_module((module_info*)&sDeviceManagerModule);
949 	_add_builtin_module((module_info*)&sDeviceRootModule);
950 	_add_builtin_module((module_info*)&gDeviceModuleInfo);
951 	_add_builtin_module((module_info*)&gDriverModuleInfo);
952 	_add_builtin_module((module_info*)&gBusModuleInfo);
953 	_add_builtin_module((module_info*)&gBusDriverModuleInfo);
954 
955 	gDeviceManager = &sDeviceManagerModule;
956 
957 	status_t status = _get_builtin_dependencies();
958 	if (status < B_OK) {
959 		fprintf(stderr, "device_manager: Could not initialize modules: %s\n",
960 			strerror(status));
961 		return 1;
962 	}
963 
964 	dm_init_root_node();
965 	dm_dump_node(sRootNode, 0);
966 
967 	return 0;
968 }
969