12912Sartem /***************************************************************************
22912Sartem  *
32912Sartem  * devinfo_usb.h : USB devices
42912Sartem  *
52912Sartem  * Copyright 2006 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 
14*3121Sartem #ifdef HAVE_CONFIG_H
15*3121Sartem #  include <config.h>
16*3121Sartem #endif
17*3121Sartem 
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);
392912Sartem 
402912Sartem DevinfoDevHandler devinfo_usb_handler = {
412912Sartem         devinfo_usb_add,
422912Sartem 	NULL,
432912Sartem 	NULL,
442912Sartem 	NULL,
452912Sartem 	NULL,
462912Sartem         NULL
472912Sartem };
482912Sartem 
492912Sartem HalDevice *
502912Sartem devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
512912Sartem {
522912Sartem 	HalDevice *d, *nd = NULL;
532912Sartem 	char	*s;
542912Sartem 	int	*i, *vid;
552912Sartem 	char	*driver_name, *binding_name;
562912Sartem         char    if_devfs_path[HAL_PATH_MAX];
572912Sartem 
582912Sartem 	/*
592912Sartem 	 * we distinguish USB devices by presence of "usb-vendor-id"
602912Sartem 	 * property. should USB devices have "device_type"?
612912Sartem 	 */
622912Sartem         if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "usb-vendor-id", &vid) <= 0) {
632912Sartem 		return (NULL);
642912Sartem 	}
652912Sartem 
662912Sartem 	d = hal_device_new ();
672912Sartem 
682912Sartem 	devinfo_set_default_properties (d, parent, node, devfs_path);
692912Sartem 	hal_device_property_set_string (d, "info.bus", "usb_device");
702912Sartem 	PROP_STR(d, node, s, "usb-product-name", "info.product");
712912Sartem 	PROP_STR(d, node, s, "usb-product-name", "usb_device.product");
722912Sartem 	PROP_STR(d, node, s, "usb-vendor-name", "usb_device.vendor");
732912Sartem 	PROP_INT(d, node, i, "usb-vendor-id", "usb_device.vendor_id");
742912Sartem 	PROP_INT(d, node, i, "usb-product-id", "usb_device.product_id");
752912Sartem 	PROP_INT(d, node, i, "usb-revision-id", "usb_device.device_revision_bcd");
762912Sartem 	PROP_INT(d, node, i, "usb-release-id", "usb_device.version_bcd");
772912Sartem 	PROP_STR(d, node, s, "usb-serialno", "usb_device.serial");
782912Sartem 
792912Sartem 	/* class, subclass */
802912Sartem 	/* hal_device_property_set_int (d, "usb_device.device_class", 8); */
812912Sartem 
822912Sartem 	/* binding name tells us if driver is bound to interface or device */
832912Sartem 	if (((binding_name = di_binding_name(node)) != NULL) &&
842912Sartem 	    (strncmp(binding_name, "usbif,", sizeof ("usbif,") - 1) == 0)) {
852912Sartem 		snprintf(if_devfs_path, sizeof (if_devfs_path), "%s:if%d", devfs_path, 0);
862912Sartem 		if ((nd = devinfo_usb_if_add(d, node, if_devfs_path, 0)) != NULL) {
872912Sartem 			d = nd;
882912Sartem 			nd = NULL;
892912Sartem 			devfs_path = if_devfs_path;
902912Sartem 		}
912912Sartem 	}
922912Sartem 
932912Sartem 	/* driver specific */
942912Sartem 	driver_name = di_driver_name (node);
952912Sartem 	if ((driver_name != NULL) && (strcmp (driver_name, "scsa2usb") == 0)) {
962912Sartem 		nd = devinfo_usb_scsa2usb_add (d, node, devfs_path);
972912Sartem 	} else {
982912Sartem 		devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler);
992912Sartem 	}
1002912Sartem 
1012912Sartem out:
1022912Sartem 	if (nd != NULL) {
1032912Sartem 		return (nd);
1042912Sartem 	} else {
1052912Sartem 		return (d);
1062912Sartem 	}
1072912Sartem }
1082912Sartem 
1092912Sartem static HalDevice *
1102912Sartem devinfo_usb_if_add(HalDevice *parent, di_node_t node, gchar *devfs_path, int ifnum)
1112912Sartem {
1122912Sartem 	HalDevice *d = NULL;
1132912Sartem         char    udi[HAL_PATH_MAX];
1142912Sartem 
1152912Sartem 	devinfo_add_enqueue (parent, devfs_path, &devinfo_usb_handler);
1162912Sartem 
1172912Sartem 	d = hal_device_new ();
1182912Sartem 
1192912Sartem 	devinfo_set_default_properties (d, parent, node, devfs_path);
1202912Sartem         hal_device_property_set_string (d, "info.bus", "usb");
1212912Sartem 
1222912Sartem         hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
123*3121Sartem 		"%s_if%d", hal_device_get_udi (parent), ifnum);
1242912Sartem         hal_device_set_udi (d, udi);
1252912Sartem         hal_device_property_set_string (d, "info.udi", udi);
1262912Sartem         hal_device_property_set_string (d, "info.product", "USB Device Interface");
1272912Sartem 
1282912Sartem 	/* copy parent's usb_device.* properties */
1292912Sartem 	hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
1302912Sartem 
1312912Sartem 	return (d);
1322912Sartem }
1332912Sartem 
1342912Sartem static int
1352912Sartem walk_devlinks(di_devlink_t devlink, void *arg)
1362912Sartem {
1372912Sartem         char **path = (char **)arg;
1382912Sartem 
1392912Sartem         *path = strdup(di_devlink_path(devlink));
1402912Sartem 
1412912Sartem         return (DI_WALK_TERMINATE);
1422912Sartem }
1432912Sartem 
1442912Sartem static char *
1452912Sartem get_devlink(di_devlink_handle_t devlink_hdl, char *path)
1462912Sartem {
1472912Sartem 	char *devlink = NULL;
1482912Sartem 
1492912Sartem         (void) di_devlink_walk(devlink_hdl, NULL, path,
1502912Sartem             DI_PRIMARY_LINK, &devlink, walk_devlinks);
1512912Sartem 
1522912Sartem         return (devlink);
1532912Sartem }
1542912Sartem 
1552912Sartem static HalDevice *
1562912Sartem devinfo_usb_scsa2usb_add(HalDevice *usbd, di_node_t node, gchar *devfs_path)
1572912Sartem {
1582912Sartem 	HalDevice *d = NULL;
1592912Sartem 	di_devlink_handle_t devlink_hdl;
1602912Sartem         int     major;
1612912Sartem         di_minor_t minor;
1622912Sartem         dev_t   devt;
1632912Sartem         char    *minor_path = NULL;
1642912Sartem 	char	*devlink = NULL;
1652912Sartem         char    udi[HAL_PATH_MAX];
1662912Sartem 
1672912Sartem 	devinfo_add_enqueue (usbd, devfs_path, &devinfo_usb_handler);
1682912Sartem 
1692912Sartem         if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
1702912Sartem                 printf("di_devlink_init() failed\n");
1712912Sartem                 return (NULL);
1722912Sartem         }
1732912Sartem 
1742912Sartem         major = di_driver_major(node);
1752912Sartem         minor = DI_MINOR_NIL;
1762912Sartem         while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
1772912Sartem                 devt = di_minor_devt(minor);
1782912Sartem                 if (major != major(devt)) {
1792912Sartem                         continue;
1802912Sartem                 }
1812912Sartem                 if ((minor_path = di_devfs_minor_path(minor)) == NULL) {
1822912Sartem                         continue;
1832912Sartem                 }
1842912Sartem                 if (di_minor_type(minor) != DDM_MINOR) {
1852912Sartem                         continue;
1862912Sartem                 }
1872912Sartem 		if (strcmp (di_minor_nodetype(minor),
1882912Sartem 		    "ddi_ctl:devctl:scsi") == 0) {
1892912Sartem                 	devlink = get_devlink(devlink_hdl, minor_path);
1902912Sartem                 	if (devlink == NULL) {
1912912Sartem 				devlink = strdup("");
1922912Sartem 			}
1932912Sartem 			break;
1942912Sartem 		}
1952912Sartem 		di_devfs_path_free (minor_path);
1962912Sartem 		minor_path = NULL;
1972912Sartem         }
1982912Sartem 
1992912Sartem 	di_devlink_fini (&devlink_hdl);
2002912Sartem 
2012912Sartem 	if (devlink == NULL) {
2022912Sartem 		goto out;
2032912Sartem 	}
2042912Sartem 
2052912Sartem 	d = hal_device_new ();
2062912Sartem 
2072912Sartem 	devinfo_set_default_properties (d, usbd, node, minor_path);
2082912Sartem        	hal_device_property_set_string (d, "scsi_host.solaris.device", devlink);
2092912Sartem         hal_device_property_set_string (d, "info.category", "scsi_host");
2102912Sartem         hal_device_property_set_int (d, "scsi_host.host", 0);
2112912Sartem 
2122912Sartem         hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
213*3121Sartem 		"%s/scsi_host%d", hal_device_get_udi (usbd),
2142912Sartem 		hal_device_property_get_int (d, "scsi_host.host"));
2152912Sartem         hal_device_set_udi (d, udi);
2162912Sartem         hal_device_property_set_string (d, "info.udi", udi);
2172912Sartem         hal_device_property_set_string (d, "info.product", "SCSI Host Adapter");
2182912Sartem 
2192912Sartem 	devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler);
2202912Sartem 
2212912Sartem out:
2222912Sartem 	if (devlink) {
2232912Sartem 		free(devlink);
2242912Sartem 	}
2252912Sartem 	if (minor_path) {
2262912Sartem 		di_devfs_path_free (minor_path);
2272912Sartem 	}
2282912Sartem 
2292912Sartem 	return (d);
2302912Sartem }
2312912Sartem 
232