12912Sartem /***************************************************************************
22912Sartem  *
32912Sartem  * devinfo_usb.h : USB devices
42912Sartem  *
5*8529SNorm.Jacobs@Sun.COM  * Copyright 2009 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 
123121Sartem #ifdef HAVE_CONFIG_H
133121Sartem #  include <config.h>
143121Sartem #endif
153121Sartem 
162912Sartem #include <stdio.h>
172912Sartem #include <string.h>
182912Sartem #include <libdevinfo.h>
192912Sartem #include <sys/types.h>
202912Sartem #include <sys/mkdev.h>
212912Sartem #include <sys/stat.h>
226112Sqz150045 #include <sys/usb/usbai.h>
232912Sartem 
242912Sartem #include "../osspec.h"
252912Sartem #include "../logger.h"
262912Sartem #include "../hald.h"
272912Sartem #include "../hald_dbus.h"
282912Sartem #include "../device_info.h"
292912Sartem #include "../util.h"
302912Sartem #include "../ids.h"
312912Sartem #include "hotplug.h"
322912Sartem #include "devinfo.h"
332912Sartem #include "devinfo_usb.h"
342912Sartem 
356112Sqz150045 static HalDevice *devinfo_usb_if_add(HalDevice *d, di_node_t node, gchar *devfs_path,
366112Sqz150045 				     gchar *if_devfs_path, int ifnum);
376112Sqz150045 static HalDevice *devinfo_usb_scsa2usb_add(HalDevice *d, di_node_t node);
386112Sqz150045 static HalDevice *devinfo_usb_printer_add(HalDevice *usbd, di_node_t node);
393536Sjacobs const gchar *devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout);
406112Sqz150045 static void set_usb_properties(HalDevice *d, di_node_t node, gchar *devfs_path, char *driver_name);
412912Sartem 
422912Sartem DevinfoDevHandler devinfo_usb_handler = {
436112Sqz150045 	devinfo_usb_add,
442912Sartem 	NULL,
452912Sartem 	NULL,
462912Sartem 	NULL,
472912Sartem 	NULL,
486112Sqz150045 	NULL
492912Sartem };
502912Sartem 
513536Sjacobs DevinfoDevHandler devinfo_usb_printer_handler = {
526112Sqz150045 	devinfo_usb_add,
533536Sjacobs 	NULL,
543536Sjacobs 	NULL,
553536Sjacobs 	NULL,
563536Sjacobs 	NULL,
576112Sqz150045 	devinfo_printer_prnio_get_prober
583536Sjacobs };
593536Sjacobs 
603710Sjacobs static gboolean
613710Sjacobs is_usb_node(di_node_t node)
623710Sjacobs {
633710Sjacobs 	int rc;
643710Sjacobs 	char *s;
653710Sjacobs 
663710Sjacobs 	/*
673710Sjacobs 	 * USB device nodes will have "compatible" propety values that
683710Sjacobs 	 * begins with "usb".
693710Sjacobs 	 */
706112Sqz150045 	rc = di_prop_lookup_strings(DDI_DEV_T_ANY, node, "compatible", &s);
713710Sjacobs 	while (rc-- > 0) {
723710Sjacobs 		if (strncmp(s, "usb", 3) == 0) {
733710Sjacobs 			return (TRUE);
743710Sjacobs 		}
753710Sjacobs 		s += (strlen(s) + 1);
763710Sjacobs 	}
773710Sjacobs 
783710Sjacobs 	return (FALSE);
793710Sjacobs }
803710Sjacobs 
812912Sartem HalDevice *
822912Sartem devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
832912Sartem {
842912Sartem 	HalDevice *d, *nd = NULL;
852912Sartem 	char	*s;
863710Sjacobs 	int	*i;
872912Sartem 	char	*driver_name, *binding_name;
886112Sqz150045 	char	if_devfs_path[HAL_PATH_MAX];
896112Sqz150045 	di_devlink_handle_t hdl;
906112Sqz150045 	double	k;
912912Sartem 
926112Sqz150045 	if (is_usb_node(node) == FALSE) {
932912Sartem 		return (NULL);
942912Sartem 	}
952912Sartem 
966112Sqz150045 	driver_name = di_driver_name (node);
976112Sqz150045 
986112Sqz150045 	if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "interface", &i) < 0) {
996112Sqz150045 		/* It is a USB device node. */
1006112Sqz150045 
1016112Sqz150045 		d = hal_device_new ();
1022912Sartem 
1036112Sqz150045 		devinfo_set_default_properties (d, parent, node, devfs_path);
1046112Sqz150045 		hal_device_property_set_string (d, "info.subsystem", "usb_device");
1056112Sqz150045 		PROP_STR(d, node, s, "usb-product-name", "info.product");
1066112Sqz150045 		PROP_STR(d, node, s, "usb-product-name", "usb_device.product");
1076112Sqz150045 		PROP_STR(d, node, s, "usb-vendor-name", "usb_device.vendor");
1086112Sqz150045 		PROP_INT(d, node, i, "usb-vendor-id", "usb_device.vendor_id");
1096112Sqz150045 		PROP_INT(d, node, i, "usb-product-id", "usb_device.product_id");
1106112Sqz150045 		PROP_INT(d, node, i, "usb-revision-id", "usb_device.device_revision_bcd");
1116112Sqz150045 		PROP_STR(d, node, s, "usb-serialno", "usb_device.serial");
1126112Sqz150045 		PROP_INT(d, node, i, "usb-port-count", "usb_device.num_ports");
1136112Sqz150045 		PROP_INT(d, node, i, "usb-num-configs", "usb_device.num_configurations");
1146112Sqz150045 		PROP_INT(d, node, i, "assigned-address", "usb_device.bus_number");
1156112Sqz150045 
1166112Sqz150045 		if  (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "usb-release", &i) > 0) {
1176112Sqz150045 			k = (double)bcd(*i);
1186112Sqz150045 			hal_device_property_set_double (d, "usb_device.version", k / 100);
1196112Sqz150045 		}
1206112Sqz150045 
1216112Sqz150045 		if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "low-speed", &i) >= 0) {
1226112Sqz150045 			k = 1.5;
1236112Sqz150045 		} else if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "high-speed", &i) >= 0) {
1246112Sqz150045 			k = 480.0;
1256112Sqz150045 		} else {
1266112Sqz150045 			/* It is the full speed device. */
1276112Sqz150045 			k = 12.0;
1286112Sqz150045 		}
1296112Sqz150045 		hal_device_property_set_double (d, "usb_device.speed", k);
1306112Sqz150045 
1316112Sqz150045 		set_usb_properties (d, node, devfs_path, driver_name);
1322912Sartem 
1336112Sqz150045 		/* wait for the ugen node's creation */
1346112Sqz150045 		if ((driver_name != NULL) && (strcmp (driver_name, "usb_mid") == 0)) {
1356112Sqz150045 			if (hdl = di_devlink_init (devfs_path, DI_MAKE_LINK)) {
1366112Sqz150045 				di_devlink_fini (&hdl);
1376112Sqz150045 			}
1386112Sqz150045 		}
1396112Sqz150045 
1406112Sqz150045 		devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler);
1416112Sqz150045 
1426112Sqz150045 		/* add to TDL so preprobing callouts and prober can access it */
1436112Sqz150045 		hal_device_store_add (hald_get_tdl (), d);
1446112Sqz150045 
1456112Sqz150045 		if (((binding_name = di_binding_name (node)) != NULL) &&
1466112Sqz150045 		    (strncmp (binding_name, "usbif,", sizeof ("usbif,") - 1) == 0)) {
1476112Sqz150045 
1486112Sqz150045 			snprintf (if_devfs_path, sizeof (if_devfs_path), "%s:if%d",
1496112Sqz150045 			     devfs_path, 0);
1506112Sqz150045 			if ((nd = devinfo_usb_if_add (d, node, if_devfs_path,
1516112Sqz150045 			     if_devfs_path, 0)) != NULL) {
1522912Sartem 
1536112Sqz150045 				d = nd;
1546112Sqz150045 				nd = NULL;
1556112Sqz150045 				devfs_path = if_devfs_path;
1566112Sqz150045 			}
1572912Sartem 		}
1586112Sqz150045 	} else {
1596112Sqz150045 		/* It is a USB interface node or IA node. */
1606112Sqz150045 		int *j;
1616112Sqz150045 
1626112Sqz150045 		if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "interface-count", &j) > 0) {
1636112Sqz150045 			/*
1646112Sqz150045 			 * The USB IA node properties are not defined in
1656112Sqz150045 			 * HAL spec so far. So IA node udi has "ia" sign
1666112Sqz150045 			 * now, different from the IF node udi with "if".
1676112Sqz150045 			 */
1686112Sqz150045 			snprintf (if_devfs_path, sizeof (if_devfs_path),
1696112Sqz150045 			    "%s:ia%d", devfs_path, *i);
1706112Sqz150045 		} else {
1716112Sqz150045 			snprintf (if_devfs_path, sizeof (if_devfs_path),
1726112Sqz150045 			    "%s:if%d", devfs_path, *i);
1736112Sqz150045 		}
1746112Sqz150045 
1756112Sqz150045 		d = devinfo_usb_if_add (parent, node, devfs_path, if_devfs_path, *i);
1762912Sartem 	}
1772912Sartem 
1782912Sartem 	/* driver specific */
1792912Sartem 	if ((driver_name != NULL) && (strcmp (driver_name, "scsa2usb") == 0)) {
1806112Sqz150045 		nd = devinfo_usb_scsa2usb_add (d, node);
1813536Sjacobs 	} else if ((driver_name != NULL) &&
1826112Sqz150045 	    (strcmp (driver_name, "usbprn") == 0)) {
1836112Sqz150045 		nd = devinfo_usb_printer_add (d, node);
1842912Sartem 	}
1852912Sartem 
1862912Sartem out:
1872912Sartem 	if (nd != NULL) {
1882912Sartem 		return (nd);
1892912Sartem 	} else {
1902912Sartem 		return (d);
1912912Sartem 	}
1922912Sartem }
1932912Sartem 
1946112Sqz150045 
1956112Sqz150045 static void
1966112Sqz150045 set_usb_properties(HalDevice *d, di_node_t node, gchar *devfs_path, char *driver_name)
1976112Sqz150045 {
1986112Sqz150045 	usb_dev_descr_t	*dev_descrp = NULL;	/* device descriptor */
1996112Sqz150045 	usb_cfg_descr_t	*cfg_descrp = NULL;	/* configuration descriptor */
2006112Sqz150045 	unsigned char	*rdata = NULL;
2016112Sqz150045 	char *p;
2026112Sqz150045 	int i = 0;
2036112Sqz150045 
2046112Sqz150045 	hal_device_property_set_int (d, "usb_device.port_number",
2056112Sqz150045 	    atoi (devfs_path + strlen (devfs_path) -1));
2066112Sqz150045 
2076112Sqz150045 	if (di_prop_lookup_bytes (DDI_DEV_T_ANY, node, "usb-dev-descriptor",
2086112Sqz150045 	    &rdata) > 0) {
2096112Sqz150045 		dev_descrp = (usb_dev_descr_t *)rdata;
2106112Sqz150045 
2116112Sqz150045 		if (dev_descrp != NULL) {
2126112Sqz150045 			hal_device_property_set_int (d, "usb_device.device_class",
2136112Sqz150045 			    dev_descrp->bDeviceClass);
2146112Sqz150045 			hal_device_property_set_int (d, "usb_device.device_subclass",
2156112Sqz150045 			    dev_descrp->bDeviceSubClass);
2166112Sqz150045 			hal_device_property_set_int (d, "usb_device.device_protocol",
2176112Sqz150045 			    dev_descrp->bDeviceProtocol);
2186112Sqz150045 		}
2196112Sqz150045 	}
2206112Sqz150045 
2216112Sqz150045 	if (di_prop_lookup_bytes (DDI_DEV_T_ANY, node, "usb-raw-cfg-descriptors",
2226112Sqz150045 	    &rdata) > 0) {
2236112Sqz150045 		cfg_descrp = (usb_cfg_descr_t *)(rdata);
2246112Sqz150045 
2256112Sqz150045 		if (cfg_descrp != NULL) {
2266112Sqz150045 			hal_device_property_set_int (d, "usb_device.configuration_value",
2276112Sqz150045 			    cfg_descrp->bConfigurationValue);
2286112Sqz150045 			hal_device_property_set_int (d, "usb_device.max_power",
2296112Sqz150045 			    cfg_descrp->bMaxPower);
2306112Sqz150045 			hal_device_property_set_int (d, "usb_device.num_interfaces",
2316112Sqz150045 			    cfg_descrp->bNumInterfaces);
2326112Sqz150045 			hal_device_property_set_bool (d, "usb_device.can_wake_up",
2336112Sqz150045 			    (cfg_descrp->bmAttributes & 0x20) ? TRUE : FALSE);
2346112Sqz150045 			hal_device_property_set_bool (d, "usb_device.is_self_powered",
2356112Sqz150045 			    (cfg_descrp->bmAttributes & 0x40) ? TRUE : FALSE);
2366112Sqz150045 		}
2376112Sqz150045 	}
2386112Sqz150045 
2396112Sqz150045 	/* get the node's usb tree level by counting hub numbers */
2406112Sqz150045 	do {
2416112Sqz150045 		if (p = strstr (devfs_path, "/hub@")) {
2426112Sqz150045 			devfs_path = p + strlen ("/hub@");
2436112Sqz150045 			i ++;
2446112Sqz150045 		}
2456112Sqz150045 	} while (p != NULL);
2466112Sqz150045 
2476112Sqz150045 	if ((driver_name != NULL) && (strcmp (driver_name, "hubd") == 0) && (i > 0))
2486112Sqz150045 		i --;
2496112Sqz150045 
2506112Sqz150045 	hal_device_property_set_int (d, "usb_device.level_number", i);
2516112Sqz150045 }
2526112Sqz150045 
2536112Sqz150045 
2546112Sqz150045 static usb_if_descr_t *
2556112Sqz150045 parse_usb_if_descr(di_node_t node, int ifnum)
2562912Sartem {
2576112Sqz150045 	unsigned char	*rdata = NULL;
2586112Sqz150045 	usb_if_descr_t	*if_descrp=NULL;	/* interface descriptor */
2596112Sqz150045 	di_node_t tmp_node = DI_NODE_NIL;
2606112Sqz150045 	uint8_t num, length, type;
2616112Sqz150045 	int rlen;
2626112Sqz150045 	gchar *devpath = NULL;
2636112Sqz150045 
2646112Sqz150045 	if ((rlen = di_prop_lookup_bytes (DDI_DEV_T_ANY, node,
2656112Sqz150045 	     "usb-raw-cfg-descriptors", &rdata)) < 0) {
2666112Sqz150045 
2676112Sqz150045 		char *p;
2686112Sqz150045 		int i;
2696112Sqz150045 
2706112Sqz150045 		if ((devpath = di_devfs_path (node)) == NULL)
2716112Sqz150045 			goto out;
2726112Sqz150045 
2736112Sqz150045 		/* Look up its parent that may be a USB IA or USB mid. */
2746112Sqz150045 		for (i = 0; i < 2; i++) {
2756112Sqz150045 			p = strrchr (devpath, '/');
2766112Sqz150045 			if (p == NULL)
2776112Sqz150045 				goto out;
2786112Sqz150045 			*p = '\0';
2796112Sqz150045 
2806112Sqz150045 			if ((tmp_node = di_init (devpath, DINFOCPYALL)) == DI_NODE_NIL)
2816112Sqz150045 				goto out;
2826112Sqz150045 
2836112Sqz150045 			if ((rlen = di_prop_lookup_bytes (DDI_DEV_T_ANY, tmp_node,
2846112Sqz150045 			     "usb-raw-cfg-descriptors", &rdata)) > 0)
2856112Sqz150045 				break;
2866112Sqz150045 
2876112Sqz150045 			di_fini (tmp_node);
2886112Sqz150045 		}
2896112Sqz150045 	}
2902912Sartem 
2916112Sqz150045 	if (rdata == NULL)
2926112Sqz150045 		goto out;
2936112Sqz150045 
2946112Sqz150045 	do {
2956112Sqz150045 		length = (uint8_t)*rdata;
2966112Sqz150045 		type = (uint8_t)*(rdata + 1);
2976112Sqz150045 		if (type == USB_DESCR_TYPE_IF) {
2986112Sqz150045 			num = (uint8_t)*(rdata + 2);
2996112Sqz150045 			if (num == ifnum) {
3006112Sqz150045 				if_descrp = (usb_if_descr_t *)rdata;
3016112Sqz150045 				break;
3026112Sqz150045 			}
3036112Sqz150045 		}
3046112Sqz150045 		rdata += length;
3056112Sqz150045 		rlen -= length;
3066112Sqz150045 	} while ((length > 0 ) && (rlen > 0));
3076112Sqz150045 
3086112Sqz150045 out:
3096112Sqz150045 	if (devpath != NULL)
3106112Sqz150045 		di_devfs_path_free (devpath);
3116112Sqz150045 	if (tmp_node != DI_NODE_NIL)
3126112Sqz150045 		di_fini (tmp_node);
3136112Sqz150045 	return (if_descrp);
3146112Sqz150045 }
3156112Sqz150045 
3166112Sqz150045 
3176112Sqz150045 static HalDevice *
3186112Sqz150045 devinfo_usb_if_add(HalDevice *parent, di_node_t node, gchar *devfs_path,
3196112Sqz150045 		   gchar *if_devfs_path, int ifnum)
3206112Sqz150045 {
3216112Sqz150045 	HalDevice	*d = NULL;
3226112Sqz150045 	char		udi[HAL_PATH_MAX];
3236112Sqz150045 	const char	*parent_info;
3246112Sqz150045 	usb_if_descr_t	*if_descrp=NULL;	/* interface descriptor */
3252912Sartem 
3262912Sartem 	d = hal_device_new ();
3272912Sartem 
3286112Sqz150045 	devinfo_set_default_properties (d, parent, node, if_devfs_path);
3296112Sqz150045 
3306112Sqz150045 	/* Set the existed physical device path. */
3316112Sqz150045 	hal_device_property_set_string (d, "solaris.devfs_path", devfs_path);
3326112Sqz150045 	hal_device_property_set_string (d, "info.subsystem", "usb");
3336112Sqz150045 	hal_device_property_set_string (d, "info.product", "USB Device Interface");
3346112Sqz150045 
3356112Sqz150045 	/* Set usb interface properties to interface node. */
3366112Sqz150045 	if (strstr (if_devfs_path, ":ia") == NULL) {
3376112Sqz150045 		if_descrp = parse_usb_if_descr (node, ifnum);
3386112Sqz150045 
3396112Sqz150045 		if (if_descrp != NULL) {
3406112Sqz150045 			hal_device_property_set_int (d, "usb.interface.class",
3416112Sqz150045 			    if_descrp->bInterfaceClass);
3426112Sqz150045 			hal_device_property_set_int (d, "usb.interface.subclass",
3436112Sqz150045 			    if_descrp->bInterfaceSubClass);
3446112Sqz150045 			hal_device_property_set_int (d, "usb.interface.protocol",
3456112Sqz150045 			    if_descrp->bInterfaceProtocol);
3466112Sqz150045 			hal_device_property_set_int (d, "usb.interface.number",
3476112Sqz150045 			    if_descrp->bInterfaceNumber);
3486112Sqz150045 		}
3496112Sqz150045 	}
3502912Sartem 
3512912Sartem 	/* copy parent's usb_device.* properties */
3526112Sqz150045 	parent_info = hal_device_property_get_string (parent, "info.subsystem");
3536112Sqz150045 	if (parent_info != NULL) {
3546112Sqz150045 		if (strcmp (parent_info, "usb_device") == 0) {
3556112Sqz150045 			hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
3566112Sqz150045 		} else if (strcmp (parent_info, "usb") == 0) {
3576112Sqz150045 			/* for the case that the parent is IA node */
3586112Sqz150045 			hal_device_merge_with_rewrite (d, parent, "usb.", "usb.");
3596112Sqz150045 		}
3606112Sqz150045 	}
3616112Sqz150045 
3626112Sqz150045 	devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler);
3636112Sqz150045 
3646112Sqz150045 	/* add to TDL so preprobing callouts and prober can access it */
3656112Sqz150045 	hal_device_store_add (hald_get_tdl (), d);
3662912Sartem 
3672912Sartem 	return (d);
3682912Sartem }
3692912Sartem 
3702912Sartem 
3713536Sjacobs static void
3723536Sjacobs get_dev_link_path(di_node_t node, char *nodetype, char *re, char **devlink, char **minor_path)
3733536Sjacobs {
3743536Sjacobs 	di_devlink_handle_t devlink_hdl;
3756112Sqz150045 	int	major;
3766112Sqz150045 	di_minor_t minor;
3776112Sqz150045 	dev_t	devt;
3782912Sartem 
3793536Sjacobs 	*devlink = NULL;
3806112Sqz150045 	*minor_path = NULL;
3813536Sjacobs 
3826112Sqz150045 	if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
3836112Sqz150045 		printf("di_devlink_init() failed\n");
3846112Sqz150045 		return;
3856112Sqz150045 	}
3862912Sartem 
3876112Sqz150045 	major = di_driver_major(node);
3886112Sqz150045 	minor = DI_MINOR_NIL;
3896112Sqz150045 	while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
3906112Sqz150045 		devt = di_minor_devt(minor);
3916112Sqz150045 		if (major != major(devt)) {
3926112Sqz150045 			continue;
3936112Sqz150045 		}
3943536Sjacobs 
3956112Sqz150045 		if (di_minor_type(minor) != DDM_MINOR) {
3966112Sqz150045 			continue;
3976112Sqz150045 		}
3982912Sartem 
3996112Sqz150045 		if ((*minor_path = di_devfs_minor_path(minor)) == NULL) {
4006112Sqz150045 			continue;
4016112Sqz150045 		}
4022912Sartem 
4033536Sjacobs 		if ((strcmp (di_minor_nodetype(minor), nodetype) == 0) &&
4043536Sjacobs 		    ((*devlink = get_devlink(devlink_hdl, re, *minor_path)) != NULL)) {
4053536Sjacobs 			break;
4063536Sjacobs 		}
4073536Sjacobs 		di_devfs_path_free (*minor_path);
4083710Sjacobs 		*minor_path = NULL;
4093536Sjacobs 	}
4103536Sjacobs 	di_devlink_fini (&devlink_hdl);
4112912Sartem }
4122912Sartem 
4132912Sartem static HalDevice *
4146112Sqz150045 devinfo_usb_scsa2usb_add(HalDevice *usbd, di_node_t node)
4152912Sartem {
4162912Sartem 	HalDevice *d = NULL;
4172912Sartem 	di_devlink_handle_t devlink_hdl;
4186112Sqz150045 	int	major;
4196112Sqz150045 	di_minor_t minor;
4206112Sqz150045 	dev_t	devt;
4216112Sqz150045 	char	*minor_path = NULL;
4222912Sartem 	char	*devlink = NULL;
4236112Sqz150045 	char	udi[HAL_PATH_MAX];
4242912Sartem 
4253536Sjacobs 	get_dev_link_path(node, "ddi_ctl:devctl:scsi", NULL,  &devlink, &minor_path);
4262912Sartem 
4273536Sjacobs 	if ((devlink == NULL) || (minor_path == NULL)) {
4282912Sartem 		goto out;
4292912Sartem 	}
4302912Sartem 
4312912Sartem 	d = hal_device_new ();
4322912Sartem 
4332912Sartem 	devinfo_set_default_properties (d, usbd, node, minor_path);
4346112Sqz150045 	hal_device_property_set_string (d, "scsi_host.solaris.device", devlink);
4356112Sqz150045 	hal_device_property_set_string (d, "info.category", "scsi_host");
4366112Sqz150045 	hal_device_property_set_int (d, "scsi_host.host", 0);
4372912Sartem 
4386112Sqz150045 	hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
4396112Sqz150045 	    "%s/scsi_host%d", hal_device_get_udi (usbd),
4406112Sqz150045 	    hal_device_property_get_int (d, "scsi_host.host"));
4416112Sqz150045 	hal_device_set_udi (d, udi);
4426112Sqz150045 	hal_device_property_set_string (d, "info.udi", udi);
4436112Sqz150045 	hal_device_property_set_string (d, "info.product", "SCSI Host Adapter");
4442912Sartem 
4452912Sartem 	devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler);
4462912Sartem 
4472912Sartem out:
4482912Sartem 	if (devlink) {
4492912Sartem 		free(devlink);
4502912Sartem 	}
4512912Sartem 	if (minor_path) {
4522912Sartem 		di_devfs_path_free (minor_path);
4532912Sartem 	}
4542912Sartem 
4552912Sartem 	return (d);
4562912Sartem }
4572912Sartem 
4583536Sjacobs static HalDevice *
4596112Sqz150045 devinfo_usb_printer_add(HalDevice *parent, di_node_t node)
4603536Sjacobs {
461*8529SNorm.Jacobs@Sun.COM 	char *properties[] = { "vendor", "product", "serial", NULL };
462*8529SNorm.Jacobs@Sun.COM 	int i;
4633536Sjacobs 	HalDevice *d = NULL;
4646112Sqz150045 	char	udi[HAL_PATH_MAX];
4653536Sjacobs 	char *s;
4663536Sjacobs 	char *devlink = NULL, *minor_path = NULL;
467*8529SNorm.Jacobs@Sun.COM 	const char	*subsystem;
4683536Sjacobs 
4693536Sjacobs 	get_dev_link_path(node, "ddi_printer", "printers/.+", &devlink, &minor_path);
4703536Sjacobs 
4713536Sjacobs 	if ((devlink == NULL) || (minor_path == NULL)) {
4723536Sjacobs 		goto out;
4733536Sjacobs 	}
4743536Sjacobs 
4753536Sjacobs 	d = hal_device_new ();
4763536Sjacobs 
4773536Sjacobs 	devinfo_set_default_properties (d, parent, node, minor_path);
4786112Sqz150045 	hal_device_property_set_string (d, "info.category", "printer");
4793536Sjacobs 	hal_device_add_capability (d, "printer");
4803536Sjacobs 
4813536Sjacobs 	/* add printer properties */
4826112Sqz150045 	hal_device_property_set_string (d, "printer.device", devlink);
483*8529SNorm.Jacobs@Sun.COM 
484*8529SNorm.Jacobs@Sun.COM 	/* copy parent's selected usb* properties to printer properties */
485*8529SNorm.Jacobs@Sun.COM 	subsystem = hal_device_property_get_string (parent, "info.subsystem");
486*8529SNorm.Jacobs@Sun.COM 	for (i = 0; properties[i] != NULL; i++) {
487*8529SNorm.Jacobs@Sun.COM 		char src[32], dst[32]; /* "subsystem.property" names */
488*8529SNorm.Jacobs@Sun.COM 
489*8529SNorm.Jacobs@Sun.COM 		snprintf(src, sizeof (src), "%s.%s", subsystem, properties[i]);
490*8529SNorm.Jacobs@Sun.COM 		snprintf(dst, sizeof (dst), "printer.%s", properties[i]);
491*8529SNorm.Jacobs@Sun.COM 		hal_device_copy_property(parent, src, d, dst);
492*8529SNorm.Jacobs@Sun.COM 	}
4933536Sjacobs 
4943536Sjacobs 	devinfo_add_enqueue (d, minor_path, &devinfo_usb_printer_handler);
4953536Sjacobs 
4963536Sjacobs out:
4973536Sjacobs 	if (devlink) {
4983536Sjacobs 		free(devlink);
4993536Sjacobs 	}
5003536Sjacobs 	if (minor_path) {
5013536Sjacobs 		di_devfs_path_free (minor_path);
5023536Sjacobs 	}
5033536Sjacobs 
5043536Sjacobs 	return (d);
5053536Sjacobs }
5063536Sjacobs 
5073536Sjacobs const gchar *
5083536Sjacobs devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout)
5093536Sjacobs {
5103536Sjacobs 	*timeout = 5 * 1000;	/* 5 second timeout */
5113536Sjacobs 	return ("hald-probe-printer");
5123536Sjacobs }
513