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