12912Sartem /***************************************************************************
22912Sartem  *
32912Sartem  * devinfo_usb.h : USB devices
42912Sartem  *
53536Sjacobs  * Copyright 2007 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>
242912Sartem 
252912Sartem #include "../osspec.h"
262912Sartem #include "../logger.h"
272912Sartem #include "../hald.h"
282912Sartem #include "../hald_dbus.h"
292912Sartem #include "../device_info.h"
302912Sartem #include "../util.h"
312912Sartem #include "../ids.h"
322912Sartem #include "hotplug.h"
332912Sartem #include "devinfo.h"
342912Sartem #include "devinfo_usb.h"
352912Sartem 
362912Sartem HalDevice *devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type);
372912Sartem static HalDevice *devinfo_usb_if_add(HalDevice *d, di_node_t node, gchar *devfs_path, int ifnum);
382912Sartem static HalDevice *devinfo_usb_scsa2usb_add(HalDevice *d, di_node_t node, gchar *devfs_path);
393536Sjacobs static HalDevice *devinfo_usb_printer_add(HalDevice *usbd, di_node_t node, gchar *devfs_path);
403536Sjacobs const gchar *devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout);
412912Sartem 
422912Sartem DevinfoDevHandler devinfo_usb_handler = {
432912Sartem         devinfo_usb_add,
442912Sartem 	NULL,
452912Sartem 	NULL,
462912Sartem 	NULL,
472912Sartem 	NULL,
482912Sartem         NULL
492912Sartem };
502912Sartem 
513536Sjacobs DevinfoDevHandler devinfo_usb_printer_handler = {
523536Sjacobs         devinfo_usb_add,
533536Sjacobs 	NULL,
543536Sjacobs 	NULL,
553536Sjacobs 	NULL,
563536Sjacobs 	NULL,
573536Sjacobs         devinfo_printer_prnio_get_prober
583536Sjacobs };
593536Sjacobs 
60*3710Sjacobs static gboolean
61*3710Sjacobs is_usb_node(di_node_t node)
62*3710Sjacobs {
63*3710Sjacobs 	int rc;
64*3710Sjacobs 	char *s;
65*3710Sjacobs 
66*3710Sjacobs 	/*
67*3710Sjacobs 	 * USB device nodes will have "compatible" propety values that
68*3710Sjacobs 	 * begins with "usb".
69*3710Sjacobs 	 */
70*3710Sjacobs         rc = di_prop_lookup_strings(DDI_DEV_T_ANY, node, "compatible", &s);
71*3710Sjacobs 	while (rc-- > 0) {
72*3710Sjacobs 		if (strncmp(s, "usb", 3) == 0) {
73*3710Sjacobs 			return (TRUE);
74*3710Sjacobs 		}
75*3710Sjacobs 		s += (strlen(s) + 1);
76*3710Sjacobs 	}
77*3710Sjacobs 
78*3710Sjacobs 	return (FALSE);
79*3710Sjacobs }
80*3710Sjacobs 
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;
86*3710Sjacobs 	int	*i;
872912Sartem 	char	*driver_name, *binding_name;
882912Sartem         char    if_devfs_path[HAL_PATH_MAX];
892912Sartem 
90*3710Sjacobs         if (is_usb_node(node) == FALSE) {
912912Sartem 		return (NULL);
922912Sartem 	}
932912Sartem 
942912Sartem 	d = hal_device_new ();
952912Sartem 
962912Sartem 	devinfo_set_default_properties (d, parent, node, devfs_path);
972912Sartem 	hal_device_property_set_string (d, "info.bus", "usb_device");
982912Sartem 	PROP_STR(d, node, s, "usb-product-name", "info.product");
992912Sartem 	PROP_STR(d, node, s, "usb-product-name", "usb_device.product");
1002912Sartem 	PROP_STR(d, node, s, "usb-vendor-name", "usb_device.vendor");
1012912Sartem 	PROP_INT(d, node, i, "usb-vendor-id", "usb_device.vendor_id");
1022912Sartem 	PROP_INT(d, node, i, "usb-product-id", "usb_device.product_id");
1032912Sartem 	PROP_INT(d, node, i, "usb-revision-id", "usb_device.device_revision_bcd");
1042912Sartem 	PROP_INT(d, node, i, "usb-release-id", "usb_device.version_bcd");
1052912Sartem 	PROP_STR(d, node, s, "usb-serialno", "usb_device.serial");
1062912Sartem 
1072912Sartem 	/* class, subclass */
1082912Sartem 	/* hal_device_property_set_int (d, "usb_device.device_class", 8); */
1092912Sartem 
1102912Sartem 	/* binding name tells us if driver is bound to interface or device */
1112912Sartem 	if (((binding_name = di_binding_name(node)) != NULL) &&
1122912Sartem 	    (strncmp(binding_name, "usbif,", sizeof ("usbif,") - 1) == 0)) {
1132912Sartem 		snprintf(if_devfs_path, sizeof (if_devfs_path), "%s:if%d", devfs_path, 0);
1142912Sartem 		if ((nd = devinfo_usb_if_add(d, node, if_devfs_path, 0)) != NULL) {
1152912Sartem 			d = nd;
1162912Sartem 			nd = NULL;
1172912Sartem 			devfs_path = if_devfs_path;
1182912Sartem 		}
1192912Sartem 	}
1202912Sartem 
1212912Sartem 	/* driver specific */
1222912Sartem 	driver_name = di_driver_name (node);
1232912Sartem 	if ((driver_name != NULL) && (strcmp (driver_name, "scsa2usb") == 0)) {
1242912Sartem 		nd = devinfo_usb_scsa2usb_add (d, node, devfs_path);
1253536Sjacobs 	} else if ((driver_name != NULL) &&
126*3710Sjacobs 		    (strcmp (driver_name, "usbprn") == 0)) {
1273536Sjacobs 		nd = devinfo_usb_printer_add (d, node, devfs_path);
1282912Sartem 	} else {
1292912Sartem 		devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler);
1302912Sartem 	}
1312912Sartem 
1322912Sartem out:
1332912Sartem 	if (nd != NULL) {
1342912Sartem 		return (nd);
1352912Sartem 	} else {
1362912Sartem 		return (d);
1372912Sartem 	}
1382912Sartem }
1392912Sartem 
1402912Sartem static HalDevice *
1412912Sartem devinfo_usb_if_add(HalDevice *parent, di_node_t node, gchar *devfs_path, int ifnum)
1422912Sartem {
1432912Sartem 	HalDevice *d = NULL;
1442912Sartem         char    udi[HAL_PATH_MAX];
1452912Sartem 
1462912Sartem 	devinfo_add_enqueue (parent, devfs_path, &devinfo_usb_handler);
1472912Sartem 
1482912Sartem 	d = hal_device_new ();
1492912Sartem 
1502912Sartem 	devinfo_set_default_properties (d, parent, node, devfs_path);
1512912Sartem         hal_device_property_set_string (d, "info.bus", "usb");
1522912Sartem         hal_device_property_set_string (d, "info.product", "USB Device Interface");
1532912Sartem 
1542912Sartem 	/* copy parent's usb_device.* properties */
1552912Sartem 	hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
1562912Sartem 
1572912Sartem 	return (d);
1582912Sartem }
1592912Sartem 
1602912Sartem 
1613536Sjacobs static void
1623536Sjacobs get_dev_link_path(di_node_t node, char *nodetype, char *re, char **devlink, char **minor_path)
1633536Sjacobs {
1643536Sjacobs 	di_devlink_handle_t devlink_hdl;
1653536Sjacobs         int     major;
1663536Sjacobs         di_minor_t minor;
1673536Sjacobs         dev_t   devt;
1682912Sartem 
1693536Sjacobs 	*devlink = NULL;
1703536Sjacobs         *minor_path = NULL;
1713536Sjacobs 
1723536Sjacobs         if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
1733536Sjacobs                 printf("di_devlink_init() failed\n");
1743536Sjacobs                 return;
1753536Sjacobs         }
1762912Sartem 
1773536Sjacobs         major = di_driver_major(node);
1783536Sjacobs         minor = DI_MINOR_NIL;
1793536Sjacobs         while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
1803536Sjacobs                 devt = di_minor_devt(minor);
1813536Sjacobs                 if (major != major(devt)) {
1823536Sjacobs                         continue;
1833536Sjacobs                 }
1843536Sjacobs 
1853536Sjacobs                 if (di_minor_type(minor) != DDM_MINOR) {
1863536Sjacobs                         continue;
1873536Sjacobs                 }
1882912Sartem 
1893536Sjacobs                 if ((*minor_path = di_devfs_minor_path(minor)) == NULL) {
1903536Sjacobs                         continue;
1913536Sjacobs                 }
1922912Sartem 
1933536Sjacobs 		if ((strcmp (di_minor_nodetype(minor), nodetype) == 0) &&
1943536Sjacobs 		    ((*devlink = get_devlink(devlink_hdl, re, *minor_path)) != NULL)) {
1953536Sjacobs 			break;
1963536Sjacobs 		}
1973536Sjacobs 		di_devfs_path_free (*minor_path);
198*3710Sjacobs 		*minor_path = NULL;
1993536Sjacobs 	}
2003536Sjacobs 	di_devlink_fini (&devlink_hdl);
2012912Sartem }
2022912Sartem 
2032912Sartem static HalDevice *
2042912Sartem devinfo_usb_scsa2usb_add(HalDevice *usbd, di_node_t node, gchar *devfs_path)
2052912Sartem {
2062912Sartem 	HalDevice *d = NULL;
2072912Sartem 	di_devlink_handle_t devlink_hdl;
2082912Sartem         int     major;
2092912Sartem         di_minor_t minor;
2102912Sartem         dev_t   devt;
2112912Sartem         char    *minor_path = NULL;
2122912Sartem 	char	*devlink = NULL;
2132912Sartem         char    udi[HAL_PATH_MAX];
2142912Sartem 
2152912Sartem 	devinfo_add_enqueue (usbd, devfs_path, &devinfo_usb_handler);
2162912Sartem 
2173536Sjacobs 	get_dev_link_path(node, "ddi_ctl:devctl:scsi", NULL,  &devlink, &minor_path);
2182912Sartem 
2193536Sjacobs 	if ((devlink == NULL) || (minor_path == NULL)) {
2202912Sartem 		goto out;
2212912Sartem 	}
2222912Sartem 
2232912Sartem 	d = hal_device_new ();
2242912Sartem 
2252912Sartem 	devinfo_set_default_properties (d, usbd, node, minor_path);
2262912Sartem        	hal_device_property_set_string (d, "scsi_host.solaris.device", devlink);
2272912Sartem         hal_device_property_set_string (d, "info.category", "scsi_host");
2282912Sartem         hal_device_property_set_int (d, "scsi_host.host", 0);
2292912Sartem 
2302912Sartem         hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
2313121Sartem 		"%s/scsi_host%d", hal_device_get_udi (usbd),
2322912Sartem 		hal_device_property_get_int (d, "scsi_host.host"));
2332912Sartem         hal_device_set_udi (d, udi);
2342912Sartem         hal_device_property_set_string (d, "info.udi", udi);
2352912Sartem         hal_device_property_set_string (d, "info.product", "SCSI Host Adapter");
2362912Sartem 
2372912Sartem 	devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler);
2382912Sartem 
2392912Sartem out:
2402912Sartem 	if (devlink) {
2412912Sartem 		free(devlink);
2422912Sartem 	}
2432912Sartem 	if (minor_path) {
2442912Sartem 		di_devfs_path_free (minor_path);
2452912Sartem 	}
2462912Sartem 
2472912Sartem 	return (d);
2482912Sartem }
2492912Sartem 
2503536Sjacobs static HalDevice *
2513536Sjacobs devinfo_usb_printer_add(HalDevice *parent, di_node_t node, gchar *devfs_path)
2523536Sjacobs {
2533536Sjacobs 	HalDevice *d = NULL;
2543536Sjacobs         char    udi[HAL_PATH_MAX];
2553536Sjacobs 	char *s;
2563536Sjacobs 	char *devlink = NULL, *minor_path = NULL;
2573536Sjacobs 
2583536Sjacobs 	devinfo_add_enqueue (parent, devfs_path, &devinfo_usb_handler);
2593536Sjacobs 
2603536Sjacobs 	get_dev_link_path(node, "ddi_printer", "printers/.+", &devlink, &minor_path);
2613536Sjacobs 
2623536Sjacobs 	if ((devlink == NULL) || (minor_path == NULL)) {
2633536Sjacobs 		goto out;
2643536Sjacobs 	}
2653536Sjacobs 
2663536Sjacobs 	d = hal_device_new ();
2673536Sjacobs 
2683536Sjacobs 	devinfo_set_default_properties (d, parent, node, minor_path);
2693536Sjacobs         hal_device_property_set_string (d, "info.category", "printer");
2703536Sjacobs 	hal_device_add_capability (d, "printer");
2713536Sjacobs 
2723536Sjacobs 	/* copy parent's usb_device.* properties */
2733536Sjacobs 	hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
2743536Sjacobs 
2753536Sjacobs 	/* add printer properties */
2763536Sjacobs         hal_device_property_set_string (d, "printer.device", devlink);
2773536Sjacobs 	PROP_STR(d, node, s, "usb-vendor-name", "printer.vendor");
2783536Sjacobs 	PROP_STR(d, node, s, "usb-product-name", "printer.product");
2793536Sjacobs 	PROP_STR(d, node, s, "usb-serialno", "printer.serial");
2803536Sjacobs 
2813536Sjacobs 	devinfo_add_enqueue (d, minor_path, &devinfo_usb_printer_handler);
2823536Sjacobs 
2833536Sjacobs out:
2843536Sjacobs 	if (devlink) {
2853536Sjacobs 		free(devlink);
2863536Sjacobs 	}
2873536Sjacobs 	if (minor_path) {
2883536Sjacobs 		di_devfs_path_free (minor_path);
2893536Sjacobs 	}
2903536Sjacobs 
2913536Sjacobs 	return (d);
2923536Sjacobs }
2933536Sjacobs 
2943536Sjacobs const gchar *
2953536Sjacobs devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout)
2963536Sjacobs {
2973536Sjacobs 	*timeout = 5 * 1000;	/* 5 second timeout */
2983536Sjacobs 	return ("hald-probe-printer");
2993536Sjacobs }
300