12912Sartem /***************************************************************************
22912Sartem  *
32912Sartem  * devinfo.c : main file for libdevinfo-based device enumeration
42912Sartem  *
56112Sqz150045  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
62912Sartem  * Use is subject to license terms.
72912Sartem  *
82912Sartem  * Licensed under the Academic Free License version 2.1
92912Sartem  *
102912Sartem  **************************************************************************/
112912Sartem 
123121Sartem #ifdef HAVE_CONFIG_H
133121Sartem #  include <config.h>
143121Sartem #endif
153121Sartem 
162912Sartem #include <stdio.h>
172912Sartem #include <string.h>
182912Sartem #include <libdevinfo.h>
192912Sartem 
202912Sartem #include "../osspec.h"
212912Sartem #include "../logger.h"
222912Sartem #include "../hald.h"
232912Sartem #include "../hald_dbus.h"
242912Sartem #include "../device_info.h"
252912Sartem #include "../util.h"
262912Sartem #include "../hald_runner.h"
272912Sartem #include "osspec_solaris.h"
282912Sartem #include "hotplug.h"
292912Sartem #include "devinfo.h"
302912Sartem #include "devinfo_pci.h"
312912Sartem #include "devinfo_storage.h"
322912Sartem #include "devinfo_ieee1394.h"
332912Sartem #include "devinfo_usb.h"
342912Sartem #include "devinfo_misc.h"
354035Sphitran #include "devinfo_acpi.h"
366654Snp146283 #include "devinfo_cpu.h"
372912Sartem 
382912Sartem void devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root);
392912Sartem HalDevice *devinfo_add_node(HalDevice *parent, di_node_t node);
402912Sartem 
412912Sartem void
422912Sartem devinfo_add(HalDevice *parent, gchar *path)
432912Sartem {
442912Sartem 	di_node_t	root;
452912Sartem 
462912Sartem 	if (strcmp (path, "/") == 0) {
472912Sartem 		if ((root = di_init(path, DINFOCACHE)) == DI_NODE_NIL) {
482912Sartem 			HAL_INFO (("di_init() failed %d", errno));
492912Sartem 			return;
502912Sartem 		}
512912Sartem 	} else {
522912Sartem 		if ((root = di_init(path, DINFOCPYALL)) == DI_NODE_NIL) {
532912Sartem 			HAL_INFO (("di_init() failed %d", errno));
542912Sartem 			return;
552912Sartem 		}
562912Sartem 	}
572912Sartem 
582912Sartem 	devinfo_add_subtree(parent, root, TRUE);
592912Sartem 
602912Sartem 	di_fini (root);
612912Sartem }
622912Sartem 
632912Sartem void
642912Sartem devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root)
652912Sartem {
662912Sartem 	HalDevice *d;
672912Sartem 	di_node_t root_node, child_node;
682912Sartem 
692912Sartem 	HAL_INFO (("add_subtree: %s", di_node_name (node)));
702912Sartem 
712912Sartem 	root_node = node;
722912Sartem 	do {
732912Sartem 		d = devinfo_add_node (parent, node);
742912Sartem 
752912Sartem 		if ((d != NULL) &&
762912Sartem 		    (child_node = di_child_node (node)) != DI_NODE_NIL) {
772912Sartem 			devinfo_add_subtree (d, child_node, FALSE);
782912Sartem 		}
792912Sartem 
802912Sartem 		node = di_sibling_node (node);
812912Sartem 	} while ((node != DI_NODE_NIL) &&
822912Sartem 		(!is_root || di_parent_node (node) == root_node));
832912Sartem }
842912Sartem 
852912Sartem void
862912Sartem devinfo_set_default_properties (HalDevice *d, HalDevice *parent, di_node_t node, char *devfs_path)
872912Sartem {
882912Sartem 	char	*driver_name, *s;
892912Sartem 	const char *s1;
902912Sartem 	char	udi[HAL_PATH_MAX];
912912Sartem 
922912Sartem 	if (parent != NULL) {
933121Sartem 		hal_device_property_set_string (d, "info.parent", hal_device_get_udi (parent));
942912Sartem 	} else {
952912Sartem 		hal_device_property_set_string (d, "info.parent", "/org/freedesktop/Hal/devices/local");
962912Sartem 	}
972912Sartem 
982912Sartem 	hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
992912Sartem 				"/org/freedesktop/Hal/devices%s_%d",
1002912Sartem 				devfs_path,
1012912Sartem 				di_instance (node));
1022912Sartem 	hal_device_set_udi (d, udi);
1032912Sartem 	hal_device_property_set_string (d, "info.udi", udi);
1042912Sartem 
1052912Sartem 	if (di_prop_lookup_strings (DDI_DEV_T_ANY, node, "model", &s) > 0) {
1062912Sartem 		hal_device_property_set_string (d, "info.product", s);
1072912Sartem 	} else {
1082912Sartem 		hal_device_property_set_string (d, "info.product", di_node_name (node));
1092912Sartem 	}
1102912Sartem 
1112912Sartem 	hal_device_property_set_string (d, "solaris.devfs_path", devfs_path);
1122912Sartem 
1132912Sartem 	if ((driver_name = di_driver_name (node)) != NULL) {
1142912Sartem 		hal_device_property_set_string (d, "info.solaris.driver",
1152912Sartem 						driver_name);
1162912Sartem 	}
1172912Sartem 
1182912Sartem 
1192912Sartem 	/* inherit parent's claim attributes */
1202912Sartem 	if (hal_device_property_get_bool (parent, "info.claimed")) {
1212912Sartem 		s1 = hal_device_property_get_string (parent, "info.claimed.service");
1222912Sartem 		if (s1 != NULL) {
1232912Sartem 			hal_device_property_set_bool (d, "info.claimed", TRUE);
1242912Sartem 			hal_device_property_set_string (d, "info.claimed.service", s1);
1252912Sartem 		}
1262912Sartem 	}
1272912Sartem }
1282912Sartem 
1292912Sartem /* device handlers, ordered specific to generic */
1302912Sartem static DevinfoDevHandler *devinfo_handlers[] = {
1312912Sartem 	&devinfo_computer_handler,
1322912Sartem 	&devinfo_cpu_handler,
1332912Sartem 	&devinfo_ide_handler,
1342912Sartem 	&devinfo_scsi_handler,
1353121Sartem 	&devinfo_pcata_handler,
1362912Sartem 	&devinfo_floppy_handler,
1372912Sartem 	&devinfo_usb_handler,
1382912Sartem 	&devinfo_ieee1394_handler,
1392912Sartem 	&devinfo_pci_handler,
1402912Sartem 	&devinfo_lofi_handler,
1414035Sphitran 	&devinfo_acpi_handler,
1426573Sphitran 	&devinfo_power_button_handler,
1436573Sphitran 	&devinfo_keyboard_handler,
1442912Sartem 	&devinfo_default_handler,
1452912Sartem 	NULL
1462912Sartem };
1472912Sartem 
1482912Sartem HalDevice *
1492912Sartem devinfo_add_node(HalDevice *parent, di_node_t node)
1502912Sartem {
1512912Sartem 	HalDevice *d = NULL;
1522912Sartem 	char	*devfs_path;
1532912Sartem 	char	*device_type = NULL;
1542912Sartem 	DevinfoDevHandler *handler;
1552912Sartem 	int	i;
1562912Sartem 
1572912Sartem 	devfs_path = di_devfs_path (node);
1582912Sartem 
1592912Sartem         (void) di_prop_lookup_strings (DDI_DEV_T_ANY, node, "device_type",
1602912Sartem 	    &device_type);
1612912Sartem 
1622912Sartem 	for (i = 0; (d == NULL) && (devinfo_handlers[i] != NULL); i++) {
1632912Sartem 		handler = devinfo_handlers[i];
1642912Sartem 		d = handler->add (parent, node, devfs_path, device_type);
1652912Sartem 	}
1662912Sartem 
1672912Sartem 	di_devfs_path_free(devfs_path);
1682912Sartem 
1693121Sartem 	HAL_INFO (("add_node: %s", d ? hal_device_get_udi (d) : "none"));
1702912Sartem 	return (d);
1712912Sartem }
1722912Sartem 
1732912Sartem void
1742912Sartem devinfo_hotplug_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler, int action, int front)
1752912Sartem {
1762912Sartem 	HotplugEvent *hotplug_event;
1772912Sartem 
1782912Sartem 	hotplug_event = g_new0 (HotplugEvent, 1);
1792912Sartem 	hotplug_event->action = action;
1802912Sartem 	hotplug_event->type = HOTPLUG_EVENT_DEVFS;
1812912Sartem 	hotplug_event->d = d;
1822912Sartem 	strlcpy (hotplug_event->un.devfs.devfs_path, devfs_path,
1832912Sartem 		sizeof (hotplug_event->un.devfs.devfs_path));
1842912Sartem 	hotplug_event->un.devfs.handler = handler;
1852912Sartem 
1862912Sartem 	hotplug_event_enqueue (hotplug_event, front);
1872912Sartem }
1882912Sartem 
1892912Sartem void
1902912Sartem devinfo_add_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler)
1912912Sartem {
1922912Sartem 	devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 0);
1932912Sartem }
1942912Sartem 
1952912Sartem void
1962912Sartem devinfo_add_enqueue_at_front(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler)
1972912Sartem {
1982912Sartem 	devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 1);
1992912Sartem }
2002912Sartem 
2012912Sartem void
2022912Sartem devinfo_remove_enqueue(gchar *devfs_path, DevinfoDevHandler *handler)
2032912Sartem {
2042912Sartem 	devinfo_hotplug_enqueue (NULL, devfs_path, handler, HOTPLUG_ACTION_REMOVE, 0);
2052912Sartem }
2062912Sartem 
2072912Sartem void
2082912Sartem devinfo_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
2092912Sartem {
2102912Sartem         void *end_token = (void *) userdata1;
2112912Sartem 
2122912Sartem         /* Move from temporary to global device store */
2132912Sartem         hal_device_store_remove (hald_get_tdl (), d);
2142912Sartem         hal_device_store_add (hald_get_gdl (), d);
2152912Sartem 
2162912Sartem         hotplug_event_end (end_token);
2172912Sartem }
2182912Sartem 
2192912Sartem void
2202912Sartem devinfo_callouts_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2)
2212912Sartem {
2222912Sartem         void *end_token = (void *) userdata1;
2232912Sartem 
2242912Sartem         /* Discard device if probing reports failure */
2252912Sartem         if (exit_type != HALD_RUN_SUCCESS || (return_code != 0)) {
2263121Sartem 		HAL_INFO (("Probing for %s failed %d", hal_device_get_udi (d), return_code));
2272912Sartem                 hal_device_store_remove (hald_get_tdl (), d);
2282912Sartem                 g_object_unref (d);
2292912Sartem                 hotplug_event_end (end_token);
2302912Sartem 		return;
2312912Sartem         }
2322912Sartem 
2332912Sartem         /* Merge properties from .fdi files */
2342912Sartem         di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION);
2352912Sartem         di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY);
2362912Sartem 
2372912Sartem 	hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL);
2382912Sartem }
2392912Sartem 
2402912Sartem void
2412912Sartem devinfo_callouts_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
2422912Sartem {
2432912Sartem         void *end_token = (void *) userdata1;
2442912Sartem 	DevinfoDevHandler *handler = (DevinfoDevHandler *) userdata2;
2452912Sartem 	void (*probing_done) (HalDevice *, guint32, gint, char **, gpointer, gpointer);
2462912Sartem 	const gchar *prober;
2472912Sartem 	int prober_timeout;
2482912Sartem 
2492912Sartem         if (hal_device_property_get_bool (d, "info.ignore")) {
2502912Sartem 		HAL_INFO (("Preprobing merged info.ignore==TRUE"));
2512912Sartem 
2522912Sartem                 /* Leave device with info.ignore==TRUE so we won't pick up children */
2532912Sartem 		hal_device_property_remove (d, "info.category");
2542912Sartem 		hal_device_property_remove (d, "info.capabilities");
2552912Sartem 
2562912Sartem 		hal_device_store_remove (hald_get_tdl (), d);
2572912Sartem 		hal_device_store_add (hald_get_gdl (), d);
2582912Sartem 
2592912Sartem 		hotplug_event_end (end_token);
2602912Sartem 		return;
2612912Sartem         }
2622912Sartem 
2632912Sartem         if (handler != NULL && handler->get_prober != NULL) {
2642912Sartem                 prober = handler->get_prober (d, &prober_timeout);
2652912Sartem         } else {
2662912Sartem                 prober = NULL;
2672912Sartem 	}
2682912Sartem 
2692912Sartem 	if (handler->probing_done != NULL) {
2702912Sartem 		probing_done = handler->probing_done;
2712912Sartem 	} else {
2722912Sartem 		probing_done = devinfo_callouts_probing_done;
2732912Sartem 	}
2742912Sartem 
2752912Sartem         if (prober != NULL) {
2762912Sartem                 /* probe the device */
2773121Sartem 		HAL_INFO(("Probing udi=%s", hal_device_get_udi (d)));
2782912Sartem                 hald_runner_run (d,
2792912Sartem 				prober, NULL,
2802912Sartem 				prober_timeout,
2812912Sartem 				probing_done,
2822912Sartem 				(gpointer) end_token, (gpointer) handler);
2832912Sartem 	} else {
2842912Sartem 		probing_done (d, 0, 0, NULL, userdata1, userdata2);
2852912Sartem 	}
2862912Sartem }
2872912Sartem 
2882912Sartem /* This is the beginning of hotplug even handling */
2892912Sartem void
2902912Sartem hotplug_event_begin_add_devinfo (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token)
2912912Sartem {
2923121Sartem 	HAL_INFO(("Preprobing udi=%s", hal_device_get_udi (d)));
2932912Sartem 
2942912Sartem 	if (parent != NULL && hal_device_property_get_bool (parent, "info.ignore")) {
2952912Sartem 		HAL_INFO (("Ignoring device since parent has info.ignore==TRUE"));
2962912Sartem 
2976112Sqz150045 		if (hal_device_store_find (hald_get_tdl (), hal_device_get_udi (d)))
2986112Sqz150045 			hal_device_store_remove (hald_get_tdl (), d);
2996112Sqz150045 
3002912Sartem 		hotplug_event_end (end_token);
3012912Sartem 		return;
3022912Sartem 	}
3032912Sartem 
3046112Sqz150045 	if (hal_device_store_find (hald_get_tdl (), hal_device_get_udi (d)) == NULL) {
3056112Sqz150045 
3066112Sqz150045 		/* add to TDL so preprobing callouts and prober can access it */
3076112Sqz150045 		hal_device_store_add (hald_get_tdl (), d);
3086112Sqz150045 	}
3092912Sartem 
3102912Sartem         /* Process preprobe fdi files */
3112912Sartem         di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE);
3122912Sartem 
3132912Sartem         /* Run preprobe callouts */
3142912Sartem         hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler);
3152912Sartem }
3162912Sartem 
3172912Sartem void
3182912Sartem devinfo_remove (gchar *devfs_path)
3192912Sartem {
3202912Sartem 	devinfo_remove_enqueue ((gchar *)devfs_path, NULL);
3212912Sartem }
3222912Sartem 
3232912Sartem /* generate hotplug event for each device in this branch */
3242912Sartem void
3252912Sartem devinfo_remove_branch (gchar *devfs_path, HalDevice *d)
3262912Sartem {
3272912Sartem 	GSList *i;
3282912Sartem 	GSList *children;
3292912Sartem 	HalDevice *child;
3302912Sartem 	char *child_devfs_path;
3312912Sartem 
3322912Sartem 	if (d == NULL) {
3332912Sartem 		d = hal_device_store_match_key_value_string (hald_get_gdl (),
3342912Sartem 			"solaris.devfs_path", devfs_path);
3352912Sartem 		if (d == NULL)
3362912Sartem 			return;
3372912Sartem 	}
3382912Sartem 
3393121Sartem 	HAL_INFO (("remove_branch: %s %s\n", devfs_path, hal_device_get_udi (d)));
3402912Sartem 
3412912Sartem 	/* first remove children */
3422912Sartem 	children = hal_device_store_match_multiple_key_value_string (hald_get_gdl(),
3433121Sartem 		"info.parent", hal_device_get_udi (d));
3442912Sartem         for (i = children; i != NULL; i = g_slist_next (i)) {
3452912Sartem                 child = HAL_DEVICE (i->data);
3463121Sartem 		HAL_INFO (("remove_branch: child %s\n", hal_device_get_udi (child)));
3472912Sartem 		devinfo_remove_branch ((gchar *)hal_device_property_get_string (child, "solaris.devfs_path"), child);
3482912Sartem 	}
3492912Sartem 	g_slist_free (children);
3502912Sartem 	HAL_INFO (("remove_branch: done with children"));
3512912Sartem 
3522912Sartem 	/* then remove self */
3532912Sartem 	HAL_INFO (("remove_branch: queueing %s", devfs_path));
3542912Sartem 	devinfo_remove_enqueue (devfs_path, NULL);
3552912Sartem }
3562912Sartem 
3572912Sartem void
3582912Sartem devinfo_callouts_remove_done (HalDevice *d, gpointer userdata1, gpointer userdata2)
3592912Sartem {
3602912Sartem         void *end_token = (void *) userdata1;
3612912Sartem 
3623121Sartem         HAL_INFO (("Remove callouts completed udi=%s", hal_device_get_udi (d)));
3632912Sartem 
3642912Sartem         if (!hal_device_store_remove (hald_get_gdl (), d)) {
3652912Sartem                 HAL_WARNING (("Error removing device"));
3662912Sartem         }
3672912Sartem         g_object_unref (d);
3682912Sartem 
3692912Sartem         hotplug_event_end (end_token);
3702912Sartem }
3712912Sartem 
3722912Sartem void
3732912Sartem hotplug_event_begin_remove_devinfo (HalDevice *d, gchar *devfs_path, void *end_token)
3742912Sartem {
3752912Sartem 	if (hal_device_has_capability (d, "volume")) {
3762912Sartem 		devinfo_volume_hotplug_begin_remove (d, devfs_path, end_token);
3772912Sartem 	} else {
3782912Sartem 		hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL);
3792912Sartem 	}
3802912Sartem }
3812912Sartem 
3822912Sartem gboolean
3832912Sartem devinfo_device_rescan (HalDevice *d)
3842912Sartem {
3852912Sartem 	if (hal_device_has_capability (d, "block")) {
3862912Sartem 		return (devinfo_storage_device_rescan (d));
387*7651SPhi.Tran@Sun.COM 	} else if (hal_device_has_capability (d, "button")) {
388*7651SPhi.Tran@Sun.COM 		return (devinfo_lid_rescan (d));
3894035Sphitran         } else {
3902912Sartem 		return (FALSE);
3912912Sartem 	}
3922912Sartem }
3933536Sjacobs 
3943536Sjacobs static int
3953536Sjacobs walk_devlinks(di_devlink_t devlink, void *arg)
3963536Sjacobs {
3973536Sjacobs         char    **path= (char **)arg;
3983536Sjacobs 
3993536Sjacobs         *path = strdup(di_devlink_path(devlink));
4003536Sjacobs 
4013536Sjacobs         return (DI_WALK_TERMINATE);
4023536Sjacobs }
4033536Sjacobs 
4043536Sjacobs char *
4053536Sjacobs get_devlink(di_devlink_handle_t devlink_hdl, char *re, char *path)
4063536Sjacobs {
4073536Sjacobs         char    *devlink_path = NULL;
4083536Sjacobs 
4093536Sjacobs         (void) di_devlink_walk(devlink_hdl, re, path,
4103536Sjacobs             DI_PRIMARY_LINK, &devlink_path, walk_devlinks);
4113536Sjacobs 
4123536Sjacobs         return (devlink_path);
4133536Sjacobs }
4143536Sjacobs 
415