xref: /haiku/src/system/kernel/device_manager/device_manager.cpp (revision 02354704729d38c3b078c696adc1bbbd33cbcf72)
1 /*
2  * Copyright 2008-2009, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  */
5 
6 
7 #include <kdevice_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 <boot_device.h>
21 #include <device_manager_defs.h>
22 #include <fs/devfs.h>
23 #include <fs/KPath.h>
24 #include <kernel.h>
25 #include <generic_syscall.h>
26 #include <util/AutoLock.h>
27 #include <util/DoublyLinkedList.h>
28 #include <util/Stack.h>
29 
30 #include "AbstractModuleDevice.h"
31 #include "devfs_private.h"
32 #include "id_generator.h"
33 #include "IORequest.h"
34 #include "io_resources.h"
35 #include "IOSchedulerRoster.h"
36 
37 
38 //#define TRACE_DEVICE_MANAGER
39 #ifdef TRACE_DEVICE_MANAGER
40 #	define TRACE(a) dprintf a
41 #else
42 #	define TRACE(a) ;
43 #endif
44 
45 
46 #define DEVICE_MANAGER_ROOT_NAME "system/devices_root/driver_v1"
47 #define DEVICE_MANAGER_GENERIC_NAME "system/devices_generic/driver_v1"
48 
49 
50 struct device_attr_private : device_attr,
51 		DoublyLinkedListLinkImpl<device_attr_private> {
52 						device_attr_private();
53 						device_attr_private(const device_attr& attr);
54 						~device_attr_private();
55 
56 			status_t	InitCheck();
57 			status_t	CopyFrom(const device_attr& attr);
58 
59 	static	int			Compare(const device_attr* attrA,
60 							const device_attr *attrB);
61 
62 private:
63 			void		_Unset();
64 };
65 
66 typedef DoublyLinkedList<device_attr_private> AttributeList;
67 
68 // I/O resource
69 typedef struct io_resource_info {
70 	struct io_resource_info *prev, *next;
71 	device_node*		owner;			// associated node; NULL for temporary allocation
72 	io_resource			resource;		// info about actual resource
73 } io_resource_info;
74 
75 
76 namespace {
77 
78 
79 class Device : public AbstractModuleDevice,
80 	public DoublyLinkedListLinkImpl<Device> {
81 public:
82 							Device(device_node* node, const char* moduleName);
83 	virtual					~Device();
84 
85 			status_t		InitCheck() const;
86 
87 			const char*		ModuleName() const { return fModuleName; }
88 
89 	virtual	status_t		InitDevice();
90 	virtual	void			UninitDevice();
91 
92 	virtual void			Removed();
93 
94 			void			SetRemovedFromParent(bool removed)
95 								{ fRemovedFromParent = removed; }
96 
97 private:
98 	const char*				fModuleName;
99 	bool					fRemovedFromParent;
100 };
101 
102 
103 } // unnamed namespace
104 
105 
106 typedef DoublyLinkedList<Device> DeviceList;
107 typedef DoublyLinkedList<device_node> NodeList;
108 
109 struct device_node : DoublyLinkedListLinkImpl<device_node> {
110 							device_node(const char* moduleName,
111 								const device_attr* attrs);
112 							~device_node();
113 
114 			status_t		InitCheck() const;
115 
116 			status_t		AcquireResources(const io_resource* resources);
117 
118 			const char*		ModuleName() const { return fModuleName; }
119 			device_node*	Parent() const { return fParent; }
120 			AttributeList&	Attributes() { return fAttributes; }
121 			const AttributeList& Attributes() const { return fAttributes; }
122 
123 			status_t		InitDriver();
124 			bool			UninitDriver();
125 			void			UninitUnusedDriver();
126 
127 			// The following two are only valid, if the node's driver is
128 			// initialized
129 			driver_module_info* DriverModule() const { return fDriver; }
130 			void*			DriverData() const { return fDriverData; }
131 
132 			void			AddChild(device_node *node);
133 			void			RemoveChild(device_node *node);
134 			const NodeList&	Children() const { return fChildren; }
135 			void			DeviceRemoved();
136 
137 			status_t		Register(device_node* parent);
138 			status_t		Probe(const char* devicePath, uint32 updateCycle);
139 			status_t		Reprobe();
140 			status_t		Rescan();
141 
142 			bool			IsRegistered() const { return fRegistered; }
143 			bool			IsInitialized() const { return fInitialized > 0; }
144 			bool			IsProbed() const { return fLastUpdateCycle != 0; }
145 			uint32			Flags() const { return fFlags; }
146 
147 			void			Acquire();
148 			bool			Release();
149 
150 			const DeviceList& Devices() const { return fDevices; }
151 			void			AddDevice(Device* device);
152 			void			RemoveDevice(Device* device);
153 
154 			int				CompareTo(const device_attr* attributes) const;
155 			device_node*	FindChild(const device_attr* attributes) const;
156 			device_node*	FindChild(const char* moduleName) const;
157 
158 			int32			Priority();
159 
160 			void			Dump(int32 level = 0);
161 
162 private:
163 			status_t		_RegisterFixed(uint32& registered);
164 			bool			_AlwaysRegisterDynamic();
165 			status_t		_AddPath(Stack<KPath*>& stack, const char* path,
166 								const char* subPath = NULL);
167 			status_t		_GetNextDriverPath(void*& cookie, KPath& _path);
168 			status_t		_GetNextDriver(void* list,
169 								driver_module_info*& driver);
170 			status_t		_FindBestDriver(const char* path,
171 								driver_module_info*& bestDriver,
172 								float& bestSupport,
173 								device_node* previous = NULL);
174 			status_t		_RegisterPath(const char* path);
175 			status_t		_RegisterDynamic(device_node* previous = NULL);
176 			status_t		_RemoveChildren();
177 			device_node*	_FindCurrentChild();
178 			status_t		_Probe();
179 			void			_ReleaseWaiting();
180 
181 	device_node*			fParent;
182 	NodeList				fChildren;
183 	int32					fRefCount;
184 	int32					fInitialized;
185 	bool					fRegistered;
186 	uint32					fFlags;
187 	float					fSupportsParent;
188 	uint32					fLastUpdateCycle;
189 
190 	const char*				fModuleName;
191 
192 	driver_module_info*		fDriver;
193 	void*					fDriverData;
194 
195 	DeviceList				fDevices;
196 	AttributeList			fAttributes;
197 	ResourceList			fResources;
198 };
199 
200 // flags in addition to those specified by B_DEVICE_FLAGS
201 enum node_flags {
202 	NODE_FLAG_REGISTER_INITIALIZED	= 0x00010000,
203 	NODE_FLAG_DEVICE_REMOVED		= 0x00020000,
204 	NODE_FLAG_OBSOLETE_DRIVER		= 0x00040000,
205 	NODE_FLAG_WAITING_FOR_DRIVER	= 0x00080000,
206 
207 	NODE_FLAG_PUBLIC_MASK			= 0x0000ffff
208 };
209 
210 
211 static device_node *sRootNode;
212 static recursive_lock sLock;
213 static const char* sGenericContextPath;
214 
215 
216 //	#pragma mark -
217 
218 
219 static device_attr_private*
220 find_attr(const device_node* node, const char* name, bool recursive,
221 	type_code type)
222 {
223 	do {
224 		AttributeList::ConstIterator iterator
225 			= node->Attributes().GetIterator();
226 
227 		while (iterator.HasNext()) {
228 			device_attr_private* attr = iterator.Next();
229 
230 			if (type != B_ANY_TYPE && attr->type != type)
231 				continue;
232 
233 			if (!strcmp(attr->name, name))
234 				return attr;
235 		}
236 
237 		node = node->Parent();
238 	} while (node != NULL && recursive);
239 
240 	return NULL;
241 }
242 
243 
244 static void
245 put_level(int32 level)
246 {
247 	while (level-- > 0)
248 		kprintf("   ");
249 }
250 
251 
252 static void
253 dump_attribute(device_attr* attr, int32 level)
254 {
255 	if (attr == NULL)
256 		return;
257 
258 	put_level(level + 2);
259 	kprintf("\"%s\" : ", attr->name);
260 	switch (attr->type) {
261 		case B_STRING_TYPE:
262 			kprintf("string : \"%s\"", attr->value.string);
263 			break;
264 		case B_INT8_TYPE:
265 		case B_UINT8_TYPE:
266 			kprintf("uint8 : %" B_PRIu8 " (%#" B_PRIx8 ")", attr->value.ui8,
267 				attr->value.ui8);
268 			break;
269 		case B_INT16_TYPE:
270 		case B_UINT16_TYPE:
271 			kprintf("uint16 : %" B_PRIu16 " (%#" B_PRIx16 ")", attr->value.ui16,
272 				attr->value.ui16);
273 			break;
274 		case B_INT32_TYPE:
275 		case B_UINT32_TYPE:
276 			kprintf("uint32 : %" B_PRIu32 " (%#" B_PRIx32 ")", attr->value.ui32,
277 				attr->value.ui32);
278 			break;
279 		case B_INT64_TYPE:
280 		case B_UINT64_TYPE:
281 			kprintf("uint64 : %" B_PRIu64 " (%#" B_PRIx64 ")", attr->value.ui64,
282 				attr->value.ui64);
283 			break;
284 		default:
285 			kprintf("raw data");
286 	}
287 	kprintf("\n");
288 }
289 
290 
291 static int
292 dump_io_scheduler(int argc, char** argv)
293 {
294 	if (argc != 2) {
295 		print_debugger_command_usage(argv[0]);
296 		return 0;
297 	}
298 
299 	IOScheduler* scheduler = (IOScheduler*)parse_expression(argv[1]);
300 	scheduler->Dump();
301 	return 0;
302 }
303 
304 
305 static int
306 dump_io_request_owner(int argc, char** argv)
307 {
308 	if (argc != 2) {
309 		print_debugger_command_usage(argv[0]);
310 		return 0;
311 	}
312 
313 	IORequestOwner* owner = (IORequestOwner*)parse_expression(argv[1]);
314 	owner->Dump();
315 	return 0;
316 }
317 
318 
319 static int
320 dump_io_request(int argc, char** argv)
321 {
322 	if (argc != 2 || !strcmp(argv[1], "--help")) {
323 		kprintf("usage: %s <ptr-to-io-request>\n", argv[0]);
324 		return 0;
325 	}
326 
327 	IORequest* request = (IORequest*)parse_expression(argv[1]);
328 	request->Dump();
329 	return 0;
330 }
331 
332 
333 static int
334 dump_io_operation(int argc, char** argv)
335 {
336 	if (argc != 2 || !strcmp(argv[1], "--help")) {
337 		kprintf("usage: %s <ptr-to-io-operation>\n", argv[0]);
338 		return 0;
339 	}
340 
341 	IOOperation* operation = (IOOperation*)parse_expression(argv[1]);
342 	operation->Dump();
343 	return 0;
344 }
345 
346 
347 static int
348 dump_io_buffer(int argc, char** argv)
349 {
350 	if (argc != 2 || !strcmp(argv[1], "--help")) {
351 		kprintf("usage: %s <ptr-to-io-buffer>\n", argv[0]);
352 		return 0;
353 	}
354 
355 	IOBuffer* buffer = (IOBuffer*)parse_expression(argv[1]);
356 	buffer->Dump();
357 	return 0;
358 }
359 
360 
361 static int
362 dump_dma_buffer(int argc, char** argv)
363 {
364 	if (argc != 2 || !strcmp(argv[1], "--help")) {
365 		kprintf("usage: %s <ptr-to-dma-buffer>\n", argv[0]);
366 		return 0;
367 	}
368 
369 	DMABuffer* buffer = (DMABuffer*)parse_expression(argv[1]);
370 	buffer->Dump();
371 	return 0;
372 }
373 
374 
375 static int
376 dump_device_nodes(int argc, char** argv)
377 {
378 	sRootNode->Dump();
379 	return 0;
380 }
381 
382 
383 static void
384 publish_directories(const char* subPath)
385 {
386 	if (gBootDevice < 0) {
387 		if (subPath[0]) {
388 			// we only support the top-level directory for modules
389 			return;
390 		}
391 
392 		// we can only iterate over the known modules to find all directories
393 		KPath path("drivers");
394 		if (path.Append(subPath) != B_OK)
395 			return;
396 
397 		size_t length = strlen(path.Path()) + 1;
398 			// account for the separating '/'
399 
400 		void* list = open_module_list_etc(path.Path(), "driver_v1");
401 		char name[B_FILE_NAME_LENGTH];
402 		size_t nameLength = sizeof(name);
403 		while (read_next_module_name(list, name, &nameLength) == B_OK) {
404 			if (nameLength == length)
405 				continue;
406 
407 			char* leaf = name + length;
408 			char* end = strchr(leaf, '/');
409 			if (end != NULL)
410 				end[0] = '\0';
411 
412 			path.SetTo(subPath);
413 			path.Append(leaf);
414 
415 			devfs_publish_directory(path.Path());
416 		}
417 		close_module_list(list);
418 	} else {
419 		// TODO: implement module directory traversal!
420 	}
421 }
422 
423 
424 static status_t
425 control_device_manager(const char* subsystem, uint32 function, void* buffer,
426 	size_t bufferSize)
427 {
428 	// TODO: this function passes pointers to userland, and uses pointers
429 	// to device nodes that came from userland - this is completely unsafe
430 	// and should be changed.
431 	switch (function) {
432 		case DM_GET_ROOT:
433 		{
434 			device_node_cookie cookie;
435 			if (!IS_USER_ADDRESS(buffer))
436 				return B_BAD_ADDRESS;
437 			if (bufferSize != sizeof(device_node_cookie))
438 				return B_BAD_VALUE;
439 			cookie = (device_node_cookie)sRootNode;
440 
441 			// copy back to user space
442 			return user_memcpy(buffer, &cookie, sizeof(device_node_cookie));
443 		}
444 
445 		case DM_GET_CHILD:
446 		{
447 			if (!IS_USER_ADDRESS(buffer))
448 				return B_BAD_ADDRESS;
449 			if (bufferSize != sizeof(device_node_cookie))
450 				return B_BAD_VALUE;
451 
452 			device_node_cookie cookie;
453 			if (user_memcpy(&cookie, buffer, sizeof(device_node_cookie)) < B_OK)
454 				return B_BAD_ADDRESS;
455 
456 			device_node* node = (device_node*)cookie;
457 			NodeList::ConstIterator iterator = node->Children().GetIterator();
458 
459 			if (!iterator.HasNext()) {
460 				return B_ENTRY_NOT_FOUND;
461 			}
462 			node = iterator.Next();
463 			cookie = (device_node_cookie)node;
464 
465 			// copy back to user space
466 			return user_memcpy(buffer, &cookie, sizeof(device_node_cookie));
467 		}
468 
469 		case DM_GET_NEXT_CHILD:
470 		{
471 			if (!IS_USER_ADDRESS(buffer))
472 				return B_BAD_ADDRESS;
473 			if (bufferSize != sizeof(device_node_cookie))
474 				return B_BAD_VALUE;
475 
476 			device_node_cookie cookie;
477 			if (user_memcpy(&cookie, buffer, sizeof(device_node_cookie)) < B_OK)
478 				return B_BAD_ADDRESS;
479 
480 			device_node* last = (device_node*)cookie;
481 			if (!last->Parent())
482 				return B_ENTRY_NOT_FOUND;
483 
484 			NodeList::ConstIterator iterator
485 				= last->Parent()->Children().GetIterator();
486 
487 			// skip those we already traversed
488 			while (iterator.HasNext()) {
489 				device_node* node = iterator.Next();
490 
491 				if (node == last)
492 					break;
493 			}
494 
495 			if (!iterator.HasNext())
496 				return B_ENTRY_NOT_FOUND;
497 			device_node* node = iterator.Next();
498 			cookie = (device_node_cookie)node;
499 
500 			// copy back to user space
501 			return user_memcpy(buffer, &cookie, sizeof(device_node_cookie));
502 		}
503 
504 		case DM_GET_NEXT_ATTRIBUTE:
505 		{
506 			struct device_attr_info attrInfo;
507 			if (!IS_USER_ADDRESS(buffer))
508 				return B_BAD_ADDRESS;
509 			if (bufferSize != sizeof(device_attr_info))
510 				return B_BAD_VALUE;
511 			if (user_memcpy(&attrInfo, buffer, sizeof(device_attr_info)) < B_OK)
512 				return B_BAD_ADDRESS;
513 
514 			device_node* node = (device_node*)attrInfo.node_cookie;
515 			device_attr* last = (device_attr*)attrInfo.cookie;
516 			AttributeList::Iterator iterator = node->Attributes().GetIterator();
517 			// skip those we already traversed
518 			while (iterator.HasNext() && last != NULL) {
519 				device_attr* attr = iterator.Next();
520 
521 				if (attr == last)
522 					break;
523 			}
524 
525 			if (!iterator.HasNext()) {
526 				attrInfo.cookie = 0;
527 				return B_ENTRY_NOT_FOUND;
528 			}
529 
530 			device_attr* attr = iterator.Next();
531 			attrInfo.cookie = (device_node_cookie)attr;
532 			if (attr->name != NULL)
533 				strlcpy(attrInfo.name, attr->name, 254);
534 			else
535 				attrInfo.name[0] = '\0';
536 			attrInfo.type = attr->type;
537 			switch (attrInfo.type) {
538 				case B_UINT8_TYPE:
539 					attrInfo.value.ui8 = attr->value.ui8;
540 					break;
541 				case B_UINT16_TYPE:
542 					attrInfo.value.ui16 = attr->value.ui16;
543 					break;
544 				case B_UINT32_TYPE:
545 					attrInfo.value.ui32 = attr->value.ui32;
546 					break;
547 				case B_UINT64_TYPE:
548 					attrInfo.value.ui64 = attr->value.ui64;
549 					break;
550 				case B_STRING_TYPE:
551 					if (attr->value.string != NULL)
552 						strlcpy(attrInfo.value.string, attr->value.string, 254);
553 					else
554 						attrInfo.value.string[0] = '\0';
555 					break;
556 				/*case B_RAW_TYPE:
557 					if (attr.value.raw.length > attr_info->attr.value.raw.length)
558 						attr.value.raw.length = attr_info->attr.value.raw.length;
559 					user_memcpy(attr.value.raw.data, attr_info->attr.value.raw.data,
560 						attr.value.raw.length);
561 					break;*/
562 			}
563 
564 			// copy back to user space
565 			return user_memcpy(buffer, &attrInfo, sizeof(device_attr_info));
566 		}
567 	}
568 
569 	return B_BAD_HANDLER;
570 }
571 
572 
573 //	#pragma mark - Device Manager module API
574 
575 
576 static status_t
577 rescan_node(device_node* node)
578 {
579 	RecursiveLocker _(sLock);
580 	return node->Rescan();
581 }
582 
583 
584 static status_t
585 register_node(device_node* parent, const char* moduleName,
586 	const device_attr* attrs, const io_resource* ioResources,
587 	device_node** _node)
588 {
589 	if ((parent == NULL && sRootNode != NULL) || moduleName == NULL)
590 		return B_BAD_VALUE;
591 
592 	if (parent != NULL && parent->FindChild(attrs) != NULL) {
593 		// A node like this one already exists for this parent
594 		return B_NAME_IN_USE;
595 	}
596 
597 	RecursiveLocker _(sLock);
598 
599 	device_node* newNode = new(std::nothrow) device_node(moduleName, attrs);
600 	if (newNode == NULL)
601 		return B_NO_MEMORY;
602 
603 	TRACE(("%p: register node \"%s\", parent %p\n", newNode, moduleName,
604 		parent));
605 
606 	status_t status = newNode->InitCheck();
607 	if (status == B_OK)
608 		status = newNode->AcquireResources(ioResources);
609 	if (status == B_OK)
610 		status = newNode->Register(parent);
611 
612 	if (status != B_OK) {
613 		newNode->Release();
614 		return status;
615 	}
616 
617 	if (_node)
618 		*_node = newNode;
619 
620 	return B_OK;
621 }
622 
623 
624 /*!	Unregisters the device \a node.
625 
626 	If the node is currently in use, this function will return B_BUSY to
627 	indicate that the node hasn't been removed yet - it will still remove
628 	the node as soon as possible.
629 */
630 static status_t
631 unregister_node(device_node* node)
632 {
633 	TRACE(("unregister_node(node %p)\n", node));
634 	RecursiveLocker _(sLock);
635 
636 	bool initialized = node->IsInitialized();
637 
638 	node->DeviceRemoved();
639 
640 	return initialized ? B_BUSY : B_OK;
641 }
642 
643 
644 static status_t
645 get_driver(device_node* node, driver_module_info** _module, void** _data)
646 {
647 	if (node->DriverModule() == NULL)
648 		return B_NO_INIT;
649 
650 	if (_module != NULL)
651 		*_module = node->DriverModule();
652 	if (_data != NULL)
653 		*_data = node->DriverData();
654 
655 	return B_OK;
656 }
657 
658 
659 static device_node*
660 get_root_node(void)
661 {
662 	if (sRootNode != NULL)
663 		sRootNode->Acquire();
664 
665 	return sRootNode;
666 }
667 
668 
669 static status_t
670 get_next_child_node(device_node* parent, const device_attr* attributes,
671 	device_node** _node)
672 {
673 	RecursiveLocker _(sLock);
674 
675 	NodeList::ConstIterator iterator = parent->Children().GetIterator();
676 	device_node* last = *_node;
677 
678 	// skip those we already traversed
679 	while (iterator.HasNext() && last != NULL) {
680 		device_node* node = iterator.Next();
681 
682 		if (node != last)
683 			continue;
684 	}
685 
686 	// find the next one that fits
687 	while (iterator.HasNext()) {
688 		device_node* node = iterator.Next();
689 
690 		if (!node->IsRegistered())
691 			continue;
692 
693 		if (!node->CompareTo(attributes)) {
694 			if (last != NULL)
695 				last->Release();
696 
697 			node->Acquire();
698 			*_node = node;
699 			return B_OK;
700 		}
701 	}
702 
703 	if (last != NULL)
704 		last->Release();
705 
706 	return B_ENTRY_NOT_FOUND;
707 }
708 
709 
710 static device_node*
711 get_parent_node(device_node* node)
712 {
713 	if (node == NULL)
714 		return NULL;
715 
716 	RecursiveLocker _(sLock);
717 
718 	device_node* parent = node->Parent();
719 	parent->Acquire();
720 
721 	return parent;
722 }
723 
724 
725 static void
726 put_node(device_node* node)
727 {
728 	RecursiveLocker _(sLock);
729 	node->Release();
730 }
731 
732 
733 static status_t
734 publish_device(device_node *node, const char *path, const char *moduleName)
735 {
736 	if (path == NULL || !path[0] || moduleName == NULL || !moduleName[0])
737 		return B_BAD_VALUE;
738 
739 	RecursiveLocker _(sLock);
740 	dprintf("publish device: node %p, path %s, module %s\n", node, path,
741 		moduleName);
742 
743 	Device* device = new(std::nothrow) Device(node, moduleName);
744 	if (device == NULL)
745 		return B_NO_MEMORY;
746 
747 	status_t status = device->InitCheck();
748 	if (status == B_OK)
749 		status = devfs_publish_device(path, device);
750 	if (status != B_OK) {
751 		delete device;
752 		return status;
753 	}
754 
755 	node->AddDevice(device);
756 
757 	device_attr_private* attr;
758 
759 	attr = new(std::nothrow) device_attr_private();
760 	if (attr != NULL) {
761 		char buf[256];
762 		sprintf(buf, "dev/%" B_PRIdINO "/path", device->ID());
763 		attr->name = strdup(buf);
764 		attr->type = B_STRING_TYPE;
765 		attr->value.string = strdup(path);
766 		node->Attributes().Add(attr);
767 	}
768 
769 	attr = new(std::nothrow) device_attr_private();
770 	if (attr != NULL) {
771 		char buf[256];
772 		sprintf(buf, "dev/%" B_PRIdINO "/driver", device->ID());
773 		attr->name = strdup(buf);
774 		attr->type = B_STRING_TYPE;
775 		attr->value.string = strdup(moduleName);
776 		node->Attributes().Add(attr);
777 	}
778 
779 	return B_OK;
780 }
781 
782 
783 static status_t
784 unpublish_device(device_node *node, const char *path)
785 {
786 	if (path == NULL)
787 		return B_BAD_VALUE;
788 
789 	BaseDevice* baseDevice;
790 	status_t error = devfs_get_device(path, baseDevice);
791 	if (error != B_OK)
792 		return error;
793 	CObjectDeleter<BaseDevice, void, devfs_put_device>
794 		baseDevicePutter(baseDevice);
795 
796 	Device* device = dynamic_cast<Device*>(baseDevice);
797 	if (device == NULL || device->Node() != node)
798 		return B_BAD_VALUE;
799 
800 	return devfs_unpublish_device(device, true);
801 }
802 
803 
804 static status_t
805 get_attr_uint8(const device_node* node, const char* name, uint8* _value,
806 	bool recursive)
807 {
808 	if (node == NULL || name == NULL || _value == NULL)
809 		return B_BAD_VALUE;
810 
811 	device_attr_private* attr = find_attr(node, name, recursive, B_UINT8_TYPE);
812 	if (attr == NULL)
813 		return B_NAME_NOT_FOUND;
814 
815 	*_value = attr->value.ui8;
816 	return B_OK;
817 }
818 
819 
820 static status_t
821 get_attr_uint16(const device_node* node, const char* name, uint16* _value,
822 	bool recursive)
823 {
824 	if (node == NULL || name == NULL || _value == NULL)
825 		return B_BAD_VALUE;
826 
827 	device_attr_private* attr = find_attr(node, name, recursive, B_UINT16_TYPE);
828 	if (attr == NULL)
829 		return B_NAME_NOT_FOUND;
830 
831 	*_value = attr->value.ui16;
832 	return B_OK;
833 }
834 
835 
836 static status_t
837 get_attr_uint32(const device_node* node, const char* name, uint32* _value,
838 	bool recursive)
839 {
840 	if (node == NULL || name == NULL || _value == NULL)
841 		return B_BAD_VALUE;
842 
843 	device_attr_private* attr = find_attr(node, name, recursive, B_UINT32_TYPE);
844 	if (attr == NULL)
845 		return B_NAME_NOT_FOUND;
846 
847 	*_value = attr->value.ui32;
848 	return B_OK;
849 }
850 
851 
852 static status_t
853 get_attr_uint64(const device_node* node, const char* name,
854 	uint64* _value, bool recursive)
855 {
856 	if (node == NULL || name == NULL || _value == NULL)
857 		return B_BAD_VALUE;
858 
859 	device_attr_private* attr = find_attr(node, name, recursive, B_UINT64_TYPE);
860 	if (attr == NULL)
861 		return B_NAME_NOT_FOUND;
862 
863 	*_value = attr->value.ui64;
864 	return B_OK;
865 }
866 
867 
868 static status_t
869 get_attr_string(const device_node* node, const char* name,
870 	const char** _value, bool recursive)
871 {
872 	if (node == NULL || name == NULL || _value == NULL)
873 		return B_BAD_VALUE;
874 
875 	device_attr_private* attr = find_attr(node, name, recursive, B_STRING_TYPE);
876 	if (attr == NULL)
877 		return B_NAME_NOT_FOUND;
878 
879 	*_value = attr->value.string;
880 	return B_OK;
881 }
882 
883 
884 static status_t
885 get_attr_raw(const device_node* node, const char* name, const void** _data,
886 	size_t* _length, bool recursive)
887 {
888 	if (node == NULL || name == NULL || (_data == NULL && _length == NULL))
889 		return B_BAD_VALUE;
890 
891 	device_attr_private* attr = find_attr(node, name, recursive, B_RAW_TYPE);
892 	if (attr == NULL)
893 		return B_NAME_NOT_FOUND;
894 
895 	if (_data != NULL)
896 		*_data = attr->value.raw.data;
897 	if (_length != NULL)
898 		*_length = attr->value.raw.length;
899 	return B_OK;
900 }
901 
902 
903 static status_t
904 get_next_attr(device_node* node, device_attr** _attr)
905 {
906 	if (node == NULL)
907 		return B_BAD_VALUE;
908 
909 	device_attr_private* next;
910 	device_attr_private* attr = *(device_attr_private**)_attr;
911 
912 	if (attr != NULL) {
913 		// next attribute
914 		next = attr->GetDoublyLinkedListLink()->next;
915 	} else {
916 		// first attribute
917 		next = node->Attributes().First();
918 	}
919 
920 	*_attr = next;
921 
922 	return next ? B_OK : B_ENTRY_NOT_FOUND;
923 }
924 
925 
926 static status_t
927 find_child_node(device_node* parent, const device_attr* attributes,
928 	device_node** _node, bool *_lastFound)
929 {
930 	RecursiveLocker _(sLock);
931 
932 	NodeList::ConstIterator iterator = parent->Children().GetIterator();
933 	device_node* last = *_node;
934 
935 	// find the next one that fits
936 	while (iterator.HasNext()) {
937 		device_node* node = iterator.Next();
938 
939 		if (!node->IsRegistered())
940 			continue;
941 
942 		if (node == last)
943 			*_lastFound = true;
944 		else if (!node->CompareTo(attributes) && *_lastFound) {
945 			if (last != NULL)
946 				last->Release();
947 
948 			node->Acquire();
949 			*_node = node;
950 			return B_OK;
951 		}
952 		if (find_child_node(node, attributes, _node, _lastFound) == B_OK)
953 			return B_OK;
954 	}
955 
956 	return B_ENTRY_NOT_FOUND;
957 }
958 
959 
960 static status_t
961 find_child_node(device_node* parent, const device_attr* attributes,
962 	device_node** _node)
963 {
964 	device_node* last = *_node;
965 	bool lastFound = last == NULL;
966 	status_t status = find_child_node(parent, attributes, _node, &lastFound);
967 	if (status == B_ENTRY_NOT_FOUND && last != NULL && lastFound)
968 		last->Release();
969 	return status;
970 }
971 
972 
973 struct device_manager_info gDeviceManagerModule = {
974 	{
975 		B_DEVICE_MANAGER_MODULE_NAME,
976 		0,
977 		NULL
978 	},
979 
980 	// device nodes
981 	rescan_node,
982 	register_node,
983 	unregister_node,
984 	get_driver,
985 	get_root_node,
986 	get_next_child_node,
987 	get_parent_node,
988 	put_node,
989 
990 	// devices
991 	publish_device,
992 	unpublish_device,
993 
994 	// I/O resources
995 
996 	// ID generator
997 	dm_create_id,
998 	dm_free_id,
999 
1000 	// attributes
1001 	get_attr_uint8,
1002 	get_attr_uint16,
1003 	get_attr_uint32,
1004 	get_attr_uint64,
1005 	get_attr_string,
1006 	get_attr_raw,
1007 	get_next_attr,
1008 	find_child_node
1009 };
1010 
1011 
1012 //	#pragma mark - device_attr
1013 
1014 
1015 device_attr_private::device_attr_private()
1016 {
1017 	name = NULL;
1018 	type = 0;
1019 	value.raw.data = NULL;
1020 	value.raw.length = 0;
1021 }
1022 
1023 
1024 device_attr_private::device_attr_private(const device_attr& attr)
1025 {
1026 	CopyFrom(attr);
1027 }
1028 
1029 
1030 device_attr_private::~device_attr_private()
1031 {
1032 	_Unset();
1033 }
1034 
1035 
1036 status_t
1037 device_attr_private::InitCheck()
1038 {
1039 	return name != NULL ? B_OK : B_NO_INIT;
1040 }
1041 
1042 
1043 status_t
1044 device_attr_private::CopyFrom(const device_attr& attr)
1045 {
1046 	name = strdup(attr.name);
1047 	if (name == NULL)
1048 		return B_NO_MEMORY;
1049 
1050 	type = attr.type;
1051 
1052 	switch (type) {
1053 		case B_UINT8_TYPE:
1054 		case B_UINT16_TYPE:
1055 		case B_UINT32_TYPE:
1056 		case B_UINT64_TYPE:
1057 			value.ui64 = attr.value.ui64;
1058 			break;
1059 
1060 		case B_STRING_TYPE:
1061 			if (attr.value.string != NULL) {
1062 				value.string = strdup(attr.value.string);
1063 				if (value.string == NULL) {
1064 					_Unset();
1065 					return B_NO_MEMORY;
1066 				}
1067 			} else
1068 				value.string = NULL;
1069 			break;
1070 
1071 		case B_RAW_TYPE:
1072 			value.raw.data = malloc(attr.value.raw.length);
1073 			if (value.raw.data == NULL) {
1074 				_Unset();
1075 				return B_NO_MEMORY;
1076 			}
1077 
1078 			value.raw.length = attr.value.raw.length;
1079 			memcpy((void*)value.raw.data, attr.value.raw.data,
1080 				attr.value.raw.length);
1081 			break;
1082 
1083 		default:
1084 			return B_BAD_VALUE;
1085 	}
1086 
1087 	return B_OK;
1088 }
1089 
1090 
1091 void
1092 device_attr_private::_Unset()
1093 {
1094 	if (type == B_STRING_TYPE)
1095 		free((char*)value.string);
1096 	else if (type == B_RAW_TYPE)
1097 		free((void*)value.raw.data);
1098 
1099 	free((char*)name);
1100 
1101 	name = NULL;
1102 	value.raw.data = NULL;
1103 	value.raw.length = 0;
1104 }
1105 
1106 
1107 /*static*/ int
1108 device_attr_private::Compare(const device_attr* attrA, const device_attr *attrB)
1109 {
1110 	if (attrA->type != attrB->type)
1111 		return -1;
1112 
1113 	switch (attrA->type) {
1114 		case B_UINT8_TYPE:
1115 			return (int)attrA->value.ui8 - (int)attrB->value.ui8;
1116 
1117 		case B_UINT16_TYPE:
1118 			return (int)attrA->value.ui16 - (int)attrB->value.ui16;
1119 
1120 		case B_UINT32_TYPE:
1121 			if (attrA->value.ui32 > attrB->value.ui32)
1122 				return 1;
1123 			if (attrA->value.ui32 < attrB->value.ui32)
1124 				return -1;
1125 			return 0;
1126 
1127 		case B_UINT64_TYPE:
1128 			if (attrA->value.ui64 > attrB->value.ui64)
1129 				return 1;
1130 			if (attrA->value.ui64 < attrB->value.ui64)
1131 				return -1;
1132 			return 0;
1133 
1134 		case B_STRING_TYPE:
1135 			return strcmp(attrA->value.string, attrB->value.string);
1136 
1137 		case B_RAW_TYPE:
1138 			if (attrA->value.raw.length != attrB->value.raw.length)
1139 				return -1;
1140 
1141 			return memcmp(attrA->value.raw.data, attrB->value.raw.data,
1142 				attrA->value.raw.length);
1143 	}
1144 
1145 	return -1;
1146 }
1147 
1148 
1149 //	#pragma mark - Device
1150 
1151 
1152 Device::Device(device_node* node, const char* moduleName)
1153 	:
1154 	fModuleName(strdup(moduleName)),
1155 	fRemovedFromParent(false)
1156 {
1157 	fNode = node;
1158 }
1159 
1160 
1161 Device::~Device()
1162 {
1163 	free((char*)fModuleName);
1164 }
1165 
1166 
1167 status_t
1168 Device::InitCheck() const
1169 {
1170 	return fModuleName != NULL ? B_OK : B_NO_MEMORY;
1171 }
1172 
1173 
1174 status_t
1175 Device::InitDevice()
1176 {
1177 	RecursiveLocker _(sLock);
1178 
1179 	if ((fNode->Flags() & NODE_FLAG_DEVICE_REMOVED) != 0) {
1180 		// TODO: maybe the device should be unlinked in devfs, too
1181 		return ENODEV;
1182 	}
1183 	if ((fNode->Flags() & NODE_FLAG_WAITING_FOR_DRIVER) != 0)
1184 		return B_BUSY;
1185 
1186 	if (fInitialized++ > 0) {
1187 		fNode->InitDriver();
1188 			// acquire another reference to our parent as well
1189 		return B_OK;
1190 	}
1191 
1192 	status_t status = get_module(ModuleName(), (module_info**)&fDeviceModule);
1193 	if (status == B_OK) {
1194 		// our parent always has to be initialized
1195 		status = fNode->InitDriver();
1196 	}
1197 	if (status < B_OK) {
1198 		fInitialized--;
1199 		return status;
1200 	}
1201 
1202 	if (Module()->init_device != NULL)
1203 		status = Module()->init_device(fNode->DriverData(), &fDeviceData);
1204 
1205 	if (status < B_OK) {
1206 		fNode->UninitDriver();
1207 		fInitialized--;
1208 
1209 		put_module(ModuleName());
1210 		fDeviceModule = NULL;
1211 		fDeviceData = NULL;
1212 	}
1213 
1214 	return status;
1215 }
1216 
1217 
1218 void
1219 Device::UninitDevice()
1220 {
1221 	RecursiveLocker _(sLock);
1222 
1223 	if (fInitialized-- > 1) {
1224 		fNode->UninitDriver();
1225 		return;
1226 	}
1227 
1228 	TRACE(("uninit driver for node %p\n", this));
1229 
1230 	if (Module()->uninit_device != NULL)
1231 		Module()->uninit_device(fDeviceData);
1232 
1233 	fDeviceModule = NULL;
1234 	fDeviceData = NULL;
1235 
1236 	put_module(ModuleName());
1237 
1238 	fNode->UninitDriver();
1239 }
1240 
1241 
1242 void
1243 Device::Removed()
1244 {
1245 	RecursiveLocker _(sLock);
1246 
1247 	if (!fRemovedFromParent)
1248 		fNode->RemoveDevice(this);
1249 
1250 	delete this;
1251 }
1252 
1253 
1254 //	#pragma mark - device_node
1255 
1256 
1257 device_node::device_node(const char* moduleName, const device_attr* attrs)
1258 {
1259 	fModuleName = strdup(moduleName);
1260 	if (fModuleName == NULL)
1261 		return;
1262 
1263 	fParent = NULL;
1264 	fRefCount = 1;
1265 	fInitialized = 0;
1266 	fRegistered = false;
1267 	fFlags = 0;
1268 	fSupportsParent = 0.0;
1269 	fLastUpdateCycle = 0;
1270 	fDriver = NULL;
1271 	fDriverData = NULL;
1272 
1273 	// copy attributes
1274 
1275 	while (attrs != NULL && attrs->name != NULL) {
1276 		device_attr_private* attr
1277 			= new(std::nothrow) device_attr_private(*attrs);
1278 		if (attr == NULL)
1279 			break;
1280 
1281 		fAttributes.Add(attr);
1282 		attrs++;
1283 	}
1284 
1285 	device_attr_private* attr = new(std::nothrow) device_attr_private();
1286 	if (attr != NULL) {
1287 		attr->name = strdup("device/driver");
1288 		attr->type = B_STRING_TYPE;
1289 		attr->value.string = strdup(fModuleName);
1290 		fAttributes.Add(attr);
1291 	}
1292 
1293 	get_attr_uint32(this, B_DEVICE_FLAGS, &fFlags, false);
1294 	fFlags &= NODE_FLAG_PUBLIC_MASK;
1295 }
1296 
1297 
1298 device_node::~device_node()
1299 {
1300 	TRACE(("delete node %p\n", this));
1301 	ASSERT(DriverModule() == NULL);
1302 
1303 	if (Parent() != NULL) {
1304 		if ((fFlags & NODE_FLAG_OBSOLETE_DRIVER) != 0) {
1305 			// This driver has been obsoleted; another driver has been waiting
1306 			// for us - make it available
1307 			Parent()->_ReleaseWaiting();
1308 		}
1309 		Parent()->RemoveChild(this);
1310 	}
1311 
1312 	// Delete children
1313 	while (device_node* child = fChildren.RemoveHead()) {
1314 		delete child;
1315 	}
1316 
1317 	// Delete devices
1318 	while (Device* device = fDevices.RemoveHead()) {
1319 		device->SetRemovedFromParent(true);
1320 		devfs_unpublish_device(device, true);
1321 	}
1322 
1323 	// Delete attributes
1324 	while (device_attr_private* attr = fAttributes.RemoveHead()) {
1325 		delete attr;
1326 	}
1327 
1328 	// Delete resources
1329 	while (io_resource_private* resource = fResources.RemoveHead()) {
1330 		delete resource;
1331 	}
1332 
1333 	free((char*)fModuleName);
1334 }
1335 
1336 
1337 status_t
1338 device_node::InitCheck() const
1339 {
1340 	return fModuleName != NULL ? B_OK : B_NO_MEMORY;
1341 }
1342 
1343 
1344 status_t
1345 device_node::AcquireResources(const io_resource* resources)
1346 {
1347 	if (resources == NULL)
1348 		return B_OK;
1349 
1350 	for (uint32 i = 0; resources[i].type != 0; i++) {
1351 		io_resource_private* resource = new(std::nothrow) io_resource_private;
1352 		if (resource == NULL)
1353 			return B_NO_MEMORY;
1354 
1355 		status_t status = resource->Acquire(resources[i]);
1356 		if (status != B_OK) {
1357 			delete resource;
1358 			return status;
1359 		}
1360 
1361 		fResources.Add(resource);
1362 	}
1363 
1364 	return B_OK;
1365 }
1366 
1367 
1368 status_t
1369 device_node::InitDriver()
1370 {
1371 	if (fInitialized++ > 0) {
1372 		if (Parent() != NULL) {
1373 			Parent()->InitDriver();
1374 				// acquire another reference to our parent as well
1375 		}
1376 		Acquire();
1377 		return B_OK;
1378 	}
1379 
1380 	status_t status = get_module(ModuleName(), (module_info**)&fDriver);
1381 	if (status == B_OK && Parent() != NULL) {
1382 		// our parent always has to be initialized
1383 		status = Parent()->InitDriver();
1384 	}
1385 	if (status < B_OK) {
1386 		fInitialized--;
1387 		return status;
1388 	}
1389 
1390 	if (fDriver->init_driver != NULL) {
1391 		status = fDriver->init_driver(this, &fDriverData);
1392 		if (status != B_OK) {
1393 			dprintf("driver %s init failed: %s\n", ModuleName(),
1394 				strerror(status));
1395 		}
1396 	}
1397 
1398 	if (status < B_OK) {
1399 		if (Parent() != NULL)
1400 			Parent()->UninitDriver();
1401 		fInitialized--;
1402 
1403 		put_module(ModuleName());
1404 		fDriver = NULL;
1405 		fDriverData = NULL;
1406 		return status;
1407 	}
1408 
1409 	Acquire();
1410 	return B_OK;
1411 }
1412 
1413 
1414 bool
1415 device_node::UninitDriver()
1416 {
1417 	if (fInitialized-- > 1) {
1418 		if (Parent() != NULL)
1419 			Parent()->UninitDriver();
1420 		Release();
1421 		return false;
1422 	}
1423 
1424 	TRACE(("uninit driver for node %p\n", this));
1425 
1426 	if (fDriver->uninit_driver != NULL)
1427 		fDriver->uninit_driver(fDriverData);
1428 
1429 	fDriver = NULL;
1430 	fDriverData = NULL;
1431 
1432 	put_module(ModuleName());
1433 
1434 	if (Parent() != NULL)
1435 		Parent()->UninitDriver();
1436 	Release();
1437 
1438 	return true;
1439 }
1440 
1441 
1442 void
1443 device_node::AddChild(device_node* node)
1444 {
1445 	// we must not be destroyed	as long as we have children
1446 	Acquire();
1447 	node->fParent = this;
1448 
1449 	int32 priority = node->Priority();
1450 
1451 	// Enforce an order in which the children are traversed - from most
1452 	// specific to least specific child.
1453 	NodeList::Iterator iterator = fChildren.GetIterator();
1454 	device_node* before = NULL;
1455 	while (iterator.HasNext()) {
1456 		device_node* child = iterator.Next();
1457 		if (child->Priority() <= priority) {
1458 			before = child;
1459 			break;
1460 		}
1461 	}
1462 
1463 	fChildren.Insert(before, node);
1464 }
1465 
1466 
1467 void
1468 device_node::RemoveChild(device_node* node)
1469 {
1470 	node->fParent = NULL;
1471 	fChildren.Remove(node);
1472 	Release();
1473 }
1474 
1475 
1476 /*!	Registers this node, and all of its children that have to be registered.
1477 	Also initializes the driver and keeps it that way on return in case
1478 	it returns successfully.
1479 */
1480 status_t
1481 device_node::Register(device_node* parent)
1482 {
1483 	// make it public
1484 	if (parent != NULL)
1485 		parent->AddChild(this);
1486 	else
1487 		sRootNode = this;
1488 
1489 	status_t status = InitDriver();
1490 	if (status != B_OK)
1491 		return status;
1492 
1493 	if ((fFlags & B_KEEP_DRIVER_LOADED) != 0) {
1494 		// We keep this driver loaded by having it always initialized
1495 		InitDriver();
1496 	}
1497 
1498 	fFlags |= NODE_FLAG_REGISTER_INITIALIZED;
1499 		// We don't uninitialize the driver - this is done by the caller
1500 		// in order to save reinitializing during driver loading.
1501 
1502 	uint32 registeredFixedCount;
1503 	status = _RegisterFixed(registeredFixedCount);
1504 	if (status != B_OK) {
1505 		UninitUnusedDriver();
1506 		return status;
1507 	}
1508 
1509 	// Register the children the driver wants
1510 
1511 	if (DriverModule()->register_child_devices != NULL) {
1512 		status = DriverModule()->register_child_devices(DriverData());
1513 		if (status != B_OK) {
1514 			UninitUnusedDriver();
1515 			return status;
1516 		}
1517 
1518 		if (!fChildren.IsEmpty()) {
1519 			fRegistered = true;
1520 			return B_OK;
1521 		}
1522 	}
1523 
1524 	if (registeredFixedCount > 0) {
1525 		// Nodes with fixed children cannot have any dynamic children, so bail
1526 		// out here
1527 		fRegistered = true;
1528 		return B_OK;
1529 	}
1530 
1531 	// Register all possible child device nodes
1532 
1533 	status = _RegisterDynamic();
1534 	if (status == B_OK)
1535 		fRegistered = true;
1536 	else
1537 		UninitUnusedDriver();
1538 
1539 	return status;
1540 }
1541 
1542 
1543 /*!	Registers any children that are identified via the B_DEVICE_FIXED_CHILD
1544 	attribute.
1545 	If any of these children cannot be registered, this call will fail (we
1546 	don't remove children we already registered up to this point in this case).
1547 */
1548 status_t
1549 device_node::_RegisterFixed(uint32& registered)
1550 {
1551 	AttributeList::Iterator iterator = fAttributes.GetIterator();
1552 	registered = 0;
1553 
1554 	while (iterator.HasNext()) {
1555 		device_attr_private* attr = iterator.Next();
1556 		if (strcmp(attr->name, B_DEVICE_FIXED_CHILD))
1557 			continue;
1558 
1559 		driver_module_info* driver;
1560 		status_t status = get_module(attr->value.string,
1561 			(module_info**)&driver);
1562 		if (status != B_OK) {
1563 			TRACE(("register fixed child %s failed: %s\n", attr->value.string,
1564 				strerror(status)));
1565 			return status;
1566 		}
1567 
1568 		if (driver->register_device != NULL) {
1569 			status = driver->register_device(this);
1570 			if (status == B_OK)
1571 				registered++;
1572 		}
1573 
1574 		put_module(attr->value.string);
1575 
1576 		if (status != B_OK)
1577 			return status;
1578 	}
1579 
1580 	return B_OK;
1581 }
1582 
1583 
1584 status_t
1585 device_node::_AddPath(Stack<KPath*>& stack, const char* basePath,
1586 	const char* subPath)
1587 {
1588 	KPath* path = new(std::nothrow) KPath;
1589 	if (path == NULL)
1590 		return B_NO_MEMORY;
1591 
1592 	status_t status = path->SetTo(basePath);
1593 	if (status == B_OK && subPath != NULL && subPath[0])
1594 		status = path->Append(subPath);
1595 	if (status == B_OK)
1596 		status = stack.Push(path);
1597 
1598 	TRACE(("  add path: \"%s\", %" B_PRId32 "\n", path->Path(), status));
1599 
1600 	if (status != B_OK)
1601 		delete path;
1602 
1603 	return status;
1604 }
1605 
1606 
1607 status_t
1608 device_node::_GetNextDriverPath(void*& cookie, KPath& _path)
1609 {
1610 	Stack<KPath*>* stack = NULL;
1611 
1612 	if (cookie == NULL) {
1613 		// find all paths and add them
1614 		stack = new(std::nothrow) Stack<KPath*>();
1615 		if (stack == NULL)
1616 			return B_NO_MEMORY;
1617 
1618 		StackDeleter<KPath*> stackDeleter(stack);
1619 
1620 		bool generic = false;
1621 		uint16 type = 0;
1622 		uint16 subType = 0;
1623 		uint16 interface = 0;
1624 		if (get_attr_uint16(this, B_DEVICE_TYPE, &type, false) != B_OK
1625 			|| get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false)
1626 					!= B_OK)
1627 			generic = true;
1628 
1629 		get_attr_uint16(this, B_DEVICE_INTERFACE, &interface, false);
1630 
1631 		// TODO: maybe make this extendible via settings file?
1632 		switch (type) {
1633 			case PCI_mass_storage:
1634 				switch (subType) {
1635 					case PCI_scsi:
1636 						_AddPath(*stack, "busses", "scsi");
1637 						_AddPath(*stack, "busses", "virtio");
1638 						break;
1639 					case PCI_ide:
1640 						_AddPath(*stack, "busses", "ata");
1641 						_AddPath(*stack, "busses", "ide");
1642 						break;
1643 					case PCI_sata:
1644 						// TODO: check for ahci interface
1645 						_AddPath(*stack, "busses", "scsi");
1646 						_AddPath(*stack, "busses", "ata");
1647 						_AddPath(*stack, "busses", "ide");
1648 						break;
1649 					case PCI_nvm:
1650 						_AddPath(*stack, "drivers", "disk");
1651 						break;
1652 					default:
1653 						_AddPath(*stack, "busses");
1654 						break;
1655 				}
1656 				break;
1657 			case PCI_serial_bus:
1658 				switch (subType) {
1659 					case PCI_firewire:
1660 						_AddPath(*stack, "busses", "firewire");
1661 						break;
1662 					case PCI_usb:
1663 						_AddPath(*stack, "busses", "usb");
1664 						break;
1665 					default:
1666 						_AddPath(*stack, "busses");
1667 						break;
1668 				}
1669 				break;
1670 			case PCI_network:
1671 				_AddPath(*stack, "drivers", "net");
1672 				_AddPath(*stack, "busses", "virtio");
1673 				break;
1674 			case PCI_display:
1675 				_AddPath(*stack, "drivers", "graphics");
1676 				break;
1677 			case PCI_multimedia:
1678 				switch (subType) {
1679 					case PCI_audio:
1680 					case PCI_hd_audio:
1681 						_AddPath(*stack, "drivers", "audio");
1682 						break;
1683 					case PCI_video:
1684 						_AddPath(*stack, "drivers", "video");
1685 						break;
1686 					default:
1687 						_AddPath(*stack, "drivers");
1688 						break;
1689 				}
1690 				break;
1691 			case PCI_base_peripheral:
1692 				switch (subType) {
1693 					case PCI_sd_host:
1694 						_AddPath(*stack, "busses", "mmc");
1695 						break;
1696 					case PCI_system_peripheral_other:
1697 						_AddPath(*stack, "busses", "mmc");
1698 						_AddPath(*stack, "drivers");
1699 						break;
1700 					default:
1701 						_AddPath(*stack, "drivers");
1702 						break;
1703 				}
1704 				break;
1705 			case PCI_data_acquisition:
1706 				switch (subType) {
1707 					case PCI_data_acquisition_other:
1708 						_AddPath(*stack, "busses", "i2c");
1709 						break;
1710 					default:
1711 						_AddPath(*stack, "drivers");
1712 						break;
1713 				}
1714 				break;
1715 			default:
1716 				if (sRootNode == this) {
1717 					_AddPath(*stack, "busses/pci");
1718 					_AddPath(*stack, "bus_managers");
1719 				} else if (!generic) {
1720 					_AddPath(*stack, "busses", "virtio");
1721 					_AddPath(*stack, "drivers");
1722 				} else {
1723 					// For generic drivers, we only allow busses when the
1724 					// request is more specified
1725 					if (sGenericContextPath != NULL
1726 						&& (!strcmp(sGenericContextPath, "disk")
1727 							|| !strcmp(sGenericContextPath, "ports")
1728 							|| !strcmp(sGenericContextPath, "bus"))) {
1729 						_AddPath(*stack, "busses");
1730 					}
1731 					_AddPath(*stack, "drivers", sGenericContextPath);
1732 					_AddPath(*stack, "busses/i2c");
1733 					_AddPath(*stack, "busses/scsi");
1734 					_AddPath(*stack, "busses/random");
1735 					_AddPath(*stack, "bus_managers/pci");
1736 				}
1737 				break;
1738 		}
1739 
1740 		stackDeleter.Detach();
1741 
1742 		cookie = (void*)stack;
1743 	} else
1744 		stack = static_cast<Stack<KPath*>*>(cookie);
1745 
1746 	KPath* path;
1747 	if (stack->Pop(&path)) {
1748 		_path.Adopt(*path);
1749 		delete path;
1750 		return B_OK;
1751 	}
1752 
1753 	delete stack;
1754 	return B_ENTRY_NOT_FOUND;
1755 }
1756 
1757 
1758 status_t
1759 device_node::_GetNextDriver(void* list, driver_module_info*& driver)
1760 {
1761 	while (true) {
1762 		char name[B_FILE_NAME_LENGTH];
1763 		size_t nameLength = sizeof(name);
1764 
1765 		status_t status = read_next_module_name(list, name, &nameLength);
1766 		if (status != B_OK)
1767 			return status;
1768 
1769 		if (!strcmp(fModuleName, name))
1770 			continue;
1771 
1772 		if (get_module(name, (module_info**)&driver) != B_OK)
1773 			continue;
1774 
1775 		if (driver->supports_device == NULL
1776 			|| driver->register_device == NULL) {
1777 			put_module(name);
1778 			continue;
1779 		}
1780 
1781 		return B_OK;
1782 	}
1783 }
1784 
1785 
1786 status_t
1787 device_node::_FindBestDriver(const char* path, driver_module_info*& bestDriver,
1788 	float& bestSupport, device_node* previous)
1789 {
1790 	if (bestDriver == NULL)
1791 		bestSupport = previous != NULL ? previous->fSupportsParent : 0.0f;
1792 
1793 	void* list = open_module_list_etc(path, "driver_v1");
1794 	driver_module_info* driver;
1795 	while (_GetNextDriver(list, driver) == B_OK) {
1796 		if (previous != NULL && driver == previous->DriverModule()) {
1797 			put_module(driver->info.name);
1798 			continue;
1799 		}
1800 
1801 		float support = driver->supports_device(this);
1802 		if (support > bestSupport) {
1803 			if (bestDriver != NULL)
1804 				put_module(bestDriver->info.name);
1805 
1806 			bestDriver = driver;
1807 			bestSupport = support;
1808 			continue;
1809 				// keep reference to best module around
1810 		}
1811 
1812 		put_module(driver->info.name);
1813 	}
1814 	close_module_list(list);
1815 
1816 	return bestDriver != NULL ? B_OK : B_ENTRY_NOT_FOUND;
1817 }
1818 
1819 
1820 status_t
1821 device_node::_RegisterPath(const char* path)
1822 {
1823 	void* list = open_module_list_etc(path, "driver_v1");
1824 	driver_module_info* driver;
1825 	uint32 count = 0;
1826 
1827 	while (_GetNextDriver(list, driver) == B_OK) {
1828 		float support = driver->supports_device(this);
1829 		if (support > 0.0) {
1830 			TRACE(("  register module \"%s\", support %f\n", driver->info.name,
1831 				support));
1832 			if (driver->register_device(this) == B_OK)
1833 				count++;
1834 		}
1835 
1836 		put_module(driver->info.name);
1837 	}
1838 	close_module_list(list);
1839 
1840 	return count > 0 ? B_OK : B_ENTRY_NOT_FOUND;
1841 }
1842 
1843 
1844 bool
1845 device_node::_AlwaysRegisterDynamic()
1846 {
1847 	uint16 type = 0;
1848 	uint16 subType = 0;
1849 	get_attr_uint16(this, B_DEVICE_TYPE, &type, false);
1850 	get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false);
1851 
1852 	return type == PCI_serial_bus || type == PCI_bridge || type == 0;
1853 		// TODO: we may want to be a bit more specific in the future
1854 }
1855 
1856 
1857 status_t
1858 device_node::_RegisterDynamic(device_node* previous)
1859 {
1860 	// If this is not a bus, we don't have to scan it
1861 	if (find_attr(this, B_DEVICE_BUS, false, B_STRING_TYPE) == NULL)
1862 		return B_OK;
1863 
1864 	// If we're not being probed, we honour the B_FIND_CHILD_ON_DEMAND
1865 	// requirements
1866 	if (!IsProbed() && (fFlags & B_FIND_CHILD_ON_DEMAND) != 0
1867 		&& !_AlwaysRegisterDynamic())
1868 		return B_OK;
1869 
1870 	KPath path;
1871 
1872 	if ((fFlags & B_FIND_MULTIPLE_CHILDREN) == 0) {
1873 		// find the one driver
1874 		driver_module_info* bestDriver = NULL;
1875 		float bestSupport = 0.0;
1876 		void* cookie = NULL;
1877 
1878 		while (_GetNextDriverPath(cookie, path) == B_OK) {
1879 			_FindBestDriver(path.Path(), bestDriver, bestSupport, previous);
1880 		}
1881 
1882 		if (bestDriver != NULL) {
1883 			TRACE(("  register best module \"%s\", support %f\n",
1884 				bestDriver->info.name, bestSupport));
1885 			if (bestDriver->register_device(this) == B_OK) {
1886 				// There can only be one node of this driver
1887 				// (usually only one at all, but there might be a new driver
1888 				// "waiting" for its turn)
1889 				device_node* child = FindChild(bestDriver->info.name);
1890 				if (child != NULL) {
1891 					child->fSupportsParent = bestSupport;
1892 					if (previous != NULL) {
1893 						previous->fFlags |= NODE_FLAG_OBSOLETE_DRIVER;
1894 						previous->Release();
1895 						child->fFlags |= NODE_FLAG_WAITING_FOR_DRIVER;
1896 					}
1897 				}
1898 				// TODO: if this fails, we could try the second best driver,
1899 				// and so on...
1900 			}
1901 			put_module(bestDriver->info.name);
1902 		}
1903 	} else {
1904 		// register all drivers that match
1905 		void* cookie = NULL;
1906 		while (_GetNextDriverPath(cookie, path) == B_OK) {
1907 			_RegisterPath(path.Path());
1908 		}
1909 	}
1910 
1911 	return B_OK;
1912 }
1913 
1914 
1915 void
1916 device_node::_ReleaseWaiting()
1917 {
1918 	NodeList::Iterator iterator = fChildren.GetIterator();
1919 	while (iterator.HasNext()) {
1920 		device_node* child = iterator.Next();
1921 
1922 		child->fFlags &= ~NODE_FLAG_WAITING_FOR_DRIVER;
1923 	}
1924 }
1925 
1926 
1927 status_t
1928 device_node::_RemoveChildren()
1929 {
1930 	NodeList::Iterator iterator = fChildren.GetIterator();
1931 	while (iterator.HasNext()) {
1932 		device_node* child = iterator.Next();
1933 		child->Release();
1934 	}
1935 
1936 	return fChildren.IsEmpty() ? B_OK : B_BUSY;
1937 }
1938 
1939 
1940 device_node*
1941 device_node::_FindCurrentChild()
1942 {
1943 	NodeList::Iterator iterator = fChildren.GetIterator();
1944 	while (iterator.HasNext()) {
1945 		device_node* child = iterator.Next();
1946 
1947 		if ((child->Flags() & NODE_FLAG_WAITING_FOR_DRIVER) == 0)
1948 			return child;
1949 	}
1950 
1951 	return NULL;
1952 }
1953 
1954 
1955 status_t
1956 device_node::_Probe()
1957 {
1958 	device_node* previous = NULL;
1959 
1960 	if (IsProbed() && !fChildren.IsEmpty()
1961 		&& (fFlags & (B_FIND_CHILD_ON_DEMAND | B_FIND_MULTIPLE_CHILDREN))
1962 				== B_FIND_CHILD_ON_DEMAND) {
1963 		// We already have a driver that claims this node; remove all
1964 		// (unused) nodes, and evaluate it again
1965 		_RemoveChildren();
1966 
1967 		previous = _FindCurrentChild();
1968 		if (previous != NULL) {
1969 			// This driver is still active - give it back the reference
1970 			// that was stolen by _RemoveChildren() - _RegisterDynamic()
1971 			// will release it, if it really isn't needed anymore
1972 			previous->Acquire();
1973 		}
1974 	}
1975 
1976 	return _RegisterDynamic(previous);
1977 }
1978 
1979 
1980 status_t
1981 device_node::Probe(const char* devicePath, uint32 updateCycle)
1982 {
1983 	if ((fFlags & NODE_FLAG_DEVICE_REMOVED) != 0
1984 		|| updateCycle == fLastUpdateCycle)
1985 		return B_OK;
1986 
1987 	status_t status = InitDriver();
1988 	if (status < B_OK)
1989 		return status;
1990 
1991 	MethodDeleter<device_node, bool, &device_node::UninitDriver> uninit(this);
1992 
1993 	if ((fFlags & B_FIND_CHILD_ON_DEMAND) != 0) {
1994 		bool matches = false;
1995 		uint16 type = 0;
1996 		uint16 subType = 0;
1997 		if (get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false) == B_OK
1998 			&& get_attr_uint16(this, B_DEVICE_TYPE, &type, false) == B_OK) {
1999 			// Check if this node matches the device path
2000 			// TODO: maybe make this extendible via settings file?
2001 			if (!strcmp(devicePath, "disk")) {
2002 				matches = type == PCI_mass_storage
2003 					|| (type == PCI_base_peripheral
2004 						&& (subType == PCI_sd_host
2005 							|| subType == PCI_system_peripheral_other));
2006 			} else if (!strcmp(devicePath, "audio")) {
2007 				matches = type == PCI_multimedia
2008 					&& (subType == PCI_audio || subType == PCI_hd_audio);
2009 			} else if (!strcmp(devicePath, "net")) {
2010 				matches = type == PCI_network;
2011 			} else if (!strcmp(devicePath, "graphics")) {
2012 				matches = type == PCI_display;
2013 			} else if (!strcmp(devicePath, "video")) {
2014 				matches = type == PCI_multimedia && subType == PCI_video;
2015 			} else if (!strcmp(devicePath, "power")) {
2016 				matches = type == PCI_data_acquisition;
2017 			} else if (!strcmp(devicePath, "input")) {
2018 				matches = type == PCI_data_acquisition
2019 					&& subType == PCI_data_acquisition_other;
2020 			}
2021 		} else {
2022 			// This driver does not support types, but still wants to its
2023 			// children explored on demand only.
2024 			matches = true;
2025 			sGenericContextPath = devicePath;
2026 		}
2027 
2028 		if (matches) {
2029 			fLastUpdateCycle = updateCycle;
2030 				// This node will be probed in this update cycle
2031 
2032 			status = _Probe();
2033 
2034 			sGenericContextPath = NULL;
2035 			return status;
2036 		}
2037 
2038 		return B_OK;
2039 	}
2040 
2041 	NodeList::Iterator iterator = fChildren.GetIterator();
2042 	while (iterator.HasNext()) {
2043 		device_node* child = iterator.Next();
2044 
2045 		status = child->Probe(devicePath, updateCycle);
2046 		if (status != B_OK)
2047 			return status;
2048 	}
2049 
2050 	return B_OK;
2051 }
2052 
2053 
2054 status_t
2055 device_node::Reprobe()
2056 {
2057 	status_t status = InitDriver();
2058 	if (status < B_OK)
2059 		return status;
2060 
2061 	MethodDeleter<device_node, bool, &device_node::UninitDriver> uninit(this);
2062 
2063 	// If this child has been probed already, probe it again
2064 	status = _Probe();
2065 	if (status != B_OK)
2066 		return status;
2067 
2068 	NodeList::Iterator iterator = fChildren.GetIterator();
2069 	while (iterator.HasNext()) {
2070 		device_node* child = iterator.Next();
2071 
2072 		status = child->Reprobe();
2073 		if (status != B_OK)
2074 			return status;
2075 	}
2076 
2077 	return B_OK;
2078 }
2079 
2080 
2081 status_t
2082 device_node::Rescan()
2083 {
2084 	status_t status = InitDriver();
2085 	if (status < B_OK)
2086 		return status;
2087 
2088 	MethodDeleter<device_node, bool, &device_node::UninitDriver> uninit(this);
2089 
2090 	if (DriverModule()->rescan_child_devices != NULL) {
2091 		status = DriverModule()->rescan_child_devices(DriverData());
2092 		if (status != B_OK)
2093 			return status;
2094 	}
2095 
2096 	NodeList::Iterator iterator = fChildren.GetIterator();
2097 	while (iterator.HasNext()) {
2098 		device_node* child = iterator.Next();
2099 
2100 		status = child->Rescan();
2101 		if (status != B_OK)
2102 			return status;
2103 	}
2104 
2105 	return B_OK;
2106 }
2107 
2108 
2109 /*!	Uninitializes all temporary references to the driver. The registration
2110 	process keeps the driver initialized to optimize the startup procedure;
2111 	this function gives this reference away again.
2112 */
2113 void
2114 device_node::UninitUnusedDriver()
2115 {
2116 	// First, we need to go to the leaf, and go back from there
2117 
2118 	NodeList::Iterator iterator = fChildren.GetIterator();
2119 	while (iterator.HasNext()) {
2120 		device_node* child = iterator.Next();
2121 
2122 		child->UninitUnusedDriver();
2123 	}
2124 
2125 	if (!IsInitialized()
2126 		|| (fFlags & NODE_FLAG_REGISTER_INITIALIZED) == 0)
2127 		return;
2128 
2129 	fFlags &= ~NODE_FLAG_REGISTER_INITIALIZED;
2130 
2131 	UninitDriver();
2132 }
2133 
2134 
2135 /*!	Calls device_removed() on this node and all of its children - starting
2136 	with the deepest and last child.
2137 	It will also remove the one reference that every node gets on its creation.
2138 */
2139 void
2140 device_node::DeviceRemoved()
2141 {
2142 	// notify children
2143 	NodeList::ConstIterator iterator = Children().GetIterator();
2144 	while (iterator.HasNext()) {
2145 		device_node* child = iterator.Next();
2146 
2147 		child->DeviceRemoved();
2148 	}
2149 
2150 	// notify devices
2151 	DeviceList::ConstIterator deviceIterator = Devices().GetIterator();
2152 	while (deviceIterator.HasNext()) {
2153 		Device* device = deviceIterator.Next();
2154 
2155 		if (device->Module() != NULL
2156 			&& device->Module()->device_removed != NULL)
2157 			device->Module()->device_removed(device->Data());
2158 	}
2159 
2160 	fFlags |= NODE_FLAG_DEVICE_REMOVED;
2161 
2162 	if (IsInitialized() && DriverModule()->device_removed != NULL)
2163 		DriverModule()->device_removed(this);
2164 
2165 	if ((fFlags & B_KEEP_DRIVER_LOADED) != 0) {
2166 		// There is no point in keeping this driver loaded when its device
2167 		// is gone
2168 		UninitDriver();
2169 	}
2170 
2171 	UninitUnusedDriver();
2172 	Release();
2173 }
2174 
2175 
2176 void
2177 device_node::Acquire()
2178 {
2179 	atomic_add(&fRefCount, 1);
2180 }
2181 
2182 
2183 bool
2184 device_node::Release()
2185 {
2186 	if (atomic_add(&fRefCount, -1) > 1)
2187 		return false;
2188 
2189 	delete this;
2190 	return true;
2191 }
2192 
2193 
2194 void
2195 device_node::AddDevice(Device* device)
2196 {
2197 	fDevices.Add(device);
2198 }
2199 
2200 
2201 void
2202 device_node::RemoveDevice(Device* device)
2203 {
2204 	char attrName[256];
2205 	device_attr_private* attr;
2206 
2207 	sprintf(attrName, "dev/%" B_PRIdINO "/path", device->ID());
2208 	attr = find_attr(this, attrName, false, B_STRING_TYPE);
2209 	if (attr != NULL) {
2210 		fAttributes.Remove(attr);
2211 		delete attr;
2212 	}
2213 
2214 	sprintf(attrName, "dev/%" B_PRIdINO "/driver", device->ID());
2215 	attr = find_attr(this, attrName, false, B_STRING_TYPE);
2216 	if (attr != NULL) {
2217 		fAttributes.Remove(attr);
2218 		delete attr;
2219 	}
2220 
2221 	fDevices.Remove(device);
2222 }
2223 
2224 
2225 int
2226 device_node::CompareTo(const device_attr* attributes) const
2227 {
2228 	if (attributes == NULL)
2229 		return -1;
2230 
2231 	for (; attributes->name != NULL; attributes++) {
2232 		// find corresponding attribute
2233 		AttributeList::ConstIterator iterator = Attributes().GetIterator();
2234 		device_attr_private* attr = NULL;
2235 		bool found = false;
2236 
2237 		while (iterator.HasNext()) {
2238 			attr = iterator.Next();
2239 
2240 			if (!strcmp(attr->name, attributes->name)) {
2241 				found = true;
2242 				break;
2243 			}
2244 		}
2245 		if (!found)
2246 			return -1;
2247 
2248 		int compare = device_attr_private::Compare(attr, attributes);
2249 		if (compare != 0)
2250 			return compare;
2251 	}
2252 
2253 	return 0;
2254 }
2255 
2256 
2257 device_node*
2258 device_node::FindChild(const device_attr* attributes) const
2259 {
2260 	if (attributes == NULL)
2261 		return NULL;
2262 
2263 	NodeList::ConstIterator iterator = Children().GetIterator();
2264 	while (iterator.HasNext()) {
2265 		device_node* child = iterator.Next();
2266 
2267 		// ignore nodes that are pending to be removed
2268 		if ((child->Flags() & NODE_FLAG_DEVICE_REMOVED) == 0
2269 			&& !child->CompareTo(attributes))
2270 			return child;
2271 	}
2272 
2273 	return NULL;
2274 }
2275 
2276 
2277 device_node*
2278 device_node::FindChild(const char* moduleName) const
2279 {
2280 	if (moduleName == NULL)
2281 		return NULL;
2282 
2283 	NodeList::ConstIterator iterator = Children().GetIterator();
2284 	while (iterator.HasNext()) {
2285 		device_node* child = iterator.Next();
2286 
2287 		if (!strcmp(child->ModuleName(), moduleName))
2288 			return child;
2289 	}
2290 
2291 	return NULL;
2292 }
2293 
2294 
2295 /*!	This returns the priority or importance of this node. Nodes with higher
2296 	priority are registered/probed first.
2297 	Currently, only the B_FIND_MULTIPLE_CHILDREN flag alters the priority;
2298 	it might make sense to be able to directly set the priority via an
2299 	attribute.
2300 */
2301 int32
2302 device_node::Priority()
2303 {
2304 	return (fFlags & B_FIND_MULTIPLE_CHILDREN) != 0 ? 0 : 100;
2305 }
2306 
2307 
2308 void
2309 device_node::Dump(int32 level)
2310 {
2311 	put_level(level);
2312 	kprintf("(%" B_PRId32 ") @%p \"%s\" (ref %" B_PRId32 ", init %" B_PRId32
2313 		", module %p, data %p)\n", level, this, ModuleName(), fRefCount,
2314 		fInitialized, DriverModule(), DriverData());
2315 
2316 	AttributeList::Iterator attribute = Attributes().GetIterator();
2317 	while (attribute.HasNext()) {
2318 		dump_attribute(attribute.Next(), level);
2319 	}
2320 
2321 	DeviceList::Iterator deviceIterator = fDevices.GetIterator();
2322 	while (deviceIterator.HasNext()) {
2323 		Device* device = deviceIterator.Next();
2324 		put_level(level);
2325 		kprintf("device: %s, %p\n", device->ModuleName(), device->Data());
2326 	}
2327 
2328 	NodeList::ConstIterator iterator = Children().GetIterator();
2329 	while (iterator.HasNext()) {
2330 		iterator.Next()->Dump(level + 1);
2331 	}
2332 }
2333 
2334 
2335 //	#pragma mark - root node
2336 
2337 
2338 static void
2339 init_node_tree(void)
2340 {
2341 	device_attr attrs[] = {
2342 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Devices Root"}},
2343 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "root"}},
2344 		{B_DEVICE_FLAGS, B_UINT32_TYPE,
2345 			{ui32: B_FIND_MULTIPLE_CHILDREN | B_KEEP_DRIVER_LOADED }},
2346 		{NULL}
2347 	};
2348 
2349 	device_node* node = NULL;
2350 	if (register_node(NULL, DEVICE_MANAGER_ROOT_NAME, attrs, NULL, &node)
2351 			!= B_OK) {
2352 		dprintf("Cannot register Devices Root Node\n");
2353 	}
2354 
2355 	device_attr genericAttrs[] = {
2356 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Generic"}},
2357 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "generic"}},
2358 		{B_DEVICE_FLAGS, B_UINT32_TYPE, {ui32: B_FIND_MULTIPLE_CHILDREN
2359 			| B_KEEP_DRIVER_LOADED | B_FIND_CHILD_ON_DEMAND}},
2360 		{NULL}
2361 	};
2362 
2363 	if (register_node(node, DEVICE_MANAGER_GENERIC_NAME, genericAttrs, NULL,
2364 			NULL) != B_OK) {
2365 		dprintf("Cannot register Generic Devices Node\n");
2366 	}
2367 }
2368 
2369 
2370 driver_module_info gDeviceRootModule = {
2371 	{
2372 		DEVICE_MANAGER_ROOT_NAME,
2373 		0,
2374 		NULL,
2375 	},
2376 };
2377 
2378 
2379 driver_module_info gDeviceGenericModule = {
2380 	{
2381 		DEVICE_MANAGER_GENERIC_NAME,
2382 		0,
2383 		NULL,
2384 	},
2385 	NULL
2386 };
2387 
2388 
2389 //	#pragma mark - private kernel API
2390 
2391 
2392 status_t
2393 device_manager_probe(const char* path, uint32 updateCycle)
2394 {
2395 	TRACE(("device_manager_probe(\"%s\")\n", path));
2396 	RecursiveLocker _(sLock);
2397 
2398 	// first, publish directories in the driver directory
2399 	publish_directories(path);
2400 
2401 	return sRootNode->Probe(path, updateCycle);
2402 }
2403 
2404 
2405 status_t
2406 device_manager_init(struct kernel_args* args)
2407 {
2408 	TRACE(("device manager init\n"));
2409 
2410 	IOSchedulerRoster::Init();
2411 
2412 	dm_init_id_generator();
2413 	dm_init_io_resources();
2414 
2415 	recursive_lock_init(&sLock, "device manager");
2416 
2417 	register_generic_syscall(DEVICE_MANAGER_SYSCALLS, control_device_manager,
2418 		1, 0);
2419 
2420 	add_debugger_command("dm_tree", &dump_device_nodes,
2421 		"dump device node tree");
2422 	add_debugger_command_etc("io_scheduler", &dump_io_scheduler,
2423 		"Dump an I/O scheduler",
2424 		"<scheduler>\n"
2425 		"Dumps I/O scheduler at address <scheduler>.\n", 0);
2426 	add_debugger_command_etc("io_request_owner", &dump_io_request_owner,
2427 		"Dump an I/O request owner",
2428 		"<owner>\n"
2429 		"Dumps I/O request owner at address <owner>.\n", 0);
2430 	add_debugger_command("io_request", &dump_io_request, "dump an I/O request");
2431 	add_debugger_command("io_operation", &dump_io_operation,
2432 		"dump an I/O operation");
2433 	add_debugger_command("io_buffer", &dump_io_buffer, "dump an I/O buffer");
2434 	add_debugger_command("dma_buffer", &dump_dma_buffer, "dump a DMA buffer");
2435 
2436 	init_node_tree();
2437 
2438 	return B_OK;
2439 }
2440 
2441 
2442 status_t
2443 device_manager_init_post_modules(struct kernel_args* args)
2444 {
2445 	RecursiveLocker _(sLock);
2446 	return sRootNode->Reprobe();
2447 }
2448