1/*
2 * Copyright 2008, Axel D��rfler, axeld@pinc-software.de. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include "device_manager.h"
8
9#include <new>
10#include <set>
11#include <stdio.h>
12#include <stdlib.h>
13#include <string.h>
14
15#include <KernelExport.h>
16#include <Locker.h>
17#include <module.h>
18#include <PCI.h>
19
20#include <fs/KPath.h>
21#include <util/AutoLock.h>
22#include <util/DoublyLinkedList.h>
23#include <util/Stack.h>
24
25#include "bus.h"
26
27#define TRACE(a) dprintf a
28
29#define DEVICE_MANAGER_ROOT_NAME "system/devices_root/driver_v1"
30
31extern struct device_module_info gDeviceModuleInfo;
32extern struct driver_module_info gDriverModuleInfo;
33extern struct device_module_info gGenericVideoDeviceModuleInfo;
34extern struct driver_module_info gGenericVideoDriverModuleInfo;
35extern struct device_module_info gSpecificVideoDeviceModuleInfo;
36extern struct driver_module_info gSpecificVideoDriverModuleInfo;
37extern struct driver_module_info gBusModuleInfo;
38extern struct driver_module_info gBusDriverModuleInfo;
39
40extern "C" status_t _add_builtin_module(module_info *info);
41extern "C" status_t _get_builtin_dependencies(void);
42extern bool gDebugOutputEnabled;
43	// from libkernelland_emu.so
44
45struct device_attr_private : device_attr,
46		DoublyLinkedListLinkImpl<device_attr_private> {
47						device_attr_private();
48						device_attr_private(const device_attr& attr);
49						~device_attr_private();
50
51			status_t	InitCheck();
52			status_t	CopyFrom(const device_attr& attr);
53
54	static	int			Compare(const device_attr* attrA,
55							const device_attr *attrB);
56
57private:
58			void		_Unset();
59};
60
61typedef DoublyLinkedList<device_attr_private> AttributeList;
62
63// I/O resource
64typedef struct io_resource_info {
65	struct io_resource_info *prev, *next;
66	device_node*		owner;			// associated node; NULL for temporary allocation
67	io_resource			resource;		// info about actual resource
68} io_resource_info;
69
70class Device : public DoublyLinkedListLinkImpl<Device> {
71public:
72							Device(device_node* node, const char* path,
73								const char* moduleName);
74							~Device();
75
76			status_t		InitCheck() const;
77
78			device_node*	Node() const { return fNode; }
79			const char*		Path() const { return fPath; }
80			const char*		ModuleName() const { return fModuleName; }
81
82			status_t		InitDevice();
83			void			UninitDevice();
84
85			device_module_info* DeviceModule() const { return fDeviceModule; }
86			void*			DeviceData() const { return fDeviceData; }
87
88private:
89	device_node*			fNode;
90	const char*				fPath;
91	const char*				fModuleName;
92
93	int32					fInitialized;
94	device_module_info*		fDeviceModule;
95	void*					fDeviceData;
96};
97
98typedef DoublyLinkedList<Device> DeviceList;
99typedef DoublyLinkedList<device_node> NodeList;
100
101struct device_node : DoublyLinkedListLinkImpl<device_node> {
102							device_node(const char* moduleName,
103								const device_attr* attrs,
104								const io_resource* resources);
105							~device_node();
106
107			status_t		InitCheck() const;
108
109			const char*		ModuleName() const { return fModuleName; }
110			device_node*	Parent() const { return fParent; }
111			AttributeList&	Attributes() { return fAttributes; }
112			const AttributeList& Attributes() const { return fAttributes; }
113
114			status_t		InitDriver();
115			bool			UninitDriver();
116			void			UninitUnusedDriver();
117
118			// The following two are only valid, if the node's driver is
119			// initialized
120			driver_module_info* DriverModule() const { return fDriver; }
121			void*			DriverData() const { return fDriverData; }
122
123			void			AddChild(device_node *node);
124			void			RemoveChild(device_node *node);
125			const NodeList&	Children() const { return fChildren; }
126			void			DeviceRemoved();
127
128			status_t		Register(device_node* parent);
129			status_t		Probe(const char* devicePath, uint32 updateCycle);
130			bool			IsRegistered() const { return fRegistered; }
131			bool			IsInitialized() const { return fInitialized > 0; }
132			uint32			Flags() const { return fFlags; }
133
134			void			Acquire();
135			bool			Release();
136
137			const DeviceList& Devices() const { return fDevices; }
138			void			AddDevice(Device* device);
139			void			RemoveDevice(Device* device);
140
141			int				CompareTo(const device_attr* attributes) const;
142			device_node*	FindChild(const device_attr* attributes) const;
143			device_node*	FindChild(const char* moduleName) const;
144
145			void			Dump(int32 level = 0);
146
147private:
148			status_t		_RegisterFixed(uint32& registered);
149			bool			_AlwaysRegisterDynamic();
150			status_t		_AddPath(Stack<KPath*>& stack, const char* path,
151								const char* subPath = NULL);
152			status_t		_GetNextDriverPath(void*& cookie, KPath& _path);
153			status_t		_GetNextDriver(void* list,
154								driver_module_info*& driver);
155			status_t		_FindBestDriver(const char* path,
156								driver_module_info*& bestDriver,
157								float& bestSupport,
158								device_node* previous = NULL);
159			status_t		_RegisterPath(const char* path);
160			status_t		_RegisterDynamic(device_node* previous = NULL);
161			status_t		_RemoveChildren();
162			device_node*	_FindCurrentChild();
163			void			_ReleaseWaiting();
164
165	device_node*			fParent;
166	NodeList				fChildren;
167	int32					fRefCount;
168	int32					fInitialized;
169	bool					fRegistered;
170	uint32					fFlags;
171	float					fSupportsParent;
172	uint32					fLastUpdateCycle;
173
174	const char*				fModuleName;
175
176	driver_module_info*		fDriver;
177	void*					fDriverData;
178
179	DeviceList				fDevices;
180	AttributeList			fAttributes;
181};
182
183// flags in addition to those specified by B_DEVICE_FLAGS
184enum node_flags {
185	NODE_FLAG_REGISTER_INITIALIZED	= 0x00010000,
186	NODE_FLAG_DEVICE_REMOVED		= 0x00020000,
187	NODE_FLAG_OBSOLETE_DRIVER		= 0x00040000,
188	NODE_FLAG_WAITING_FOR_DRIVER	= 0x00080000,
189
190	NODE_FLAG_PUBLIC_MASK			= 0x0000ffff
191};
192
193device_manager_info *gDeviceManager;
194
195static device_node *sRootNode;
196static recursive_lock sLock;
197
198static uint32 sDriverUpdateCycle = 1;
199	// this is a *very* basic devfs emulation
200
201
202//	#pragma mark -
203
204
205static device_attr_private*
206find_attr(const device_node* node, const char* name, bool recursive,
207	type_code type)
208{
209	do {
210		AttributeList::ConstIterator iterator
211			= node->Attributes().GetIterator();
212
213		while (iterator.HasNext()) {
214			device_attr_private* attr = iterator.Next();
215
216			if (type != B_ANY_TYPE && attr->type != type)
217				continue;
218
219			if (!strcmp(attr->name, name))
220				return attr;
221		}
222
223		node = node->Parent();
224	} while (node != NULL && recursive);
225
226	return NULL;
227}
228
229
230static void
231put_level(int32 level)
232{
233	while (level-- > 0)
234		dprintf("   ");
235}
236
237
238static void
239dump_attribute(device_attr* attr, int32 level)
240{
241	if (attr == NULL)
242		return;
243
244	put_level(level + 2);
245	dprintf("\"%s\" : ", attr->name);
246	switch (attr->type) {
247		case B_STRING_TYPE:
248			dprintf("string : \"%s\"", attr->value.string);
249			break;
250		case B_INT8_TYPE:
251		case B_UINT8_TYPE:
252			dprintf("uint8 : %u (%#x)", attr->value.ui8, attr->value.ui8);
253			break;
254		case B_INT16_TYPE:
255		case B_UINT16_TYPE:
256			dprintf("uint16 : %u (%#x)", attr->value.ui16, attr->value.ui16);
257			break;
258		case B_INT32_TYPE:
259		case B_UINT32_TYPE:
260			dprintf("uint32 : %lu (%#lx)", attr->value.ui32, attr->value.ui32);
261			break;
262		case B_INT64_TYPE:
263		case B_UINT64_TYPE:
264			dprintf("uint64 : %Lu (%#Lx)", attr->value.ui64, attr->value.ui64);
265			break;
266		default:
267			dprintf("raw data");
268	}
269	dprintf("\n");
270}
271
272
273static void
274uninit_unused()
275{
276	puts("uninit unused");
277	RecursiveLocker _(sLock);
278	sRootNode->UninitUnusedDriver();
279}
280
281
282static status_t
283probe_path(const char* path)
284{
285	printf("probe path \"%s\"\n", path);
286	RecursiveLocker _(sLock);
287	return sRootNode->Probe(path, sDriverUpdateCycle);
288}
289
290
291static void
292close_path(void* cookie)
293{
294	Device* device = (Device*)cookie;
295	if (device == NULL)
296		return;
297
298	printf("close path \"%s\" (node %p)\n", device->Path(), device->Node());
299	device->UninitDevice();
300}
301
302
303static Device*
304get_device(device_node* node, const char* path)
305{
306	DeviceList::ConstIterator iterator = node->Devices().GetIterator();
307	while (iterator.HasNext()) {
308		Device* device = iterator.Next();
309		if (!strcmp(device->Path(), path)) {
310			status_t status = device->InitDevice();
311			if (status != B_OK) {
312				printf("opening path \"%s\" failed: %s\n", path,
313					strerror(status));
314				return NULL;
315			}
316
317			printf("open path \"%s\" (node %p)\n", device->Path(),
318				device->Node());
319			return device;
320		}
321	}
322
323	// search in children
324
325	NodeList::ConstIterator nodeIterator = node->Children().GetIterator();
326	while (nodeIterator.HasNext()) {
327		device_node* child = nodeIterator.Next();
328
329		Device* device = get_device(child, path);
330		if (device != NULL)
331			return device;
332	}
333
334	return NULL;
335}
336
337
338static void*
339open_path(const char* path)
340{
341	return get_device(sRootNode, path);
342}
343
344
345//	#pragma mark - Device Manager module API
346
347
348static status_t
349rescan_node(device_node* node)
350{
351	return B_ERROR;
352}
353
354
355static status_t
356register_node(device_node* parent, const char* moduleName,
357	const device_attr* attrs, const io_resource* ioResources,
358	device_node** _node)
359{
360	if ((parent == NULL && sRootNode != NULL) || moduleName == NULL)
361		return B_BAD_VALUE;
362
363	if (parent != NULL && parent->FindChild(attrs) != NULL) {
364		// A node like this one already exists for this parent
365		return B_NAME_IN_USE;
366	}
367
368	// TODO: handle I/O resources!
369
370	device_node *newNode = new(std::nothrow) device_node(moduleName, attrs,
371		ioResources);
372	if (newNode == NULL)
373		return B_NO_MEMORY;
374
375	TRACE(("%p: register node \"%s\", parent %p\n", newNode, moduleName,
376		parent));
377
378	RecursiveLocker _(sLock);
379
380	status_t status = newNode->InitCheck();
381	if (status != B_OK)
382		goto err1;
383
384#if 0
385	// The following is done to reduce the stack usage of deeply nested
386	// child device nodes.
387	// There is no other need to delay the complete registration process
388	// the way done here. This approach is also slightly different as
389	// the registration might fail later than it used in case of errors.
390
391	if (!parent->IsRegistered()) {
392		// The parent has not been registered completely yet - child
393		// registration is deferred to the parent registration
394		return B_OK;
395	}
396#endif
397
398	status = newNode->Register(parent);
399	if (status < B_OK) {
400		parent->RemoveChild(newNode);
401		goto err1;
402	}
403
404	if (_node)
405		*_node = newNode;
406
407	return B_OK;
408
409err1:
410	newNode->Release();
411	return status;
412}
413
414
415/*!	Unregisters the device \a node.
416
417	If the node is currently in use, this function will return B_BUSY to
418	indicate that the node hasn't been removed yet - it will still remove
419	the node as soon as possible.
420*/
421static status_t
422unregister_node(device_node* node)
423{
424	TRACE(("unregister_node(node %p)\n", node));
425	RecursiveLocker _(sLock);
426
427	bool initialized = node->IsInitialized();
428
429	node->DeviceRemoved();
430
431	return initialized ? B_BUSY : B_OK;
432}
433
434
435static status_t
436get_driver(device_node* node, driver_module_info** _module, void** _data)
437{
438	if (node->DriverModule() == NULL)
439		return B_NO_INIT;
440
441	if (_module != NULL)
442		*_module = node->DriverModule();
443	if (_data != NULL)
444		*_data = node->DriverData();
445
446	return B_OK;
447}
448
449
450static device_node*
451get_root_node(void)
452{
453	if (sRootNode != NULL)
454		sRootNode->Acquire();
455
456	return sRootNode;
457}
458
459
460static status_t
461get_next_child_node(device_node* parent, const device_attr* attributes,
462	device_node** _node)
463{
464	RecursiveLocker _(sLock);
465
466	NodeList::ConstIterator iterator = parent->Children().GetIterator();
467	device_node* last = *_node;
468
469	// skip those we already traversed
470	while (iterator.HasNext() && last != NULL) {
471		device_node* node = iterator.Next();
472
473		if (node != last)
474			continue;
475	}
476
477	// find the next one that fits
478	while (iterator.HasNext()) {
479		device_node* node = iterator.Next();
480
481		if (!node->IsRegistered())
482			continue;
483
484		if (!node->CompareTo(attributes)) {
485			if (last != NULL)
486				last->Release();
487
488			node->Acquire();
489			*_node = node;
490			return B_OK;
491		}
492	}
493
494	if (last != NULL)
495		last->Release();
496
497	return B_ENTRY_NOT_FOUND;
498}
499
500
501static device_node*
502get_parent_node(device_node* node)
503{
504	if (node == NULL)
505		return NULL;
506
507	RecursiveLocker _(sLock);
508
509	device_node* parent = node->Parent();
510	parent->Acquire();
511
512	return parent;
513}
514
515
516static void
517put_node(device_node* node)
518{
519	RecursiveLocker _(sLock);
520	node->Release();
521}
522
523
524static status_t
525publish_device(device_node *node, const char *path, const char *moduleName)
526{
527	if (path == NULL || !path[0] || moduleName == NULL || !moduleName[0])
528		return B_BAD_VALUE;
529
530	RecursiveLocker _(sLock);
531	dprintf("publish device: node %p, path %s, module %s\n", node, path,
532		moduleName);
533
534	Device* device = new(std::nothrow) Device(node, path, moduleName);
535	if (device == NULL)
536		return B_NO_MEMORY;
537
538	if (device->InitCheck() != B_OK) {
539		delete device;
540		return B_NO_MEMORY;
541	}
542
543	node->AddDevice(device);
544	return B_OK;
545}
546
547
548static status_t
549unpublish_device(device_node *node, const char *path)
550{
551	if (path == NULL)
552		return B_BAD_VALUE;
553
554	RecursiveLocker _(sLock);
555
556	DeviceList::ConstIterator iterator = node->Devices().GetIterator();
557	while (iterator.HasNext()) {
558		Device* device = iterator.Next();
559		if (!strcmp(device->Path(), path)) {
560			node->RemoveDevice(device);
561			delete device;
562			return B_OK;
563		}
564	}
565
566	return B_ENTRY_NOT_FOUND;
567}
568
569
570static status_t
571get_attr_uint8(const device_node* node, const char* name, uint8* _value,
572	bool recursive)
573{
574	if (node == NULL || name == NULL || _value == NULL)
575		return B_BAD_VALUE;
576
577	device_attr_private* attr = find_attr(node, name, recursive, B_UINT8_TYPE);
578	if (attr == NULL)
579		return B_NAME_NOT_FOUND;
580
581	*_value = attr->value.ui8;
582	return B_OK;
583}
584
585
586static status_t
587get_attr_uint16(const device_node* node, const char* name, uint16* _value,
588	bool recursive)
589{
590	if (node == NULL || name == NULL || _value == NULL)
591		return B_BAD_VALUE;
592
593	device_attr_private* attr = find_attr(node, name, recursive, B_UINT16_TYPE);
594	if (attr == NULL)
595		return B_NAME_NOT_FOUND;
596
597	*_value = attr->value.ui16;
598	return B_OK;
599}
600
601
602static status_t
603get_attr_uint32(const device_node* node, const char* name, uint32* _value,
604	bool recursive)
605{
606	if (node == NULL || name == NULL || _value == NULL)
607		return B_BAD_VALUE;
608
609	device_attr_private* attr = find_attr(node, name, recursive, B_UINT32_TYPE);
610	if (attr == NULL)
611		return B_NAME_NOT_FOUND;
612
613	*_value = attr->value.ui32;
614	return B_OK;
615}
616
617
618static status_t
619get_attr_uint64(const device_node* node, const char* name,
620	uint64* _value, bool recursive)
621{
622	if (node == NULL || name == NULL || _value == NULL)
623		return B_BAD_VALUE;
624
625	device_attr_private* attr = find_attr(node, name, recursive, B_UINT64_TYPE);
626	if (attr == NULL)
627		return B_NAME_NOT_FOUND;
628
629	*_value = attr->value.ui64;
630	return B_OK;
631}
632
633
634static status_t
635get_attr_string(const device_node* node, const char* name,
636	const char** _value, bool recursive)
637{
638	if (node == NULL || name == NULL || _value == NULL)
639		return B_BAD_VALUE;
640
641	device_attr_private* attr = find_attr(node, name, recursive, B_STRING_TYPE);
642	if (attr == NULL)
643		return B_NAME_NOT_FOUND;
644
645	*_value = attr->value.string;
646	return B_OK;
647}
648
649
650static status_t
651get_attr_raw(const device_node* node, const char* name, const void** _data,
652	size_t* _length, bool recursive)
653{
654	if (node == NULL || name == NULL || (_data == NULL && _length == NULL))
655		return B_BAD_VALUE;
656
657	device_attr_private* attr = find_attr(node, name, recursive, B_RAW_TYPE);
658	if (attr == NULL)
659		return B_NAME_NOT_FOUND;
660
661	if (_data != NULL)
662		*_data = attr->value.raw.data;
663	if (_length != NULL)
664		*_length = attr->value.raw.length;
665	return B_OK;
666}
667
668
669static status_t
670get_next_attr(device_node* node, device_attr** _attr)
671{
672	if (node == NULL)
673		return B_BAD_VALUE;
674
675	device_attr_private* next;
676	device_attr_private* attr = *(device_attr_private**)_attr;
677
678	if (attr != NULL) {
679		// next attribute
680		next = attr->GetDoublyLinkedListLink()->next;
681	} else {
682		// first attribute
683		next = node->Attributes().First();
684	}
685
686	*_attr = next;
687
688	return next ? B_OK : B_ENTRY_NOT_FOUND;
689}
690
691
692static struct device_manager_info sDeviceManagerModule = {
693	{
694		B_DEVICE_MANAGER_MODULE_NAME,
695		0,
696		NULL
697	},
698
699	// device nodes
700	rescan_node,
701	register_node,
702	unregister_node,
703	get_driver,
704	get_root_node,
705	get_next_child_node,
706	get_parent_node,
707	put_node,
708
709	// devices
710	publish_device,
711	unpublish_device,
712
713	// attributes
714	get_attr_uint8,
715	get_attr_uint16,
716	get_attr_uint32,
717	get_attr_uint64,
718	get_attr_string,
719	get_attr_raw,
720	get_next_attr,
721};
722
723
724//	#pragma mark - device_attr
725
726
727device_attr_private::device_attr_private()
728{
729	name = NULL;
730	type = 0;
731	value.raw.data = NULL;
732	value.raw.length = 0;
733}
734
735
736device_attr_private::device_attr_private(const device_attr& attr)
737{
738	CopyFrom(attr);
739}
740
741
742device_attr_private::~device_attr_private()
743{
744	_Unset();
745}
746
747
748status_t
749device_attr_private::InitCheck()
750{
751	return name != NULL ? B_OK : B_NO_INIT;
752}
753
754
755status_t
756device_attr_private::CopyFrom(const device_attr& attr)
757{
758	name = strdup(attr.name);
759	if (name == NULL)
760		return B_NO_MEMORY;
761
762	type = attr.type;
763
764	switch (type) {
765		case B_UINT8_TYPE:
766		case B_UINT16_TYPE:
767		case B_UINT32_TYPE:
768		case B_UINT64_TYPE:
769			value.ui64 = attr.value.ui64;
770			break;
771
772		case B_STRING_TYPE:
773			if (attr.value.string != NULL) {
774				value.string = strdup(attr.value.string);
775				if (value.string == NULL) {
776					_Unset();
777					return B_NO_MEMORY;
778				}
779			} else
780				value.string = NULL;
781			break;
782
783		case B_RAW_TYPE:
784			value.raw.data = malloc(attr.value.raw.length);
785			if (value.raw.data == NULL) {
786				_Unset();
787				return B_NO_MEMORY;
788			}
789
790			value.raw.length = attr.value.raw.length;
791			memcpy((void*)value.raw.data, attr.value.raw.data,
792				attr.value.raw.length);
793			break;
794
795		default:
796			return B_BAD_VALUE;
797	}
798
799	return B_OK;
800}
801
802
803void
804device_attr_private::_Unset()
805{
806	if (type == B_STRING_TYPE)
807		free((char*)value.string);
808	else if (type == B_RAW_TYPE)
809		free((void*)value.raw.data);
810
811	free((char*)name);
812
813	name = NULL;
814	value.raw.data = NULL;
815	value.raw.length = 0;
816}
817
818
819/*static*/ int
820device_attr_private::Compare(const device_attr* attrA, const device_attr *attrB)
821{
822	if (attrA->type != attrB->type)
823		return -1;
824
825	switch (attrA->type) {
826		case B_UINT8_TYPE:
827			return (int)attrA->value.ui8 - (int)attrB->value.ui8;
828
829		case B_UINT16_TYPE:
830			return (int)attrA->value.ui16 - (int)attrB->value.ui16;
831
832		case B_UINT32_TYPE:
833			if (attrA->value.ui32 > attrB->value.ui32)
834				return 1;
835			if (attrA->value.ui32 < attrB->value.ui32)
836				return -1;
837			return 0;
838
839		case B_UINT64_TYPE:
840			if (attrA->value.ui64 > attrB->value.ui64)
841				return 1;
842			if (attrA->value.ui64 < attrB->value.ui64)
843				return -1;
844			return 0;
845
846		case B_STRING_TYPE:
847			return strcmp(attrA->value.string, attrB->value.string);
848
849		case B_RAW_TYPE:
850			if (attrA->value.raw.length != attrB->value.raw.length)
851				return -1;
852
853			return memcmp(attrA->value.raw.data, attrB->value.raw.data,
854				attrA->value.raw.length);
855	}
856
857	return -1;
858}
859
860
861//	#pragma mark - Device
862
863
864Device::Device(device_node* node, const char* path, const char* moduleName)
865	:
866	fNode(node),
867	fInitialized(0),
868	fDeviceModule(NULL),
869	fDeviceData(NULL)
870{
871	fPath = strdup(path);
872	fModuleName = strdup(moduleName);
873}
874
875
876Device::~Device()
877{
878	free((char*)fPath);
879	free((char*)fModuleName);
880}
881
882
883status_t
884Device::InitCheck() const
885{
886	return fPath != NULL && fModuleName != NULL ? B_OK : B_NO_MEMORY;
887}
888
889
890status_t
891Device::InitDevice()
892{
893	if ((fNode->Flags() & NODE_FLAG_DEVICE_REMOVED) != 0) {
894		// TODO: maybe the device should be unlinked in devfs, too
895		return ENODEV;
896	}
897	if ((fNode->Flags() & NODE_FLAG_WAITING_FOR_DRIVER) != 0)
898		return B_BUSY;
899
900	if (fInitialized++ > 0) {
901		fNode->InitDriver();
902			// acquire another reference to our parent as well
903		return B_OK;
904	}
905
906	status_t status = get_module(ModuleName(), (module_info**)&fDeviceModule);
907	if (status == B_OK) {
908		// our parent always has to be initialized
909		status = fNode->InitDriver();
910	}
911	if (status < B_OK) {
912		fInitialized--;
913		return status;
914	}
915
916	if (fDeviceModule->init_device != NULL)
917		status = fDeviceModule->init_device(fNode->DriverData(), &fDeviceData);
918
919	if (status < B_OK) {
920		fNode->UninitDriver();
921		fInitialized--;
922
923		put_module(ModuleName());
924		fDeviceModule = NULL;
925		fDeviceData = NULL;
926	}
927
928	return status;
929}
930
931
932void
933Device::UninitDevice()
934{
935	if (fInitialized-- > 1) {
936		fNode->UninitDriver();
937		return;
938	}
939
940	TRACE(("uninit driver for node %p\n", this));
941
942	if (fDeviceModule->uninit_device != NULL)
943		fDeviceModule->uninit_device(fDeviceData);
944
945	fDeviceModule = NULL;
946	fDeviceData = NULL;
947
948	put_module(ModuleName());
949
950	fNode->UninitDriver();
951}
952
953
954//	#pragma mark - device_node
955
956
957/*!	Allocate device node info structure;
958	initially, ref_count is one to make sure node won't get destroyed by mistake
959*/
960device_node::device_node(const char* moduleName, const device_attr* attrs,
961	const io_resource* resources)
962{
963	fModuleName = strdup(moduleName);
964	if (fModuleName == NULL)
965		return;
966
967	fParent = NULL;
968	fRefCount = 1;
969	fInitialized = 0;
970	fRegistered = false;
971	fFlags = 0;
972	fSupportsParent = 0.0;
973	fLastUpdateCycle = 0;
974	fDriver = NULL;
975	fDriverData = NULL;
976
977	// copy attributes
978
979	while (attrs != NULL && attrs->name != NULL) {
980		device_attr_private* attr
981			= new(std::nothrow) device_attr_private(*attrs);
982		if (attr == NULL)
983			break;
984
985		fAttributes.Add(attr);
986		attrs++;
987	}
988
989	get_attr_uint32(this, B_DEVICE_FLAGS, &fFlags, false);
990	fFlags &= NODE_FLAG_PUBLIC_MASK;
991}
992
993
994device_node::~device_node()
995{
996	TRACE(("delete node %p\n", this));
997	ASSERT(DriverModule() == NULL);
998
999	if (Parent() != NULL) {
1000		if ((fFlags & NODE_FLAG_OBSOLETE_DRIVER) != 0) {
1001			// This driver has been obsoleted; another driver has been waiting
1002			// for us - make it available
1003			Parent()->_ReleaseWaiting();
1004		}
1005		Parent()->RemoveChild(this);
1006	}
1007
1008	// Delete children
1009	NodeList::Iterator nodeIterator = fChildren.GetIterator();
1010	while (nodeIterator.HasNext()) {
1011		device_node* child = nodeIterator.Next();
1012		nodeIterator.Remove();
1013		delete child;
1014	}
1015
1016	// Delete devices
1017	DeviceList::Iterator deviceIterator = fDevices.GetIterator();
1018	while (deviceIterator.HasNext()) {
1019		Device* device = deviceIterator.Next();
1020		deviceIterator.Remove();
1021		// TODO: unpublish!
1022		delete device;
1023	}
1024
1025	// Delete attributes
1026	AttributeList::Iterator attrIterator = fAttributes.GetIterator();
1027	while (attrIterator.HasNext()) {
1028		device_attr_private* attr = attrIterator.Next();
1029		attrIterator.Remove();
1030		delete attr;
1031	}
1032
1033	free((char*)fModuleName);
1034}
1035
1036
1037status_t
1038device_node::InitCheck() const
1039{
1040	return fModuleName != NULL ? B_OK : B_NO_MEMORY;
1041}
1042
1043
1044status_t
1045device_node::InitDriver()
1046{
1047	if (fInitialized++ > 0) {
1048		if (Parent() != NULL) {
1049			Parent()->InitDriver();
1050				// acquire another reference to our parent as well
1051		}
1052		Acquire();
1053		return B_OK;
1054	}
1055
1056	status_t status = get_module(ModuleName(), (module_info**)&fDriver);
1057	if (status == B_OK && Parent() != NULL) {
1058		// our parent always has to be initialized
1059		status = Parent()->InitDriver();
1060	}
1061	if (status < B_OK) {
1062		fInitialized--;
1063		return status;
1064	}
1065
1066	if (fDriver->init_driver != NULL)
1067		status = fDriver->init_driver(this, &fDriverData);
1068
1069	if (status < B_OK) {
1070		if (Parent() != NULL)
1071			Parent()->UninitDriver();
1072		fInitialized--;
1073
1074		put_module(ModuleName());
1075		fDriver = NULL;
1076		fDriverData = NULL;
1077		return status;
1078	}
1079
1080	Acquire();
1081	return B_OK;
1082}
1083
1084
1085bool
1086device_node::UninitDriver()
1087{
1088	if (fInitialized-- > 1) {
1089		if (Parent() != NULL)
1090			Parent()->UninitDriver();
1091		Release();
1092		return false;
1093	}
1094
1095	TRACE(("uninit driver for node %p\n", this));
1096
1097	if (fDriver->uninit_driver != NULL)
1098		fDriver->uninit_driver(fDriverData);
1099
1100	fDriver = NULL;
1101	fDriverData = NULL;
1102
1103	put_module(ModuleName());
1104
1105	if (Parent() != NULL)
1106		Parent()->UninitDriver();
1107	Release();
1108
1109	return true;
1110}
1111
1112
1113void
1114device_node::AddChild(device_node* node)
1115{
1116	// we must not be destroyed	as long as we have children
1117	Acquire();
1118	node->fParent = this;
1119	fChildren.Add(node);
1120}
1121
1122
1123void
1124device_node::RemoveChild(device_node* node)
1125{
1126	node->fParent = NULL;
1127	fChildren.Remove(node);
1128	Release();
1129}
1130
1131
1132/*!	Registers this node, and all of its children that have to be registered.
1133	Also initializes the driver and keeps it that way on return in case
1134	it returns successfully.
1135*/
1136status_t
1137device_node::Register(device_node* parent)
1138{
1139	// make it public
1140	if (parent != NULL)
1141		parent->AddChild(this);
1142	else
1143		sRootNode = this;
1144
1145	status_t status = InitDriver();
1146	if (status != B_OK)
1147		return status;
1148
1149	if ((fFlags & B_KEEP_DRIVER_LOADED) != 0) {
1150		// We keep this driver loaded by having it always initialized
1151		InitDriver();
1152	}
1153
1154	fFlags |= NODE_FLAG_REGISTER_INITIALIZED;
1155		// We don't uninitialize the driver - this is done by the caller
1156		// in order to save reinitializing during driver loading.
1157
1158	uint32 registered;
1159	status = _RegisterFixed(registered);
1160	if (status != B_OK) {
1161		UninitUnusedDriver();
1162		return status;
1163	}
1164	if (registered > 0) {
1165		fRegistered = true;
1166		return B_OK;
1167	}
1168
1169	// Register the children the driver wants
1170
1171	if (DriverModule()->register_child_devices != NULL) {
1172		status = DriverModule()->register_child_devices(this);
1173		if (status != B_OK) {
1174			UninitUnusedDriver();
1175			return status;
1176		}
1177
1178		if (!fChildren.IsEmpty()) {
1179			fRegistered = true;
1180			return B_OK;
1181		}
1182	}
1183
1184	// Register all possible child device nodes
1185
1186	status = _RegisterDynamic();
1187	if (status == B_OK)
1188		fRegistered = true;
1189	else
1190		UninitUnusedDriver();
1191
1192	return status;
1193}
1194
1195
1196/*!	Registers any children that are identified via the B_DRIVER_FIXED_CHILD
1197	attribute.
1198	If any of these children cannot be registered, this call will fail (we
1199	don't remove children we already registered up to this point in this case).
1200*/
1201status_t
1202device_node::_RegisterFixed(uint32& registered)
1203{
1204	AttributeList::Iterator iterator = fAttributes.GetIterator();
1205	registered = 0;
1206
1207	while (iterator.HasNext()) {
1208		device_attr_private* attr = iterator.Next();
1209		if (strcmp(attr->name, B_DEVICE_FIXED_CHILD))
1210			continue;
1211
1212		driver_module_info* driver;
1213		status_t status = get_module(attr->value.string,
1214			(module_info**)&driver);
1215		if (status != B_OK)
1216			return status;
1217
1218		if (driver->register_device != NULL) {
1219			status = driver->register_device(this);
1220			if (status == B_OK)
1221				registered++;
1222		}
1223
1224		put_module(attr->value.string);
1225
1226		if (status != B_OK)
1227			return status;
1228	}
1229
1230	return B_OK;
1231}
1232
1233
1234status_t
1235device_node::_AddPath(Stack<KPath*>& stack, const char* basePath,
1236	const char* subPath)
1237{
1238	KPath* path = new(std::nothrow) KPath;
1239	if (path == NULL)
1240		return B_NO_MEMORY;
1241
1242	status_t status = path->SetTo(basePath);
1243	if (status == B_OK && subPath != NULL && subPath[0])
1244		status = path->Append(subPath);
1245	if (status == B_OK)
1246		status = stack.Push(path);
1247
1248	if (status != B_OK)
1249		delete path;
1250
1251	return status;
1252}
1253
1254
1255status_t
1256device_node::_GetNextDriverPath(void*& cookie, KPath& _path)
1257{
1258	Stack<KPath*>* stack = NULL;
1259
1260	if (cookie == NULL) {
1261		// find all paths and add them
1262		stack = new(std::nothrow) Stack<KPath*>();
1263		if (stack == NULL)
1264			return B_NO_MEMORY;
1265
1266		StackDeleter<KPath*> stackDeleter(stack);
1267		uint16 type = 0;
1268		uint16 subType = 0;
1269		uint16 interface = 0;
1270		get_attr_uint16(this, B_DEVICE_TYPE, &type, false);
1271		get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false);
1272		get_attr_uint16(this, B_DEVICE_INTERFACE, &interface, false);
1273
1274		// TODO: maybe make this extendible via settings file?
1275		switch (type) {
1276			case PCI_mass_storage:
1277				switch (subType) {
1278					case PCI_scsi:
1279						_AddPath(*stack, "busses", "scsi");
1280						break;
1281					case PCI_ide:
1282						_AddPath(*stack, "busses", "ide");
1283						break;
1284					case PCI_sata:
1285						_AddPath(*stack, "busses", "sata");
1286						break;
1287					default:
1288						_AddPath(*stack, "busses", "disk");
1289						break;
1290				}
1291				break;
1292			case PCI_serial_bus:
1293				switch (subType) {
1294					case PCI_firewire:
1295						_AddPath(*stack, "busses", "firewire");
1296						break;
1297					case PCI_usb:
1298						_AddPath(*stack, "busses", "usb");
1299						break;
1300					default:
1301						_AddPath(*stack, "busses");
1302						break;
1303				}
1304				break;
1305			case PCI_network:
1306				_AddPath(*stack, "drivers", "net");
1307				break;
1308			case PCI_display:
1309				_AddPath(*stack, "drivers", "graphics");
1310				break;
1311			case PCI_multimedia:
1312				switch (subType) {
1313					case PCI_audio:
1314					case PCI_hd_audio:
1315						_AddPath(*stack, "drivers", "audio");
1316						break;
1317					case PCI_video:
1318						_AddPath(*stack, "drivers", "video");
1319						break;
1320					default:
1321						_AddPath(*stack, "drivers");
1322						break;
1323				}
1324				break;
1325			default:
1326				if (sRootNode == this) {
1327					_AddPath(*stack, "busses/pci");
1328					_AddPath(*stack, "bus_managers");
1329				} else
1330					_AddPath(*stack, "drivers");
1331				break;
1332		}
1333
1334		stackDeleter.Detach();
1335
1336		cookie = (void*)stack;
1337	} else
1338		stack = static_cast<Stack<KPath*>*>(cookie);
1339
1340	KPath* path;
1341	if (stack->Pop(&path)) {
1342		_path.Adopt(*path);
1343		delete path;
1344		return B_OK;
1345	}
1346
1347	delete stack;
1348	return B_ENTRY_NOT_FOUND;
1349}
1350
1351
1352status_t
1353device_node::_GetNextDriver(void* list, driver_module_info*& driver)
1354{
1355	while (true) {
1356		char name[B_FILE_NAME_LENGTH];
1357		size_t nameLength = sizeof(name);
1358
1359		status_t status = read_next_module_name(list, name, &nameLength);
1360		if (status != B_OK)
1361			return status;
1362
1363		if (!strcmp(fModuleName, name))
1364			continue;
1365
1366		if (get_module(name, (module_info**)&driver) != B_OK)
1367			continue;
1368
1369		if (driver->supports_device == NULL
1370			|| driver->register_device == NULL) {
1371			put_module(name);
1372			continue;
1373		}
1374
1375		return B_OK;
1376	}
1377}
1378
1379
1380status_t
1381device_node::_FindBestDriver(const char* path, driver_module_info*& bestDriver,
1382	float& bestSupport, device_node* previous)
1383{
1384	if (bestDriver == NULL)
1385		bestSupport = previous != NULL ? previous->fSupportsParent : 0.0f;
1386
1387	void* list = open_module_list_etc(path, "driver_v1");
1388	driver_module_info* driver;
1389	while (_GetNextDriver(list, driver) == B_OK) {
1390		if (previous != NULL && driver == previous->DriverModule()) {
1391			put_module(driver->info.name);
1392			continue;
1393		}
1394
1395		float support = driver->supports_device(this);
1396		if (support > bestSupport) {
1397			if (bestDriver != NULL)
1398				put_module(bestDriver->info.name);
1399
1400			bestDriver = driver;
1401			bestSupport = support;
1402			continue;
1403				// keep reference to best module around
1404		}
1405
1406		put_module(driver->info.name);
1407	}
1408	close_module_list(list);
1409
1410	return bestDriver != NULL ? B_OK : B_ENTRY_NOT_FOUND;
1411}
1412
1413
1414status_t
1415device_node::_RegisterPath(const char* path)
1416{
1417	void* list = open_module_list_etc(path, "driver_v1");
1418	driver_module_info* driver;
1419	uint32 count = 0;
1420
1421	while (_GetNextDriver(list, driver) == B_OK) {
1422		float support = driver->supports_device(this);
1423		if (support > 0.0) {
1424			TRACE(("  register module \"%s\", support %f\n", driver->info.name,
1425				support));
1426			if (driver->register_device(this) == B_OK)
1427				count++;
1428		}
1429
1430		put_module(driver->info.name);
1431	}
1432	close_module_list(list);
1433
1434	return count > 0 ? B_OK : B_ENTRY_NOT_FOUND;
1435}
1436
1437
1438bool
1439device_node::_AlwaysRegisterDynamic()
1440{
1441	uint16 type = 0;
1442	uint16 subType = 0;
1443	get_attr_uint16(this, B_DEVICE_TYPE, &type, false);
1444	get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false);
1445
1446	return type == PCI_serial_bus || type == PCI_bridge;
1447		// TODO: we may want to be a bit more specific in the future
1448}
1449
1450
1451status_t
1452device_node::_RegisterDynamic(device_node* previous)
1453{
1454	// If this is our initial registration, we honour the B_FIND_CHILD_ON_DEMAND
1455	// requirements
1456	if (!fRegistered && (fFlags & B_FIND_CHILD_ON_DEMAND) != 0
1457		&& !_AlwaysRegisterDynamic())
1458		return B_OK;
1459
1460	KPath path;
1461
1462	if ((fFlags & B_FIND_MULTIPLE_CHILDREN) == 0) {
1463		// find the one driver
1464		driver_module_info* bestDriver = NULL;
1465		float bestSupport = 0.0;
1466		void* cookie = NULL;
1467
1468		while (_GetNextDriverPath(cookie, path) == B_OK) {
1469			_FindBestDriver(path.Path(), bestDriver, bestSupport, previous);
1470		}
1471
1472		if (bestDriver != NULL) {
1473			TRACE(("  register best module \"%s\", support %f\n",
1474				bestDriver->info.name, bestSupport));
1475			if (bestDriver->register_device(this) == B_OK) {
1476				// There can only be one node of this driver
1477				// (usually only one at all, but there might be a new driver
1478				// "waiting" for its turn)
1479				device_node* child = FindChild(bestDriver->info.name);
1480				if (child != NULL) {
1481					child->fSupportsParent = bestSupport;
1482					if (previous != NULL) {
1483						previous->fFlags |= NODE_FLAG_OBSOLETE_DRIVER;
1484						previous->Release();
1485						child->fFlags |= NODE_FLAG_WAITING_FOR_DRIVER;
1486					}
1487				}
1488				// TODO: if this fails, we could try the second best driver,
1489				// and so on...
1490			}
1491			put_module(bestDriver->info.name);
1492		}
1493	} else {
1494		// register all drivers that match
1495		void* cookie = NULL;
1496		while (_GetNextDriverPath(cookie, path) == B_OK) {
1497			_RegisterPath(path.Path());
1498		}
1499	}
1500
1501	return B_OK;
1502}
1503
1504
1505void
1506device_node::_ReleaseWaiting()
1507{
1508	NodeList::Iterator iterator = fChildren.GetIterator();
1509	while (iterator.HasNext()) {
1510		device_node* child = iterator.Next();
1511
1512		child->fFlags &= ~NODE_FLAG_WAITING_FOR_DRIVER;
1513	}
1514}
1515
1516
1517status_t
1518device_node::_RemoveChildren()
1519{
1520	NodeList::Iterator iterator = fChildren.GetIterator();
1521	while (iterator.HasNext()) {
1522		device_node* child = iterator.Next();
1523		child->Release();
1524	}
1525
1526	return fChildren.IsEmpty() ? B_OK : B_BUSY;
1527}
1528
1529
1530device_node*
1531device_node::_FindCurrentChild()
1532{
1533	NodeList::Iterator iterator = fChildren.GetIterator();
1534	while (iterator.HasNext()) {
1535		device_node* child = iterator.Next();
1536
1537		if ((child->Flags() & NODE_FLAG_WAITING_FOR_DRIVER) == 0)
1538			return child;
1539	}
1540
1541	return NULL;
1542}
1543
1544
1545status_t
1546device_node::Probe(const char* devicePath, uint32 updateCycle)
1547{
1548	if ((fFlags & NODE_FLAG_DEVICE_REMOVED) != 0
1549		|| updateCycle == fLastUpdateCycle)
1550		return B_OK;
1551
1552	status_t status = InitDriver();
1553	if (status < B_OK)
1554		return status;
1555
1556	MethodDeleter<device_node, bool> uninit(this,
1557		&device_node::UninitDriver);
1558
1559	uint16 type = 0;
1560	uint16 subType = 0;
1561	if (get_attr_uint16(this, B_DEVICE_TYPE, &type, false) == B_OK
1562		&& get_attr_uint16(this, B_DEVICE_SUB_TYPE, &subType, false)
1563			== B_OK) {
1564		// Check if this node matches the device path
1565		// TODO: maybe make this extendible via settings file?
1566		bool matches = false;
1567		if (!strcmp(devicePath, "disk")) {
1568			matches = type == PCI_mass_storage;
1569		} else if (!strcmp(devicePath, "audio")) {
1570			matches = type == PCI_multimedia
1571				&& (subType == PCI_audio || subType == PCI_hd_audio);
1572		} else if (!strcmp(devicePath, "net")) {
1573			matches = type == PCI_network;
1574		} else if (!strcmp(devicePath, "graphics")) {
1575			matches = type == PCI_display;
1576		} else if (!strcmp(devicePath, "video")) {
1577			matches = type == PCI_multimedia && subType == PCI_video;
1578		}
1579
1580		if (matches) {
1581			device_node* previous = NULL;
1582
1583			fLastUpdateCycle = updateCycle;
1584				// This node will be probed in this update cycle
1585
1586			if (!fChildren.IsEmpty()
1587				&& (fFlags & B_FIND_MULTIPLE_CHILDREN) == 0) {
1588				// We already have a driver that claims this node; remove all
1589				// (unused) nodes, and evaluate it again
1590				_RemoveChildren();
1591
1592				previous = _FindCurrentChild();
1593				if (previous != NULL) {
1594					// This driver is still active - give it back the reference
1595					// that was stolen by _RemoveChildren() - _RegisterDynamic()
1596					// will release it, if it really isn't needed anymore
1597					previous->Acquire();
1598				}
1599			}
1600			return _RegisterDynamic(previous);
1601		}
1602
1603		return B_OK;
1604	}
1605
1606	NodeList::Iterator iterator = fChildren.GetIterator();
1607	while (iterator.HasNext()) {
1608		device_node* child = iterator.Next();
1609
1610		status = child->Probe(devicePath, updateCycle);
1611		if (status != B_OK)
1612			return status;
1613	}
1614
1615	return B_OK;
1616}
1617
1618
1619/*!	Uninitializes all temporary references to the driver. The registration
1620	process keeps the driver initialized to optimize the startup procedure;
1621	this function gives this reference away again.
1622*/
1623void
1624device_node::UninitUnusedDriver()
1625{
1626	// First, we need to go to the leaf, and go back from there
1627
1628	NodeList::Iterator iterator = fChildren.GetIterator();
1629	while (iterator.HasNext()) {
1630		device_node* child = iterator.Next();
1631
1632		child->UninitUnusedDriver();
1633	}
1634
1635	if (!IsInitialized()
1636		|| (fFlags & NODE_FLAG_REGISTER_INITIALIZED) == 0)
1637		return;
1638
1639	fFlags &= ~NODE_FLAG_REGISTER_INITIALIZED;
1640
1641	UninitDriver();
1642}
1643
1644
1645/*!	Calls device_removed() on this node and all of its children - starting
1646	with the deepest and last child.
1647	It will also remove the one reference that every node gets on its creation.
1648*/
1649void
1650device_node::DeviceRemoved()
1651{
1652	// notify children
1653	NodeList::ConstIterator iterator = Children().GetIterator();
1654	while (iterator.HasNext()) {
1655		device_node* child = iterator.Next();
1656
1657		child->DeviceRemoved();
1658	}
1659
1660	// notify devices
1661	DeviceList::ConstIterator deviceIterator = Devices().GetIterator();
1662	while (deviceIterator.HasNext()) {
1663		Device* device = deviceIterator.Next();
1664
1665		if (device->DeviceModule() != NULL
1666			&& device->DeviceModule()->device_removed != NULL)
1667			device->DeviceModule()->device_removed(device->DeviceData());
1668	}
1669
1670	fFlags |= NODE_FLAG_DEVICE_REMOVED;
1671
1672	if (IsInitialized() && DriverModule()->device_removed != NULL)
1673		DriverModule()->device_removed(this);
1674
1675	if ((fFlags & B_KEEP_DRIVER_LOADED) != 0) {
1676		// There is no point in keeping this driver loaded when its device
1677		// is gone
1678		UninitDriver();
1679	}
1680
1681	UninitUnusedDriver();
1682	Release();
1683}
1684
1685
1686void
1687device_node::Acquire()
1688{
1689	atomic_add(&fRefCount, 1);
1690}
1691
1692
1693bool
1694device_node::Release()
1695{
1696	if (atomic_add(&fRefCount, -1) > 1)
1697		return false;
1698
1699	delete this;
1700	return true;
1701}
1702
1703
1704void
1705device_node::AddDevice(Device* device)
1706{
1707	fDevices.Add(device);
1708}
1709
1710
1711void
1712device_node::RemoveDevice(Device* device)
1713{
1714	fDevices.Remove(device);
1715}
1716
1717
1718int
1719device_node::CompareTo(const device_attr* attributes) const
1720{
1721	if (attributes == NULL)
1722		return -1;
1723
1724	for (; attributes->name != NULL; attributes++) {
1725		// find corresponding attribute
1726		AttributeList::ConstIterator iterator = Attributes().GetIterator();
1727		device_attr_private* attr = NULL;
1728		while (iterator.HasNext()) {
1729			attr = iterator.Next();
1730
1731			if (!strcmp(attr->name, attributes->name))
1732				break;
1733		}
1734		if (!iterator.HasNext())
1735			return -1;
1736
1737		int compare = device_attr_private::Compare(attr, attributes);
1738		if (compare != 0)
1739			return compare;
1740	}
1741
1742	return 0;
1743}
1744
1745
1746device_node*
1747device_node::FindChild(const device_attr* attributes) const
1748{
1749	if (attributes == NULL)
1750		return NULL;
1751
1752	NodeList::ConstIterator iterator = Children().GetIterator();
1753	while (iterator.HasNext()) {
1754		device_node* child = iterator.Next();
1755
1756		// ignore nodes that are pending to be removed
1757		if ((child->Flags() & NODE_FLAG_DEVICE_REMOVED) == 0
1758			&& !child->CompareTo(attributes))
1759			return child;
1760	}
1761
1762	return NULL;
1763}
1764
1765
1766device_node*
1767device_node::FindChild(const char* moduleName) const
1768{
1769	if (moduleName == NULL)
1770		return NULL;
1771
1772	NodeList::ConstIterator iterator = Children().GetIterator();
1773	while (iterator.HasNext()) {
1774		device_node* child = iterator.Next();
1775
1776		if (!strcmp(child->ModuleName(), moduleName))
1777			return child;
1778	}
1779
1780	return NULL;
1781}
1782
1783
1784void
1785device_node::Dump(int32 level = 0)
1786{
1787	put_level(level);
1788	dprintf("(%ld) @%p \"%s\" (ref %ld, init %ld)\n", level, this, ModuleName(),
1789		fRefCount, fInitialized);
1790
1791	AttributeList::Iterator attribute = Attributes().GetIterator();
1792	while (attribute.HasNext()) {
1793		dump_attribute(attribute.Next(), level);
1794	}
1795
1796	NodeList::ConstIterator iterator = Children().GetIterator();
1797	while (iterator.HasNext()) {
1798		iterator.Next()->Dump(level + 1);
1799	}
1800}
1801
1802
1803//	#pragma mark - root node
1804
1805
1806static void
1807init_root_node(void)
1808{
1809	device_attr attrs[] = {
1810		{B_DEVICE_PRETTY_NAME, B_STRING_TYPE, {string: "Devices Root"}},
1811		{B_DEVICE_BUS, B_STRING_TYPE, {string: "root"}},
1812		{B_DEVICE_FLAGS, B_UINT32_TYPE,
1813			{ui32: B_FIND_MULTIPLE_CHILDREN | B_KEEP_DRIVER_LOADED }},
1814		{NULL}
1815	};
1816
1817	if (register_node(NULL, DEVICE_MANAGER_ROOT_NAME, attrs, NULL, NULL)
1818			!= B_OK) {
1819		dprintf("Cannot register Devices Root Node\n");
1820	}
1821}
1822
1823
1824static driver_module_info sDeviceRootModule = {
1825	{
1826		DEVICE_MANAGER_ROOT_NAME,
1827		0,
1828		NULL,
1829	},
1830	NULL
1831};
1832
1833
1834//	#pragma mark -
1835
1836
1837int
1838main(int argc, char** argv)
1839{
1840	_add_builtin_module((module_info*)&sDeviceManagerModule);
1841	_add_builtin_module((module_info*)&sDeviceRootModule);
1842
1843	// bus
1844	_add_builtin_module((module_info*)&gBusModuleInfo);
1845	_add_builtin_module((module_info*)&gBusDriverModuleInfo);
1846
1847	// sample driver
1848	_add_builtin_module((module_info*)&gDriverModuleInfo);
1849	_add_builtin_module((module_info*)&gDeviceModuleInfo);
1850
1851	// generic video driver
1852	_add_builtin_module((module_info*)&gGenericVideoDriverModuleInfo);
1853	_add_builtin_module((module_info*)&gGenericVideoDeviceModuleInfo);
1854
1855	gDeviceManager = &sDeviceManagerModule;
1856
1857	status_t status = _get_builtin_dependencies();
1858	if (status < B_OK) {
1859		fprintf(stderr, "device_manager: Could not initialize modules: %s\n",
1860			strerror(status));
1861		return 1;
1862	}
1863
1864	recursive_lock_init(&sLock, "device manager");
1865
1866	init_root_node();
1867	sRootNode->Dump();
1868
1869	probe_path("net");
1870	probe_path("graphics");
1871
1872	void* netHandle = open_path("net/sample/0");
1873
1874	uninit_unused();
1875
1876	puts("remove net driver");
1877	device_node* busNode = sRootNode->FindChild(BUS_MODULE_NAME);
1878	bus_trigger_device_removed(busNode);
1879
1880	close_path(netHandle);
1881		// the net nodes must be removed with this call
1882
1883	void* graphicsHandle = open_path("graphics/generic/0");
1884
1885	// add specific video driver - ie. simulate installing it
1886	_add_builtin_module((module_info*)&gSpecificVideoDriverModuleInfo);
1887	_add_builtin_module((module_info*)&gSpecificVideoDeviceModuleInfo);
1888	sDriverUpdateCycle++;
1889	probe_path("graphics");
1890
1891	open_path("graphics/specific/0");
1892		// this will fail
1893
1894	close_path(graphicsHandle);
1895		// the graphics drivers must be switched with this call
1896
1897	graphicsHandle = open_path("graphics/specific/0");
1898	close_path(graphicsHandle);
1899
1900	uninit_unused();
1901
1902	recursive_lock_destroy(&sLock);
1903	return 0;
1904}
1905