12912Sartem /*************************************************************************** 22912Sartem * 32912Sartem * devinfo.c : main file for libdevinfo-based device enumeration 42912Sartem * 52912Sartem * Copyright 2006 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 12*2916Sartem #pragma ident "%Z%%M% %I% %E% SMI" 132912Sartem 142912Sartem #include <stdio.h> 152912Sartem #include <string.h> 162912Sartem #include <libdevinfo.h> 172912Sartem 182912Sartem #include "../osspec.h" 192912Sartem #include "../logger.h" 202912Sartem #include "../hald.h" 212912Sartem #include "../hald_dbus.h" 222912Sartem #include "../device_info.h" 232912Sartem #include "../util.h" 242912Sartem #include "../hald_runner.h" 252912Sartem #include "osspec_solaris.h" 262912Sartem #include "hotplug.h" 272912Sartem #include "devinfo.h" 282912Sartem #include "devinfo_pci.h" 292912Sartem #include "devinfo_storage.h" 302912Sartem #include "devinfo_ieee1394.h" 312912Sartem #include "devinfo_usb.h" 322912Sartem #include "devinfo_misc.h" 332912Sartem 342912Sartem void devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root); 352912Sartem HalDevice *devinfo_add_node(HalDevice *parent, di_node_t node); 362912Sartem 372912Sartem void 382912Sartem devinfo_add(HalDevice *parent, gchar *path) 392912Sartem { 402912Sartem di_node_t root; 412912Sartem 422912Sartem if (strcmp (path, "/") == 0) { 432912Sartem if ((root = di_init(path, DINFOCACHE)) == DI_NODE_NIL) { 442912Sartem HAL_INFO (("di_init() failed %d", errno)); 452912Sartem return; 462912Sartem } 472912Sartem } else { 482912Sartem if ((root = di_init(path, DINFOCPYALL)) == DI_NODE_NIL) { 492912Sartem HAL_INFO (("di_init() failed %d", errno)); 502912Sartem return; 512912Sartem } 522912Sartem } 532912Sartem 542912Sartem devinfo_add_subtree(parent, root, TRUE); 552912Sartem 562912Sartem di_fini (root); 572912Sartem } 582912Sartem 592912Sartem void 602912Sartem devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root) 612912Sartem { 622912Sartem HalDevice *d; 632912Sartem di_node_t root_node, child_node; 642912Sartem 652912Sartem HAL_INFO (("add_subtree: %s", di_node_name (node))); 662912Sartem 672912Sartem root_node = node; 682912Sartem do { 692912Sartem d = devinfo_add_node (parent, node); 702912Sartem 712912Sartem if ((d != NULL) && 722912Sartem (child_node = di_child_node (node)) != DI_NODE_NIL) { 732912Sartem devinfo_add_subtree (d, child_node, FALSE); 742912Sartem } 752912Sartem 762912Sartem node = di_sibling_node (node); 772912Sartem } while ((node != DI_NODE_NIL) && 782912Sartem (!is_root || di_parent_node (node) == root_node)); 792912Sartem } 802912Sartem 812912Sartem void 822912Sartem devinfo_set_default_properties (HalDevice *d, HalDevice *parent, di_node_t node, char *devfs_path) 832912Sartem { 842912Sartem char *driver_name, *s; 852912Sartem const char *s1; 862912Sartem char udi[HAL_PATH_MAX]; 872912Sartem 882912Sartem if (parent != NULL) { 892912Sartem hal_device_property_set_string (d, "info.parent", parent->udi); 902912Sartem } else { 912912Sartem hal_device_property_set_string (d, "info.parent", "/org/freedesktop/Hal/devices/local"); 922912Sartem } 932912Sartem 942912Sartem hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 952912Sartem "/org/freedesktop/Hal/devices%s_%d", 962912Sartem devfs_path, 972912Sartem di_instance (node)); 982912Sartem hal_device_set_udi (d, udi); 992912Sartem hal_device_property_set_string (d, "info.udi", udi); 1002912Sartem 1012912Sartem if (di_prop_lookup_strings (DDI_DEV_T_ANY, node, "model", &s) > 0) { 1022912Sartem hal_device_property_set_string (d, "info.product", s); 1032912Sartem } else { 1042912Sartem hal_device_property_set_string (d, "info.product", di_node_name (node)); 1052912Sartem } 1062912Sartem 1072912Sartem hal_device_property_set_string (d, "solaris.devfs_path", devfs_path); 1082912Sartem 1092912Sartem if ((driver_name = di_driver_name (node)) != NULL) { 1102912Sartem hal_device_property_set_string (d, "info.solaris.driver", 1112912Sartem driver_name); 1122912Sartem } 1132912Sartem 1142912Sartem 1152912Sartem /* inherit parent's claim attributes */ 1162912Sartem if (hal_device_property_get_bool (parent, "info.claimed")) { 1172912Sartem s1 = hal_device_property_get_string (parent, "info.claimed.service"); 1182912Sartem if (s1 != NULL) { 1192912Sartem hal_device_property_set_bool (d, "info.claimed", TRUE); 1202912Sartem hal_device_property_set_string (d, "info.claimed.service", s1); 1212912Sartem } 1222912Sartem } 1232912Sartem } 1242912Sartem 1252912Sartem /* device handlers, ordered specific to generic */ 1262912Sartem static DevinfoDevHandler *devinfo_handlers[] = { 1272912Sartem &devinfo_computer_handler, 1282912Sartem &devinfo_cpu_handler, 1292912Sartem &devinfo_ide_handler, 1302912Sartem &devinfo_scsi_handler, 1312912Sartem &devinfo_floppy_handler, 1322912Sartem &devinfo_usb_handler, 1332912Sartem &devinfo_ieee1394_handler, 1342912Sartem &devinfo_pci_handler, 1352912Sartem &devinfo_lofi_handler, 1362912Sartem &devinfo_default_handler, 1372912Sartem NULL 1382912Sartem }; 1392912Sartem 1402912Sartem HalDevice * 1412912Sartem devinfo_add_node(HalDevice *parent, di_node_t node) 1422912Sartem { 1432912Sartem HalDevice *d = NULL; 1442912Sartem char *devfs_path; 1452912Sartem char *device_type = NULL; 1462912Sartem DevinfoDevHandler *handler; 1472912Sartem int i; 1482912Sartem 1492912Sartem devfs_path = di_devfs_path (node); 1502912Sartem 1512912Sartem (void) di_prop_lookup_strings (DDI_DEV_T_ANY, node, "device_type", 1522912Sartem &device_type); 1532912Sartem 1542912Sartem for (i = 0; (d == NULL) && (devinfo_handlers[i] != NULL); i++) { 1552912Sartem handler = devinfo_handlers[i]; 1562912Sartem d = handler->add (parent, node, devfs_path, device_type); 1572912Sartem } 1582912Sartem 1592912Sartem di_devfs_path_free(devfs_path); 1602912Sartem 1612912Sartem HAL_INFO (("add_node: %s", d ? d->udi : "none")); 1622912Sartem return (d); 1632912Sartem } 1642912Sartem 1652912Sartem void 1662912Sartem devinfo_hotplug_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler, int action, int front) 1672912Sartem { 1682912Sartem HotplugEvent *hotplug_event; 1692912Sartem 1702912Sartem hotplug_event = g_new0 (HotplugEvent, 1); 1712912Sartem hotplug_event->action = action; 1722912Sartem hotplug_event->type = HOTPLUG_EVENT_DEVFS; 1732912Sartem hotplug_event->d = d; 1742912Sartem strlcpy (hotplug_event->un.devfs.devfs_path, devfs_path, 1752912Sartem sizeof (hotplug_event->un.devfs.devfs_path)); 1762912Sartem hotplug_event->un.devfs.handler = handler; 1772912Sartem 1782912Sartem hotplug_event_enqueue (hotplug_event, front); 1792912Sartem } 1802912Sartem 1812912Sartem void 1822912Sartem devinfo_add_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler) 1832912Sartem { 1842912Sartem devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 0); 1852912Sartem } 1862912Sartem 1872912Sartem void 1882912Sartem devinfo_add_enqueue_at_front(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler) 1892912Sartem { 1902912Sartem devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 1); 1912912Sartem } 1922912Sartem 1932912Sartem void 1942912Sartem devinfo_remove_enqueue(gchar *devfs_path, DevinfoDevHandler *handler) 1952912Sartem { 1962912Sartem devinfo_hotplug_enqueue (NULL, devfs_path, handler, HOTPLUG_ACTION_REMOVE, 0); 1972912Sartem } 1982912Sartem 1992912Sartem void 2002912Sartem devinfo_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 2012912Sartem { 2022912Sartem void *end_token = (void *) userdata1; 2032912Sartem 2042912Sartem /* Move from temporary to global device store */ 2052912Sartem hal_device_store_remove (hald_get_tdl (), d); 2062912Sartem hal_device_store_add (hald_get_gdl (), d); 2072912Sartem 2082912Sartem hotplug_event_end (end_token); 2092912Sartem } 2102912Sartem 2112912Sartem void 2122912Sartem devinfo_callouts_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2) 2132912Sartem { 2142912Sartem void *end_token = (void *) userdata1; 2152912Sartem 2162912Sartem /* Discard device if probing reports failure */ 2172912Sartem if (exit_type != HALD_RUN_SUCCESS || (return_code != 0)) { 2182912Sartem HAL_INFO (("Probing for %s failed %d", d->udi, return_code)); 2192912Sartem hal_device_store_remove (hald_get_tdl (), d); 2202912Sartem g_object_unref (d); 2212912Sartem hotplug_event_end (end_token); 2222912Sartem return; 2232912Sartem } 2242912Sartem 2252912Sartem /* Merge properties from .fdi files */ 2262912Sartem di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION); 2272912Sartem di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY); 2282912Sartem 2292912Sartem hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL); 2302912Sartem } 2312912Sartem 2322912Sartem void 2332912Sartem devinfo_callouts_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 2342912Sartem { 2352912Sartem void *end_token = (void *) userdata1; 2362912Sartem DevinfoDevHandler *handler = (DevinfoDevHandler *) userdata2; 2372912Sartem void (*probing_done) (HalDevice *, guint32, gint, char **, gpointer, gpointer); 2382912Sartem const gchar *prober; 2392912Sartem int prober_timeout; 2402912Sartem 2412912Sartem if (hal_device_property_get_bool (d, "info.ignore")) { 2422912Sartem HAL_INFO (("Preprobing merged info.ignore==TRUE")); 2432912Sartem 2442912Sartem /* Leave device with info.ignore==TRUE so we won't pick up children */ 2452912Sartem hal_device_property_remove (d, "info.category"); 2462912Sartem hal_device_property_remove (d, "info.capabilities"); 2472912Sartem 2482912Sartem hal_device_store_remove (hald_get_tdl (), d); 2492912Sartem hal_device_store_add (hald_get_gdl (), d); 2502912Sartem 2512912Sartem hotplug_event_end (end_token); 2522912Sartem return; 2532912Sartem } 2542912Sartem 2552912Sartem if (handler != NULL && handler->get_prober != NULL) { 2562912Sartem prober = handler->get_prober (d, &prober_timeout); 2572912Sartem } else { 2582912Sartem prober = NULL; 2592912Sartem } 2602912Sartem 2612912Sartem if (handler->probing_done != NULL) { 2622912Sartem probing_done = handler->probing_done; 2632912Sartem } else { 2642912Sartem probing_done = devinfo_callouts_probing_done; 2652912Sartem } 2662912Sartem 2672912Sartem if (prober != NULL) { 2682912Sartem /* probe the device */ 2692912Sartem HAL_INFO(("Probing udi=%s", d->udi)); 2702912Sartem hald_runner_run (d, 2712912Sartem prober, NULL, 2722912Sartem prober_timeout, 2732912Sartem probing_done, 2742912Sartem (gpointer) end_token, (gpointer) handler); 2752912Sartem } else { 2762912Sartem probing_done (d, 0, 0, NULL, userdata1, userdata2); 2772912Sartem } 2782912Sartem } 2792912Sartem 2802912Sartem /* This is the beginning of hotplug even handling */ 2812912Sartem void 2822912Sartem hotplug_event_begin_add_devinfo (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token) 2832912Sartem { 2842912Sartem HAL_INFO(("Preprobing udi=%s", d->udi)); 2852912Sartem 2862912Sartem if (parent != NULL && hal_device_property_get_bool (parent, "info.ignore")) { 2872912Sartem HAL_INFO (("Ignoring device since parent has info.ignore==TRUE")); 2882912Sartem 2892912Sartem hotplug_event_end (end_token); 2902912Sartem return; 2912912Sartem } 2922912Sartem 2932912Sartem /* add to TDL so preprobing callouts and prober can access it */ 2942912Sartem hal_device_store_add (hald_get_tdl (), d); 2952912Sartem 2962912Sartem /* Process preprobe fdi files */ 2972912Sartem di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE); 2982912Sartem 2992912Sartem /* Run preprobe callouts */ 3002912Sartem hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler); 3012912Sartem } 3022912Sartem 3032912Sartem void 3042912Sartem devinfo_remove (gchar *devfs_path) 3052912Sartem { 3062912Sartem devinfo_remove_enqueue ((gchar *)devfs_path, NULL); 3072912Sartem } 3082912Sartem 3092912Sartem /* generate hotplug event for each device in this branch */ 3102912Sartem void 3112912Sartem devinfo_remove_branch (gchar *devfs_path, HalDevice *d) 3122912Sartem { 3132912Sartem GSList *i; 3142912Sartem GSList *children; 3152912Sartem HalDevice *child; 3162912Sartem char *child_devfs_path; 3172912Sartem 3182912Sartem if (d == NULL) { 3192912Sartem d = hal_device_store_match_key_value_string (hald_get_gdl (), 3202912Sartem "solaris.devfs_path", devfs_path); 3212912Sartem if (d == NULL) 3222912Sartem return; 3232912Sartem } 3242912Sartem 3252912Sartem HAL_INFO (("remove_branch: %s %s\n", devfs_path, d->udi)); 3262912Sartem 3272912Sartem /* first remove children */ 3282912Sartem children = hal_device_store_match_multiple_key_value_string (hald_get_gdl(), 3292912Sartem "info.parent", d->udi); 3302912Sartem for (i = children; i != NULL; i = g_slist_next (i)) { 3312912Sartem child = HAL_DEVICE (i->data); 3322912Sartem HAL_INFO (("remove_branch: child %s\n", child->udi)); 3332912Sartem devinfo_remove_branch ((gchar *)hal_device_property_get_string (child, "solaris.devfs_path"), child); 3342912Sartem } 3352912Sartem g_slist_free (children); 3362912Sartem HAL_INFO (("remove_branch: done with children")); 3372912Sartem 3382912Sartem /* then remove self */ 3392912Sartem HAL_INFO (("remove_branch: queueing %s", devfs_path)); 3402912Sartem devinfo_remove_enqueue (devfs_path, NULL); 3412912Sartem } 3422912Sartem 3432912Sartem void 3442912Sartem devinfo_callouts_remove_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 3452912Sartem { 3462912Sartem void *end_token = (void *) userdata1; 3472912Sartem 3482912Sartem HAL_INFO (("Remove callouts completed udi=%s", d->udi)); 3492912Sartem 3502912Sartem if (!hal_device_store_remove (hald_get_gdl (), d)) { 3512912Sartem HAL_WARNING (("Error removing device")); 3522912Sartem } 3532912Sartem g_object_unref (d); 3542912Sartem 3552912Sartem hotplug_event_end (end_token); 3562912Sartem } 3572912Sartem 3582912Sartem void 3592912Sartem hotplug_event_begin_remove_devinfo (HalDevice *d, gchar *devfs_path, void *end_token) 3602912Sartem { 3612912Sartem if (hal_device_has_capability (d, "volume")) { 3622912Sartem devinfo_volume_hotplug_begin_remove (d, devfs_path, end_token); 3632912Sartem } else { 3642912Sartem hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL); 3652912Sartem } 3662912Sartem } 3672912Sartem 3682912Sartem gboolean 3692912Sartem devinfo_device_rescan (HalDevice *d) 3702912Sartem { 3712912Sartem if (hal_device_has_capability (d, "block")) { 3722912Sartem return (devinfo_storage_device_rescan (d)); 3732912Sartem } else { 3742912Sartem return (FALSE); 3752912Sartem } 3762912Sartem } 377