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