1*2912Sartem /***************************************************************************
2*2912Sartem  *
3*2912Sartem  * devinfo_usb.h : USB devices
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 #include <sys/types.h>
18*2912Sartem #include <sys/mkdev.h>
19*2912Sartem #include <sys/stat.h>
20*2912Sartem 
21*2912Sartem #include "../osspec.h"
22*2912Sartem #include "../logger.h"
23*2912Sartem #include "../hald.h"
24*2912Sartem #include "../hald_dbus.h"
25*2912Sartem #include "../device_info.h"
26*2912Sartem #include "../util.h"
27*2912Sartem #include "../ids.h"
28*2912Sartem #include "hotplug.h"
29*2912Sartem #include "devinfo.h"
30*2912Sartem #include "devinfo_usb.h"
31*2912Sartem 
32*2912Sartem HalDevice *devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
33*2912Sartem static HalDevice *devinfo_usb_if_add(HalDevice *d, di_node_t node, gchar *devfs_path, int ifnum);
34*2912Sartem static HalDevice *devinfo_usb_scsa2usb_add(HalDevice *d, di_node_t node, gchar *devfs_path);
35*2912Sartem 
36*2912Sartem DevinfoDevHandler devinfo_usb_handler = {
37*2912Sartem         devinfo_usb_add,
38*2912Sartem 	NULL,
39*2912Sartem 	NULL,
40*2912Sartem 	NULL,
41*2912Sartem 	NULL,
42*2912Sartem         NULL
43*2912Sartem };
44*2912Sartem 
45*2912Sartem HalDevice *
46*2912Sartem devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
47*2912Sartem {
48*2912Sartem 	HalDevice *d, *nd = NULL;
49*2912Sartem 	char	*s;
50*2912Sartem 	int	*i, *vid;
51*2912Sartem 	char	*driver_name, *binding_name;
52*2912Sartem         char    if_devfs_path[HAL_PATH_MAX];
53*2912Sartem 
54*2912Sartem 	/*
55*2912Sartem 	 * we distinguish USB devices by presence of "usb-vendor-id"
56*2912Sartem 	 * property. should USB devices have "device_type"?
57*2912Sartem 	 */
58*2912Sartem         if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "usb-vendor-id", &vid) <= 0) {
59*2912Sartem 		return (NULL);
60*2912Sartem 	}
61*2912Sartem 
62*2912Sartem 	d = hal_device_new ();
63*2912Sartem 
64*2912Sartem 	devinfo_set_default_properties (d, parent, node, devfs_path);
65*2912Sartem 	hal_device_property_set_string (d, "info.bus", "usb_device");
66*2912Sartem 	PROP_STR(d, node, s, "usb-product-name", "info.product");
67*2912Sartem 	PROP_STR(d, node, s, "usb-product-name", "usb_device.product");
68*2912Sartem 	PROP_STR(d, node, s, "usb-vendor-name", "usb_device.vendor");
69*2912Sartem 	PROP_INT(d, node, i, "usb-vendor-id", "usb_device.vendor_id");
70*2912Sartem 	PROP_INT(d, node, i, "usb-product-id", "usb_device.product_id");
71*2912Sartem 	PROP_INT(d, node, i, "usb-revision-id", "usb_device.device_revision_bcd");
72*2912Sartem 	PROP_INT(d, node, i, "usb-release-id", "usb_device.version_bcd");
73*2912Sartem 	PROP_STR(d, node, s, "usb-serialno", "usb_device.serial");
74*2912Sartem 
75*2912Sartem 	/* class, subclass */
76*2912Sartem 	/* hal_device_property_set_int (d, "usb_device.device_class", 8); */
77*2912Sartem 
78*2912Sartem 	/* binding name tells us if driver is bound to interface or device */
79*2912Sartem 	if (((binding_name = di_binding_name(node)) != NULL) &&
80*2912Sartem 	    (strncmp(binding_name, "usbif,", sizeof ("usbif,") - 1) == 0)) {
81*2912Sartem 		snprintf(if_devfs_path, sizeof (if_devfs_path), "%s:if%d", devfs_path, 0);
82*2912Sartem 		if ((nd = devinfo_usb_if_add(d, node, if_devfs_path, 0)) != NULL) {
83*2912Sartem 			d = nd;
84*2912Sartem 			nd = NULL;
85*2912Sartem 			devfs_path = if_devfs_path;
86*2912Sartem 		}
87*2912Sartem 	}
88*2912Sartem 
89*2912Sartem 	/* driver specific */
90*2912Sartem 	driver_name = di_driver_name (node);
91*2912Sartem 	if ((driver_name != NULL) && (strcmp (driver_name, "scsa2usb") == 0)) {
92*2912Sartem 		nd = devinfo_usb_scsa2usb_add (d, node, devfs_path);
93*2912Sartem 	} else {
94*2912Sartem 		devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler);
95*2912Sartem 	}
96*2912Sartem 
97*2912Sartem out:
98*2912Sartem 	if (nd != NULL) {
99*2912Sartem 		return (nd);
100*2912Sartem 	} else {
101*2912Sartem 		return (d);
102*2912Sartem 	}
103*2912Sartem }
104*2912Sartem 
105*2912Sartem static HalDevice *
106*2912Sartem devinfo_usb_if_add(HalDevice *parent, di_node_t node, gchar *devfs_path, int ifnum)
107*2912Sartem {
108*2912Sartem 	HalDevice *d = NULL;
109*2912Sartem         char    udi[HAL_PATH_MAX];
110*2912Sartem 
111*2912Sartem 	devinfo_add_enqueue (parent, devfs_path, &devinfo_usb_handler);
112*2912Sartem 
113*2912Sartem 	d = hal_device_new ();
114*2912Sartem 
115*2912Sartem 	devinfo_set_default_properties (d, parent, node, devfs_path);
116*2912Sartem         hal_device_property_set_string (d, "info.bus", "usb");
117*2912Sartem 
118*2912Sartem         hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
119*2912Sartem 		"%s_if%d", parent->udi, ifnum);
120*2912Sartem         hal_device_set_udi (d, udi);
121*2912Sartem         hal_device_property_set_string (d, "info.udi", udi);
122*2912Sartem         hal_device_property_set_string (d, "info.product", "USB Device Interface");
123*2912Sartem 
124*2912Sartem 	/* copy parent's usb_device.* properties */
125*2912Sartem 	hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
126*2912Sartem 
127*2912Sartem 	return (d);
128*2912Sartem }
129*2912Sartem 
130*2912Sartem static int
131*2912Sartem walk_devlinks(di_devlink_t devlink, void *arg)
132*2912Sartem {
133*2912Sartem         char **path = (char **)arg;
134*2912Sartem 
135*2912Sartem         *path = strdup(di_devlink_path(devlink));
136*2912Sartem 
137*2912Sartem         return (DI_WALK_TERMINATE);
138*2912Sartem }
139*2912Sartem 
140*2912Sartem static char *
141*2912Sartem get_devlink(di_devlink_handle_t devlink_hdl, char *path)
142*2912Sartem {
143*2912Sartem 	char *devlink = NULL;
144*2912Sartem 
145*2912Sartem         (void) di_devlink_walk(devlink_hdl, NULL, path,
146*2912Sartem             DI_PRIMARY_LINK, &devlink, walk_devlinks);
147*2912Sartem 
148*2912Sartem         return (devlink);
149*2912Sartem }
150*2912Sartem 
151*2912Sartem static HalDevice *
152*2912Sartem devinfo_usb_scsa2usb_add(HalDevice *usbd, di_node_t node, gchar *devfs_path)
153*2912Sartem {
154*2912Sartem 	HalDevice *d = NULL;
155*2912Sartem 	di_devlink_handle_t devlink_hdl;
156*2912Sartem         int     major;
157*2912Sartem         di_minor_t minor;
158*2912Sartem         dev_t   devt;
159*2912Sartem         char    *minor_path = NULL;
160*2912Sartem 	char	*devlink = NULL;
161*2912Sartem         char    udi[HAL_PATH_MAX];
162*2912Sartem 
163*2912Sartem 	devinfo_add_enqueue (usbd, devfs_path, &devinfo_usb_handler);
164*2912Sartem 
165*2912Sartem         if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
166*2912Sartem                 printf("di_devlink_init() failed\n");
167*2912Sartem                 return (NULL);
168*2912Sartem         }
169*2912Sartem 
170*2912Sartem         major = di_driver_major(node);
171*2912Sartem         minor = DI_MINOR_NIL;
172*2912Sartem         while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
173*2912Sartem                 devt = di_minor_devt(minor);
174*2912Sartem                 if (major != major(devt)) {
175*2912Sartem                         continue;
176*2912Sartem                 }
177*2912Sartem                 if ((minor_path = di_devfs_minor_path(minor)) == NULL) {
178*2912Sartem                         continue;
179*2912Sartem                 }
180*2912Sartem                 if (di_minor_type(minor) != DDM_MINOR) {
181*2912Sartem                         continue;
182*2912Sartem                 }
183*2912Sartem 		if (strcmp (di_minor_nodetype(minor),
184*2912Sartem 		    "ddi_ctl:devctl:scsi") == 0) {
185*2912Sartem                 	devlink = get_devlink(devlink_hdl, minor_path);
186*2912Sartem                 	if (devlink == NULL) {
187*2912Sartem 				devlink = strdup("");
188*2912Sartem 			}
189*2912Sartem 			break;
190*2912Sartem 		}
191*2912Sartem 		di_devfs_path_free (minor_path);
192*2912Sartem 		minor_path = NULL;
193*2912Sartem         }
194*2912Sartem 
195*2912Sartem 	di_devlink_fini (&devlink_hdl);
196*2912Sartem 
197*2912Sartem 	if (devlink == NULL) {
198*2912Sartem 		goto out;
199*2912Sartem 	}
200*2912Sartem 
201*2912Sartem 	d = hal_device_new ();
202*2912Sartem 
203*2912Sartem 	devinfo_set_default_properties (d, usbd, node, minor_path);
204*2912Sartem        	hal_device_property_set_string (d, "scsi_host.solaris.device", devlink);
205*2912Sartem         hal_device_property_set_string (d, "info.category", "scsi_host");
206*2912Sartem         hal_device_property_set_int (d, "scsi_host.host", 0);
207*2912Sartem 
208*2912Sartem         hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
209*2912Sartem 		"%s/scsi_host%d", usbd->udi,
210*2912Sartem 		hal_device_property_get_int (d, "scsi_host.host"));
211*2912Sartem         hal_device_set_udi (d, udi);
212*2912Sartem         hal_device_property_set_string (d, "info.udi", udi);
213*2912Sartem         hal_device_property_set_string (d, "info.product", "SCSI Host Adapter");
214*2912Sartem 
215*2912Sartem 	devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler);
216*2912Sartem 
217*2912Sartem out:
218*2912Sartem 	if (devlink) {
219*2912Sartem 		free(devlink);
220*2912Sartem 	}
221*2912Sartem 	if (minor_path) {
222*2912Sartem 		di_devfs_path_free (minor_path);
223*2912Sartem 	}
224*2912Sartem 
225*2912Sartem 	return (d);
226*2912Sartem }
227*2912Sartem 
228