1*2912Sartem /*************************************************************************** 2*2912Sartem * 3*2912Sartem * devinfo.c : main file for libdevinfo-based device enumeration 4*2912Sartem * 5*2912Sartem * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 6*2912Sartem * Use is subject to license terms. 7*2912Sartem * 8*2912Sartem * Licensed under the Academic Free License version 2.1 9*2912Sartem * 10*2912Sartem **************************************************************************/ 11*2912Sartem 12*2912Sartem #pragma ident "%Z%%M% %I% %E% SMI" 13*2912Sartem 14*2912Sartem #include <stdio.h> 15*2912Sartem #include <string.h> 16*2912Sartem #include <libdevinfo.h> 17*2912Sartem 18*2912Sartem #include "../osspec.h" 19*2912Sartem #include "../logger.h" 20*2912Sartem #include "../hald.h" 21*2912Sartem #include "../hald_dbus.h" 22*2912Sartem #include "../device_info.h" 23*2912Sartem #include "../util.h" 24*2912Sartem #include "../hald_runner.h" 25*2912Sartem #include "osspec_solaris.h" 26*2912Sartem #include "hotplug.h" 27*2912Sartem #include "devinfo.h" 28*2912Sartem #include "devinfo_pci.h" 29*2912Sartem #include "devinfo_storage.h" 30*2912Sartem #include "devinfo_ieee1394.h" 31*2912Sartem #include "devinfo_usb.h" 32*2912Sartem #include "devinfo_misc.h" 33*2912Sartem 34*2912Sartem void devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root); 35*2912Sartem HalDevice *devinfo_add_node(HalDevice *parent, di_node_t node); 36*2912Sartem 37*2912Sartem void 38*2912Sartem devinfo_add(HalDevice *parent, gchar *path) 39*2912Sartem { 40*2912Sartem di_node_t root; 41*2912Sartem 42*2912Sartem if (strcmp (path, "/") == 0) { 43*2912Sartem if ((root = di_init(path, DINFOCACHE)) == DI_NODE_NIL) { 44*2912Sartem HAL_INFO (("di_init() failed %d", errno)); 45*2912Sartem return; 46*2912Sartem } 47*2912Sartem } else { 48*2912Sartem if ((root = di_init(path, DINFOCPYALL)) == DI_NODE_NIL) { 49*2912Sartem HAL_INFO (("di_init() failed %d", errno)); 50*2912Sartem return; 51*2912Sartem } 52*2912Sartem } 53*2912Sartem 54*2912Sartem devinfo_add_subtree(parent, root, TRUE); 55*2912Sartem 56*2912Sartem di_fini (root); 57*2912Sartem } 58*2912Sartem 59*2912Sartem void 60*2912Sartem devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root) 61*2912Sartem { 62*2912Sartem HalDevice *d; 63*2912Sartem di_node_t root_node, child_node; 64*2912Sartem 65*2912Sartem HAL_INFO (("add_subtree: %s", di_node_name (node))); 66*2912Sartem 67*2912Sartem root_node = node; 68*2912Sartem do { 69*2912Sartem d = devinfo_add_node (parent, node); 70*2912Sartem 71*2912Sartem if ((d != NULL) && 72*2912Sartem (child_node = di_child_node (node)) != DI_NODE_NIL) { 73*2912Sartem devinfo_add_subtree (d, child_node, FALSE); 74*2912Sartem } 75*2912Sartem 76*2912Sartem node = di_sibling_node (node); 77*2912Sartem } while ((node != DI_NODE_NIL) && 78*2912Sartem (!is_root || di_parent_node (node) == root_node)); 79*2912Sartem } 80*2912Sartem 81*2912Sartem void 82*2912Sartem devinfo_set_default_properties (HalDevice *d, HalDevice *parent, di_node_t node, char *devfs_path) 83*2912Sartem { 84*2912Sartem char *driver_name, *s; 85*2912Sartem const char *s1; 86*2912Sartem char udi[HAL_PATH_MAX]; 87*2912Sartem 88*2912Sartem if (parent != NULL) { 89*2912Sartem hal_device_property_set_string (d, "info.parent", parent->udi); 90*2912Sartem } else { 91*2912Sartem hal_device_property_set_string (d, "info.parent", "/org/freedesktop/Hal/devices/local"); 92*2912Sartem } 93*2912Sartem 94*2912Sartem hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 95*2912Sartem "/org/freedesktop/Hal/devices%s_%d", 96*2912Sartem devfs_path, 97*2912Sartem di_instance (node)); 98*2912Sartem hal_device_set_udi (d, udi); 99*2912Sartem hal_device_property_set_string (d, "info.udi", udi); 100*2912Sartem 101*2912Sartem if (di_prop_lookup_strings (DDI_DEV_T_ANY, node, "model", &s) > 0) { 102*2912Sartem hal_device_property_set_string (d, "info.product", s); 103*2912Sartem } else { 104*2912Sartem hal_device_property_set_string (d, "info.product", di_node_name (node)); 105*2912Sartem } 106*2912Sartem 107*2912Sartem hal_device_property_set_string (d, "solaris.devfs_path", devfs_path); 108*2912Sartem 109*2912Sartem if ((driver_name = di_driver_name (node)) != NULL) { 110*2912Sartem hal_device_property_set_string (d, "info.solaris.driver", 111*2912Sartem driver_name); 112*2912Sartem } 113*2912Sartem 114*2912Sartem 115*2912Sartem /* inherit parent's claim attributes */ 116*2912Sartem if (hal_device_property_get_bool (parent, "info.claimed")) { 117*2912Sartem s1 = hal_device_property_get_string (parent, "info.claimed.service"); 118*2912Sartem if (s1 != NULL) { 119*2912Sartem hal_device_property_set_bool (d, "info.claimed", TRUE); 120*2912Sartem hal_device_property_set_string (d, "info.claimed.service", s1); 121*2912Sartem } 122*2912Sartem } 123*2912Sartem } 124*2912Sartem 125*2912Sartem /* device handlers, ordered specific to generic */ 126*2912Sartem static DevinfoDevHandler *devinfo_handlers[] = { 127*2912Sartem &devinfo_computer_handler, 128*2912Sartem &devinfo_cpu_handler, 129*2912Sartem &devinfo_ide_handler, 130*2912Sartem &devinfo_scsi_handler, 131*2912Sartem &devinfo_floppy_handler, 132*2912Sartem &devinfo_usb_handler, 133*2912Sartem &devinfo_ieee1394_handler, 134*2912Sartem &devinfo_pci_handler, 135*2912Sartem &devinfo_lofi_handler, 136*2912Sartem &devinfo_default_handler, 137*2912Sartem NULL 138*2912Sartem }; 139*2912Sartem 140*2912Sartem HalDevice * 141*2912Sartem devinfo_add_node(HalDevice *parent, di_node_t node) 142*2912Sartem { 143*2912Sartem HalDevice *d = NULL; 144*2912Sartem char *devfs_path; 145*2912Sartem char *device_type = NULL; 146*2912Sartem DevinfoDevHandler *handler; 147*2912Sartem int i; 148*2912Sartem 149*2912Sartem devfs_path = di_devfs_path (node); 150*2912Sartem 151*2912Sartem (void) di_prop_lookup_strings (DDI_DEV_T_ANY, node, "device_type", 152*2912Sartem &device_type); 153*2912Sartem 154*2912Sartem for (i = 0; (d == NULL) && (devinfo_handlers[i] != NULL); i++) { 155*2912Sartem handler = devinfo_handlers[i]; 156*2912Sartem d = handler->add (parent, node, devfs_path, device_type); 157*2912Sartem } 158*2912Sartem 159*2912Sartem di_devfs_path_free(devfs_path); 160*2912Sartem 161*2912Sartem HAL_INFO (("add_node: %s", d ? d->udi : "none")); 162*2912Sartem return (d); 163*2912Sartem } 164*2912Sartem 165*2912Sartem void 166*2912Sartem devinfo_hotplug_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler, int action, int front) 167*2912Sartem { 168*2912Sartem HotplugEvent *hotplug_event; 169*2912Sartem 170*2912Sartem hotplug_event = g_new0 (HotplugEvent, 1); 171*2912Sartem hotplug_event->action = action; 172*2912Sartem hotplug_event->type = HOTPLUG_EVENT_DEVFS; 173*2912Sartem hotplug_event->d = d; 174*2912Sartem strlcpy (hotplug_event->un.devfs.devfs_path, devfs_path, 175*2912Sartem sizeof (hotplug_event->un.devfs.devfs_path)); 176*2912Sartem hotplug_event->un.devfs.handler = handler; 177*2912Sartem 178*2912Sartem hotplug_event_enqueue (hotplug_event, front); 179*2912Sartem } 180*2912Sartem 181*2912Sartem void 182*2912Sartem devinfo_add_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler) 183*2912Sartem { 184*2912Sartem devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 0); 185*2912Sartem } 186*2912Sartem 187*2912Sartem void 188*2912Sartem devinfo_add_enqueue_at_front(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler) 189*2912Sartem { 190*2912Sartem devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 1); 191*2912Sartem } 192*2912Sartem 193*2912Sartem void 194*2912Sartem devinfo_remove_enqueue(gchar *devfs_path, DevinfoDevHandler *handler) 195*2912Sartem { 196*2912Sartem devinfo_hotplug_enqueue (NULL, devfs_path, handler, HOTPLUG_ACTION_REMOVE, 0); 197*2912Sartem } 198*2912Sartem 199*2912Sartem void 200*2912Sartem devinfo_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 201*2912Sartem { 202*2912Sartem void *end_token = (void *) userdata1; 203*2912Sartem 204*2912Sartem /* Move from temporary to global device store */ 205*2912Sartem hal_device_store_remove (hald_get_tdl (), d); 206*2912Sartem hal_device_store_add (hald_get_gdl (), d); 207*2912Sartem 208*2912Sartem hotplug_event_end (end_token); 209*2912Sartem } 210*2912Sartem 211*2912Sartem void 212*2912Sartem devinfo_callouts_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2) 213*2912Sartem { 214*2912Sartem void *end_token = (void *) userdata1; 215*2912Sartem 216*2912Sartem /* Discard device if probing reports failure */ 217*2912Sartem if (exit_type != HALD_RUN_SUCCESS || (return_code != 0)) { 218*2912Sartem HAL_INFO (("Probing for %s failed %d", d->udi, return_code)); 219*2912Sartem hal_device_store_remove (hald_get_tdl (), d); 220*2912Sartem g_object_unref (d); 221*2912Sartem hotplug_event_end (end_token); 222*2912Sartem return; 223*2912Sartem } 224*2912Sartem 225*2912Sartem /* Merge properties from .fdi files */ 226*2912Sartem di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION); 227*2912Sartem di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY); 228*2912Sartem 229*2912Sartem hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL); 230*2912Sartem } 231*2912Sartem 232*2912Sartem void 233*2912Sartem devinfo_callouts_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 234*2912Sartem { 235*2912Sartem void *end_token = (void *) userdata1; 236*2912Sartem DevinfoDevHandler *handler = (DevinfoDevHandler *) userdata2; 237*2912Sartem void (*probing_done) (HalDevice *, guint32, gint, char **, gpointer, gpointer); 238*2912Sartem const gchar *prober; 239*2912Sartem int prober_timeout; 240*2912Sartem 241*2912Sartem if (hal_device_property_get_bool (d, "info.ignore")) { 242*2912Sartem HAL_INFO (("Preprobing merged info.ignore==TRUE")); 243*2912Sartem 244*2912Sartem /* Leave device with info.ignore==TRUE so we won't pick up children */ 245*2912Sartem hal_device_property_remove (d, "info.category"); 246*2912Sartem hal_device_property_remove (d, "info.capabilities"); 247*2912Sartem 248*2912Sartem hal_device_store_remove (hald_get_tdl (), d); 249*2912Sartem hal_device_store_add (hald_get_gdl (), d); 250*2912Sartem 251*2912Sartem hotplug_event_end (end_token); 252*2912Sartem return; 253*2912Sartem } 254*2912Sartem 255*2912Sartem if (handler != NULL && handler->get_prober != NULL) { 256*2912Sartem prober = handler->get_prober (d, &prober_timeout); 257*2912Sartem } else { 258*2912Sartem prober = NULL; 259*2912Sartem } 260*2912Sartem 261*2912Sartem if (handler->probing_done != NULL) { 262*2912Sartem probing_done = handler->probing_done; 263*2912Sartem } else { 264*2912Sartem probing_done = devinfo_callouts_probing_done; 265*2912Sartem } 266*2912Sartem 267*2912Sartem if (prober != NULL) { 268*2912Sartem /* probe the device */ 269*2912Sartem HAL_INFO(("Probing udi=%s", d->udi)); 270*2912Sartem hald_runner_run (d, 271*2912Sartem prober, NULL, 272*2912Sartem prober_timeout, 273*2912Sartem probing_done, 274*2912Sartem (gpointer) end_token, (gpointer) handler); 275*2912Sartem } else { 276*2912Sartem probing_done (d, 0, 0, NULL, userdata1, userdata2); 277*2912Sartem } 278*2912Sartem } 279*2912Sartem 280*2912Sartem /* This is the beginning of hotplug even handling */ 281*2912Sartem void 282*2912Sartem hotplug_event_begin_add_devinfo (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token) 283*2912Sartem { 284*2912Sartem HAL_INFO(("Preprobing udi=%s", d->udi)); 285*2912Sartem 286*2912Sartem if (parent != NULL && hal_device_property_get_bool (parent, "info.ignore")) { 287*2912Sartem HAL_INFO (("Ignoring device since parent has info.ignore==TRUE")); 288*2912Sartem 289*2912Sartem hotplug_event_end (end_token); 290*2912Sartem return; 291*2912Sartem } 292*2912Sartem 293*2912Sartem /* add to TDL so preprobing callouts and prober can access it */ 294*2912Sartem hal_device_store_add (hald_get_tdl (), d); 295*2912Sartem 296*2912Sartem /* Process preprobe fdi files */ 297*2912Sartem di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE); 298*2912Sartem 299*2912Sartem /* Run preprobe callouts */ 300*2912Sartem hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler); 301*2912Sartem } 302*2912Sartem 303*2912Sartem void 304*2912Sartem devinfo_remove (gchar *devfs_path) 305*2912Sartem { 306*2912Sartem devinfo_remove_enqueue ((gchar *)devfs_path, NULL); 307*2912Sartem } 308*2912Sartem 309*2912Sartem /* generate hotplug event for each device in this branch */ 310*2912Sartem void 311*2912Sartem devinfo_remove_branch (gchar *devfs_path, HalDevice *d) 312*2912Sartem { 313*2912Sartem GSList *i; 314*2912Sartem GSList *children; 315*2912Sartem HalDevice *child; 316*2912Sartem char *child_devfs_path; 317*2912Sartem 318*2912Sartem if (d == NULL) { 319*2912Sartem d = hal_device_store_match_key_value_string (hald_get_gdl (), 320*2912Sartem "solaris.devfs_path", devfs_path); 321*2912Sartem if (d == NULL) 322*2912Sartem return; 323*2912Sartem } 324*2912Sartem 325*2912Sartem HAL_INFO (("remove_branch: %s %s\n", devfs_path, d->udi)); 326*2912Sartem 327*2912Sartem /* first remove children */ 328*2912Sartem children = hal_device_store_match_multiple_key_value_string (hald_get_gdl(), 329*2912Sartem "info.parent", d->udi); 330*2912Sartem for (i = children; i != NULL; i = g_slist_next (i)) { 331*2912Sartem child = HAL_DEVICE (i->data); 332*2912Sartem HAL_INFO (("remove_branch: child %s\n", child->udi)); 333*2912Sartem devinfo_remove_branch ((gchar *)hal_device_property_get_string (child, "solaris.devfs_path"), child); 334*2912Sartem } 335*2912Sartem g_slist_free (children); 336*2912Sartem HAL_INFO (("remove_branch: done with children")); 337*2912Sartem 338*2912Sartem /* then remove self */ 339*2912Sartem HAL_INFO (("remove_branch: queueing %s", devfs_path)); 340*2912Sartem devinfo_remove_enqueue (devfs_path, NULL); 341*2912Sartem } 342*2912Sartem 343*2912Sartem void 344*2912Sartem devinfo_callouts_remove_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 345*2912Sartem { 346*2912Sartem void *end_token = (void *) userdata1; 347*2912Sartem 348*2912Sartem HAL_INFO (("Remove callouts completed udi=%s", d->udi)); 349*2912Sartem 350*2912Sartem if (!hal_device_store_remove (hald_get_gdl (), d)) { 351*2912Sartem HAL_WARNING (("Error removing device")); 352*2912Sartem } 353*2912Sartem g_object_unref (d); 354*2912Sartem 355*2912Sartem hotplug_event_end (end_token); 356*2912Sartem } 357*2912Sartem 358*2912Sartem void 359*2912Sartem hotplug_event_begin_remove_devinfo (HalDevice *d, gchar *devfs_path, void *end_token) 360*2912Sartem { 361*2912Sartem if (hal_device_has_capability (d, "volume")) { 362*2912Sartem devinfo_volume_hotplug_begin_remove (d, devfs_path, end_token); 363*2912Sartem } else { 364*2912Sartem hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL); 365*2912Sartem } 366*2912Sartem } 367*2912Sartem 368*2912Sartem gboolean 369*2912Sartem devinfo_device_rescan (HalDevice *d) 370*2912Sartem { 371*2912Sartem if (hal_device_has_capability (d, "block")) { 372*2912Sartem return (devinfo_storage_device_rescan (d)); 373*2912Sartem } else { 374*2912Sartem return (FALSE); 375*2912Sartem } 376*2912Sartem } 377