12912Sartem /*************************************************************************** 22912Sartem * 32912Sartem * devinfo.c : main file for libdevinfo-based device enumeration 42912Sartem * 5*9608SLin.Guo@Sun.COM * Copyright 2009 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, 144*9608SLin.Guo@Sun.COM &devinfo_mouse_handler, 1452912Sartem &devinfo_default_handler, 1462912Sartem NULL 1472912Sartem }; 1482912Sartem 1492912Sartem HalDevice * 1502912Sartem devinfo_add_node(HalDevice *parent, di_node_t node) 1512912Sartem { 1522912Sartem HalDevice *d = NULL; 1532912Sartem char *devfs_path; 1542912Sartem char *device_type = NULL; 1552912Sartem DevinfoDevHandler *handler; 1562912Sartem int i; 1572912Sartem 1582912Sartem devfs_path = di_devfs_path (node); 1592912Sartem 1602912Sartem (void) di_prop_lookup_strings (DDI_DEV_T_ANY, node, "device_type", 1612912Sartem &device_type); 1622912Sartem 1632912Sartem for (i = 0; (d == NULL) && (devinfo_handlers[i] != NULL); i++) { 1642912Sartem handler = devinfo_handlers[i]; 1652912Sartem d = handler->add (parent, node, devfs_path, device_type); 1662912Sartem } 1672912Sartem 1682912Sartem di_devfs_path_free(devfs_path); 1692912Sartem 1703121Sartem HAL_INFO (("add_node: %s", d ? hal_device_get_udi (d) : "none")); 1712912Sartem return (d); 1722912Sartem } 1732912Sartem 1742912Sartem void 1752912Sartem devinfo_hotplug_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler, int action, int front) 1762912Sartem { 1772912Sartem HotplugEvent *hotplug_event; 1782912Sartem 1792912Sartem hotplug_event = g_new0 (HotplugEvent, 1); 1802912Sartem hotplug_event->action = action; 1812912Sartem hotplug_event->type = HOTPLUG_EVENT_DEVFS; 1822912Sartem hotplug_event->d = d; 1832912Sartem strlcpy (hotplug_event->un.devfs.devfs_path, devfs_path, 1842912Sartem sizeof (hotplug_event->un.devfs.devfs_path)); 1852912Sartem hotplug_event->un.devfs.handler = handler; 1862912Sartem 1872912Sartem hotplug_event_enqueue (hotplug_event, front); 1882912Sartem } 1892912Sartem 1902912Sartem void 1912912Sartem devinfo_add_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler) 1922912Sartem { 1932912Sartem devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 0); 1942912Sartem } 1952912Sartem 1962912Sartem void 1972912Sartem devinfo_add_enqueue_at_front(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler) 1982912Sartem { 1992912Sartem devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 1); 2002912Sartem } 2012912Sartem 2022912Sartem void 2032912Sartem devinfo_remove_enqueue(gchar *devfs_path, DevinfoDevHandler *handler) 2042912Sartem { 2052912Sartem devinfo_hotplug_enqueue (NULL, devfs_path, handler, HOTPLUG_ACTION_REMOVE, 0); 2062912Sartem } 2072912Sartem 2082912Sartem void 2092912Sartem devinfo_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 2102912Sartem { 2112912Sartem void *end_token = (void *) userdata1; 2122912Sartem 2132912Sartem /* Move from temporary to global device store */ 2142912Sartem hal_device_store_remove (hald_get_tdl (), d); 2152912Sartem hal_device_store_add (hald_get_gdl (), d); 2162912Sartem 2172912Sartem hotplug_event_end (end_token); 2182912Sartem } 2192912Sartem 2202912Sartem void 2212912Sartem devinfo_callouts_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2) 2222912Sartem { 2232912Sartem void *end_token = (void *) userdata1; 2242912Sartem 2252912Sartem /* Discard device if probing reports failure */ 2262912Sartem if (exit_type != HALD_RUN_SUCCESS || (return_code != 0)) { 2273121Sartem HAL_INFO (("Probing for %s failed %d", hal_device_get_udi (d), return_code)); 2282912Sartem hal_device_store_remove (hald_get_tdl (), d); 2292912Sartem g_object_unref (d); 2302912Sartem hotplug_event_end (end_token); 2312912Sartem return; 2322912Sartem } 2332912Sartem 2342912Sartem /* Merge properties from .fdi files */ 2352912Sartem di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION); 2362912Sartem di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY); 2372912Sartem 2382912Sartem hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL); 2392912Sartem } 2402912Sartem 2412912Sartem void 2422912Sartem devinfo_callouts_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 2432912Sartem { 2442912Sartem void *end_token = (void *) userdata1; 2452912Sartem DevinfoDevHandler *handler = (DevinfoDevHandler *) userdata2; 2462912Sartem void (*probing_done) (HalDevice *, guint32, gint, char **, gpointer, gpointer); 2472912Sartem const gchar *prober; 2482912Sartem int prober_timeout; 2492912Sartem 2502912Sartem if (hal_device_property_get_bool (d, "info.ignore")) { 2512912Sartem HAL_INFO (("Preprobing merged info.ignore==TRUE")); 2522912Sartem 2532912Sartem /* Leave device with info.ignore==TRUE so we won't pick up children */ 2542912Sartem hal_device_property_remove (d, "info.category"); 2552912Sartem hal_device_property_remove (d, "info.capabilities"); 2562912Sartem 2572912Sartem hal_device_store_remove (hald_get_tdl (), d); 2582912Sartem hal_device_store_add (hald_get_gdl (), d); 2592912Sartem 2602912Sartem hotplug_event_end (end_token); 2612912Sartem return; 2622912Sartem } 2632912Sartem 2642912Sartem if (handler != NULL && handler->get_prober != NULL) { 2652912Sartem prober = handler->get_prober (d, &prober_timeout); 2662912Sartem } else { 2672912Sartem prober = NULL; 2682912Sartem } 2692912Sartem 2702912Sartem if (handler->probing_done != NULL) { 2712912Sartem probing_done = handler->probing_done; 2722912Sartem } else { 2732912Sartem probing_done = devinfo_callouts_probing_done; 2742912Sartem } 2752912Sartem 2762912Sartem if (prober != NULL) { 2772912Sartem /* probe the device */ 2783121Sartem HAL_INFO(("Probing udi=%s", hal_device_get_udi (d))); 2792912Sartem hald_runner_run (d, 2802912Sartem prober, NULL, 2812912Sartem prober_timeout, 2822912Sartem probing_done, 2832912Sartem (gpointer) end_token, (gpointer) handler); 2842912Sartem } else { 2852912Sartem probing_done (d, 0, 0, NULL, userdata1, userdata2); 2862912Sartem } 2872912Sartem } 2882912Sartem 2892912Sartem /* This is the beginning of hotplug even handling */ 2902912Sartem void 2912912Sartem hotplug_event_begin_add_devinfo (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token) 2922912Sartem { 2938100SLin.Guo@Sun.COM HotplugEvent *hotplug_event = (HotplugEvent *)end_token; 2948100SLin.Guo@Sun.COM 2953121Sartem HAL_INFO(("Preprobing udi=%s", hal_device_get_udi (d))); 2962912Sartem 2978100SLin.Guo@Sun.COM if (parent == NULL && (strcmp(hotplug_event->un.devfs.devfs_path, "/") != 0)) { 2988100SLin.Guo@Sun.COM HAL_ERROR (("Parent is NULL, devfs_path=%s", hotplug_event->un.devfs.devfs_path)); 2998100SLin.Guo@Sun.COM 3008100SLin.Guo@Sun.COM goto skip; 3018100SLin.Guo@Sun.COM } 3028100SLin.Guo@Sun.COM 3038100SLin.Guo@Sun.COM 3042912Sartem if (parent != NULL && hal_device_property_get_bool (parent, "info.ignore")) { 3052912Sartem HAL_INFO (("Ignoring device since parent has info.ignore==TRUE")); 3062912Sartem 3078100SLin.Guo@Sun.COM goto skip; 3082912Sartem } 3092912Sartem 3106112Sqz150045 if (hal_device_store_find (hald_get_tdl (), hal_device_get_udi (d)) == NULL) { 3116112Sqz150045 3126112Sqz150045 /* add to TDL so preprobing callouts and prober can access it */ 3136112Sqz150045 hal_device_store_add (hald_get_tdl (), d); 3146112Sqz150045 } 3152912Sartem 3162912Sartem /* Process preprobe fdi files */ 3172912Sartem di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE); 3182912Sartem 3192912Sartem /* Run preprobe callouts */ 3202912Sartem hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler); 3218100SLin.Guo@Sun.COM 3228100SLin.Guo@Sun.COM return; 3238100SLin.Guo@Sun.COM 3248100SLin.Guo@Sun.COM skip: 3258100SLin.Guo@Sun.COM if (hal_device_store_find (hald_get_tdl (), hal_device_get_udi (d))) 3268100SLin.Guo@Sun.COM hal_device_store_remove (hald_get_tdl (), d); 3278100SLin.Guo@Sun.COM 3288100SLin.Guo@Sun.COM g_object_unref (d); 3298100SLin.Guo@Sun.COM hotplug_event_end (end_token); 3308100SLin.Guo@Sun.COM 3318100SLin.Guo@Sun.COM return; 3322912Sartem } 3332912Sartem 3342912Sartem void 3352912Sartem devinfo_remove (gchar *devfs_path) 3362912Sartem { 3372912Sartem devinfo_remove_enqueue ((gchar *)devfs_path, NULL); 3382912Sartem } 3392912Sartem 3402912Sartem /* generate hotplug event for each device in this branch */ 3412912Sartem void 3422912Sartem devinfo_remove_branch (gchar *devfs_path, HalDevice *d) 3432912Sartem { 3442912Sartem GSList *i; 3452912Sartem GSList *children; 3462912Sartem HalDevice *child; 3472912Sartem char *child_devfs_path; 3482912Sartem 3492912Sartem if (d == NULL) { 3502912Sartem d = hal_device_store_match_key_value_string (hald_get_gdl (), 3512912Sartem "solaris.devfs_path", devfs_path); 3522912Sartem if (d == NULL) 3532912Sartem return; 3542912Sartem } 3552912Sartem 3563121Sartem HAL_INFO (("remove_branch: %s %s\n", devfs_path, hal_device_get_udi (d))); 3572912Sartem 3582912Sartem /* first remove children */ 3592912Sartem children = hal_device_store_match_multiple_key_value_string (hald_get_gdl(), 3603121Sartem "info.parent", hal_device_get_udi (d)); 3612912Sartem for (i = children; i != NULL; i = g_slist_next (i)) { 3622912Sartem child = HAL_DEVICE (i->data); 3633121Sartem HAL_INFO (("remove_branch: child %s\n", hal_device_get_udi (child))); 3642912Sartem devinfo_remove_branch ((gchar *)hal_device_property_get_string (child, "solaris.devfs_path"), child); 3652912Sartem } 3662912Sartem g_slist_free (children); 3672912Sartem HAL_INFO (("remove_branch: done with children")); 3682912Sartem 3692912Sartem /* then remove self */ 3702912Sartem HAL_INFO (("remove_branch: queueing %s", devfs_path)); 3712912Sartem devinfo_remove_enqueue (devfs_path, NULL); 3722912Sartem } 3732912Sartem 3742912Sartem void 3752912Sartem devinfo_callouts_remove_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 3762912Sartem { 3772912Sartem void *end_token = (void *) userdata1; 3782912Sartem 3793121Sartem HAL_INFO (("Remove callouts completed udi=%s", hal_device_get_udi (d))); 3802912Sartem 3812912Sartem if (!hal_device_store_remove (hald_get_gdl (), d)) { 3822912Sartem HAL_WARNING (("Error removing device")); 3832912Sartem } 3842912Sartem g_object_unref (d); 3852912Sartem 3862912Sartem hotplug_event_end (end_token); 3872912Sartem } 3882912Sartem 3892912Sartem void 3902912Sartem hotplug_event_begin_remove_devinfo (HalDevice *d, gchar *devfs_path, void *end_token) 3912912Sartem { 3922912Sartem if (hal_device_has_capability (d, "volume")) { 3932912Sartem devinfo_volume_hotplug_begin_remove (d, devfs_path, end_token); 3942912Sartem } else { 3952912Sartem hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL); 3962912Sartem } 3972912Sartem } 3982912Sartem 3992912Sartem gboolean 4002912Sartem devinfo_device_rescan (HalDevice *d) 4012912Sartem { 4022912Sartem if (hal_device_has_capability (d, "block")) { 4032912Sartem return (devinfo_storage_device_rescan (d)); 4047651SPhi.Tran@Sun.COM } else if (hal_device_has_capability (d, "button")) { 4057651SPhi.Tran@Sun.COM return (devinfo_lid_rescan (d)); 4064035Sphitran } else { 4072912Sartem return (FALSE); 4082912Sartem } 4092912Sartem } 4103536Sjacobs 4113536Sjacobs static int 4123536Sjacobs walk_devlinks(di_devlink_t devlink, void *arg) 4133536Sjacobs { 4143536Sjacobs char **path= (char **)arg; 4153536Sjacobs 4163536Sjacobs *path = strdup(di_devlink_path(devlink)); 4173536Sjacobs 4183536Sjacobs return (DI_WALK_TERMINATE); 4193536Sjacobs } 4203536Sjacobs 4213536Sjacobs char * 4223536Sjacobs get_devlink(di_devlink_handle_t devlink_hdl, char *re, char *path) 4233536Sjacobs { 4243536Sjacobs char *devlink_path = NULL; 4253536Sjacobs 4263536Sjacobs (void) di_devlink_walk(devlink_hdl, re, path, 4273536Sjacobs DI_PRIMARY_LINK, &devlink_path, walk_devlinks); 4283536Sjacobs 4293536Sjacobs return (devlink_path); 4303536Sjacobs } 431