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 HalDevice *
61 devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
62 {
63 	HalDevice *d, *nd = NULL;
64 	char	*s;
65 	int	*i, *vid;
66 	char	*driver_name, *binding_name;
67         char    if_devfs_path[HAL_PATH_MAX];
68 
69 	/*
70 	 * we distinguish USB devices by presence of "usb-vendor-id"
71 	 * property. should USB devices have "device_type"?
72 	 */
73         if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "usb-vendor-id", &vid) <= 0) {
74 		return (NULL);
75 	}
76 
77 	d = hal_device_new ();
78 
79 	devinfo_set_default_properties (d, parent, node, devfs_path);
80 	hal_device_property_set_string (d, "info.bus", "usb_device");
81 	PROP_STR(d, node, s, "usb-product-name", "info.product");
82 	PROP_STR(d, node, s, "usb-product-name", "usb_device.product");
83 	PROP_STR(d, node, s, "usb-vendor-name", "usb_device.vendor");
84 	PROP_INT(d, node, i, "usb-vendor-id", "usb_device.vendor_id");
85 	PROP_INT(d, node, i, "usb-product-id", "usb_device.product_id");
86 	PROP_INT(d, node, i, "usb-revision-id", "usb_device.device_revision_bcd");
87 	PROP_INT(d, node, i, "usb-release-id", "usb_device.version_bcd");
88 	PROP_STR(d, node, s, "usb-serialno", "usb_device.serial");
89 
90 	/* class, subclass */
91 	/* hal_device_property_set_int (d, "usb_device.device_class", 8); */
92 
93 	/* binding name tells us if driver is bound to interface or device */
94 	if (((binding_name = di_binding_name(node)) != NULL) &&
95 	    (strncmp(binding_name, "usbif,", sizeof ("usbif,") - 1) == 0)) {
96 		snprintf(if_devfs_path, sizeof (if_devfs_path), "%s:if%d", devfs_path, 0);
97 		if ((nd = devinfo_usb_if_add(d, node, if_devfs_path, 0)) != NULL) {
98 			d = nd;
99 			nd = NULL;
100 			devfs_path = if_devfs_path;
101 		}
102 	}
103 
104 	/* driver specific */
105 	driver_name = di_driver_name (node);
106 	if ((driver_name != NULL) && (strcmp (driver_name, "scsa2usb") == 0)) {
107 		nd = devinfo_usb_scsa2usb_add (d, node, devfs_path);
108 	} else if ((driver_name != NULL) &&
109 		   (strcmp (driver_name, "usbprn") == 0)) {
110 		nd = devinfo_usb_printer_add (d, node, devfs_path);
111 	} else {
112 		devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler);
113 	}
114 
115 out:
116 	if (nd != NULL) {
117 		return (nd);
118 	} else {
119 		return (d);
120 	}
121 }
122 
123 static HalDevice *
124 devinfo_usb_if_add(HalDevice *parent, di_node_t node, gchar *devfs_path, int ifnum)
125 {
126 	HalDevice *d = NULL;
127         char    udi[HAL_PATH_MAX];
128 
129 	devinfo_add_enqueue (parent, devfs_path, &devinfo_usb_handler);
130 
131 	d = hal_device_new ();
132 
133 	devinfo_set_default_properties (d, parent, node, devfs_path);
134         hal_device_property_set_string (d, "info.bus", "usb");
135         hal_device_property_set_string (d, "info.product", "USB Device Interface");
136 
137 	/* copy parent's usb_device.* properties */
138 	hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
139 
140 	return (d);
141 }
142 
143 
144 static void
145 get_dev_link_path(di_node_t node, char *nodetype, char *re, char **devlink, char **minor_path)
146 {
147 	di_devlink_handle_t devlink_hdl;
148         int     major;
149         di_minor_t minor;
150         dev_t   devt;
151 
152 	*devlink = NULL;
153         *minor_path = NULL;
154 
155         if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
156                 printf("di_devlink_init() failed\n");
157                 return;
158         }
159 
160         major = di_driver_major(node);
161         minor = DI_MINOR_NIL;
162         while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
163                 devt = di_minor_devt(minor);
164                 if (major != major(devt)) {
165                         continue;
166                 }
167 
168                 if (di_minor_type(minor) != DDM_MINOR) {
169                         continue;
170                 }
171 
172                 if ((*minor_path = di_devfs_minor_path(minor)) == NULL) {
173                         continue;
174                 }
175 
176 		if ((strcmp (di_minor_nodetype(minor), nodetype) == 0) &&
177 		    ((*devlink = get_devlink(devlink_hdl, re, *minor_path)) != NULL)) {
178 			break;
179 		}
180 		di_devfs_path_free (*minor_path);
181 		minor_path = NULL;
182 	}
183 	di_devlink_fini (&devlink_hdl);
184 }
185 
186 static HalDevice *
187 devinfo_usb_scsa2usb_add(HalDevice *usbd, di_node_t node, gchar *devfs_path)
188 {
189 	HalDevice *d = NULL;
190 	di_devlink_handle_t devlink_hdl;
191         int     major;
192         di_minor_t minor;
193         dev_t   devt;
194         char    *minor_path = NULL;
195 	char	*devlink = NULL;
196         char    udi[HAL_PATH_MAX];
197 
198 	devinfo_add_enqueue (usbd, devfs_path, &devinfo_usb_handler);
199 
200 	get_dev_link_path(node, "ddi_ctl:devctl:scsi", NULL,  &devlink, &minor_path);
201 
202 	if ((devlink == NULL) || (minor_path == NULL)) {
203 		goto out;
204 	}
205 
206 	d = hal_device_new ();
207 
208 	devinfo_set_default_properties (d, usbd, node, minor_path);
209        	hal_device_property_set_string (d, "scsi_host.solaris.device", devlink);
210         hal_device_property_set_string (d, "info.category", "scsi_host");
211         hal_device_property_set_int (d, "scsi_host.host", 0);
212 
213         hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
214 		"%s/scsi_host%d", hal_device_get_udi (usbd),
215 		hal_device_property_get_int (d, "scsi_host.host"));
216         hal_device_set_udi (d, udi);
217         hal_device_property_set_string (d, "info.udi", udi);
218         hal_device_property_set_string (d, "info.product", "SCSI Host Adapter");
219 
220 	devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler);
221 
222 out:
223 	if (devlink) {
224 		free(devlink);
225 	}
226 	if (minor_path) {
227 		di_devfs_path_free (minor_path);
228 	}
229 
230 	return (d);
231 }
232 
233 static HalDevice *
234 devinfo_usb_printer_add(HalDevice *parent, di_node_t node, gchar *devfs_path)
235 {
236 	HalDevice *d = NULL;
237         char    udi[HAL_PATH_MAX];
238 	char *s;
239 	char *devlink = NULL, *minor_path = NULL;
240 
241 	devinfo_add_enqueue (parent, devfs_path, &devinfo_usb_handler);
242 
243 	get_dev_link_path(node, "ddi_printer", "printers/.+", &devlink, &minor_path);
244 
245 	if ((devlink == NULL) || (minor_path == NULL)) {
246 		goto out;
247 	}
248 
249 	d = hal_device_new ();
250 
251 	devinfo_set_default_properties (d, parent, node, minor_path);
252         hal_device_property_set_string (d, "info.category", "printer");
253 	hal_device_add_capability (d, "printer");
254 
255 	/* copy parent's usb_device.* properties */
256 	hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
257 
258 	/* add printer properties */
259         hal_device_property_set_string (d, "printer.device", devlink);
260 	PROP_STR(d, node, s, "usb-vendor-name", "printer.vendor");
261 	PROP_STR(d, node, s, "usb-product-name", "printer.product");
262 	PROP_STR(d, node, s, "usb-serialno", "printer.serial");
263 
264 	devinfo_add_enqueue (d, minor_path, &devinfo_usb_printer_handler);
265 
266 out:
267 	if (devlink) {
268 		free(devlink);
269 	}
270 	if (minor_path) {
271 		di_devfs_path_free (minor_path);
272 	}
273 
274 	return (d);
275 }
276 
277 const gchar *
278 devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout)
279 {
280 	*timeout = 5 * 1000;	/* 5 second timeout */
281 	return ("hald-probe-printer");
282 }
283