devinfo.c revision 6112:28ee9a48b832
118334Speter/***************************************************************************
290075Sobrien *
3169689Skan * devinfo.c : main file for libdevinfo-based device enumeration
418334Speter *
590075Sobrien * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
618334Speter * Use is subject to license terms.
790075Sobrien *
890075Sobrien * Licensed under the Academic Free License version 2.1
990075Sobrien *
1090075Sobrien **************************************************************************/
1118334Speter
1290075Sobrien#pragma ident	"%Z%%M%	%I%	%E% SMI"
1390075Sobrien
1490075Sobrien#ifdef HAVE_CONFIG_H
1590075Sobrien#  include <config.h>
1618334Speter#endif
1718334Speter
1890075Sobrien#include <stdio.h>
19169689Skan#include <string.h>
20169689Skan#include <libdevinfo.h>
2118334Speter
22169689Skan#include "../osspec.h"
23169689Skan#include "../logger.h"
2418334Speter#include "../hald.h"
2550397Sobrien#include "../hald_dbus.h"
26169689Skan#include "../device_info.h"
27117395Skan#include "../util.h"
28117395Skan#include "../hald_runner.h"
2918334Speter#include "osspec_solaris.h"
3018334Speter#include "hotplug.h"
3118334Speter#include "devinfo.h"
3290075Sobrien#include "devinfo_pci.h"
3390075Sobrien#include "devinfo_storage.h"
3490075Sobrien#include "devinfo_ieee1394.h"
3590075Sobrien#include "devinfo_usb.h"
3618334Speter#include "devinfo_misc.h"
3790075Sobrien#include "devinfo_acpi.h"
3890075Sobrien
3990075Sobrienvoid devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root);
4018334SpeterHalDevice *devinfo_add_node(HalDevice *parent, di_node_t node);
4150397Sobrien
4250397Sobrienvoid
4350397Sobriendevinfo_add(HalDevice *parent, gchar *path)
4450397Sobrien{
4518334Speter	di_node_t	root;
4618334Speter
4718334Speter	if (strcmp (path, "/") == 0) {
4818334Speter		if ((root = di_init(path, DINFOCACHE)) == DI_NODE_NIL) {
4950397Sobrien			HAL_INFO (("di_init() failed %d", errno));
5090075Sobrien			return;
5190075Sobrien		}
5250397Sobrien	} else {
5350397Sobrien		if ((root = di_init(path, DINFOCPYALL)) == DI_NODE_NIL) {
5450397Sobrien			HAL_INFO (("di_init() failed %d", errno));
5590075Sobrien			return;
5650397Sobrien		}
5750397Sobrien	}
5850397Sobrien
5950397Sobrien	devinfo_add_subtree(parent, root, TRUE);
6090075Sobrien
6150397Sobrien	di_fini (root);
6250397Sobrien}
6350397Sobrien
64161651Skanvoid
6550397Sobriendevinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root)
6650397Sobrien{
6750397Sobrien	HalDevice *d;
68169689Skan	di_node_t root_node, child_node;
6950397Sobrien
70169689Skan	HAL_INFO (("add_subtree: %s", di_node_name (node)));
71169689Skan
72169689Skan	root_node = node;
73169689Skan	do {
74169689Skan		d = devinfo_add_node (parent, node);
7590075Sobrien
7650397Sobrien		if ((d != NULL) &&
77169689Skan		    (child_node = di_child_node (node)) != DI_NODE_NIL) {
7818334Speter			devinfo_add_subtree (d, child_node, FALSE);
7990075Sobrien		}
8090075Sobrien
81169689Skan		node = di_sibling_node (node);
8290075Sobrien	} while ((node != DI_NODE_NIL) &&
83132718Skan		(!is_root || di_parent_node (node) == root_node));
8490075Sobrien}
8590075Sobrien
8690075Sobrienvoid
8790075Sobriendevinfo_set_default_properties (HalDevice *d, HalDevice *parent, di_node_t node, char *devfs_path)
8890075Sobrien{
8990075Sobrien	char	*driver_name, *s;
9090075Sobrien	const char *s1;
9190075Sobrien	char	udi[HAL_PATH_MAX];
9290075Sobrien
9390075Sobrien	if (parent != NULL) {
9490075Sobrien		hal_device_property_set_string (d, "info.parent", hal_device_get_udi (parent));
9590075Sobrien	} else {
9690075Sobrien		hal_device_property_set_string (d, "info.parent", "/org/freedesktop/Hal/devices/local");
9790075Sobrien	}
9890075Sobrien
9990075Sobrien	hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
10090075Sobrien				"/org/freedesktop/Hal/devices%s_%d",
10150397Sobrien				devfs_path,
10250397Sobrien				di_instance (node));
10350397Sobrien	hal_device_set_udi (d, udi);
10418334Speter	hal_device_property_set_string (d, "info.udi", udi);
105169689Skan
10618334Speter	if (di_prop_lookup_strings (DDI_DEV_T_ANY, node, "model", &s) > 0) {
10718334Speter		hal_device_property_set_string (d, "info.product", s);
10818334Speter	} else {
10918334Speter		hal_device_property_set_string (d, "info.product", di_node_name (node));
11018334Speter	}
11118334Speter
11218334Speter	hal_device_property_set_string (d, "solaris.devfs_path", devfs_path);
113169689Skan
11418334Speter	if ((driver_name = di_driver_name (node)) != NULL) {
11518334Speter		hal_device_property_set_string (d, "info.solaris.driver",
11618334Speter						driver_name);
11718334Speter	}
11818334Speter
11918334Speter
12018334Speter	/* inherit parent's claim attributes */
12118334Speter	if (hal_device_property_get_bool (parent, "info.claimed")) {
12218334Speter		s1 = hal_device_property_get_string (parent, "info.claimed.service");
12318334Speter		if (s1 != NULL) {
12418334Speter			hal_device_property_set_bool (d, "info.claimed", TRUE);
12518334Speter			hal_device_property_set_string (d, "info.claimed.service", s1);
12618334Speter		}
12718334Speter	}
12818334Speter}
12918334Speter
13018334Speter/* device handlers, ordered specific to generic */
13118334Speterstatic DevinfoDevHandler *devinfo_handlers[] = {
132169689Skan	&devinfo_computer_handler,
133169689Skan	&devinfo_cpu_handler,
13418334Speter	&devinfo_ide_handler,
135161651Skan	&devinfo_scsi_handler,
136161651Skan	&devinfo_pcata_handler,
137161651Skan	&devinfo_floppy_handler,
138161651Skan	&devinfo_usb_handler,
139169689Skan	&devinfo_ieee1394_handler,
140161651Skan	&devinfo_pci_handler,
14118334Speter	&devinfo_lofi_handler,
14218334Speter	&devinfo_acpi_handler,
14318334Speter	&devinfo_battery_handler,
14418334Speter	&devinfo_default_handler,
14518334Speter	NULL
14618334Speter};
14718334Speter
14818334SpeterHalDevice *
14918334Speterdevinfo_add_node(HalDevice *parent, di_node_t node)
15018334Speter{
15118334Speter	HalDevice *d = NULL;
15218334Speter	char	*devfs_path;
15318334Speter	char	*device_type = NULL;
15418334Speter	DevinfoDevHandler *handler;
15518334Speter	int	i;
156169689Skan
157169689Skan	devfs_path = di_devfs_path (node);
15818334Speter
15918334Speter        (void) di_prop_lookup_strings (DDI_DEV_T_ANY, node, "device_type",
16050397Sobrien	    &device_type);
16118334Speter
16250397Sobrien	for (i = 0; (d == NULL) && (devinfo_handlers[i] != NULL); i++) {
16350397Sobrien		handler = devinfo_handlers[i];
16450397Sobrien		d = handler->add (parent, node, devfs_path, device_type);
16550397Sobrien	}
16618334Speter
16718334Speter	di_devfs_path_free(devfs_path);
168132718Skan
16918334Speter	HAL_INFO (("add_node: %s", d ? hal_device_get_udi (d) : "none"));
17018334Speter	return (d);
17118334Speter}
172132718Skan
17318334Spetervoid
174132718Skandevinfo_hotplug_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler, int action, int front)
17518334Speter{
176169689Skan	HotplugEvent *hotplug_event;
177169689Skan
178169689Skan	hotplug_event = g_new0 (HotplugEvent, 1);
179169689Skan	hotplug_event->action = action;
18018334Speter	hotplug_event->type = HOTPLUG_EVENT_DEVFS;
18118334Speter	hotplug_event->d = d;
18218334Speter	strlcpy (hotplug_event->un.devfs.devfs_path, devfs_path,
18318334Speter		sizeof (hotplug_event->un.devfs.devfs_path));
18418334Speter	hotplug_event->un.devfs.handler = handler;
18518334Speter
18618334Speter	hotplug_event_enqueue (hotplug_event, front);
18718334Speter}
18818334Speter
18918334Spetervoid
19018334Speterdevinfo_add_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler)
19118334Speter{
192169689Skan	devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 0);
19318334Speter}
19418334Speter
19518334Spetervoid
19618334Speterdevinfo_add_enqueue_at_front(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler)
19718334Speter{
19818334Speter	devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 1);
19918334Speter}
200169689Skan
20118334Spetervoid
20218334Speterdevinfo_remove_enqueue(gchar *devfs_path, DevinfoDevHandler *handler)
20318334Speter{
20418334Speter	devinfo_hotplug_enqueue (NULL, devfs_path, handler, HOTPLUG_ACTION_REMOVE, 0);
20518334Speter}
20618334Speter
20718334Spetervoid
20818334Speterdevinfo_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
20918334Speter{
21018334Speter        void *end_token = (void *) userdata1;
21118334Speter
21218334Speter        /* Move from temporary to global device store */
21318334Speter        hal_device_store_remove (hald_get_tdl (), d);
21418334Speter        hal_device_store_add (hald_get_gdl (), d);
21518334Speter
21618334Speter        hotplug_event_end (end_token);
21718334Speter}
21818334Speter
21950397Sobrienvoid
22050397Sobriendevinfo_callouts_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2)
22150397Sobrien{
22250397Sobrien        void *end_token = (void *) userdata1;
22350397Sobrien
22450397Sobrien        /* Discard device if probing reports failure */
22552284Sobrien        if (exit_type != HALD_RUN_SUCCESS || (return_code != 0)) {
22652284Sobrien		HAL_INFO (("Probing for %s failed %d", hal_device_get_udi (d), return_code));
22790075Sobrien                hal_device_store_remove (hald_get_tdl (), d);
228132718Skan                g_object_unref (d);
22952284Sobrien                hotplug_event_end (end_token);
23018334Speter		return;
231132718Skan        }
23252284Sobrien
23352284Sobrien        /* Merge properties from .fdi files */
23452284Sobrien        di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION);
23552284Sobrien        di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY);
23650397Sobrien
23750397Sobrien	hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL);
238132718Skan}
239169689Skan
240169689Skanvoid
241169689Skandevinfo_callouts_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
242259268Spfg{
243259268Spfg        void *end_token = (void *) userdata1;
244169689Skan	DevinfoDevHandler *handler = (DevinfoDevHandler *) userdata2;
245259268Spfg	void (*probing_done) (HalDevice *, guint32, gint, char **, gpointer, gpointer);
246259268Spfg	const gchar *prober;
247259268Spfg	int prober_timeout;
248259268Spfg
249259268Spfg        if (hal_device_property_get_bool (d, "info.ignore")) {
250259268Spfg		HAL_INFO (("Preprobing merged info.ignore==TRUE"));
251259268Spfg
252259268Spfg                /* Leave device with info.ignore==TRUE so we won't pick up children */
253259268Spfg		hal_device_property_remove (d, "info.category");
254259268Spfg		hal_device_property_remove (d, "info.capabilities");
255259268Spfg
256259268Spfg		hal_device_store_remove (hald_get_tdl (), d);
257259268Spfg		hal_device_store_add (hald_get_gdl (), d);
258259268Spfg
259259268Spfg		hotplug_event_end (end_token);
260259268Spfg		return;
261259268Spfg        }
262259268Spfg
263259268Spfg        if (handler != NULL && handler->get_prober != NULL) {
264259268Spfg                prober = handler->get_prober (d, &prober_timeout);
265259268Spfg        } else {
266259268Spfg                prober = NULL;
267259268Spfg	}
268259268Spfg
269259268Spfg	if (handler->probing_done != NULL) {
270259268Spfg		probing_done = handler->probing_done;
271259268Spfg	} else {
272259268Spfg		probing_done = devinfo_callouts_probing_done;
273259268Spfg	}
274259268Spfg
275259268Spfg        if (prober != NULL) {
276259268Spfg                /* probe the device */
277259268Spfg		HAL_INFO(("Probing udi=%s", hal_device_get_udi (d)));
278259268Spfg                hald_runner_run (d,
279169689Skan				prober, NULL,
280				prober_timeout,
281				probing_done,
282				(gpointer) end_token, (gpointer) handler);
283	} else {
284		probing_done (d, 0, 0, NULL, userdata1, userdata2);
285	}
286}
287
288/* This is the beginning of hotplug even handling */
289void
290hotplug_event_begin_add_devinfo (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
291{
292	HAL_INFO(("Preprobing udi=%s", hal_device_get_udi (d)));
293
294	if (parent != NULL && hal_device_property_get_bool (parent, "info.ignore")) {
295		HAL_INFO (("Ignoring device since parent has info.ignore==TRUE"));
296
297		if (hal_device_store_find (hald_get_tdl (), hal_device_get_udi (d)))
298			hal_device_store_remove (hald_get_tdl (), d);
299
300		hotplug_event_end (end_token);
301		return;
302	}
303
304	if (hal_device_store_find (hald_get_tdl (), hal_device_get_udi (d)) == NULL) {
305
306		/* add to TDL so preprobing callouts and prober can access it */
307		hal_device_store_add (hald_get_tdl (), d);
308	}
309
310        /* Process preprobe fdi files */
311        di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
312
313        /* Run preprobe callouts */
314        hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler);
315}
316
317void
318devinfo_remove (gchar *devfs_path)
319{
320	devinfo_remove_enqueue ((gchar *)devfs_path, NULL);
321}
322
323/* generate hotplug event for each device in this branch */
324void
325devinfo_remove_branch (gchar *devfs_path, HalDevice *d)
326{
327	GSList *i;
328	GSList *children;
329	HalDevice *child;
330	char *child_devfs_path;
331
332	if (d == NULL) {
333		d = hal_device_store_match_key_value_string (hald_get_gdl (),
334			"solaris.devfs_path", devfs_path);
335		if (d == NULL)
336			return;
337	}
338
339	HAL_INFO (("remove_branch: %s %s\n", devfs_path, hal_device_get_udi (d)));
340
341	/* first remove children */
342	children = hal_device_store_match_multiple_key_value_string (hald_get_gdl(),
343		"info.parent", hal_device_get_udi (d));
344        for (i = children; i != NULL; i = g_slist_next (i)) {
345                child = HAL_DEVICE (i->data);
346		HAL_INFO (("remove_branch: child %s\n", hal_device_get_udi (child)));
347		devinfo_remove_branch ((gchar *)hal_device_property_get_string (child, "solaris.devfs_path"), child);
348	}
349	g_slist_free (children);
350	HAL_INFO (("remove_branch: done with children"));
351
352	/* then remove self */
353	HAL_INFO (("remove_branch: queueing %s", devfs_path));
354	devinfo_remove_enqueue (devfs_path, NULL);
355}
356
357void
358devinfo_callouts_remove_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
359{
360        void *end_token = (void *) userdata1;
361
362        HAL_INFO (("Remove callouts completed udi=%s", hal_device_get_udi (d)));
363
364        if (!hal_device_store_remove (hald_get_gdl (), d)) {
365                HAL_WARNING (("Error removing device"));
366        }
367        g_object_unref (d);
368
369        hotplug_event_end (end_token);
370}
371
372void
373hotplug_event_begin_remove_devinfo (HalDevice *d, gchar *devfs_path, void *end_token)
374{
375	if (hal_device_has_capability (d, "volume")) {
376		devinfo_volume_hotplug_begin_remove (d, devfs_path, end_token);
377	} else {
378		hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
379	}
380}
381
382gboolean
383devinfo_device_rescan (HalDevice *d)
384{
385	if (hal_device_has_capability (d, "block")) {
386		return (devinfo_storage_device_rescan (d));
387        } else {
388		return (FALSE);
389	}
390}
391
392static int
393walk_devlinks(di_devlink_t devlink, void *arg)
394{
395        char    **path= (char **)arg;
396
397        *path = strdup(di_devlink_path(devlink));
398
399        return (DI_WALK_TERMINATE);
400}
401
402char *
403get_devlink(di_devlink_handle_t devlink_hdl, char *re, char *path)
404{
405        char    *devlink_path = NULL;
406
407        (void) di_devlink_walk(devlink_hdl, re, path,
408            DI_PRIMARY_LINK, &devlink_path, walk_devlinks);
409
410        return (devlink_path);
411}
412
413