1 /***************************************************************************
3 * devinfo.c : main file for libdevinfo-based device enumeration
5 * Copyright 2013 Garrett D'Amore <garrett@damore.org>
6 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
8 * Licensed under the Academic Free License version 2.1
10 **************************************************************************/
18 #include <libdevinfo.h>
20 #include "../osspec.h"
21 #include "../logger.h"
23 #include "../hald_dbus.h"
24 #include "../device_info.h"
26 #include "../hald_runner.h"
27 #include "osspec_solaris.h"
30 #include "devinfo_pci.h"
31 #include "devinfo_storage.h"
32 #include "devinfo_ieee1394.h"
33 #include "devinfo_usb.h"
34 #include "devinfo_misc.h"
35 #include "devinfo_acpi.h"
36 #include "devinfo_cpu.h"
38 void devinfo_add_subtree(HalDevice
*parent
, di_node_t node
, gboolean is_root
);
39 HalDevice
*devinfo_add_node(HalDevice
*parent
, di_node_t node
);
42 devinfo_add(HalDevice
*parent
, gchar
*path
)
46 if (strcmp (path
, "/") == 0) {
47 if ((root
= di_init(path
, DINFOCACHE
)) == DI_NODE_NIL
) {
48 HAL_INFO (("di_init() failed %d", errno
));
52 if ((root
= di_init(path
, DINFOCPYALL
)) == DI_NODE_NIL
) {
53 HAL_INFO (("di_init() failed %d", errno
));
58 devinfo_add_subtree(parent
, root
, TRUE
);
64 devinfo_add_subtree(HalDevice
*parent
, di_node_t node
, gboolean is_root
)
67 di_node_t root_node
, child_node
;
69 HAL_INFO (("add_subtree: %s", di_node_name (node
)));
73 d
= devinfo_add_node (parent
, node
);
76 (child_node
= di_child_node (node
)) != DI_NODE_NIL
) {
77 devinfo_add_subtree (d
, child_node
, FALSE
);
80 node
= di_sibling_node (node
);
81 } while ((node
!= DI_NODE_NIL
) &&
82 (!is_root
|| di_parent_node (node
) == root_node
));
86 devinfo_set_default_properties (HalDevice
*d
, HalDevice
*parent
, di_node_t node
, char *devfs_path
)
88 char *driver_name
, *s
;
90 char udi
[HAL_PATH_MAX
];
93 hal_device_property_set_string (d
, "info.parent", hal_device_get_udi (parent
));
95 hal_device_property_set_string (d
, "info.parent", "/org/freedesktop/Hal/devices/local");
98 hal_util_compute_udi (hald_get_gdl (), udi
, sizeof (udi
),
99 "/org/freedesktop/Hal/devices%s_%d",
102 hal_device_set_udi (d
, udi
);
103 hal_device_property_set_string (d
, "info.udi", udi
);
105 if (di_prop_lookup_strings (DDI_DEV_T_ANY
, node
, "model", &s
) > 0) {
106 hal_device_property_set_string (d
, "info.product", s
);
108 hal_device_property_set_string (d
, "info.product", di_node_name (node
));
111 hal_device_property_set_string (d
, "solaris.devfs_path", devfs_path
);
113 if ((driver_name
= di_driver_name (node
)) != NULL
) {
114 hal_device_property_set_string (d
, "info.solaris.driver",
119 /* inherit parent's claim attributes */
120 if (hal_device_property_get_bool (parent
, "info.claimed")) {
121 s1
= hal_device_property_get_string (parent
, "info.claimed.service");
123 hal_device_property_set_bool (d
, "info.claimed", TRUE
);
124 hal_device_property_set_string (d
, "info.claimed.service", s1
);
129 /* device handlers, ordered specific to generic */
130 static DevinfoDevHandler
*devinfo_handlers
[] = {
131 &devinfo_computer_handler
,
132 &devinfo_cpu_handler
,
133 &devinfo_ide_handler
,
134 &devinfo_scsi_handler
,
135 &devinfo_blkdev_handler
,
136 &devinfo_floppy_handler
,
137 &devinfo_usb_handler
,
138 &devinfo_ieee1394_handler
,
139 &devinfo_lofi_handler
,
140 &devinfo_acpi_handler
,
141 &devinfo_power_button_handler
,
142 &devinfo_keyboard_handler
,
143 &devinfo_mouse_handler
,
144 &devinfo_pci_handler
,
145 &devinfo_default_handler
,
150 devinfo_add_node(HalDevice
*parent
, di_node_t node
)
154 char *device_type
= NULL
;
155 DevinfoDevHandler
*handler
;
158 devfs_path
= di_devfs_path (node
);
160 (void) di_prop_lookup_strings (DDI_DEV_T_ANY
, node
, "device_type",
163 for (i
= 0; (d
== NULL
) && (devinfo_handlers
[i
] != NULL
); i
++) {
164 handler
= devinfo_handlers
[i
];
165 d
= handler
->add (parent
, node
, devfs_path
, device_type
);
168 di_devfs_path_free(devfs_path
);
170 HAL_INFO (("add_node: %s", d
? hal_device_get_udi (d
) : "none"));
175 devinfo_hotplug_enqueue(HalDevice
*d
, gchar
*devfs_path
, DevinfoDevHandler
*handler
, int action
, int front
)
177 HotplugEvent
*hotplug_event
;
179 hotplug_event
= g_new0 (HotplugEvent
, 1);
180 hotplug_event
->action
= action
;
181 hotplug_event
->type
= HOTPLUG_EVENT_DEVFS
;
182 hotplug_event
->d
= d
;
183 strlcpy (hotplug_event
->un
.devfs
.devfs_path
, devfs_path
,
184 sizeof (hotplug_event
->un
.devfs
.devfs_path
));
185 hotplug_event
->un
.devfs
.handler
= handler
;
187 hotplug_event_enqueue (hotplug_event
, front
);
191 devinfo_add_enqueue(HalDevice
*d
, gchar
*devfs_path
, DevinfoDevHandler
*handler
)
193 devinfo_hotplug_enqueue (d
, devfs_path
, handler
, HOTPLUG_ACTION_ADD
, 0);
197 devinfo_add_enqueue_at_front(HalDevice
*d
, gchar
*devfs_path
, DevinfoDevHandler
*handler
)
199 devinfo_hotplug_enqueue (d
, devfs_path
, handler
, HOTPLUG_ACTION_ADD
, 1);
203 devinfo_remove_enqueue(gchar
*devfs_path
, DevinfoDevHandler
*handler
)
205 devinfo_hotplug_enqueue (NULL
, devfs_path
, handler
, HOTPLUG_ACTION_REMOVE
, 0);
209 devinfo_callouts_add_done (HalDevice
*d
, gpointer userdata1
, gpointer userdata2
)
211 void *end_token
= (void *) userdata1
;
213 /* Move from temporary to global device store */
214 hal_device_store_remove (hald_get_tdl (), d
);
215 hal_device_store_add (hald_get_gdl (), d
);
217 hotplug_event_end (end_token
);
221 devinfo_callouts_probing_done (HalDevice
*d
, guint32 exit_type
, gint return_code
, char **error
, gpointer userdata1
, gpointer userdata2
)
223 void *end_token
= (void *) userdata1
;
225 /* Discard device if probing reports failure */
226 if (exit_type
!= HALD_RUN_SUCCESS
|| (return_code
!= 0)) {
227 HAL_INFO (("Probing for %s failed %d", hal_device_get_udi (d
), return_code
));
228 hal_device_store_remove (hald_get_tdl (), d
);
230 hotplug_event_end (end_token
);
234 /* Merge properties from .fdi files */
235 di_search_and_merge (d
, DEVICE_INFO_TYPE_INFORMATION
);
236 di_search_and_merge (d
, DEVICE_INFO_TYPE_POLICY
);
238 hal_util_callout_device_add (d
, devinfo_callouts_add_done
, end_token
, NULL
);
242 devinfo_callouts_preprobing_done (HalDevice
*d
, gpointer userdata1
, gpointer userdata2
)
244 void *end_token
= (void *) userdata1
;
245 DevinfoDevHandler
*handler
= (DevinfoDevHandler
*) userdata2
;
246 void (*probing_done
) (HalDevice
*, guint32
, gint
, char **, gpointer
, gpointer
);
250 if (hal_device_property_get_bool (d
, "info.ignore")) {
251 HAL_INFO (("Preprobing merged info.ignore==TRUE"));
253 /* Leave device with info.ignore==TRUE so we won't pick up children */
254 hal_device_property_remove (d
, "info.category");
255 hal_device_property_remove (d
, "info.capabilities");
257 hal_device_store_remove (hald_get_tdl (), d
);
258 hal_device_store_add (hald_get_gdl (), d
);
260 hotplug_event_end (end_token
);
264 if (handler
!= NULL
&& handler
->get_prober
!= NULL
) {
265 prober
= handler
->get_prober (d
, &prober_timeout
);
270 if (handler
->probing_done
!= NULL
) {
271 probing_done
= handler
->probing_done
;
273 probing_done
= devinfo_callouts_probing_done
;
276 if (prober
!= NULL
) {
277 /* probe the device */
278 HAL_INFO(("Probing udi=%s", hal_device_get_udi (d
)));
283 (gpointer
) end_token
, (gpointer
) handler
);
285 probing_done (d
, 0, 0, NULL
, userdata1
, userdata2
);
289 /* This is the beginning of hotplug even handling */
291 hotplug_event_begin_add_devinfo (HalDevice
*d
, HalDevice
*parent
, DevinfoDevHandler
*handler
, void *end_token
)
293 HotplugEvent
*hotplug_event
= (HotplugEvent
*)end_token
;
295 HAL_INFO(("Preprobing udi=%s", hal_device_get_udi (d
)));
297 if (parent
== NULL
&& (strcmp(hotplug_event
->un
.devfs
.devfs_path
, "/") != 0)) {
298 HAL_ERROR (("Parent is NULL, devfs_path=%s", hotplug_event
->un
.devfs
.devfs_path
));
304 if (parent
!= NULL
&& hal_device_property_get_bool (parent
, "info.ignore")) {
305 HAL_INFO (("Ignoring device since parent has info.ignore==TRUE"));
310 if (hal_device_store_find (hald_get_tdl (), hal_device_get_udi (d
)) == NULL
) {
312 /* add to TDL so preprobing callouts and prober can access it */
313 hal_device_store_add (hald_get_tdl (), d
);
316 /* Process preprobe fdi files */
317 di_search_and_merge (d
, DEVICE_INFO_TYPE_PREPROBE
);
319 /* Run preprobe callouts */
320 hal_util_callout_device_preprobe (d
, devinfo_callouts_preprobing_done
, end_token
, handler
);
325 if (hal_device_store_find (hald_get_tdl (), hal_device_get_udi (d
)))
326 hal_device_store_remove (hald_get_tdl (), d
);
329 hotplug_event_end (end_token
);
335 devinfo_remove (gchar
*devfs_path
)
337 devinfo_remove_enqueue ((gchar
*)devfs_path
, NULL
);
340 /* generate hotplug event for each device in this branch */
342 devinfo_remove_branch (gchar
*devfs_path
, HalDevice
*d
)
347 char *child_devfs_path
;
350 d
= hal_device_store_match_key_value_string (hald_get_gdl (),
351 "solaris.devfs_path", devfs_path
);
356 HAL_INFO (("remove_branch: %s %s\n", devfs_path
, hal_device_get_udi (d
)));
358 /* first remove children */
359 children
= hal_device_store_match_multiple_key_value_string (hald_get_gdl(),
360 "info.parent", hal_device_get_udi (d
));
361 for (i
= children
; i
!= NULL
; i
= g_slist_next (i
)) {
362 child
= HAL_DEVICE (i
->data
);
363 HAL_INFO (("remove_branch: child %s\n", hal_device_get_udi (child
)));
364 devinfo_remove_branch ((gchar
*)hal_device_property_get_string (child
, "solaris.devfs_path"), child
);
366 g_slist_free (children
);
367 HAL_INFO (("remove_branch: done with children"));
369 /* then remove self */
370 HAL_INFO (("remove_branch: queueing %s", devfs_path
));
371 devinfo_remove_enqueue (devfs_path
, NULL
);
375 devinfo_callouts_remove_done (HalDevice
*d
, gpointer userdata1
, gpointer userdata2
)
377 void *end_token
= (void *) userdata1
;
379 HAL_INFO (("Remove callouts completed udi=%s", hal_device_get_udi (d
)));
381 if (!hal_device_store_remove (hald_get_gdl (), d
)) {
382 HAL_WARNING (("Error removing device"));
386 hotplug_event_end (end_token
);
390 hotplug_event_begin_remove_devinfo (HalDevice
*d
, gchar
*devfs_path
, void *end_token
)
392 if (hal_device_has_capability (d
, "volume")) {
393 devinfo_volume_hotplug_begin_remove (d
, devfs_path
, end_token
);
395 hal_util_callout_device_remove (d
, devinfo_callouts_remove_done
, end_token
, NULL
);
400 devinfo_device_rescan (HalDevice
*d
)
402 if (hal_device_has_capability (d
, "block")) {
403 return (devinfo_storage_device_rescan (d
));
404 } else if (hal_device_has_capability (d
, "button")) {
405 return (devinfo_lid_rescan (d
));
412 walk_devlinks(di_devlink_t devlink
, void *arg
)
414 char **path
= (char **)arg
;
416 *path
= strdup(di_devlink_path(devlink
));
418 return (DI_WALK_TERMINATE
);
422 get_devlink(di_devlink_handle_t devlink_hdl
, char *re
, char *path
)
424 char *devlink_path
= NULL
;
426 (void) di_devlink_walk(devlink_hdl
, re
, path
,
427 DI_PRIMARY_LINK
, &devlink_path
, walk_devlinks
);
429 return (devlink_path
);