devinfo.c revision 6112:28ee9a48b832
118334Speter/*************************************************************************** 290075Sobrien * 3169689Skan * devinfo.c : main file for libdevinfo-based device enumeration 418334Speter * 590075Sobrien * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 618334Speter * Use is subject to license terms. 790075Sobrien * 890075Sobrien * Licensed under the Academic Free License version 2.1 990075Sobrien * 1090075Sobrien **************************************************************************/ 1118334Speter 1290075Sobrien#pragma ident "%Z%%M% %I% %E% SMI" 1390075Sobrien 1490075Sobrien#ifdef HAVE_CONFIG_H 1590075Sobrien# include <config.h> 1618334Speter#endif 1718334Speter 1890075Sobrien#include <stdio.h> 19169689Skan#include <string.h> 20169689Skan#include <libdevinfo.h> 2118334Speter 22169689Skan#include "../osspec.h" 23169689Skan#include "../logger.h" 2418334Speter#include "../hald.h" 2550397Sobrien#include "../hald_dbus.h" 26169689Skan#include "../device_info.h" 27117395Skan#include "../util.h" 28117395Skan#include "../hald_runner.h" 2918334Speter#include "osspec_solaris.h" 3018334Speter#include "hotplug.h" 3118334Speter#include "devinfo.h" 3290075Sobrien#include "devinfo_pci.h" 3390075Sobrien#include "devinfo_storage.h" 3490075Sobrien#include "devinfo_ieee1394.h" 3590075Sobrien#include "devinfo_usb.h" 3618334Speter#include "devinfo_misc.h" 3790075Sobrien#include "devinfo_acpi.h" 3890075Sobrien 3990075Sobrienvoid devinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root); 4018334SpeterHalDevice *devinfo_add_node(HalDevice *parent, di_node_t node); 4150397Sobrien 4250397Sobrienvoid 4350397Sobriendevinfo_add(HalDevice *parent, gchar *path) 4450397Sobrien{ 4518334Speter di_node_t root; 4618334Speter 4718334Speter if (strcmp (path, "/") == 0) { 4818334Speter if ((root = di_init(path, DINFOCACHE)) == DI_NODE_NIL) { 4950397Sobrien HAL_INFO (("di_init() failed %d", errno)); 5090075Sobrien return; 5190075Sobrien } 5250397Sobrien } else { 5350397Sobrien if ((root = di_init(path, DINFOCPYALL)) == DI_NODE_NIL) { 5450397Sobrien HAL_INFO (("di_init() failed %d", errno)); 5590075Sobrien return; 5650397Sobrien } 5750397Sobrien } 5850397Sobrien 5950397Sobrien devinfo_add_subtree(parent, root, TRUE); 6090075Sobrien 6150397Sobrien di_fini (root); 6250397Sobrien} 6350397Sobrien 64161651Skanvoid 6550397Sobriendevinfo_add_subtree(HalDevice *parent, di_node_t node, gboolean is_root) 6650397Sobrien{ 6750397Sobrien HalDevice *d; 68169689Skan di_node_t root_node, child_node; 6950397Sobrien 70169689Skan HAL_INFO (("add_subtree: %s", di_node_name (node))); 71169689Skan 72169689Skan root_node = node; 73169689Skan do { 74169689Skan d = devinfo_add_node (parent, node); 7590075Sobrien 7650397Sobrien if ((d != NULL) && 77169689Skan (child_node = di_child_node (node)) != DI_NODE_NIL) { 7818334Speter devinfo_add_subtree (d, child_node, FALSE); 7990075Sobrien } 8090075Sobrien 81169689Skan node = di_sibling_node (node); 8290075Sobrien } while ((node != DI_NODE_NIL) && 83132718Skan (!is_root || di_parent_node (node) == root_node)); 8490075Sobrien} 8590075Sobrien 8690075Sobrienvoid 8790075Sobriendevinfo_set_default_properties (HalDevice *d, HalDevice *parent, di_node_t node, char *devfs_path) 8890075Sobrien{ 8990075Sobrien char *driver_name, *s; 9090075Sobrien const char *s1; 9190075Sobrien char udi[HAL_PATH_MAX]; 9290075Sobrien 9390075Sobrien if (parent != NULL) { 9490075Sobrien hal_device_property_set_string (d, "info.parent", hal_device_get_udi (parent)); 9590075Sobrien } else { 9690075Sobrien hal_device_property_set_string (d, "info.parent", "/org/freedesktop/Hal/devices/local"); 9790075Sobrien } 9890075Sobrien 9990075Sobrien hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 10090075Sobrien "/org/freedesktop/Hal/devices%s_%d", 10150397Sobrien devfs_path, 10250397Sobrien di_instance (node)); 10350397Sobrien hal_device_set_udi (d, udi); 10418334Speter hal_device_property_set_string (d, "info.udi", udi); 105169689Skan 10618334Speter if (di_prop_lookup_strings (DDI_DEV_T_ANY, node, "model", &s) > 0) { 10718334Speter hal_device_property_set_string (d, "info.product", s); 10818334Speter } else { 10918334Speter hal_device_property_set_string (d, "info.product", di_node_name (node)); 11018334Speter } 11118334Speter 11218334Speter hal_device_property_set_string (d, "solaris.devfs_path", devfs_path); 113169689Skan 11418334Speter if ((driver_name = di_driver_name (node)) != NULL) { 11518334Speter hal_device_property_set_string (d, "info.solaris.driver", 11618334Speter driver_name); 11718334Speter } 11818334Speter 11918334Speter 12018334Speter /* inherit parent's claim attributes */ 12118334Speter if (hal_device_property_get_bool (parent, "info.claimed")) { 12218334Speter s1 = hal_device_property_get_string (parent, "info.claimed.service"); 12318334Speter if (s1 != NULL) { 12418334Speter hal_device_property_set_bool (d, "info.claimed", TRUE); 12518334Speter hal_device_property_set_string (d, "info.claimed.service", s1); 12618334Speter } 12718334Speter } 12818334Speter} 12918334Speter 13018334Speter/* device handlers, ordered specific to generic */ 13118334Speterstatic DevinfoDevHandler *devinfo_handlers[] = { 132169689Skan &devinfo_computer_handler, 133169689Skan &devinfo_cpu_handler, 13418334Speter &devinfo_ide_handler, 135161651Skan &devinfo_scsi_handler, 136161651Skan &devinfo_pcata_handler, 137161651Skan &devinfo_floppy_handler, 138161651Skan &devinfo_usb_handler, 139169689Skan &devinfo_ieee1394_handler, 140161651Skan &devinfo_pci_handler, 14118334Speter &devinfo_lofi_handler, 14218334Speter &devinfo_acpi_handler, 14318334Speter &devinfo_battery_handler, 14418334Speter &devinfo_default_handler, 14518334Speter NULL 14618334Speter}; 14718334Speter 14818334SpeterHalDevice * 14918334Speterdevinfo_add_node(HalDevice *parent, di_node_t node) 15018334Speter{ 15118334Speter HalDevice *d = NULL; 15218334Speter char *devfs_path; 15318334Speter char *device_type = NULL; 15418334Speter DevinfoDevHandler *handler; 15518334Speter int i; 156169689Skan 157169689Skan devfs_path = di_devfs_path (node); 15818334Speter 15918334Speter (void) di_prop_lookup_strings (DDI_DEV_T_ANY, node, "device_type", 16050397Sobrien &device_type); 16118334Speter 16250397Sobrien for (i = 0; (d == NULL) && (devinfo_handlers[i] != NULL); i++) { 16350397Sobrien handler = devinfo_handlers[i]; 16450397Sobrien d = handler->add (parent, node, devfs_path, device_type); 16550397Sobrien } 16618334Speter 16718334Speter di_devfs_path_free(devfs_path); 168132718Skan 16918334Speter HAL_INFO (("add_node: %s", d ? hal_device_get_udi (d) : "none")); 17018334Speter return (d); 17118334Speter} 172132718Skan 17318334Spetervoid 174132718Skandevinfo_hotplug_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler, int action, int front) 17518334Speter{ 176169689Skan HotplugEvent *hotplug_event; 177169689Skan 178169689Skan hotplug_event = g_new0 (HotplugEvent, 1); 179169689Skan hotplug_event->action = action; 18018334Speter hotplug_event->type = HOTPLUG_EVENT_DEVFS; 18118334Speter hotplug_event->d = d; 18218334Speter strlcpy (hotplug_event->un.devfs.devfs_path, devfs_path, 18318334Speter sizeof (hotplug_event->un.devfs.devfs_path)); 18418334Speter hotplug_event->un.devfs.handler = handler; 18518334Speter 18618334Speter hotplug_event_enqueue (hotplug_event, front); 18718334Speter} 18818334Speter 18918334Spetervoid 19018334Speterdevinfo_add_enqueue(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler) 19118334Speter{ 192169689Skan devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 0); 19318334Speter} 19418334Speter 19518334Spetervoid 19618334Speterdevinfo_add_enqueue_at_front(HalDevice *d, gchar *devfs_path, DevinfoDevHandler *handler) 19718334Speter{ 19818334Speter devinfo_hotplug_enqueue (d, devfs_path, handler, HOTPLUG_ACTION_ADD, 1); 19918334Speter} 200169689Skan 20118334Spetervoid 20218334Speterdevinfo_remove_enqueue(gchar *devfs_path, DevinfoDevHandler *handler) 20318334Speter{ 20418334Speter devinfo_hotplug_enqueue (NULL, devfs_path, handler, HOTPLUG_ACTION_REMOVE, 0); 20518334Speter} 20618334Speter 20718334Spetervoid 20818334Speterdevinfo_callouts_add_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 20918334Speter{ 21018334Speter void *end_token = (void *) userdata1; 21118334Speter 21218334Speter /* Move from temporary to global device store */ 21318334Speter hal_device_store_remove (hald_get_tdl (), d); 21418334Speter hal_device_store_add (hald_get_gdl (), d); 21518334Speter 21618334Speter hotplug_event_end (end_token); 21718334Speter} 21818334Speter 21950397Sobrienvoid 22050397Sobriendevinfo_callouts_probing_done (HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2) 22150397Sobrien{ 22250397Sobrien void *end_token = (void *) userdata1; 22350397Sobrien 22450397Sobrien /* Discard device if probing reports failure */ 22552284Sobrien if (exit_type != HALD_RUN_SUCCESS || (return_code != 0)) { 22652284Sobrien HAL_INFO (("Probing for %s failed %d", hal_device_get_udi (d), return_code)); 22790075Sobrien hal_device_store_remove (hald_get_tdl (), d); 228132718Skan g_object_unref (d); 22952284Sobrien hotplug_event_end (end_token); 23018334Speter return; 231132718Skan } 23252284Sobrien 23352284Sobrien /* Merge properties from .fdi files */ 23452284Sobrien di_search_and_merge (d, DEVICE_INFO_TYPE_INFORMATION); 23552284Sobrien di_search_and_merge (d, DEVICE_INFO_TYPE_POLICY); 23650397Sobrien 23750397Sobrien hal_util_callout_device_add (d, devinfo_callouts_add_done, end_token, NULL); 238132718Skan} 239169689Skan 240169689Skanvoid 241169689Skandevinfo_callouts_preprobing_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 242259268Spfg{ 243259268Spfg void *end_token = (void *) userdata1; 244169689Skan DevinfoDevHandler *handler = (DevinfoDevHandler *) userdata2; 245259268Spfg void (*probing_done) (HalDevice *, guint32, gint, char **, gpointer, gpointer); 246259268Spfg const gchar *prober; 247259268Spfg int prober_timeout; 248259268Spfg 249259268Spfg if (hal_device_property_get_bool (d, "info.ignore")) { 250259268Spfg HAL_INFO (("Preprobing merged info.ignore==TRUE")); 251259268Spfg 252259268Spfg /* Leave device with info.ignore==TRUE so we won't pick up children */ 253259268Spfg hal_device_property_remove (d, "info.category"); 254259268Spfg hal_device_property_remove (d, "info.capabilities"); 255259268Spfg 256259268Spfg hal_device_store_remove (hald_get_tdl (), d); 257259268Spfg hal_device_store_add (hald_get_gdl (), d); 258259268Spfg 259259268Spfg hotplug_event_end (end_token); 260259268Spfg return; 261259268Spfg } 262259268Spfg 263259268Spfg if (handler != NULL && handler->get_prober != NULL) { 264259268Spfg prober = handler->get_prober (d, &prober_timeout); 265259268Spfg } else { 266259268Spfg prober = NULL; 267259268Spfg } 268259268Spfg 269259268Spfg if (handler->probing_done != NULL) { 270259268Spfg probing_done = handler->probing_done; 271259268Spfg } else { 272259268Spfg probing_done = devinfo_callouts_probing_done; 273259268Spfg } 274259268Spfg 275259268Spfg if (prober != NULL) { 276259268Spfg /* probe the device */ 277259268Spfg HAL_INFO(("Probing udi=%s", hal_device_get_udi (d))); 278259268Spfg hald_runner_run (d, 279169689Skan prober, NULL, 280 prober_timeout, 281 probing_done, 282 (gpointer) end_token, (gpointer) handler); 283 } else { 284 probing_done (d, 0, 0, NULL, userdata1, userdata2); 285 } 286} 287 288/* This is the beginning of hotplug even handling */ 289void 290hotplug_event_begin_add_devinfo (HalDevice *d, HalDevice *parent, DevinfoDevHandler *handler, void *end_token) 291{ 292 HAL_INFO(("Preprobing udi=%s", hal_device_get_udi (d))); 293 294 if (parent != NULL && hal_device_property_get_bool (parent, "info.ignore")) { 295 HAL_INFO (("Ignoring device since parent has info.ignore==TRUE")); 296 297 if (hal_device_store_find (hald_get_tdl (), hal_device_get_udi (d))) 298 hal_device_store_remove (hald_get_tdl (), d); 299 300 hotplug_event_end (end_token); 301 return; 302 } 303 304 if (hal_device_store_find (hald_get_tdl (), hal_device_get_udi (d)) == NULL) { 305 306 /* add to TDL so preprobing callouts and prober can access it */ 307 hal_device_store_add (hald_get_tdl (), d); 308 } 309 310 /* Process preprobe fdi files */ 311 di_search_and_merge (d, DEVICE_INFO_TYPE_PREPROBE); 312 313 /* Run preprobe callouts */ 314 hal_util_callout_device_preprobe (d, devinfo_callouts_preprobing_done, end_token, handler); 315} 316 317void 318devinfo_remove (gchar *devfs_path) 319{ 320 devinfo_remove_enqueue ((gchar *)devfs_path, NULL); 321} 322 323/* generate hotplug event for each device in this branch */ 324void 325devinfo_remove_branch (gchar *devfs_path, HalDevice *d) 326{ 327 GSList *i; 328 GSList *children; 329 HalDevice *child; 330 char *child_devfs_path; 331 332 if (d == NULL) { 333 d = hal_device_store_match_key_value_string (hald_get_gdl (), 334 "solaris.devfs_path", devfs_path); 335 if (d == NULL) 336 return; 337 } 338 339 HAL_INFO (("remove_branch: %s %s\n", devfs_path, hal_device_get_udi (d))); 340 341 /* first remove children */ 342 children = hal_device_store_match_multiple_key_value_string (hald_get_gdl(), 343 "info.parent", hal_device_get_udi (d)); 344 for (i = children; i != NULL; i = g_slist_next (i)) { 345 child = HAL_DEVICE (i->data); 346 HAL_INFO (("remove_branch: child %s\n", hal_device_get_udi (child))); 347 devinfo_remove_branch ((gchar *)hal_device_property_get_string (child, "solaris.devfs_path"), child); 348 } 349 g_slist_free (children); 350 HAL_INFO (("remove_branch: done with children")); 351 352 /* then remove self */ 353 HAL_INFO (("remove_branch: queueing %s", devfs_path)); 354 devinfo_remove_enqueue (devfs_path, NULL); 355} 356 357void 358devinfo_callouts_remove_done (HalDevice *d, gpointer userdata1, gpointer userdata2) 359{ 360 void *end_token = (void *) userdata1; 361 362 HAL_INFO (("Remove callouts completed udi=%s", hal_device_get_udi (d))); 363 364 if (!hal_device_store_remove (hald_get_gdl (), d)) { 365 HAL_WARNING (("Error removing device")); 366 } 367 g_object_unref (d); 368 369 hotplug_event_end (end_token); 370} 371 372void 373hotplug_event_begin_remove_devinfo (HalDevice *d, gchar *devfs_path, void *end_token) 374{ 375 if (hal_device_has_capability (d, "volume")) { 376 devinfo_volume_hotplug_begin_remove (d, devfs_path, end_token); 377 } else { 378 hal_util_callout_device_remove (d, devinfo_callouts_remove_done, end_token, NULL); 379 } 380} 381 382gboolean 383devinfo_device_rescan (HalDevice *d) 384{ 385 if (hal_device_has_capability (d, "block")) { 386 return (devinfo_storage_device_rescan (d)); 387 } else { 388 return (FALSE); 389 } 390} 391 392static int 393walk_devlinks(di_devlink_t devlink, void *arg) 394{ 395 char **path= (char **)arg; 396 397 *path = strdup(di_devlink_path(devlink)); 398 399 return (DI_WALK_TERMINATE); 400} 401 402char * 403get_devlink(di_devlink_handle_t devlink_hdl, char *re, char *path) 404{ 405 char *devlink_path = NULL; 406 407 (void) di_devlink_walk(devlink_hdl, re, path, 408 DI_PRIMARY_LINK, &devlink_path, walk_devlinks); 409 410 return (devlink_path); 411} 412 413