xref: /illumos-gate/usr/src/cmd/hal/hald/solaris/devinfo_usb.c (revision 8d483882aa3390058094b043f3d62187b5d1de03)
1 /***************************************************************************
2  *
3  * devinfo_usb.h : USB devices
4  *
5  * Copyright 2007 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 #include <sys/types.h>
22 #include <sys/mkdev.h>
23 #include <sys/stat.h>
24 
25 #include "../osspec.h"
26 #include "../logger.h"
27 #include "../hald.h"
28 #include "../hald_dbus.h"
29 #include "../device_info.h"
30 #include "../util.h"
31 #include "../ids.h"
32 #include "hotplug.h"
33 #include "devinfo.h"
34 #include "devinfo_usb.h"
35 
36 HalDevice *devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
37 static HalDevice *devinfo_usb_if_add(HalDevice *d, di_node_t node, gchar *devfs_path, int ifnum);
38 static HalDevice *devinfo_usb_scsa2usb_add(HalDevice *d, di_node_t node, gchar *devfs_path);
39 static HalDevice *devinfo_usb_printer_add(HalDevice *usbd, di_node_t node, gchar *devfs_path);
40 const gchar *devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout);
41 
42 DevinfoDevHandler devinfo_usb_handler = {
43         devinfo_usb_add,
44 	NULL,
45 	NULL,
46 	NULL,
47 	NULL,
48         NULL
49 };
50 
51 DevinfoDevHandler devinfo_usb_printer_handler = {
52         devinfo_usb_add,
53 	NULL,
54 	NULL,
55 	NULL,
56 	NULL,
57         devinfo_printer_prnio_get_prober
58 };
59 
60 static gboolean
61 is_usb_node(di_node_t node)
62 {
63 	int rc;
64 	char *s;
65 
66 	/*
67 	 * USB device nodes will have "compatible" propety values that
68 	 * begins with "usb".
69 	 */
70         rc = di_prop_lookup_strings(DDI_DEV_T_ANY, node, "compatible", &s);
71 	while (rc-- > 0) {
72 		if (strncmp(s, "usb", 3) == 0) {
73 			return (TRUE);
74 		}
75 		s += (strlen(s) + 1);
76 	}
77 
78 	return (FALSE);
79 }
80 
81 HalDevice *
82 devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
83 {
84 	HalDevice *d, *nd = NULL;
85 	char	*s;
86 	int	*i;
87 	char	*driver_name, *binding_name;
88         char    if_devfs_path[HAL_PATH_MAX];
89 
90         if (is_usb_node(node) == FALSE) {
91 		return (NULL);
92 	}
93 
94 	d = hal_device_new ();
95 
96 	devinfo_set_default_properties (d, parent, node, devfs_path);
97 	hal_device_property_set_string (d, "info.bus", "usb_device");
98 	PROP_STR(d, node, s, "usb-product-name", "info.product");
99 	PROP_STR(d, node, s, "usb-product-name", "usb_device.product");
100 	PROP_STR(d, node, s, "usb-vendor-name", "usb_device.vendor");
101 	PROP_INT(d, node, i, "usb-vendor-id", "usb_device.vendor_id");
102 	PROP_INT(d, node, i, "usb-product-id", "usb_device.product_id");
103 	PROP_INT(d, node, i, "usb-revision-id", "usb_device.device_revision_bcd");
104 	PROP_INT(d, node, i, "usb-release-id", "usb_device.version_bcd");
105 	PROP_STR(d, node, s, "usb-serialno", "usb_device.serial");
106 
107 	/* class, subclass */
108 	/* hal_device_property_set_int (d, "usb_device.device_class", 8); */
109 
110 	/* binding name tells us if driver is bound to interface or device */
111 	if (((binding_name = di_binding_name(node)) != NULL) &&
112 	    (strncmp(binding_name, "usbif,", sizeof ("usbif,") - 1) == 0)) {
113 		snprintf(if_devfs_path, sizeof (if_devfs_path), "%s:if%d", devfs_path, 0);
114 		if ((nd = devinfo_usb_if_add(d, node, if_devfs_path, 0)) != NULL) {
115 			d = nd;
116 			nd = NULL;
117 			devfs_path = if_devfs_path;
118 		}
119 	}
120 
121 	/* driver specific */
122 	driver_name = di_driver_name (node);
123 	if ((driver_name != NULL) && (strcmp (driver_name, "scsa2usb") == 0)) {
124 		nd = devinfo_usb_scsa2usb_add (d, node, devfs_path);
125 	} else if ((driver_name != NULL) &&
126 		    (strcmp (driver_name, "usbprn") == 0)) {
127 		nd = devinfo_usb_printer_add (d, node, devfs_path);
128 	} else {
129 		devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler);
130 	}
131 
132 out:
133 	if (nd != NULL) {
134 		return (nd);
135 	} else {
136 		return (d);
137 	}
138 }
139 
140 static HalDevice *
141 devinfo_usb_if_add(HalDevice *parent, di_node_t node, gchar *devfs_path, int ifnum)
142 {
143 	HalDevice *d = NULL;
144         char    udi[HAL_PATH_MAX];
145 
146 	devinfo_add_enqueue (parent, devfs_path, &devinfo_usb_handler);
147 
148 	d = hal_device_new ();
149 
150 	devinfo_set_default_properties (d, parent, node, devfs_path);
151         hal_device_property_set_string (d, "info.bus", "usb");
152         hal_device_property_set_string (d, "info.product", "USB Device Interface");
153 
154 	/* copy parent's usb_device.* properties */
155 	hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
156 
157 	return (d);
158 }
159 
160 
161 static void
162 get_dev_link_path(di_node_t node, char *nodetype, char *re, char **devlink, char **minor_path)
163 {
164 	di_devlink_handle_t devlink_hdl;
165         int     major;
166         di_minor_t minor;
167         dev_t   devt;
168 
169 	*devlink = NULL;
170         *minor_path = NULL;
171 
172         if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
173                 printf("di_devlink_init() failed\n");
174                 return;
175         }
176 
177         major = di_driver_major(node);
178         minor = DI_MINOR_NIL;
179         while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
180                 devt = di_minor_devt(minor);
181                 if (major != major(devt)) {
182                         continue;
183                 }
184 
185                 if (di_minor_type(minor) != DDM_MINOR) {
186                         continue;
187                 }
188 
189                 if ((*minor_path = di_devfs_minor_path(minor)) == NULL) {
190                         continue;
191                 }
192 
193 		if ((strcmp (di_minor_nodetype(minor), nodetype) == 0) &&
194 		    ((*devlink = get_devlink(devlink_hdl, re, *minor_path)) != NULL)) {
195 			break;
196 		}
197 		di_devfs_path_free (*minor_path);
198 		*minor_path = NULL;
199 	}
200 	di_devlink_fini (&devlink_hdl);
201 }
202 
203 static HalDevice *
204 devinfo_usb_scsa2usb_add(HalDevice *usbd, di_node_t node, gchar *devfs_path)
205 {
206 	HalDevice *d = NULL;
207 	di_devlink_handle_t devlink_hdl;
208         int     major;
209         di_minor_t minor;
210         dev_t   devt;
211         char    *minor_path = NULL;
212 	char	*devlink = NULL;
213         char    udi[HAL_PATH_MAX];
214 
215 	devinfo_add_enqueue (usbd, devfs_path, &devinfo_usb_handler);
216 
217 	get_dev_link_path(node, "ddi_ctl:devctl:scsi", NULL,  &devlink, &minor_path);
218 
219 	if ((devlink == NULL) || (minor_path == NULL)) {
220 		goto out;
221 	}
222 
223 	d = hal_device_new ();
224 
225 	devinfo_set_default_properties (d, usbd, node, minor_path);
226        	hal_device_property_set_string (d, "scsi_host.solaris.device", devlink);
227         hal_device_property_set_string (d, "info.category", "scsi_host");
228         hal_device_property_set_int (d, "scsi_host.host", 0);
229 
230         hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
231 		"%s/scsi_host%d", hal_device_get_udi (usbd),
232 		hal_device_property_get_int (d, "scsi_host.host"));
233         hal_device_set_udi (d, udi);
234         hal_device_property_set_string (d, "info.udi", udi);
235         hal_device_property_set_string (d, "info.product", "SCSI Host Adapter");
236 
237 	devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler);
238 
239 out:
240 	if (devlink) {
241 		free(devlink);
242 	}
243 	if (minor_path) {
244 		di_devfs_path_free (minor_path);
245 	}
246 
247 	return (d);
248 }
249 
250 static HalDevice *
251 devinfo_usb_printer_add(HalDevice *parent, di_node_t node, gchar *devfs_path)
252 {
253 	HalDevice *d = NULL;
254         char    udi[HAL_PATH_MAX];
255 	char *s;
256 	char *devlink = NULL, *minor_path = NULL;
257 
258 	devinfo_add_enqueue (parent, devfs_path, &devinfo_usb_handler);
259 
260 	get_dev_link_path(node, "ddi_printer", "printers/.+", &devlink, &minor_path);
261 
262 	if ((devlink == NULL) || (minor_path == NULL)) {
263 		goto out;
264 	}
265 
266 	d = hal_device_new ();
267 
268 	devinfo_set_default_properties (d, parent, node, minor_path);
269         hal_device_property_set_string (d, "info.category", "printer");
270 	hal_device_add_capability (d, "printer");
271 
272 	/* copy parent's usb_device.* properties */
273 	hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
274 
275 	/* add printer properties */
276         hal_device_property_set_string (d, "printer.device", devlink);
277 	PROP_STR(d, node, s, "usb-vendor-name", "printer.vendor");
278 	PROP_STR(d, node, s, "usb-product-name", "printer.product");
279 	PROP_STR(d, node, s, "usb-serialno", "printer.serial");
280 
281 	devinfo_add_enqueue (d, minor_path, &devinfo_usb_printer_handler);
282 
283 out:
284 	if (devlink) {
285 		free(devlink);
286 	}
287 	if (minor_path) {
288 		di_devfs_path_free (minor_path);
289 	}
290 
291 	return (d);
292 }
293 
294 const gchar *
295 devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout)
296 {
297 	*timeout = 5 * 1000;	/* 5 second timeout */
298 	return ("hald-probe-printer");
299 }
300