1368167edSAxel Dörfler/*
2ea8749b6SAxel Dörfler * Copyright 2002-2011, Axel D��rfler, axeld@pinc-software.de.
3368167edSAxel Dörfler * Distributed under the terms of the MIT License.
4368167edSAxel Dörfler */
5368167edSAxel Dörfler
6368167edSAxel Dörfler
7368167edSAxel Dörfler#include "legacy_drivers.h"
8368167edSAxel Dörfler
9368167edSAxel Dörfler#include <dirent.h>
10368167edSAxel Dörfler#include <errno.h>
11368167edSAxel Dörfler#include <new>
12368167edSAxel Dörfler#include <stdio.h>
13368167edSAxel Dörfler
14368167edSAxel Dörfler#include <FindDirectory.h>
15368167edSAxel Dörfler#include <image.h>
16368167edSAxel Dörfler#include <NodeMonitor.h>
17368167edSAxel Dörfler
18368167edSAxel Dörfler#include <boot_device.h>
1945bd7bb3SIngo Weinhold#include <boot/kernel_args.h>
20368167edSAxel Dörfler#include <elf.h>
21de49e349SIngo Weinhold#include <find_directory_private.h>
22368167edSAxel Dörfler#include <fs/devfs.h>
23368167edSAxel Dörfler#include <fs/KPath.h>
24368167edSAxel Dörfler#include <fs/node_monitor.h>
25368167edSAxel Dörfler#include <Notifications.h>
26368167edSAxel Dörfler#include <safemode.h>
27368167edSAxel Dörfler#include <util/DoublyLinkedList.h>
28368167edSAxel Dörfler#include <util/OpenHashTable.h>
29368167edSAxel Dörfler#include <util/Stack.h>
30368167edSAxel Dörfler#include <vfs.h>
31368167edSAxel Dörfler
32a9689e84SIngo Weinhold#include "AbstractModuleDevice.h"
33368167edSAxel Dörfler#include "devfs_private.h"
34368167edSAxel Dörfler
35368167edSAxel Dörfler
36368167edSAxel Dörfler//#define TRACE_LEGACY_DRIVERS
37368167edSAxel Dörfler#ifdef TRACE_LEGACY_DRIVERS
38368167edSAxel Dörfler#	define TRACE(x) dprintf x
39368167edSAxel Dörfler#else
40368167edSAxel Dörfler#	define TRACE(x)
41368167edSAxel Dörfler#endif
42368167edSAxel Dörfler
43368167edSAxel Dörfler#define DRIVER_HASH_SIZE 16
44368167edSAxel Dörfler
4599f77939SJérôme Duval
46097b4917SIngo Weinholdnamespace {
4799f77939SJérôme Duval
48368167edSAxel Dörflerstruct legacy_driver;
49368167edSAxel Dörfler
50a9689e84SIngo Weinholdclass LegacyDevice : public AbstractModuleDevice,
51368167edSAxel Dörfler	public DoublyLinkedListLinkImpl<LegacyDevice> {
52368167edSAxel Dörflerpublic:
53368167edSAxel Dörfler							LegacyDevice(legacy_driver* driver,
54368167edSAxel Dörfler								const char* path, device_hooks* hooks);
55368167edSAxel Dörfler	virtual					~LegacyDevice();
56368167edSAxel Dörfler
57368167edSAxel Dörfler			status_t		InitCheck() const;
58368167edSAxel Dörfler
59368167edSAxel Dörfler	virtual	status_t		InitDevice();
60368167edSAxel Dörfler	virtual	void			UninitDevice();
61368167edSAxel Dörfler
626015793fSAxel Dörfler	virtual	void			Removed();
636015793fSAxel Dörfler
64368167edSAxel Dörfler			void			SetHooks(device_hooks* hooks);
65368167edSAxel Dörfler
66368167edSAxel Dörfler			legacy_driver*	Driver() const { return fDriver; }
67368167edSAxel Dörfler			const char*		Path() const { return fPath; }
68368167edSAxel Dörfler			device_hooks*	Hooks() const { return fHooks; }
69368167edSAxel Dörfler
70368167edSAxel Dörfler	virtual	status_t		Open(const char* path, int openMode,
71368167edSAxel Dörfler								void** _cookie);
72368167edSAxel Dörfler	virtual	status_t		Select(void* cookie, uint8 event, selectsync* sync);
73368167edSAxel Dörfler
74f15da085SAxel Dörfler			bool			Republished() const { return fRepublished; }
75f15da085SAxel Dörfler			void			SetRepublished(bool republished)
76f15da085SAxel Dörfler								{ fRepublished = republished; }
776015793fSAxel Dörfler
786015793fSAxel Dörfler			void			SetRemovedFromParent(bool removed)
796015793fSAxel Dörfler								{ fRemovedFromParent = removed; }
806015793fSAxel Dörfler
81368167edSAxel Dörflerprivate:
82368167edSAxel Dörfler	legacy_driver*			fDriver;
83368167edSAxel Dörfler	const char*				fPath;
84368167edSAxel Dörfler	device_hooks*			fHooks;
85f15da085SAxel Dörfler	bool					fRepublished;
866015793fSAxel Dörfler	bool					fRemovedFromParent;
87368167edSAxel Dörfler};
88368167edSAxel Dörfler
89368167edSAxel Dörflertypedef DoublyLinkedList<LegacyDevice> DeviceList;
90368167edSAxel Dörfler
91368167edSAxel Dörflerstruct legacy_driver {
92368167edSAxel Dörfler	legacy_driver*	next;
93368167edSAxel Dörfler	const char*		path;
94368167edSAxel Dörfler	const char*		name;
95368167edSAxel Dörfler	dev_t			device;
96368167edSAxel Dörfler	ino_t			node;
97fa00207cSAxel Dörfler	timespec		last_modified;
98368167edSAxel Dörfler	image_id		image;
99368167edSAxel Dörfler	uint32			devices_used;
100368167edSAxel Dörfler	bool			binary_updated;
101368167edSAxel Dörfler	int32			priority;
102368167edSAxel Dörfler	DeviceList		devices;
103368167edSAxel Dörfler
104368167edSAxel Dörfler	// driver image information
105368167edSAxel Dörfler	int32			api_version;
106368167edSAxel Dörfler	device_hooks*	(*find_device)(const char *);
107368167edSAxel Dörfler	const char**	(*publish_devices)(void);
108368167edSAxel Dörfler	status_t		(*uninit_driver)(void);
109368167edSAxel Dörfler	status_t		(*uninit_hardware)(void);
110368167edSAxel Dörfler};
111368167edSAxel Dörfler
112fb407401SAxel Dörfler
113fb407401SAxel Dörflerenum driver_event_type {
114fb407401SAxel Dörfler	kAddDriver,
115fb407401SAxel Dörfler	kRemoveDriver,
116fb407401SAxel Dörfler	kAddWatcher,
117fb407401SAxel Dörfler	kRemoveWatcher
118fb407401SAxel Dörfler};
119fb407401SAxel Dörfler
120fb407401SAxel Dörflerstruct driver_event : DoublyLinkedListLinkImpl<driver_event> {
121fb407401SAxel Dörfler	driver_event(driver_event_type _type) : type(_type) {}
122fb407401SAxel Dörfler
123fb407401SAxel Dörfler	struct ref {
124fb407401SAxel Dörfler		dev_t		device;
125fb407401SAxel Dörfler		ino_t		node;
126fb407401SAxel Dörfler	};
127fb407401SAxel Dörfler
128fb407401SAxel Dörfler	driver_event_type	type;
129fb407401SAxel Dörfler	union {
130fb407401SAxel Dörfler		char			path[B_PATH_NAME_LENGTH];
131fb407401SAxel Dörfler		ref				node;
132fb407401SAxel Dörfler	};
133368167edSAxel Dörfler};
134368167edSAxel Dörfler
135fb407401SAxel Dörflertypedef DoublyLinkedList<driver_event> DriverEventList;
136e0965f27SAxel Dörfler
137fb407401SAxel Dörfler
138fb407401SAxel Dörflerstruct driver_entry : DoublyLinkedListLinkImpl<driver_entry> {
139fb407401SAxel Dörfler	char*			path;
140fb407401SAxel Dörfler	dev_t			device;
141fb407401SAxel Dörfler	ino_t			node;
142fb407401SAxel Dörfler	int32			busses;
143368167edSAxel Dörfler};
144368167edSAxel Dörfler
145368167edSAxel Dörflertypedef DoublyLinkedList<driver_entry> DriverEntryList;
146368167edSAxel Dörfler
147fb407401SAxel Dörfler
148fb407401SAxel Dörflerstruct node_entry : DoublyLinkedListLinkImpl<node_entry> {
149fb407401SAxel Dörfler};
150fb407401SAxel Dörfler
151fb407401SAxel Dörflertypedef DoublyLinkedList<node_entry> NodeList;
152fb407401SAxel Dörfler
153fb407401SAxel Dörfler
154368167edSAxel Dörflerstruct directory_node_entry {
1555147963dSStephan Aßmus	directory_node_entry*	hash_link;
1565147963dSStephan Aßmus	ino_t					node;
157368167edSAxel Dörfler};
158368167edSAxel Dörfler
159368167edSAxel Dörflerstruct DirectoryNodeHashDefinition {
160368167edSAxel Dörfler	typedef ino_t* KeyType;
161368167edSAxel Dörfler	typedef directory_node_entry ValueType;
162368167edSAxel Dörfler
163368167edSAxel Dörfler	size_t HashKey(ino_t* key) const
164368167edSAxel Dörfler		{ return _Hash(*key); }
165368167edSAxel Dörfler	size_t Hash(directory_node_entry* entry) const
166368167edSAxel Dörfler		{ return _Hash(entry->node); }
167368167edSAxel Dörfler	bool Compare(ino_t* key, directory_node_entry* entry) const
168368167edSAxel Dörfler		{ return *key == entry->node; }
1695147963dSStephan Aßmus	directory_node_entry*&
170368167edSAxel Dörfler		GetLink(directory_node_entry* entry) const
1715147963dSStephan Aßmus		{ return entry->hash_link; }
172368167edSAxel Dörfler
173368167edSAxel Dörfler	uint32 _Hash(ino_t node) const
174368167edSAxel Dörfler		{ return (uint32)(node >> 32) + (uint32)node; }
175368167edSAxel Dörfler};
176368167edSAxel Dörfler
1775147963dSStephan Aßmustypedef BOpenHashTable<DirectoryNodeHashDefinition> DirectoryNodeHash;
178368167edSAxel Dörfler
179368167edSAxel Dörflerclass DirectoryIterator {
180368167edSAxel Dörflerpublic:
181368167edSAxel Dörfler						DirectoryIterator(const char *path,
182368167edSAxel Dörfler							const char *subPath = NULL, bool recursive = false);
183368167edSAxel Dörfler						~DirectoryIterator();
184368167edSAxel Dörfler
185368167edSAxel Dörfler			void		SetTo(const char *path, const char *subPath = NULL,
186368167edSAxel Dörfler							bool recursive = false);
187368167edSAxel Dörfler
188368167edSAxel Dörfler			status_t	GetNext(KPath &path, struct stat &stat);
189368167edSAxel Dörfler			const char*	CurrentName() const { return fCurrentName; }
190368167edSAxel Dörfler
191368167edSAxel Dörfler			void		Unset();
192368167edSAxel Dörfler			void		AddPath(const char *path, const char *subPath = NULL);
193368167edSAxel Dörfler
194368167edSAxel Dörflerprivate:
195368167edSAxel Dörfler	Stack<KPath*>		fPaths;
196368167edSAxel Dörfler	bool				fRecursive;
197368167edSAxel Dörfler	DIR*				fDirectory;
198368167edSAxel Dörfler	KPath*				fBasePath;
199368167edSAxel Dörfler	const char*			fCurrentName;
200368167edSAxel Dörfler};
201368167edSAxel Dörfler
202368167edSAxel Dörfler
203368167edSAxel Dörflerclass DirectoryWatcher : public NotificationListener {
204368167edSAxel Dörflerpublic:
205368167edSAxel Dörfler						DirectoryWatcher();
206368167edSAxel Dörfler	virtual				~DirectoryWatcher();
207368167edSAxel Dörfler
2089837ec16SIngo Weinhold	virtual void		EventOccurred(NotificationService& service,
209368167edSAxel Dörfler							const KMessage* event);
210368167edSAxel Dörfler};
211368167edSAxel Dörfler
212368167edSAxel Dörflerclass DriverWatcher : public NotificationListener {
213368167edSAxel Dörflerpublic:
214368167edSAxel Dörfler						DriverWatcher();
215368167edSAxel Dörfler	virtual				~DriverWatcher();
216368167edSAxel Dörfler
2179837ec16SIngo Weinhold	virtual void		EventOccurred(NotificationService& service,
218368167edSAxel Dörfler							const KMessage* event);
219368167edSAxel Dörfler};
220368167edSAxel Dörfler
22199f77939SJérôme Duval
22279b12613SAdrien Destuguesstruct DriverHash {
22379b12613SAdrien Destugues	typedef const char*			KeyType;
22479b12613SAdrien Destugues	typedef legacy_driver		ValueType;
225368167edSAxel Dörfler
22679b12613SAdrien Destugues	size_t HashKey(KeyType key) const
22779b12613SAdrien Destugues	{
22879b12613SAdrien Destugues		return hash_hash_string(key);
22979b12613SAdrien Destugues	}
230368167edSAxel Dörfler
23179b12613SAdrien Destugues	size_t Hash(ValueType* driver) const
23279b12613SAdrien Destugues	{
23379b12613SAdrien Destugues		return HashKey(driver->name);
23479b12613SAdrien Destugues	}
235368167edSAxel Dörfler
23679b12613SAdrien Destugues	bool Compare(KeyType key, ValueType* driver) const
23779b12613SAdrien Destugues	{
23879b12613SAdrien Destugues		return strcmp(driver->name, key) == 0;
23979b12613SAdrien Destugues	}
240368167edSAxel Dörfler
24179b12613SAdrien Destugues	ValueType*& GetLink(ValueType* value) const
24279b12613SAdrien Destugues	{
24379b12613SAdrien Destugues		return value->next;
24479b12613SAdrien Destugues	}
24579b12613SAdrien Destugues};
246368167edSAxel Dörfler
24779b12613SAdrien Destuguestypedef BOpenHashTable<DriverHash> DriverTable;
24879b12613SAdrien Destugues
24979b12613SAdrien Destugues
250c73d1301SMichael Lotz}	// unnamed namespace
251c73d1301SMichael Lotz
252c73d1301SMichael Lotz
253c73d1301SMichael Lotzstatic status_t unload_driver(legacy_driver *driver);
254c73d1301SMichael Lotzstatic status_t load_driver(legacy_driver *driver);
255c73d1301SMichael Lotz
256c73d1301SMichael Lotz
2578e9c7a36SAugustin Cavalierstatic const directory_which kDriverPaths[] = {
2588e9c7a36SAugustin Cavalier	B_USER_NONPACKAGED_ADDONS_DIRECTORY,
2598e9c7a36SAugustin Cavalier	B_USER_ADDONS_DIRECTORY,
2608e9c7a36SAugustin Cavalier	B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
2618e9c7a36SAugustin Cavalier	B_SYSTEM_ADDONS_DIRECTORY
2628e9c7a36SAugustin Cavalier};
2638e9c7a36SAugustin Cavalier
264c73d1301SMichael Lotzstatic DriverWatcher sDriverWatcher;
265c73d1301SMichael Lotzstatic int32 sDriverEventsPending;
266c73d1301SMichael Lotzstatic DriverEventList sDriverEvents;
267c73d1301SMichael Lotzstatic mutex sDriverEventsLock = MUTEX_INITIALIZER("driver events");
268c73d1301SMichael Lotz	// inner lock, protects the sDriverEvents list only
269c73d1301SMichael Lotzstatic DirectoryWatcher sDirectoryWatcher;
270c73d1301SMichael Lotzstatic DirectoryNodeHash sDirectoryNodeHash;
271c73d1301SMichael Lotzstatic recursive_lock sLock;
272c73d1301SMichael Lotzstatic bool sWatching;
273c73d1301SMichael Lotz
27479b12613SAdrien Destuguesstatic DriverTable* sDriverHash;
275368167edSAxel Dörfler
276368167edSAxel Dörfler
277c73d1301SMichael Lotz//	#pragma mark - driver private
278c73d1301SMichael Lotz
279c73d1301SMichael Lotz
280368167edSAxel Dörfler/*!	Collects all published devices of a driver, compares them to what the
281368167edSAxel Dörfler	driver would publish now, and then publishes/unpublishes the devices
282368167edSAxel Dörfler	as needed.
283368167edSAxel Dörfler	If the driver does not publish any devices anymore, it is unloaded.
284368167edSAxel Dörfler*/
285368167edSAxel Dörflerstatic status_t
286368167edSAxel Dörflerrepublish_driver(legacy_driver* driver)
287368167edSAxel Dörfler{
288368167edSAxel Dörfler	if (driver->image < 0) {
289368167edSAxel Dörfler		// The driver is not yet loaded - go through the normal load procedure
290368167edSAxel Dörfler		return load_driver(driver);
291368167edSAxel Dörfler	}
292368167edSAxel Dörfler
293f15da085SAxel Dörfler	// mark all devices
294368167edSAxel Dörfler	DeviceList::Iterator iterator = driver->devices.GetIterator();
295f15da085SAxel Dörfler	while (LegacyDevice* device = iterator.Next()) {
296f15da085SAxel Dörfler		device->SetRepublished(false);
297368167edSAxel Dörfler	}
298368167edSAxel Dörfler
299368167edSAxel Dörfler	// now ask the driver for it's currently published devices
300f15da085SAxel Dörfler	const char** devicePaths = driver->publish_devices();
301368167edSAxel Dörfler
302368167edSAxel Dörfler	int32 exported = 0;
303368167edSAxel Dörfler	for (; devicePaths != NULL && devicePaths[0]; devicePaths++) {
304f15da085SAxel Dörfler		LegacyDevice* device;
305f15da085SAxel Dörfler
306f15da085SAxel Dörfler		iterator = driver->devices.GetIterator();
307f15da085SAxel Dörfler		while ((device = iterator.Next()) != NULL) {
308f15da085SAxel Dörfler			if (!strncmp(device->Path(), devicePaths[0], B_PATH_NAME_LENGTH)) {
309f15da085SAxel Dörfler				// mark device as republished
310f15da085SAxel Dörfler				device->SetRepublished(true);
311368167edSAxel Dörfler				exported++;
312368167edSAxel Dörfler				break;
313368167edSAxel Dörfler			}
314368167edSAxel Dörfler		}
315368167edSAxel Dörfler
316f15da085SAxel Dörfler		device_hooks* hooks = driver->find_device(devicePaths[0]);
317368167edSAxel Dörfler		if (hooks == NULL)
318368167edSAxel Dörfler			continue;
319368167edSAxel Dörfler
320f15da085SAxel Dörfler		if (device != NULL) {
321368167edSAxel Dörfler			// update hooks
322f15da085SAxel Dörfler			device->SetHooks(hooks);
323368167edSAxel Dörfler			continue;
324368167edSAxel Dörfler		}
325368167edSAxel Dörfler
326368167edSAxel Dörfler		// the device was not present before -> publish it now
327368167edSAxel Dörfler		TRACE(("devfs: publishing new device \"%s\"\n", devicePaths[0]));
328f15da085SAxel Dörfler		device = new(std::nothrow) LegacyDevice(driver, devicePaths[0], hooks);
329368167edSAxel Dörfler		if (device != NULL && device->InitCheck() == B_OK
330368167edSAxel Dörfler			&& devfs_publish_device(devicePaths[0], device) == B_OK) {
331368167edSAxel Dörfler			driver->devices.Add(device);
332368167edSAxel Dörfler			exported++;
333368167edSAxel Dörfler		} else
334368167edSAxel Dörfler			delete device;
335368167edSAxel Dörfler	}
336368167edSAxel Dörfler
337f15da085SAxel Dörfler	// remove all devices that weren't republished
338f15da085SAxel Dörfler	iterator = driver->devices.GetIterator();
339f15da085SAxel Dörfler	while (LegacyDevice* device = iterator.Next()) {
340f15da085SAxel Dörfler		if (device->Republished())
341f15da085SAxel Dörfler			continue;
342368167edSAxel Dörfler
343f15da085SAxel Dörfler		TRACE(("devfs: unpublishing no more present \"%s\"\n", device->Path()));
344f15da085SAxel Dörfler		iterator.Remove();
3456015793fSAxel Dörfler		device->SetRemovedFromParent(true);
346368167edSAxel Dörfler
347f15da085SAxel Dörfler		devfs_unpublish_device(device, true);
348368167edSAxel Dörfler	}
349368167edSAxel Dörfler
350ea8749b6SAxel Dörfler	if (exported == 0 && driver->devices_used == 0) {
351f15da085SAxel Dörfler		TRACE(("devfs: driver \"%s\" does not publish any more nodes and is "
352f15da085SAxel Dörfler			"unloaded\n", driver->path));
353368167edSAxel Dörfler		unload_driver(driver);
354368167edSAxel Dörfler	}
355368167edSAxel Dörfler
356368167edSAxel Dörfler	return B_OK;
357368167edSAxel Dörfler}
358368167edSAxel Dörfler
359368167edSAxel Dörfler
360368167edSAxel Dörflerstatic status_t
36156583ffbSAugustin Cavalierload_driver(legacy_driver* driver)
362368167edSAxel Dörfler{
363368167edSAxel Dörfler	status_t (*init_hardware)(void);
364368167edSAxel Dörfler	status_t (*init_driver)(void);
365368167edSAxel Dörfler	status_t status;
366368167edSAxel Dörfler
367368167edSAxel Dörfler	driver->binary_updated = false;
368368167edSAxel Dörfler
369368167edSAxel Dörfler	// load the module
370368167edSAxel Dörfler	image_id image = driver->image;
371368167edSAxel Dörfler	if (image < 0) {
372368167edSAxel Dörfler		image = load_kernel_add_on(driver->path);
373368167edSAxel Dörfler		if (image < 0)
374368167edSAxel Dörfler			return image;
375368167edSAxel Dörfler	}
376368167edSAxel Dörfler
377368167edSAxel Dörfler	// For a valid device driver the following exports are required
378368167edSAxel Dörfler
37956583ffbSAugustin Cavalier	int32* apiVersion;
380368167edSAxel Dörfler	if (get_image_symbol(image, "api_version", B_SYMBOL_TYPE_DATA,
38156583ffbSAugustin Cavalier			(void**)&apiVersion) == B_OK) {
382368167edSAxel Dörfler#if B_CUR_DRIVER_API_VERSION != 2
383368167edSAxel Dörfler		// just in case someone decides to bump up the api version
384368167edSAxel Dörfler#error Add checks here for new vs old api version!
385368167edSAxel Dörfler#endif
386368167edSAxel Dörfler		if (*apiVersion > B_CUR_DRIVER_API_VERSION) {
3874be4fc6bSAlex Smith			dprintf("devfs: \"%s\" api_version %" B_PRId32 " not handled\n",
3884be4fc6bSAlex Smith				driver->name, *apiVersion);
389368167edSAxel Dörfler			status = B_BAD_VALUE;
390368167edSAxel Dörfler			goto error1;
391368167edSAxel Dörfler		}
392368167edSAxel Dörfler		if (*apiVersion < 1) {
393368167edSAxel Dörfler			dprintf("devfs: \"%s\" api_version invalid\n", driver->name);
394368167edSAxel Dörfler			status = B_BAD_VALUE;
395368167edSAxel Dörfler			goto error1;
396368167edSAxel Dörfler		}
397368167edSAxel Dörfler
398368167edSAxel Dörfler		driver->api_version = *apiVersion;
399368167edSAxel Dörfler	} else
400368167edSAxel Dörfler		dprintf("devfs: \"%s\" api_version missing\n", driver->name);
401368167edSAxel Dörfler
402368167edSAxel Dörfler	if (get_image_symbol(image, "publish_devices", B_SYMBOL_TYPE_TEXT,
40356583ffbSAugustin Cavalier				(void**)&driver->publish_devices) != B_OK
404368167edSAxel Dörfler		|| get_image_symbol(image, "find_device", B_SYMBOL_TYPE_TEXT,
40556583ffbSAugustin Cavalier				(void**)&driver->find_device) != B_OK) {
406368167edSAxel Dörfler		dprintf("devfs: \"%s\" mandatory driver symbol(s) missing!\n",
407368167edSAxel Dörfler			driver->name);
408368167edSAxel Dörfler		status = B_BAD_VALUE;
409