12912Sartem /***************************************************************************
22912Sartem  *
32912Sartem  * devinfo_usb.h : USB devices
42912Sartem  *
5*6112Sqz150045  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
62912Sartem  * Use is subject to license terms.
72912Sartem  *
82912Sartem  * Licensed under the Academic Free License version 2.1
92912Sartem  *
102912Sartem  **************************************************************************/
112912Sartem 
122916Sartem #pragma ident	"%Z%%M%	%I%	%E% SMI"
132912Sartem 
143121Sartem #ifdef HAVE_CONFIG_H
153121Sartem #  include <config.h>
163121Sartem #endif
173121Sartem 
182912Sartem #include <stdio.h>
192912Sartem #include <string.h>
202912Sartem #include <libdevinfo.h>
212912Sartem #include <sys/types.h>
222912Sartem #include <sys/mkdev.h>
232912Sartem #include <sys/stat.h>
24*6112Sqz150045 #include <sys/usb/usbai.h>
252912Sartem 
262912Sartem #include "../osspec.h"
272912Sartem #include "../logger.h"
282912Sartem #include "../hald.h"
292912Sartem #include "../hald_dbus.h"
302912Sartem #include "../device_info.h"
312912Sartem #include "../util.h"
322912Sartem #include "../ids.h"
332912Sartem #include "hotplug.h"
342912Sartem #include "devinfo.h"
352912Sartem #include "devinfo_usb.h"
362912Sartem 
37*6112Sqz150045 static HalDevice *devinfo_usb_if_add(HalDevice *d, di_node_t node, gchar *devfs_path,
38*6112Sqz150045 				     gchar *if_devfs_path, int ifnum);
39*6112Sqz150045 static HalDevice *devinfo_usb_scsa2usb_add(HalDevice *d, di_node_t node);
40*6112Sqz150045 static HalDevice *devinfo_usb_printer_add(HalDevice *usbd, di_node_t node);
413536Sjacobs const gchar *devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout);
42*6112Sqz150045 static void set_usb_properties(HalDevice *d, di_node_t node, gchar *devfs_path, char *driver_name);
432912Sartem 
442912Sartem DevinfoDevHandler devinfo_usb_handler = {
45*6112Sqz150045 	devinfo_usb_add,
462912Sartem 	NULL,
472912Sartem 	NULL,
482912Sartem 	NULL,
492912Sartem 	NULL,
50*6112Sqz150045 	NULL
512912Sartem };
522912Sartem 
533536Sjacobs DevinfoDevHandler devinfo_usb_printer_handler = {
54*6112Sqz150045 	devinfo_usb_add,
553536Sjacobs 	NULL,
563536Sjacobs 	NULL,
573536Sjacobs 	NULL,
583536Sjacobs 	NULL,
59*6112Sqz150045 	devinfo_printer_prnio_get_prober
603536Sjacobs };
613536Sjacobs 
623710Sjacobs static gboolean
633710Sjacobs is_usb_node(di_node_t node)
643710Sjacobs {
653710Sjacobs 	int rc;
663710Sjacobs 	char *s;
673710Sjacobs 
683710Sjacobs 	/*
693710Sjacobs 	 * USB device nodes will have "compatible" propety values that
703710Sjacobs 	 * begins with "usb".
713710Sjacobs 	 */
72*6112Sqz150045 	rc = di_prop_lookup_strings(DDI_DEV_T_ANY, node, "compatible", &s);
733710Sjacobs 	while (rc-- > 0) {
743710Sjacobs 		if (strncmp(s, "usb", 3) == 0) {
753710Sjacobs 			return (TRUE);
763710Sjacobs 		}
773710Sjacobs 		s += (strlen(s) + 1);
783710Sjacobs 	}
793710Sjacobs 
803710Sjacobs 	return (FALSE);
813710Sjacobs }
823710Sjacobs 
832912Sartem HalDevice *
842912Sartem devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
852912Sartem {
862912Sartem 	HalDevice *d, *nd = NULL;
872912Sartem 	char	*s;
883710Sjacobs 	int	*i;
892912Sartem 	char	*driver_name, *binding_name;
90*6112Sqz150045 	char	if_devfs_path[HAL_PATH_MAX];
91*6112Sqz150045 	di_devlink_handle_t hdl;
92*6112Sqz150045 	double	k;
932912Sartem 
94*6112Sqz150045 	if (is_usb_node(node) == FALSE) {
952912Sartem 		return (NULL);
962912Sartem 	}
972912Sartem 
98*6112Sqz150045 	driver_name = di_driver_name (node);
99*6112Sqz150045 
100*6112Sqz150045 	if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "interface", &i) < 0) {
101*6112Sqz150045 		/* It is a USB device node. */
102*6112Sqz150045 
103*6112Sqz150045 		d = hal_device_new ();
1042912Sartem 
105*6112Sqz150045 		devinfo_set_default_properties (d, parent, node, devfs_path);
106*6112Sqz150045 		hal_device_property_set_string (d, "info.subsystem", "usb_device");
107*6112Sqz150045 		PROP_STR(d, node, s, "usb-product-name", "info.product");
108*6112Sqz150045 		PROP_STR(d, node, s, "usb-product-name", "usb_device.product");
109*6112Sqz150045 		PROP_STR(d, node, s, "usb-vendor-name", "usb_device.vendor");
110*6112Sqz150045 		PROP_INT(d, node, i, "usb-vendor-id", "usb_device.vendor_id");
111*6112Sqz150045 		PROP_INT(d, node, i, "usb-product-id", "usb_device.product_id");
112*6112Sqz150045 		PROP_INT(d, node, i, "usb-revision-id", "usb_device.device_revision_bcd");
113*6112Sqz150045 		PROP_STR(d, node, s, "usb-serialno", "usb_device.serial");
114*6112Sqz150045 		PROP_INT(d, node, i, "usb-port-count", "usb_device.num_ports");
115*6112Sqz150045 		PROP_INT(d, node, i, "usb-num-configs", "usb_device.num_configurations");
116*6112Sqz150045 		PROP_INT(d, node, i, "assigned-address", "usb_device.bus_number");
117*6112Sqz150045 
118*6112Sqz150045 		if  (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "usb-release", &i) > 0) {
119*6112Sqz150045 			k = (double)bcd(*i);
120*6112Sqz150045 			hal_device_property_set_double (d, "usb_device.version", k / 100);
121*6112Sqz150045 		}
122*6112Sqz150045 
123*6112Sqz150045 		if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "low-speed", &i) >= 0) {
124*6112Sqz150045 			k = 1.5;
125*6112Sqz150045 		} else if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "high-speed", &i) >= 0) {
126*6112Sqz150045 			k = 480.0;
127*6112Sqz150045 		} else {
128*6112Sqz150045 			/* It is the full speed device. */
129*6112Sqz150045 			k = 12.0;
130*6112Sqz150045 		}
131*6112Sqz150045 		hal_device_property_set_double (d, "usb_device.speed", k);
132*6112Sqz150045 
133*6112Sqz150045 		set_usb_properties (d, node, devfs_path, driver_name);
1342912Sartem 
135*6112Sqz150045 		/* wait for the ugen node's creation */
136*6112Sqz150045 		if ((driver_name != NULL) && (strcmp (driver_name, "usb_mid") == 0)) {
137*6112Sqz150045 			if (hdl = di_devlink_init (devfs_path, DI_MAKE_LINK)) {
138*6112Sqz150045 				di_devlink_fini (&hdl);
139*6112Sqz150045 			}
140*6112Sqz150045 		}
141*6112Sqz150045 
142*6112Sqz150045 		devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler);
143*6112Sqz150045 
144*6112Sqz150045 		/* add to TDL so preprobing callouts and prober can access it */
145*6112Sqz150045 		hal_device_store_add (hald_get_tdl (), d);
146*6112Sqz150045 
147*6112Sqz150045 		if (((binding_name = di_binding_name (node)) != NULL) &&
148*6112Sqz150045 		    (strncmp (binding_name, "usbif,", sizeof ("usbif,") - 1) == 0)) {
149*6112Sqz150045 
150*6112Sqz150045 			snprintf (if_devfs_path, sizeof (if_devfs_path), "%s:if%d",
151*6112Sqz150045 			     devfs_path, 0);
152*6112Sqz150045 			if ((nd = devinfo_usb_if_add (d, node, if_devfs_path,
153*6112Sqz150045 			     if_devfs_path, 0)) != NULL) {
1542912Sartem 
155*6112Sqz150045 				d = nd;
156*6112Sqz150045 				nd = NULL;
157*6112Sqz150045 				devfs_path = if_devfs_path;
158*6112Sqz150045 			}
1592912Sartem 		}
160*6112Sqz150045 	} else {
161*6112Sqz150045 		/* It is a USB interface node or IA node. */
162*6112Sqz150045 		int *j;
163*6112Sqz150045 
164*6112Sqz150045 		if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "interface-count", &j) > 0) {
165*6112Sqz150045 			/*
166*6112Sqz150045 			 * The USB IA node properties are not defined in
167*6112Sqz150045 			 * HAL spec so far. So IA node udi has "ia" sign
168*6112Sqz150045 			 * now, different from the IF node udi with "if".
169*6112Sqz150045 			 */
170*6112Sqz150045 			snprintf (if_devfs_path, sizeof (if_devfs_path),
171*6112Sqz150045 			    "%s:ia%d", devfs_path, *i);
172*6112Sqz150045 		} else {
173*6112Sqz150045 			snprintf (if_devfs_path, sizeof (if_devfs_path),
174*6112Sqz150045 			    "%s:if%d", devfs_path, *i);
175*6112Sqz150045 		}
176*6112Sqz150045 
177*6112Sqz150045 		d = devinfo_usb_if_add (parent, node, devfs_path, if_devfs_path, *i);
1782912Sartem 	}
1792912Sartem 
1802912Sartem 	/* driver specific */
1812912Sartem 	if ((driver_name != NULL) && (strcmp (driver_name, "scsa2usb") == 0)) {
182*6112Sqz150045 		nd = devinfo_usb_scsa2usb_add (d, node);
1833536Sjacobs 	} else if ((driver_name != NULL) &&
184*6112Sqz150045 	    (strcmp (driver_name, "usbprn") == 0)) {
185*6112Sqz150045 		nd = devinfo_usb_printer_add (d, node);
1862912Sartem 	}
1872912Sartem 
1882912Sartem out:
1892912Sartem 	if (nd != NULL) {
1902912Sartem 		return (nd);
1912912Sartem 	} else {
1922912Sartem 		return (d);
1932912Sartem 	}
1942912Sartem }
1952912Sartem 
196*6112Sqz150045 
197*6112Sqz150045 static void
198*6112Sqz150045 set_usb_properties(HalDevice *d, di_node_t node, gchar *devfs_path, char *driver_name)
199*6112Sqz150045 {
200*6112Sqz150045 	usb_dev_descr_t	*dev_descrp = NULL;	/* device descriptor */
201*6112Sqz150045 	usb_cfg_descr_t	*cfg_descrp = NULL;	/* configuration descriptor */
202*6112Sqz150045 	unsigned char	*rdata = NULL;
203*6112Sqz150045 	char *p;
204*6112Sqz150045 	int i = 0;
205*6112Sqz150045 
206*6112Sqz150045 	hal_device_property_set_int (d, "usb_device.port_number",
207*6112Sqz150045 	    atoi (devfs_path + strlen (devfs_path) -1));
208*6112Sqz150045 
209*6112Sqz150045 	if (di_prop_lookup_bytes (DDI_DEV_T_ANY, node, "usb-dev-descriptor",
210*6112Sqz150045 	    &rdata) > 0) {
211*6112Sqz150045 		dev_descrp = (usb_dev_descr_t *)rdata;
212*6112Sqz150045 
213*6112Sqz150045 		if (dev_descrp != NULL) {
214*6112Sqz150045 			hal_device_property_set_int (d, "usb_device.device_class",
215*6112Sqz150045 			    dev_descrp->bDeviceClass);
216*6112Sqz150045 			hal_device_property_set_int (d, "usb_device.device_subclass",
217*6112Sqz150045 			    dev_descrp->bDeviceSubClass);
218*6112Sqz150045 			hal_device_property_set_int (d, "usb_device.device_protocol",
219*6112Sqz150045 			    dev_descrp->bDeviceProtocol);
220*6112Sqz150045 		}
221*6112Sqz150045 	}
222*6112Sqz150045 
223*6112Sqz150045 	if (di_prop_lookup_bytes (DDI_DEV_T_ANY, node, "usb-raw-cfg-descriptors",
224*6112Sqz150045 	    &rdata) > 0) {
225*6112Sqz150045 		cfg_descrp = (usb_cfg_descr_t *)(rdata);
226*6112Sqz150045 
227*6112Sqz150045 		if (cfg_descrp != NULL) {
228*6112Sqz150045 			hal_device_property_set_int (d, "usb_device.configuration_value",
229*6112Sqz150045 			    cfg_descrp->bConfigurationValue);
230*6112Sqz150045 			hal_device_property_set_int (d, "usb_device.max_power",
231*6112Sqz150045 			    cfg_descrp->bMaxPower);
232*6112Sqz150045 			hal_device_property_set_int (d, "usb_device.num_interfaces",
233*6112Sqz150045 			    cfg_descrp->bNumInterfaces);
234*6112Sqz150045 			hal_device_property_set_bool (d, "usb_device.can_wake_up",
235*6112Sqz150045 			    (cfg_descrp->bmAttributes & 0x20) ? TRUE : FALSE);
236*6112Sqz150045 			hal_device_property_set_bool (d, "usb_device.is_self_powered",
237*6112Sqz150045 			    (cfg_descrp->bmAttributes & 0x40) ? TRUE : FALSE);
238*6112Sqz150045 		}
239*6112Sqz150045 	}
240*6112Sqz150045 
241*6112Sqz150045 	/* get the node's usb tree level by counting hub numbers */
242*6112Sqz150045 	do {
243*6112Sqz150045 		if (p = strstr (devfs_path, "/hub@")) {
244*6112Sqz150045 			devfs_path = p + strlen ("/hub@");
245*6112Sqz150045 			i ++;
246*6112Sqz150045 		}
247*6112Sqz150045 	} while (p != NULL);
248*6112Sqz150045 
249*6112Sqz150045 	if ((driver_name != NULL) && (strcmp (driver_name, "hubd") == 0) && (i > 0))
250*6112Sqz150045 		i --;
251*6112Sqz150045 
252*6112Sqz150045 	hal_device_property_set_int (d, "usb_device.level_number", i);
253*6112Sqz150045 }
254*6112Sqz150045 
255*6112Sqz150045 
256*6112Sqz150045 static usb_if_descr_t *
257*6112Sqz150045 parse_usb_if_descr(di_node_t node, int ifnum)
2582912Sartem {
259*6112Sqz150045 	unsigned char	*rdata = NULL;
260*6112Sqz150045 	usb_if_descr_t	*if_descrp=NULL;	/* interface descriptor */
261*6112Sqz150045 	di_node_t tmp_node = DI_NODE_NIL;
262*6112Sqz150045 	uint8_t num, length, type;
263*6112Sqz150045 	int rlen;
264*6112Sqz150045 	gchar *devpath = NULL;
265*6112Sqz150045 
266*6112Sqz150045 	if ((rlen = di_prop_lookup_bytes (DDI_DEV_T_ANY, node,
267*6112Sqz150045 	     "usb-raw-cfg-descriptors", &rdata)) < 0) {
268*6112Sqz150045 
269*6112Sqz150045 		char *p;
270*6112Sqz150045 		int i;
271*6112Sqz150045 
272*6112Sqz150045 		if ((devpath = di_devfs_path (node)) == NULL)
273*6112Sqz150045 			goto out;
274*6112Sqz150045 
275*6112Sqz150045 		/* Look up its parent that may be a USB IA or USB mid. */
276*6112Sqz150045 		for (i = 0; i < 2; i++) {
277*6112Sqz150045 			p = strrchr (devpath, '/');
278*6112Sqz150045 			if (p == NULL)
279*6112Sqz150045 				goto out;
280*6112Sqz150045 			*p = '\0';
281*6112Sqz150045 
282*6112Sqz150045 			if ((tmp_node = di_init (devpath, DINFOCPYALL)) == DI_NODE_NIL)
283*6112Sqz150045 				goto out;
284*6112Sqz150045 
285*6112Sqz150045 			if ((rlen = di_prop_lookup_bytes (DDI_DEV_T_ANY, tmp_node,
286*6112Sqz150045 			     "usb-raw-cfg-descriptors", &rdata)) > 0)
287*6112Sqz150045 				break;
288*6112Sqz150045 
289*6112Sqz150045 			di_fini (tmp_node);
290*6112Sqz150045 		}
291*6112Sqz150045 	}
2922912Sartem 
293*6112Sqz150045 	if (rdata == NULL)
294*6112Sqz150045 		goto out;
295*6112Sqz150045 
296*6112Sqz150045 	do {
297*6112Sqz150045 		length = (uint8_t)*rdata;
298*6112Sqz150045 		type = (uint8_t)*(rdata + 1);
299*6112Sqz150045 		if (type == USB_DESCR_TYPE_IF) {
300*6112Sqz150045 			num = (uint8_t)*(rdata + 2);
301*6112Sqz150045 			if (num == ifnum) {
302*6112Sqz150045 				if_descrp = (usb_if_descr_t *)rdata;
303*6112Sqz150045 				break;
304*6112Sqz150045 			}
305*6112Sqz150045 		}
306*6112Sqz150045 		rdata += length;
307*6112Sqz150045 		rlen -= length;
308*6112Sqz150045 	} while ((length > 0 ) && (rlen > 0));
309*6112Sqz150045 
310*6112Sqz150045 out:
311*6112Sqz150045 	if (devpath != NULL)
312*6112Sqz150045 		di_devfs_path_free (devpath);
313*6112Sqz150045 	if (tmp_node != DI_NODE_NIL)
314*6112Sqz150045 		di_fini (tmp_node);
315*6112Sqz150045 	return (if_descrp);
316*6112Sqz150045 }
317*6112Sqz150045 
318*6112Sqz150045 
319*6112Sqz150045 static HalDevice *
320*6112Sqz150045 devinfo_usb_if_add(HalDevice *parent, di_node_t node, gchar *devfs_path,
321*6112Sqz150045 		   gchar *if_devfs_path, int ifnum)
322*6112Sqz150045 {
323*6112Sqz150045 	HalDevice	*d = NULL;
324*6112Sqz150045 	char		udi[HAL_PATH_MAX];
325*6112Sqz150045 	const char	*parent_info;
326*6112Sqz150045 	usb_if_descr_t	*if_descrp=NULL;	/* interface descriptor */
3272912Sartem 
3282912Sartem 	d = hal_device_new ();
3292912Sartem 
330*6112Sqz150045 	devinfo_set_default_properties (d, parent, node, if_devfs_path);
331*6112Sqz150045 
332*6112Sqz150045 	/* Set the existed physical device path. */
333*6112Sqz150045 	hal_device_property_set_string (d, "solaris.devfs_path", devfs_path);
334*6112Sqz150045 	hal_device_property_set_string (d, "info.subsystem", "usb");
335*6112Sqz150045 	hal_device_property_set_string (d, "info.product", "USB Device Interface");
336*6112Sqz150045 
337*6112Sqz150045 	/* Set usb interface properties to interface node. */
338*6112Sqz150045 	if (strstr (if_devfs_path, ":ia") == NULL) {
339*6112Sqz150045 		if_descrp = parse_usb_if_descr (node, ifnum);
340*6112Sqz150045 
341*6112Sqz150045 		if (if_descrp != NULL) {
342*6112Sqz150045 			hal_device_property_set_int (d, "usb.interface.class",
343*6112Sqz150045 			    if_descrp->bInterfaceClass);
344*6112Sqz150045 			hal_device_property_set_int (d, "usb.interface.subclass",
345*6112Sqz150045 			    if_descrp->bInterfaceSubClass);
346*6112Sqz150045 			hal_device_property_set_int (d, "usb.interface.protocol",
347*6112Sqz150045 			    if_descrp->bInterfaceProtocol);
348*6112Sqz150045 			hal_device_property_set_int (d, "usb.interface.number",
349*6112Sqz150045 			    if_descrp->bInterfaceNumber);
350*6112Sqz150045 		}
351*6112Sqz150045 	}
3522912Sartem 
3532912Sartem 	/* copy parent's usb_device.* properties */
354*6112Sqz150045 	parent_info = hal_device_property_get_string (parent, "info.subsystem");
355*6112Sqz150045 	if (parent_info != NULL) {
356*6112Sqz150045 		if (strcmp (parent_info, "usb_device") == 0) {
357*6112Sqz150045 			hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
358*6112Sqz150045 		} else if (strcmp (parent_info, "usb") == 0) {
359*6112Sqz150045 			/* for the case that the parent is IA node */
360*6112Sqz150045 			hal_device_merge_with_rewrite (d, parent, "usb.", "usb.");
361*6112Sqz150045 		}
362*6112Sqz150045 	}
363*6112Sqz150045 
364*6112Sqz150045 	devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler);
365*6112Sqz150045 
366*6112Sqz150045 	/* add to TDL so preprobing callouts and prober can access it */
367*6112Sqz150045 	hal_device_store_add (hald_get_tdl (), d);
3682912Sartem 
3692912Sartem 	return (d);
3702912Sartem }
3712912Sartem 
3722912Sartem 
3733536Sjacobs static void
3743536Sjacobs get_dev_link_path(di_node_t node, char *nodetype, char *re, char **devlink, char **minor_path)
3753536Sjacobs {
3763536Sjacobs 	di_devlink_handle_t devlink_hdl;
377*6112Sqz150045 	int	major;
378*6112Sqz150045 	di_minor_t minor;
379*6112Sqz150045 	dev_t	devt;
3802912Sartem 
3813536Sjacobs 	*devlink = NULL;
382*6112Sqz150045 	*minor_path = NULL;
3833536Sjacobs 
384*6112Sqz150045 	if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
385*6112Sqz150045 		printf("di_devlink_init() failed\n");
386*6112Sqz150045 		return;
387*6112Sqz150045 	}
3882912Sartem 
389*6112Sqz150045 	major = di_driver_major(node);
390*6112Sqz150045 	minor = DI_MINOR_NIL;
391*6112Sqz150045 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
392*6112Sqz150045 		devt = di_minor_devt(minor);
393*6112Sqz150045 		if (major != major(devt)) {
394*6112Sqz150045 			continue;
395*6112Sqz150045 		}
3963536Sjacobs 
397*6112Sqz150045 		if (di_minor_type(minor) != DDM_MINOR) {
398*6112Sqz150045 			continue;
399*6112Sqz150045 		}
4002912Sartem 
401*6112Sqz150045 		if ((*minor_path = di_devfs_minor_path(minor)) == NULL) {
402*6112Sqz150045 			continue;
403*6112Sqz150045 		}
4042912Sartem 
4053536Sjacobs 		if ((strcmp (di_minor_nodetype(minor), nodetype) == 0) &&
4063536Sjacobs 		    ((*devlink = get_devlink(devlink_hdl, re, *minor_path)) != NULL)) {
4073536Sjacobs 			break;
4083536Sjacobs 		}
4093536Sjacobs 		di_devfs_path_free (*minor_path);
4103710Sjacobs 		*minor_path = NULL;
4113536Sjacobs 	}
4123536Sjacobs 	di_devlink_fini (&devlink_hdl);
4132912Sartem }
4142912Sartem 
4152912Sartem static HalDevice *
416*6112Sqz150045 devinfo_usb_scsa2usb_add(HalDevice *usbd, di_node_t node)
4172912Sartem {
4182912Sartem 	HalDevice *d = NULL;
4192912Sartem 	di_devlink_handle_t devlink_hdl;
420*6112Sqz150045 	int	major;
421*6112Sqz150045 	di_minor_t minor;
422*6112Sqz150045 	dev_t	devt;
423*6112Sqz150045 	char	*minor_path = NULL;
4242912Sartem 	char	*devlink = NULL;
425*6112Sqz150045 	char	udi[HAL_PATH_MAX];
4262912Sartem 
4273536Sjacobs 	get_dev_link_path(node, "ddi_ctl:devctl:scsi", NULL,  &devlink, &minor_path);
4282912Sartem 
4293536Sjacobs 	if ((devlink == NULL) || (minor_path == NULL)) {
4302912Sartem 		goto out;
4312912Sartem 	}
4322912Sartem 
4332912Sartem 	d = hal_device_new ();
4342912Sartem 
4352912Sartem 	devinfo_set_default_properties (d, usbd, node, minor_path);
436*6112Sqz150045 	hal_device_property_set_string (d, "scsi_host.solaris.device", devlink);
437*6112Sqz150045 	hal_device_property_set_string (d, "info.category", "scsi_host");
438*6112Sqz150045 	hal_device_property_set_int (d, "scsi_host.host", 0);
4392912Sartem 
440*6112Sqz150045 	hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
441*6112Sqz150045 	    "%s/scsi_host%d", hal_device_get_udi (usbd),
442*6112Sqz150045 	    hal_device_property_get_int (d, "scsi_host.host"));
443*6112Sqz150045 	hal_device_set_udi (d, udi);
444*6112Sqz150045 	hal_device_property_set_string (d, "info.udi", udi);
445*6112Sqz150045 	hal_device_property_set_string (d, "info.product", "SCSI Host Adapter");
4462912Sartem 
4472912Sartem 	devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler);
4482912Sartem 
4492912Sartem out:
4502912Sartem 	if (devlink) {
4512912Sartem 		free(devlink);
4522912Sartem 	}
4532912Sartem 	if (minor_path) {
4542912Sartem 		di_devfs_path_free (minor_path);
4552912Sartem 	}
4562912Sartem 
4572912Sartem 	return (d);
4582912Sartem }
4592912Sartem 
4603536Sjacobs static HalDevice *
461*6112Sqz150045 devinfo_usb_printer_add(HalDevice *parent, di_node_t node)
4623536Sjacobs {
4633536Sjacobs 	HalDevice *d = NULL;
464*6112Sqz150045 	char	udi[HAL_PATH_MAX];
4653536Sjacobs 	char *s;
4663536Sjacobs 	char *devlink = NULL, *minor_path = NULL;
4673536Sjacobs 
4683536Sjacobs 	get_dev_link_path(node, "ddi_printer", "printers/.+", &devlink, &minor_path);
4693536Sjacobs 
4703536Sjacobs 	if ((devlink == NULL) || (minor_path == NULL)) {
4713536Sjacobs 		goto out;
4723536Sjacobs 	}
4733536Sjacobs 
4743536Sjacobs 	d = hal_device_new ();
4753536Sjacobs 
4763536Sjacobs 	devinfo_set_default_properties (d, parent, node, minor_path);
477*6112Sqz150045 	hal_device_property_set_string (d, "info.category", "printer");
4783536Sjacobs 	hal_device_add_capability (d, "printer");
4793536Sjacobs 
4803536Sjacobs 	/* copy parent's usb_device.* properties */
4813536Sjacobs 	hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
4823536Sjacobs 
4833536Sjacobs 	/* add printer properties */
484*6112Sqz150045 	hal_device_property_set_string (d, "printer.device", devlink);
4853536Sjacobs 	PROP_STR(d, node, s, "usb-vendor-name", "printer.vendor");
4863536Sjacobs 	PROP_STR(d, node, s, "usb-product-name", "printer.product");
4873536Sjacobs 	PROP_STR(d, node, s, "usb-serialno", "printer.serial");
4883536Sjacobs 
4893536Sjacobs 	devinfo_add_enqueue (d, minor_path, &devinfo_usb_printer_handler);
4903536Sjacobs 
4913536Sjacobs out:
4923536Sjacobs 	if (devlink) {
4933536Sjacobs 		free(devlink);
4943536Sjacobs 	}
4953536Sjacobs 	if (minor_path) {
4963536Sjacobs 		di_devfs_path_free (minor_path);
4973536Sjacobs 	}
4983536Sjacobs 
4993536Sjacobs 	return (d);
5003536Sjacobs }
5013536Sjacobs 
5023536Sjacobs const gchar *
5033536Sjacobs devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout)
5043536Sjacobs {
5053536Sjacobs 	*timeout = 5 * 1000;	/* 5 second timeout */
5063536Sjacobs 	return ("hald-probe-printer");
5073536Sjacobs }
508