xref: /haiku/src/system/kernel/device_manager/device_manager.cpp (revision 1a3518cf757c2da8006753f83962da5935bbc82b)
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 	return B_OK;
757 }
758 
759 
760 static status_t
761 unpublish_device(device_node *node, const char *path)
762 {
763 	if (path == NULL)
764 		return B_BAD_VALUE;
765 
766 	BaseDevice* baseDevice;
767 	status_t error = devfs_get_device(path, baseDevice);
768 	if (error != B_OK)
769 		return error;
770 	CObjectDeleter<BaseDevice> baseDevicePutter(baseDevice, &devfs_put_device);
771 
772 	Device* device = dynamic_cast<Device*>(baseDevice);
773 	if (device == NULL || device->Node() != node)
774 		return B_BAD_VALUE;
775 
776 	return devfs_unpublish_device(device, true);
777 }
778 
779 
780 static status_t
781 get_attr_uint8(const device_node* node, const char* name, uint8* _value,
782 	bool recursive)
783 {
784 	if (node == NULL || name == NULL || _value == NULL)
785 		return B_BAD_VALUE;
786 
787 	device_attr_private* attr = find_attr(node, name, recursive, B_UINT8_TYPE);
788 	if (attr == NULL)
789 		return B_NAME_NOT_FOUND;
790 
791 	*_value = attr->value.ui8;
792 	return B_OK;
793 }
794 
795 
796 static status_t
797 get_attr_uint16(const device_node* node, const char* name, uint16* _value,
798 	bool recursive)
799 {
800 	if (node == NULL || name == NULL || _value == NULL)
801 		return B_BAD_VALUE;
802 
803 	device_attr_private* attr = find_attr(node, name, recursive, B_UINT16_TYPE);
804 	if (attr == NULL)
805 		return B_NAME_NOT_FOUND;
806 
807 	*_value = attr->value.ui16;
808 	return B_OK;
809 }
810 
811 
812 static status_t
813 get_attr_uint32(const device_node* node, const char* name, uint32* _value,
814 	bool recursive)
815 {
816 	if (node == NULL || name == NULL || _value == NULL)
817 		return B_BAD_VALUE;
818 
819 	device_attr_private* attr = find_attr(node, name, recursive, B_UINT32_TYPE);
820 	if (attr == NULL)
821 		return B_NAME_NOT_FOUND;
822 
823 	*_value = attr->value.ui32;
824 	return B_OK;
825 }
826 
827 
828 static status_t
829 get_attr_uint64(const device_node* node, const char* name,
830 	uint64* _value, bool recursive)
831 {
832 	if (node == NULL || name == NULL || _value == NULL)
833 		return B_BAD_VALUE;
834 
835 	device_attr_private* attr = find_attr(node, name, recursive, B_UINT64_TYPE);
836 	if (attr == NULL)
837 		return B_NAME_NOT_FOUND;
838 
839 	*_value = attr->value.ui64;
840 	return B_OK;
841 }
842 
843 
844 static status_t
845 get_attr_string(const device_node* node, const char* name,
846 	const char** _value, bool recursive)
847 {
848 	if (node == NULL || name == NULL || _value == NULL)
849 		return B_BAD_VALUE;
850 
851 	device_attr_private* attr = find_attr(node, name, recursive, B_STRING_TYPE);
852 	if (attr == NULL)
853 		return B_NAME_NOT_FOUND;
854 
855 	*_value = attr->value.string;
856 	return B_OK;
857 }
858 
859 
860 static status_t
861 get_attr_raw(const device_node* node, const char* name, const void** _data,
862 	size_t* _length, bool recursive)
863 {
864 	if (node == NULL || name == NULL || (_data == NULL && _length == NULL))
865 		return B_BAD_VALUE;
866 
867 	device_attr_private* attr = find_attr(node, name, recursive, B_RAW_TYPE);
868 	if (attr == NULL)
869 		return B_NAME_NOT_FOUND;
870 
871 	if (_data != NULL)
872 		*_data = attr->value.raw.data;
873 	if (_length != NULL)
874 		*_length = attr->value.raw.length;
875 	return B_OK;
876 }
877 
878 
879 static status_t
880 get_next_attr(device_node* node, device_attr** _attr)
881 {
882 	if (node == NULL)
883 		return B_BAD_VALUE;
884 
885 	device_attr_private* next;
886 	device_attr_private* attr = *(device_attr_private**)_attr;
887 
888 	if (attr != NULL) {
889 		// next attribute
890 		next = attr->GetDoublyLinkedListLink()->next;
891 	} else {
892 		// first attribute
893 		next = node->Attributes().First();
894 	}
895 
896 	*_attr = next;
897 
898 	return next ? B_OK : B_ENTRY_NOT_FOUND;
899 }
900 
901 
902 static status_t
903 find_child_node(device_node* parent, const device_attr* attributes,
904 	device_node** _node, bool *_lastFound)
905 {
906 	RecursiveLocker _(sLock);
907 
908 	NodeList::ConstIterator iterator = parent->Children().GetIterator();
909 	device_node* last = *_node;
910 
911 	// find the next one that fits
912 	while (iterator.HasNext()) {
913 		device_node* node = iterator.Next();
914 
915 		if (!node->IsRegistered())
916 			continue;
917 
918 		if (node == last)
919 			*_lastFound = true;
920 		else if (!node->CompareTo(attributes) && *_lastFound) {
921 			if (last != NULL)
922 				last->Release();
923 
924 			node->Acquire();
925 			*_node = node;
926 			return B_OK;
927 		}
928 		if (find_child_node(node, attributes, _node, _lastFound) == B_OK)
929 			return B_OK;
930 	}
931 
932 	return B_ENTRY_NOT_FOUND;
933 }
934 
935 
936 static status_t
937 find_child_node(device_node* parent, const device_attr* attributes,
938 	device_node** _node)
939 {
940 	device_node* last = *_node;
941 	bool lastFound = last == NULL;
942 	status_t status = find_child_node(parent, attributes, _node, &lastFound);
943 	if (status == B_ENTRY_NOT_FOUND && last != NULL && lastFound)
944 		last->Release();
945 	return status;
946 }
947 
948 
949 struct device_manager_info gDeviceManagerModule = {
950 	{
951 		B_DEVICE_MANAGER_MODULE_NAME,
952 		0,
953 		NULL
954 	},
955 
956 	// device nodes
957 	rescan_node,
958 	register_node,
959 	unregister_node,
960 	get_driver,
961 	get_root_node,
962 	get_next_child_node,
963 	get_parent_node,
964 	put_node,
965 
966 	// devices
967 	publish_device,
968 	unpublish_device,
969 
970 	// I/O resources
971 
972 	// ID generator
973 	dm_create_id,
974 	dm_free_id,
975 
976 	// attributes
977 	get_attr_uint8,
978 	get_attr_uint16,
979 	get_attr_uint32,
980 	get_attr_uint64,
981 	get_attr_string,
982 	get_attr_raw,
983 	get_next_attr,
984 	find_child_node
985 };
986 
987 
988 //	#pragma mark - device_attr
989 
990 
991 device_attr_private::device_attr_private()
992 {
993 	name = NULL;
994 	type = 0;
995 	value.raw.data = NULL;
996 	value.raw.length = 0;
997 }
998 
999 
1000 device_attr_private::device_attr_private(const device_attr& attr)
1001 {
1002 	CopyFrom(attr);
1003 }
1004 
1005 
1006 device_attr_private::~device_attr_private()
1007 {
1008 	_Unset();
1009 }
1010 
1011 
1012 status_t
1013 device_attr_private::InitCheck()
1014 {
1015 	return name != NULL ? B_OK : B_NO_INIT;
1016 }
1017 
1018 
1019 status_t
1020 device_attr_private::CopyFrom(const device_attr& attr)
1021 {
1022 	name = strdup(attr.name);
1023 	if (name == NULL)
1024 		return B_NO_MEMORY;
1025 
1026 	type = attr.type;
1027 
1028 	switch (type) {
1029 		case B_UINT8_TYPE:
1030 		case B_UINT16_TYPE:
1031 		case B_UINT32_TYPE:
1032 		case B_UINT64_TYPE:
1033 			value.ui64 = attr.value.ui64;
1034 			break;
1035 
1036 		case B_STRING_TYPE:
1037 			if (attr.value.string != NULL) {
1038 				value.string = strdup(attr.value.string);
1039 				if (value.string == NULL) {
1040 					_Unset();
1041 					return B_NO_MEMORY;
1042 				}
1043 			} else
1044 				value.string = NULL;
1045 			break;
1046 
1047 		case B_RAW_TYPE:
1048 			value.raw.data = malloc(attr.value.raw.length);
1049 			if (value.raw.data == NULL) {
1050 				_Unset();
1051 				return B_NO_MEMORY;
1052 			}
1053 
1054 			value.raw.length = attr.value.raw.length;
1055 			memcpy((void*)value.raw.data, attr.value.raw.data,
1056 				attr.value.raw.length);
1057 			break;
1058 
1059 		default:
1060 			return B_BAD_VALUE;
1061 	}
1062 
1063 	return B_OK;
1064 }
1065 
1066 
1067 void
1068 device_attr_private::_Unset()
1069 {
1070 	if (type == B_STRING_TYPE)
1071 		free((char*)value.string);
1072 	else if (type == B_RAW_TYPE)
1073 		free((void*)value.raw.data);
1074 
1075 	free((char*)name);
1076 
1077 	name = NULL;
1078 	value.raw.data = NULL;
1079 	value.raw.length = 0;
1080 }
1081 
1082 
1083 /*static*/ int
1084 device_attr_private::Compare(const device_attr* attrA, const device_attr *attrB)
1085 {
1086 	if (attrA->type != attrB->type)
1087 		return -1;
1088 
1089 	switch (attrA->type) {
1090 		case B_UINT8_TYPE:
1091 			return (int)attrA->value.ui8 - (int)attrB->value.ui8;
1092 
1093 		case B_UINT16_TYPE:
1094 			return (int)attrA->value.ui16 - (int)attrB->value.ui16;
1095 
1096 		case B_UINT32_TYPE:
1097 			if (attrA->value.ui32 > attrB->value.ui32)
1098 				return 1;
1099 			if (attrA->value.ui32 < attrB->value.ui32)
1100 				return -1;
1101 			return 0;
1102 
1103 		case B_UINT64_TYPE:
1104 			if (attrA->value.ui64 > attrB->value.ui64)
1105 				return 1;
1106 			if (attrA->value.ui64 < attrB->value.ui64)
1107 				return -1;
1108 			return 0;
1109 
1110 		case B_STRING_TYPE:
1111 			return strcmp(attrA->value.string, attrB->value.string);
1112 
1113 		case B_RAW_TYPE:
1114 			if (attrA->value.raw.length != attrB->value.raw.length)
1115 				return -1;
1116 
1117 			return memcmp(attrA->value.raw.data, attrB->value.raw.data,
1118 				attrA->value.raw.length);
1119 	}
1120 
1121 	return -1;
1122 }
1123 
1124 
1125 //	#pragma mark - Device
1126 
1127 
1128 Device::Device(device_node* node, const char* moduleName)
1129 	:
1130 	fModuleName(strdup(moduleName)),
1131 	fRemovedFromParent(false)
1132 {
1133 	fNode = node;
1134 }
1135 
1136 
1137 Device::~Device()
1138 {
1139 	free((char*)fModuleName);
1140 }
1141 
1142 
1143 status_t
1144 Device::InitCheck() const
1145 {
1146 	return fModuleName != NULL ? B_OK : B_NO_MEMORY;
1147 }
1148 
1149 
1150 status_t
1151 Device::InitDevice()
1152 {
1153 	RecursiveLocker _(sLock);
1154 
1155 	if ((fNode->Flags() & NODE_FLAG_DEVICE_REMOVED) != 0) {
1156 		// TODO: maybe the device should be unlinked in devfs, too
1157 		return ENODEV;
1158 	}
1159 	if ((fNode->Flags() & NODE_FLAG_WAITING_FOR_DRIVER) != 0)
1160 		return B_BUSY;
1161 
1162 	if (fInitialized++ > 0) {
1163 		fNode->InitDriver();
1164 			// acquire another reference to our parent as well
1165 		return B_OK;
1166 	}
1167 
1168 	status_t status = get_module(ModuleName(), (module_info**)&fDeviceModule);
1169 	if (status == B_OK) {
1170 		// our parent always has to be initialized
1171 		status = fNode->InitDriver();
1172 	}
1173 	if (status < B_OK) {
1174 		fInitialized--;
1175 		return status;
1176 	}
1177 
1178 	if (Module()->init_device != NULL)
1179 		status = Module()->init_device(fNode->DriverData(), &fDeviceData);
1180 
1181 	if (status < B_OK) {
1182 		fNode->UninitDriver();
1183 		fInitialized--;
1184 
1185 		put_module(ModuleName());
1186 		fDeviceModule = NULL;
1187 		fDeviceData = NULL;
1188 	}
1189 
1190 	return status;
1191 }
1192 
1193 
1194 void
1195 Device::UninitDevice()
1196 {
1197 	RecursiveLocker _(sLock);
1198 
1199 	if (fInitialized-- > 1) {
1200 		fNode->UninitDriver();
1201 		return;
1202 	}
1203 
1204 	TRACE(("uninit driver for node %p\n", this));
1205 
1206 	if (Module()->uninit_device != NULL)
1207 		Module()->uninit_device(fDeviceData);
1208 
1209 	fDeviceModule = NULL;
1210 	fDeviceData = NULL;
1211 
1212 	put_module(ModuleName());
1213 
1214 	fNode->UninitDriver();
1215 }
1216 
1217 
1218 void
1219 Device::Removed()
1220 {
1221 	RecursiveLocker _(sLock);
1222 
1223 	if (!fRemovedFromParent)
1224 		fNode->RemoveDevice(this);
1225 
1226 	delete this;
1227 }
1228 
1229 
1230 //	#pragma mark - device_node
1231 
1232 
1233 device_node::device_node(const char* moduleName, const device_attr* attrs)
1234 {
1235 	fModuleName = strdup(moduleName);
1236 	if (fModuleName == NULL)
1237 		return;
1238 
1239 	fParent = NULL;
1240 	fRefCount = 1;
1241 	fInitialized = 0;
1242 	fRegistered = false;
1243 	fFlags = 0;
1244 	fSupportsParent = 0.0;
1245 	fLastUpdateCycle = 0;
1246 	fDriver = NULL;
1247 	fDriverData = NULL;
1248 
1249 	// copy attributes
1250 
1251 	while (attrs != NULL && attrs->name != NULL) {
1252 		device_attr_private* attr
1253 			= new(std::nothrow) device_attr_private(*attrs);
1254 		if (attr == NULL)
1255 			break;
1256 
1257 		fAttributes.Add(attr);
1258 		attrs++;
1259 	}
1260 
1261 	get_attr_uint32(this, B_DEVICE_FLAGS, &fFlags, false);
1262 	fFlags &= NODE_FLAG_PUBLIC_MASK;
1263 }
1264 
1265 
1266 device_node::~device_node()
1267 {
1268 	TRACE(("delete node %p\n", this));
1269 	ASSERT(DriverModule() == NULL);
1270 
1271 	if (Parent() != NULL) {
1272 		if ((fFlags & NODE_FLAG_OBSOLETE_DRIVER) != 0) {
1273 			// This driver has been obsoleted; another driver has been waiting
1274 			// for us - make it available
1275 			Parent()->_ReleaseWaiting();
1276 		}
1277 		Parent()->RemoveChild(this);
1278 	}
1279 
1280 	// Delete children
1281 	while (device_node* child = fChildren.RemoveHead()) {
1282 		delete child;
1283 	}
1284 
1285 	// Delete devices
1286 	while (Device* device = fDevices.RemoveHead()) {
1287 		device->SetRemovedFromParent(true);
1288 		devfs_unpublish_device(device, true);
1289 	}
1290 
1291 	// Delete attributes
1292 	while (device_attr_private* attr = fAttributes.RemoveHead()) {
1293 		delete attr;
1294 	}
1295 
1296 	// Delete resources
1297 	while (io_resource_private* resource = fResources.RemoveHead()) {
1298 		delete resource;
1299 	}
1300 
1301 	free((char*)fModuleName);
1302 }
1303 
1304 
1305 status_t
1306 device_node::InitCheck() const
1307 {
1308 	return fModuleName != NULL ? B_OK : B_NO_MEMORY;
1309 }
1310 
1311 
1312 status_t
1313 device_node::AcquireResources(const io_resource* resources)
1314 {
1315 	if (resources == NULL)
1316 		return B_OK;
1317 
1318 	for (uint32 i = 0; resources[i].type != 0; i++) {
1319 		io_resource_private* resource = new(std::nothrow) io_resource_private;
1320 		if (resource == NULL)
1321 			return B_NO_MEMORY;
1322 
1323 		status_t status = resource->Acquire(resources[i]);
1324 		if (status != B_OK) {
1325 			delete resource;
1326 			return status;
1327 		}
1328 
1329 		fResources.Add(resource);
1330 	}
1331 
1332 	return B_OK;
1333 }
1334 
1335 
1336 status_t
1337 device_node::InitDriver()
1338 {
1339 	if (fInitialized++ > 0) {
1340 		if (Parent() != NULL) {
1341 			Parent()->InitDriver();
1342 				// acquire another reference to our parent as well
1343 		}
1344 		Acquire();
1345 		return B_OK;
1346 	}
1347 
1348 	status_t status = get_module(ModuleName(), (module_info**)&fDriver);
1349 	if (status == B_OK && Parent() != NULL) {
1350 		// our parent always has to be initialized
1351 		status = Parent()->InitDriver();
1352 	}
1353 	if (status < B_OK) {
1354 		fInitialized--;
1355 		return status;
1356 	}
1357 
1358 	if (fDriver->init_driver != NULL) {
1359 		status = fDriver->init_driver(this, &fDriverData);
1360 		if (status != B_OK) {
1361 			dprintf("driver %s init failed: %s\n", ModuleName(),
1362 				strerror(status));
1363 		}
1364 	}
1365 
1366 	if (status < B_OK) {
1367 		if (Parent() != NULL)
1368 			Parent()->UninitDriver();
1369 		fInitialized--;
1370 
1371 		put_module(ModuleName());
1372 		fDriver = NULL;
1373 		fDriverData = NULL;
1374 		return status;
1375 	}
1376 
1377 	Acquire();
1378 	return B_OK;
1379 }
1380 
1381 
1382 bool
1383 device_node::UninitDriver()
1384 {
1385 	if (fInitialized-- > 1) {
1386 		if (Parent() != NULL)
1387 			Parent()->UninitDriver();
1388 		Release();
1389 		return false;
1390 	}
1391 
1392 	TRACE(("uninit driver for node %p\n", this));
1393 
1394 	if (fDriver->uninit_driver != NULL)
1395 		fDriver->uninit_driver(fDriverData);
1396 
1397 	fDriver = NULL;
1398 	fDriverData = NULL;
1399 
1400 	put_module(ModuleName());
1401 
1402 	if (Parent() != NULL)
1403 		Parent()->UninitDriver();
1404 	Release();
1405 
1406 	return true;
1407 }
1408 
1409 
1410 void
1411 device_node::AddChild(device_node* node)
1412 {
1413 	// we must not be destroyed	as long as we have children
1414 	Acquire();
1415 	node->fParent = this;
1416 
1417 	int32 priority = node->Priority();
1418 
1419 	// Enforce an order in which the children are traversed - from most
1420 	// specific to least specific child.
1421 	NodeList::Iterator iterator = fChildren.GetIterator();
1422 	device_node* before = NULL;
1423 	while (iterator.HasNext()) {
1424 		device_node* child = iterator.Next();
1425 		if (child->Priority() <= priority) {
1426 			before = child;
1427 			break;
1428 		}
1429 	}
1430 
1431 	fChildren.Insert(before, node);
1432 }
1433 
1434 
1435 void
1436 device_node::RemoveChild(device_node* node)
1437 {
1438 	node->fParent = NULL;
1439 	fChildren.Remove(node);
1440 	Release();
1441 }
1442 
1443 
1444 /*!	Registers this node, and all of its children that have to be registered.
1445 	Also initializes the driver and keeps it that way on return in case
1446 	it returns successfully.
1447 */
1448 status_t
1449 device_node::Register(device_node* parent)
1450 {
1451 	// make it public
1452 	if (parent != NULL)
1453 		parent->AddChild(this);
1454 	else
1455 		sRootNode = this;
1456 
1457 	status_t status = InitDriver();
1458 	if (status != B_OK)
1459 		return status;
1460 
1461 	if ((fFlags & B_KEEP_DRIVER_LOADED) != 0) {
1462 		// We keep this driver loaded by having it always initialized
1463 		InitDriver();
1464 	}
1465 
1466 	fFlags |= NODE_FLAG_REGISTER_INITIALIZED;
1467 		// We don't uninitialize the driver - this is done by the caller
1468 		// in order to save reinitializing during driver loading.
1469 
1470 	uint32 registeredFixedCount;
1471 	status = _RegisterFixed(registeredFixedCount);
1472 	if (status != B_OK) {
1473 		UninitUnusedDriver();
1474 		return status;
1475 	}
1476 
1477 	// Register the children the driver wants
1478 
1479 	if (DriverModule()->register_child_devices != NULL) {
1480 		status = DriverModule()->register_child_devices(DriverData());
1481 		if (status != B_OK) {
1482 			UninitUnusedDriver();
1483 			return status;
1484 		}
1485 
1486 		if (!fChildren.IsEmpty()) {
1487 			fRegistered = true;
1488 			return B_OK;
1489 		}
1490 	}
1491 
1492 	if (registeredFixedCount > 0) {
1493 		// Nodes with fixed children cannot have any dynamic children, so bail
1494 		// out here
1495 		fRegistered = true;
1496 		return B_OK;
1497 	}
1498 
1499 	// Register all possible child device nodes
1500 
1501 	status = _RegisterDynamic();
1502 	if (status == B_OK)
1503 		fRegistered = true;
1504 	else
1505 		UninitUnusedDriver();
1506 
1507 	return status;
1508 }
1509 
1510 
1511 /*!	Registers any children that are identified via the B_DEVICE_FIXED_CHILD
1512 	attribute.
1513 	If any of these children cannot be registered, this call will fail (we
1514 	don't remove children we already registered up to this point in this case).
1515 */
1516 status_t
1517 device_node::_RegisterFixed(uint32& registered)
1518 {
1519 	AttributeList::Iterator iterator = fAttributes.GetIterator();
1520 	registered = 0;
1521 
1522 	while (iterator.HasNext()) {
1523 		device_attr_private* attr = iterator.Next();
1524 		if (strcmp(attr->name, B_DEVICE_FIXED_CHILD))
1525 			continue;
1526 
1527 		driver_module_info* driver;
1528 		status_t status = get_module(attr->value.string,
1529 			(module_info**)&driver);
1530 		if (status != B_OK) {
1531 			TRACE(("register fixed child %s failed: %s\n", attr->value.string,
1532 				strerror(status)));
1533 			return status;
1534 		}
1535 
1536 		if (driver->register_device != NULL) {
1537 			status = driver->register_device(this);
1538 			if (status == B_OK)
1539 				registered++;
1540 		}
1541 
1542 		put_module(attr->value.string);
1543 
1544 		if (status != B_OK)
1545 			return status;
1546 	}
1547 
1548 	return B_OK;
1549 }
1550 
1551 
1552 status_t
1553 device_node::_AddPath(Stack<KPath*>& stack, const char* basePath,
1554 	const char* subPath)
1555 {
1556 	KPath* path = new(std::nothrow) KPath;
1557 	if (path == NULL)
1558 		return B_NO_MEMORY;
1559 
1560 	status_t status = path->SetTo(basePath);
1561 	if (status == B_OK && subPath != NULL && subPath[0])
1562 		status = path->Append(subPath);
1563 	if (status == B_OK)
1564 		status = stack.Push(path);
1565 
1566 	TRACE(("  add path: \"%s\", %" B_PRId32 "\n", path->Path(), status));
1567 
1568 	if (status != B_OK)
1569 		delete path;
1570 
1571 	return status;
1572 }
1573 
1574 
1575 status_t
1576 device_node::_GetNextDriverPath(void*& cookie, KPath& _path)
1577 {
1578 	Stack<KPath*>* stack = NULL;
1579 
1580 	if (cookie == NULL) {
1581 		// find all paths and add them
1582 		stack = new(std::nothrow) Stack<KPath*>();
1583 		if (stack == NULL)
1584 			return B_NO_MEMORY;
1585 
1586 		StackDeleter<KPath*> stackDeleter(stack);
1587 
1588 		bool generic = false;
1589 		uint16 type = 0;
1590 		uint16 subType = 0;
1591 		uint16 interface = 0;
1592 		if (get_attr_uint16(this, B_DEVICE_TYPE, &type, false) != B_OK
1593 			|| get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false)
1594 					!= B_OK)
1595 			generic = true;
1596 
1597 		get_attr_uint16(this, B_DEVICE_INTERFACE, &interface, false);
1598 
1599 		// TODO: maybe make this extendible via settings file?
1600 		switch (type) {
1601 			case PCI_mass_storage:
1602 				switch (subType) {
1603 					case PCI_scsi:
1604 						_AddPath(*stack, "busses", "scsi");
1605 						_AddPath(*stack, "busses", "virtio");
1606 						break;
1607 					case PCI_ide:
1608 						_AddPath(*stack, "busses", "ata");
1609 						_AddPath(*stack, "busses", "ide");
1610 						break;
1611 					case PCI_sata:
1612 						// TODO: check for ahci interface
1613 						_AddPath(*stack, "busses", "scsi");
1614 						_AddPath(*stack, "busses", "ata");
1615 						_AddPath(*stack, "busses", "ide");
1616 						break;
1617 					case PCI_nvm:
1618 						_AddPath(*stack, "drivers", "disk");
1619 						break;
1620 					default:
1621 						_AddPath(*stack, "busses");
1622 						break;
1623 				}
1624 				break;
1625 			case PCI_serial_bus:
1626 				switch (subType) {
1627 					case PCI_firewire:
1628 						_AddPath(*stack, "busses", "firewire");
1629 						break;
1630 					case PCI_usb:
1631 						_AddPath(*stack, "busses", "usb");
1632 						break;
1633 					default:
1634 						_AddPath(*stack, "busses");
1635 						break;
1636 				}
1637 				break;
1638 			case PCI_network:
1639 				_AddPath(*stack, "drivers", "net");
1640 				_AddPath(*stack, "busses", "virtio");
1641 				break;
1642 			case PCI_display:
1643 				_AddPath(*stack, "drivers", "graphics");
1644 				break;
1645 			case PCI_multimedia:
1646 				switch (subType) {
1647 					case PCI_audio:
1648 					case PCI_hd_audio:
1649 						_AddPath(*stack, "drivers", "audio");
1650 						break;
1651 					case PCI_video:
1652 						_AddPath(*stack, "drivers", "video");
1653 						break;
1654 					default:
1655 						_AddPath(*stack, "drivers");
1656 						break;
1657 				}
1658 				break;
1659 			case PCI_base_peripheral:
1660 				switch (subType) {
1661 					case PCI_sd_host:
1662 						_AddPath(*stack, "busses", "mmc");
1663 						break;
1664 					default:
1665 						_AddPath(*stack, "drivers");
1666 						break;
1667 				}
1668 				break;
1669 			case PCI_data_acquisition:
1670 				switch (subType) {
1671 					case PCI_data_acquisition_other:
1672 						_AddPath(*stack, "busses", "i2c");
1673 						break;
1674 					default:
1675 						_AddPath(*stack, "drivers");
1676 						break;
1677 				}
1678 				break;
1679 			default:
1680 				if (sRootNode == this) {
1681 					_AddPath(*stack, "busses/pci");
1682 					_AddPath(*stack, "bus_managers");
1683 				} else if (!generic) {
1684 					_AddPath(*stack, "busses", "virtio");
1685 					_AddPath(*stack, "drivers");
1686 				} else {
1687 					// For generic drivers, we only allow busses when the
1688 					// request is more specified
1689 					if (sGenericContextPath != NULL
1690 						&& (!strcmp(sGenericContextPath, "disk")
1691 							|| !strcmp(sGenericContextPath, "ports")
1692 							|| !strcmp(sGenericContextPath, "bus"))) {
1693 						_AddPath(*stack, "busses");
1694 					}
1695 					_AddPath(*stack, "drivers", sGenericContextPath);
1696 					_AddPath(*stack, "busses/i2c");
1697 					_AddPath(*stack, "busses/scsi");
1698 					_AddPath(*stack, "busses/random");
1699 				}
1700 				break;
1701 		}
1702 
1703 		stackDeleter.Detach();
1704 
1705 		cookie = (void*)stack;
1706 	} else
1707 		stack = static_cast<Stack<KPath*>*>(cookie);
1708 
1709 	KPath* path;
1710 	if (stack->Pop(&path)) {
1711 		_path.Adopt(*path);
1712 		delete path;
1713 		return B_OK;
1714 	}
1715 
1716 	delete stack;
1717 	return B_ENTRY_NOT_FOUND;
1718 }
1719 
1720 
1721 status_t
1722 device_node::_GetNextDriver(void* list, driver_module_info*& driver)
1723 {
1724 	while (true) {
1725 		char name[B_FILE_NAME_LENGTH];
1726 		size_t nameLength = sizeof(name);
1727 
1728 		status_t status = read_next_module_name(list, name, &nameLength);
1729 		if (status != B_OK)
1730 			return status;
1731 
1732 		if (!strcmp(fModuleName, name))
1733 			continue;
1734 
1735 		if (get_module(name, (module_info**)&driver) != B_OK)
1736 			continue;
1737 
1738 		if (driver->supports_device == NULL
1739 			|| driver->register_device == NULL) {
1740 			put_module(name);
1741 			continue;
1742 		}
1743 
1744 		return B_OK;
1745 	}
1746 }
1747 
1748 
1749 status_t
1750 device_node::_FindBestDriver(const char* path, driver_module_info*& bestDriver,
1751 	float& bestSupport, device_node* previous)
1752 {
1753 	if (bestDriver == NULL)
1754 		bestSupport = previous != NULL ? previous->fSupportsParent : 0.0f;
1755 
1756 	void* list = open_module_list_etc(path, "driver_v1");
1757 	driver_module_info* driver;
1758 	while (_GetNextDriver(list, driver) == B_OK) {
1759 		if (previous != NULL && driver == previous->DriverModule()) {
1760 			put_module(driver->info.name);
1761 			continue;
1762 		}
1763 
1764 		float support = driver->supports_device(this);
1765 		if (support > bestSupport) {
1766 			if (bestDriver != NULL)
1767 				put_module(bestDriver->info.name);
1768 
1769 			bestDriver = driver;
1770 			bestSupport = support;
1771 			continue;
1772 				// keep reference to best module around
1773 		}
1774 
1775 		put_module(driver->info.name);
1776 	}
1777 	close_module_list(list);
1778 
1779 	return bestDriver != NULL ? B_OK : B_ENTRY_NOT_FOUND;
1780 }
1781 
1782 
1783 status_t
1784 device_node::_RegisterPath(const char* path)
1785 {
1786 	void* list = open_module_list_etc(path, "driver_v1");
1787 	driver_module_info* driver;
1788 	uint32 count = 0;
1789 
1790 	while (_GetNextDriver(list, driver) == B_OK) {
1791 		float support = driver->supports_device(this);
1792 		if (support > 0.0) {
1793 			TRACE(("  register module \"%s\", support %f\n", driver->info.name,
1794 				support));
1795 			if (driver->register_device(this) == B_OK)
1796 				count++;
1797 		}
1798 
1799 		put_module(driver->info.name);
1800 	}
1801 	close_module_list(list);
1802 
1803 	return count > 0 ? B_OK : B_ENTRY_NOT_FOUND;
1804 }
1805 
1806 
1807 bool
1808 device_node::_AlwaysRegisterDynamic()
1809 {
1810 	uint16 type = 0;
1811 	uint16 subType = 0;
1812 	get_attr_uint16(this, B_DEVICE_TYPE, &type, false);
1813 	get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false);
1814 
1815 	return type == PCI_serial_bus || type == PCI_bridge || type == 0;
1816 		// TODO: we may want to be a bit more specific in the future
1817 }
1818 
1819 
1820 status_t
1821 device_node::_RegisterDynamic(device_node* previous)
1822 {
1823 	// If this is not a bus, we don't have to scan it
1824 	if (find_attr(this, B_DEVICE_BUS, false, B_STRING_TYPE) == NULL)
1825 		return B_OK;
1826 
1827 	// If we're not being probed, we honour the B_FIND_CHILD_ON_DEMAND
1828 	// requirements
1829 	if (!IsProbed() && (fFlags & B_FIND_CHILD_ON_DEMAND) != 0
1830 		&& !_AlwaysRegisterDynamic())
1831 		return B_OK;
1832 
1833 	KPath path;
1834 
1835 	if ((fFlags & B_FIND_MULTIPLE_CHILDREN) == 0) {
1836 		// find the one driver
1837 		driver_module_info* bestDriver = NULL;
1838 		float bestSupport = 0.0;
1839 		void* cookie = NULL;
1840 
1841 		while (_GetNextDriverPath(cookie, path) == B_OK) {
1842 			_FindBestDriver(path.Path(), bestDriver, bestSupport, previous);
1843 		}
1844 
1845 		if (bestDriver != NULL) {
1846 			TRACE(("  register best module \"%s\", support %f\n",
1847 				bestDriver->info.name, bestSupport));
1848 			if (bestDriver->register_device(this) == B_OK) {
1849 				// There can only be one node of this driver
1850 				// (usually only one at all, but there might be a new driver
1851 				// "waiting" for its turn)
1852 				device_node* child = FindChild(bestDriver->info.name);
1853 				if (child != NULL) {
1854 					child->fSupportsParent = bestSupport;
1855 					if (previous != NULL) {
1856 						previous->fFlags |= NODE_FLAG_OBSOLETE_DRIVER;
1857 						previous->Release();
1858 						child->fFlags |= NODE_FLAG_WAITING_FOR_DRIVER;
1859 					}
1860 				}
1861 				// TODO: if this fails, we could try the second best driver,
1862 				// and so on...
1863 			}
1864 			put_module(bestDriver->info.name);
1865 		}
1866 	} else {
1867 		// register all drivers that match
1868 		void* cookie = NULL;
1869 		while (_GetNextDriverPath(cookie, path) == B_OK) {
1870 			_RegisterPath(path.Path());
1871 		}
1872 	}
1873 
1874 	return B_OK;
1875 }
1876 
1877 
1878 void
1879 device_node::_ReleaseWaiting()
1880 {
1881 	NodeList::Iterator iterator = fChildren.GetIterator();
1882 	while (iterator.HasNext()) {
1883 		device_node* child = iterator.Next();
1884 
1885 		child->fFlags &= ~NODE_FLAG_WAITING_FOR_DRIVER;
1886 	}
1887 }
1888 
1889 
1890 status_t
1891 device_node::_RemoveChildren()
1892 {
1893 	NodeList::Iterator iterator = fChildren.GetIterator();
1894 	while (iterator.HasNext()) {
1895 		device_node* child = iterator.Next();
1896 		child->Release();
1897 	}
1898 
1899 	return fChildren.IsEmpty() ? B_OK : B_BUSY;
1900 }
1901 
1902 
1903 device_node*
1904 device_node::_FindCurrentChild()
1905 {
1906 	NodeList::Iterator iterator = fChildren.GetIterator();
1907 	while (iterator.HasNext()) {
1908 		device_node* child = iterator.Next();
1909 
1910 		if ((child->Flags() & NODE_FLAG_WAITING_FOR_DRIVER) == 0)
1911 			return child;
1912 	}
1913 
1914 	return NULL;
1915 }
1916 
1917 
1918 status_t
1919 device_node::_Probe()
1920 {
1921 	device_node* previous = NULL;
1922 
1923 	if (IsProbed() && !fChildren.IsEmpty()
1924 		&& (fFlags & (B_FIND_CHILD_ON_DEMAND | B_FIND_MULTIPLE_CHILDREN))
1925 				== B_FIND_CHILD_ON_DEMAND) {
1926 		// We already have a driver that claims this node; remove all
1927 		// (unused) nodes, and evaluate it again
1928 		_RemoveChildren();
1929 
1930 		previous = _FindCurrentChild();
1931 		if (previous != NULL) {
1932 			// This driver is still active - give it back the reference
1933 			// that was stolen by _RemoveChildren() - _RegisterDynamic()
1934 			// will release it, if it really isn't needed anymore
1935 			previous->Acquire();
1936 		}
1937 	}
1938 
1939 	return _RegisterDynamic(previous);
1940 }
1941 
1942 
1943 status_t
1944 device_node::Probe(const char* devicePath, uint32 updateCycle)
1945 {
1946 	if ((fFlags & NODE_FLAG_DEVICE_REMOVED) != 0
1947 		|| updateCycle == fLastUpdateCycle)
1948 		return B_OK;
1949 
1950 	status_t status = InitDriver();
1951 	if (status < B_OK)
1952 		return status;
1953 
1954 	MethodDeleter<device_node, bool> uninit(this,
1955 		&device_node::UninitDriver);
1956 
1957 	if ((fFlags & B_FIND_CHILD_ON_DEMAND) != 0) {
1958 		bool matches = false;
1959 		uint16 type = 0;
1960 		uint16 subType = 0;
1961 		if (get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false) == B_OK
1962 			&& get_attr_uint16(this, B_DEVICE_TYPE, &type, false) == B_OK) {
1963 			// Check if this node matches the device path
1964 			// TODO: maybe make this extendible via settings file?
1965 			if (!strcmp(devicePath, "disk")) {
1966 				matches = type == PCI_mass_storage
1967 					|| (type == PCI_base_peripheral && subType == PCI_sd_host);
1968 			} else if (!strcmp(devicePath, "audio")) {
1969 				matches = type == PCI_multimedia
1970 					&& (subType == PCI_audio || subType == PCI_hd_audio);
1971 			} else if (!strcmp(devicePath, "net")) {
1972 				matches = type == PCI_network;
1973 			} else if (!strcmp(devicePath, "graphics")) {
1974 				matches = type == PCI_display;
1975 			} else if (!strcmp(devicePath, "video")) {
1976 				matches = type == PCI_multimedia && subType == PCI_video;
1977 			} else if (!strcmp(devicePath, "power")) {
1978 				matches = type == PCI_data_acquisition;
1979 			} else if (!strcmp(devicePath, "input")) {
1980 				matches = type == PCI_data_acquisition
1981 					&& subType == PCI_data_acquisition_other;
1982 			}
1983 		} else {
1984 			// This driver does not support types, but still wants to its
1985 			// children explored on demand only.
1986 			matches = true;
1987 			sGenericContextPath = devicePath;
1988 		}
1989 
1990 		if (matches) {
1991 			fLastUpdateCycle = updateCycle;
1992 				// This node will be probed in this update cycle
1993 
1994 			status = _Probe();
1995 
1996 			sGenericContextPath = NULL;
1997 			return status;
1998 		}
1999 
2000 		return B_OK;
2001 	}
2002 
2003 	NodeList::Iterator iterator = fChildren.GetIterator();
2004 	while (iterator.HasNext()) {
2005 		device_node* child = iterator.Next();
2006 
2007 		status = child->Probe(devicePath, updateCycle);
2008 		if (status != B_OK)
2009 			return status;
2010 	}
2011 
2012 	return B_OK;
2013 }
2014 
2015 
2016 status_t
2017 device_node::Reprobe()
2018 {
2019 	status_t status = InitDriver();
2020 	if (status < B_OK)
2021 		return status;
2022 
2023 	MethodDeleter<device_node, bool> uninit(this,
2024 		&device_node::UninitDriver);
2025 
2026 	// If this child has been probed already, probe it again
2027 	status = _Probe();
2028 	if (status != B_OK)
2029 		return status;
2030 
2031 	NodeList::Iterator iterator = fChildren.GetIterator();
2032 	while (iterator.HasNext()) {
2033 		device_node* child = iterator.Next();
2034 
2035 		status = child->Reprobe();
2036 		if (status != B_OK)
2037 			return status;
2038 	}
2039 
2040 	return B_OK;
2041 }
2042 
2043 
2044 status_t
2045 device_node::Rescan()
2046 {
2047 	status_t status = InitDriver();
2048 	if (status < B_OK)
2049 		return status;
2050 
2051 	MethodDeleter<device_node, bool> uninit(this,
2052 		&device_node::UninitDriver);
2053 
2054 	if (DriverModule()->rescan_child_devices != NULL) {
2055 		status = DriverModule()->rescan_child_devices(DriverData());
2056 		if (status != B_OK)
2057 			return status;
2058 	}
2059 
2060 	NodeList::Iterator iterator = fChildren.GetIterator();
2061 	while (iterator.HasNext()) {
2062 		device_node* child = iterator.Next();
2063 
2064 		status = child->Rescan();
2065 		if (status != B_OK)
2066 			return status;
2067 	}
2068 
2069 	return B_OK;
2070 }
2071 
2072 
2073 /*!	Uninitializes all temporary references to the driver. The registration
2074 	process keeps the driver initialized to optimize the startup procedure;
2075 	this function gives this reference away again.
2076 */
2077 void
2078 device_node::UninitUnusedDriver()
2079 {
2080 	// First, we need to go to the leaf, and go back from there
2081 
2082 	NodeList::Iterator iterator = fChildren.GetIterator();
2083 	while (iterator.HasNext()) {
2084 		device_node* child = iterator.Next();
2085 
2086 		child->UninitUnusedDriver();
2087 	}
2088 
2089 	if (!IsInitialized()
2090 		|| (fFlags & NODE_FLAG_REGISTER_INITIALIZED) == 0)
2091 		return;
2092 
2093 	fFlags &= ~NODE_FLAG_REGISTER_INITIALIZED;
2094 
2095 	UninitDriver();
2096 }
2097 
2098 
2099 /*!	Calls device_removed() on this node and all of its children - starting
2100 	with the deepest and last child.
2101 	It will also remove the one reference that every node gets on its creation.
2102 */
2103 void
2104 device_node::DeviceRemoved()
2105 {
2106 	// notify children
2107 	NodeList::ConstIterator iterator = Children().GetIterator();
2108 	while (iterator.HasNext()) {
2109 		device_node* child = iterator.Next();
2110 
2111 		child->DeviceRemoved();
2112 	}
2113 
2114 	// notify devices
2115 	DeviceList::ConstIterator deviceIterator = Devices().GetIterator();
2116 	while (deviceIterator.HasNext()) {
2117 		Device* device = deviceIterator.Next();
2118 
2119 		if (device->Module() != NULL
2120 			&& device->Module()->device_removed != NULL)
2121 			device->Module()->device_removed(device->Data());
2122 	}
2123 
2124 	fFlags |= NODE_FLAG_DEVICE_REMOVED;
2125 
2126 	if (IsInitialized() && DriverModule()->device_removed != NULL)
2127 		DriverModule()->device_removed(this);
2128 
2129 	if ((fFlags & B_KEEP_DRIVER_LOADED) != 0) {
2130 		// There is no point in keeping this driver loaded when its device
2131 		// is gone
2132 		UninitDriver();
2133 	}
2134 
2135 	UninitUnusedDriver();
2136 	Release();
2137 }
2138 
2139 
2140 void
2141 device_node::Acquire()
2142 {
2143 	atomic_add(&fRefCount, 1);
2144 }
2145 
2146 
2147 bool
2148 device_node::Release()
2149 {
2150 	if (atomic_add(&fRefCount, -1) > 1)
2151 		return false;
2152 
2153 	delete this;
2154 	return true;
2155 }
2156 
2157 
2158 void
2159 device_node::AddDevice(Device* device)
2160 {
2161 	fDevices.Add(device);
2162 }
2163 
2164 
2165 void
2166 device_node::RemoveDevice(Device* device)
2167 {
2168 	fDevices.Remove(device);
2169 }
2170 
2171 
2172 int
2173 device_node::CompareTo(const device_attr* attributes) const
2174 {
2175 	if (attributes == NULL)
2176 		return -1;
2177 
2178 	for (; attributes->name != NULL; attributes++) {
2179 		// find corresponding attribute
2180 		AttributeList::ConstIterator iterator = Attributes().GetIterator();
2181 		device_attr_private* attr = NULL;
2182 		bool found = false;
2183 
2184 		while (iterator.HasNext()) {
2185 			attr = iterator.Next();
2186 
2187 			if (!strcmp(attr->name, attributes->name)) {
2188 				found = true;
2189 				break;
2190 			}
2191 		}
2192 		if (!found)
2193 			return -1;
2194 
2195 		int compare = device_attr_private::Compare(attr, attributes);
2196 		if (compare != 0)
2197 			return compare;
2198 	}
2199 
2200 	return 0;
2201 }
2202 
2203 
2204 device_node*
2205 device_node::FindChild(const device_attr* attributes) const
2206 {
2207 	if (attributes == NULL)
2208 		return NULL;
2209 
2210 	NodeList::ConstIterator iterator = Children().GetIterator();
2211 	while (iterator.HasNext()) {
2212 		device_node* child = iterator.Next();
2213 
2214 		// ignore nodes that are pending to be removed
2215 		if ((child->Flags() & NODE_FLAG_DEVICE_REMOVED) == 0
2216 			&& !child->CompareTo(attributes))
2217 			return child;
2218 	}
2219 
2220 	return NULL;
2221 }
2222 
2223 
2224 device_node*
2225 device_node::FindChild(const char* moduleName) const
2226 {
2227 	if (moduleName == NULL)
2228 		return NULL;
2229 
2230 	NodeList::ConstIterator iterator = Children().GetIterator();
2231 	while (iterator.HasNext()) {
2232 		device_node* child = iterator.Next();
2233 
2234 		if (!strcmp(child->ModuleName(), moduleName))
2235 			return child;
2236 	}
2237 
2238 	return NULL;
2239 }
2240 
2241 
2242 /*!	This returns the priority or importance of this node. Nodes with higher
2243 	priority are registered/probed first.
2244 	Currently, only the B_FIND_MULTIPLE_CHILDREN flag alters the priority;
2245 	it might make sense to be able to directly set the priority via an
2246 	attribute.
2247 */
2248 int32
2249 device_node::Priority()
2250 {
2251 	return (fFlags & B_FIND_MULTIPLE_CHILDREN) != 0 ? 0 : 100;
2252 }
2253 
2254 
2255 void
2256 device_node::Dump(int32 level)
2257 {
2258 	put_level(level);
2259 	kprintf("(%" B_PRId32 ") @%p \"%s\" (ref %" B_PRId32 ", init %" B_PRId32
2260 		", module %p, data %p)\n", level, this, ModuleName(), fRefCount,
2261 		fInitialized, DriverModule(), DriverData());
2262 
2263 	AttributeList::Iterator attribute = Attributes().GetIterator();
2264 	while (attribute.HasNext()) {
2265 		dump_attribute(attribute.Next(), level);
2266 	}
2267 
2268 	DeviceList::Iterator deviceIterator = fDevices.GetIterator();
2269 	while (deviceIterator.HasNext()) {
2270 		Device* device = deviceIterator.Next();
2271 		put_level(level);
2272 		kprintf("device: %s, %p\n", device->ModuleName(), device->Data());
2273 	}
2274 
2275 	NodeList::ConstIterator iterator = Children().GetIterator();
2276 	while (iterator.HasNext()) {
2277 		iterator.Next()->Dump(level + 1);
2278 	}
2279 }
2280 
2281 
2282 //	#pragma mark - root node
2283 
2284 
2285 static void
2286 init_node_tree(void)
2287 {
2288 	device_attr attrs[] = {
2289 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Devices Root"}},
2290 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "root"}},
2291 		{B_DEVICE_FLAGS, B_UINT32_TYPE,
2292 			{ui32: B_FIND_MULTIPLE_CHILDREN | B_KEEP_DRIVER_LOADED }},
2293 		{NULL}
2294 	};
2295 
2296 	device_node* node = NULL;
2297 	if (register_node(NULL, DEVICE_MANAGER_ROOT_NAME, attrs, NULL, &node)
2298 			!= B_OK) {
2299 		dprintf("Cannot register Devices Root Node\n");
2300 	}
2301 
2302 	device_attr genericAttrs[] = {
2303 		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Generic"}},
2304 		{B_DEVICE_BUS, B_STRING_TYPE, {string: "generic"}},
2305 		{B_DEVICE_FLAGS, B_UINT32_TYPE, {ui32: B_FIND_MULTIPLE_CHILDREN
2306 			| B_KEEP_DRIVER_LOADED | B_FIND_CHILD_ON_DEMAND}},
2307 		{NULL}
2308 	};
2309 
2310 	if (register_node(node, DEVICE_MANAGER_GENERIC_NAME, genericAttrs, NULL,
2311 			NULL) != B_OK) {
2312 		dprintf("Cannot register Generic Devices Node\n");
2313 	}
2314 }
2315 
2316 
2317 driver_module_info gDeviceRootModule = {
2318 	{
2319 		DEVICE_MANAGER_ROOT_NAME,
2320 		0,
2321 		NULL,
2322 	},
2323 };
2324 
2325 
2326 driver_module_info gDeviceGenericModule = {
2327 	{
2328 		DEVICE_MANAGER_GENERIC_NAME,
2329 		0,
2330 		NULL,
2331 	},
2332 	NULL
2333 };
2334 
2335 
2336 //	#pragma mark - private kernel API
2337 
2338 
2339 status_t
2340 device_manager_probe(const char* path, uint32 updateCycle)
2341 {
2342 	TRACE(("device_manager_probe(\"%s\")\n", path));
2343 	RecursiveLocker _(sLock);
2344 
2345 	// first, publish directories in the driver directory
2346 	publish_directories(path);
2347 
2348 	return sRootNode->Probe(path, updateCycle);
2349 }
2350 
2351 
2352 status_t
2353 device_manager_init(struct kernel_args* args)
2354 {
2355 	TRACE(("device manager init\n"));
2356 
2357 	IOSchedulerRoster::Init();
2358 
2359 	dm_init_id_generator();
2360 	dm_init_io_resources();
2361 
2362 	recursive_lock_init(&sLock, "device manager");
2363 
2364 	register_generic_syscall(DEVICE_MANAGER_SYSCALLS, control_device_manager,
2365 		1, 0);
2366 
2367 	add_debugger_command("dm_tree", &dump_device_nodes,
2368 		"dump device node tree");
2369 	add_debugger_command_etc("io_scheduler", &dump_io_scheduler,
2370 		"Dump an I/O scheduler",
2371 		"<scheduler>\n"
2372 		"Dumps I/O scheduler at address <scheduler>.\n", 0);
2373 	add_debugger_command_etc("io_request_owner", &dump_io_request_owner,
2374 		"Dump an I/O request owner",
2375 		"<owner>\n"
2376 		"Dumps I/O request owner at address <owner>.\n", 0);
2377 	add_debugger_command("io_request", &dump_io_request, "dump an I/O request");
2378 	add_debugger_command("io_operation", &dump_io_operation,
2379 		"dump an I/O operation");
2380 	add_debugger_command("io_buffer", &dump_io_buffer, "dump an I/O buffer");
2381 	add_debugger_command("dma_buffer", &dump_dma_buffer, "dump a DMA buffer");
2382 
2383 	init_node_tree();
2384 
2385 	return B_OK;
2386 }
2387 
2388 
2389 status_t
2390 device_manager_init_post_modules(struct kernel_args* args)
2391 {
2392 	RecursiveLocker _(sLock);
2393 	return sRootNode->Reprobe();
2394 }
2395