12912Sartem /***************************************************************************
22912Sartem *
32912Sartem * devinfo_usb.h : USB devices
42912Sartem *
58529SNorm.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>
199608SLin.Guo@Sun.COM #include <unistd.h>
209608SLin.Guo@Sun.COM #include <dirent.h>
212912Sartem #include <sys/types.h>
222912Sartem #include <sys/mkdev.h>
232912Sartem #include <sys/stat.h>
246112Sqz150045 #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
376112Sqz150045 static HalDevice *devinfo_usb_if_add(HalDevice *d, di_node_t node, gchar *devfs_path,
386112Sqz150045 gchar *if_devfs_path, int ifnum);
396112Sqz150045 static HalDevice *devinfo_usb_scsa2usb_add(HalDevice *d, di_node_t node);
406112Sqz150045 static HalDevice *devinfo_usb_printer_add(HalDevice *usbd, di_node_t node);
419608SLin.Guo@Sun.COM static HalDevice *devinfo_usb_input_add(HalDevice *usbd, di_node_t node);
429794SLin.Guo@Sun.COM static HalDevice *devinfo_usb_video4linux_add(HalDevice *usbd, di_node_t node);
439608SLin.Guo@Sun.COM const gchar *devinfo_printer_prnio_get_prober(HalDevice *d, int *timeout);
449608SLin.Guo@Sun.COM const gchar *devinfo_keyboard_get_prober(HalDevice *d, int *timeout);
456112Sqz150045 static void set_usb_properties(HalDevice *d, di_node_t node, gchar *devfs_path, char *driver_name);
462912Sartem
472912Sartem DevinfoDevHandler devinfo_usb_handler = {
486112Sqz150045 devinfo_usb_add,
492912Sartem NULL,
502912Sartem NULL,
512912Sartem NULL,
522912Sartem NULL,
536112Sqz150045 NULL
542912Sartem };
552912Sartem
563536Sjacobs DevinfoDevHandler devinfo_usb_printer_handler = {
576112Sqz150045 devinfo_usb_add,
583536Sjacobs NULL,
593536Sjacobs NULL,
603536Sjacobs NULL,
613536Sjacobs NULL,
626112Sqz150045 devinfo_printer_prnio_get_prober
633536Sjacobs };
643536Sjacobs
659608SLin.Guo@Sun.COM DevinfoDevHandler devinfo_usb_keyboard_handler = {
669608SLin.Guo@Sun.COM devinfo_usb_add,
679608SLin.Guo@Sun.COM NULL,
689608SLin.Guo@Sun.COM NULL,
699608SLin.Guo@Sun.COM NULL,
709608SLin.Guo@Sun.COM NULL,
719608SLin.Guo@Sun.COM devinfo_keyboard_get_prober
729608SLin.Guo@Sun.COM };
739608SLin.Guo@Sun.COM
743710Sjacobs static gboolean
is_usb_node(di_node_t node)753710Sjacobs is_usb_node(di_node_t node)
763710Sjacobs {
773710Sjacobs int rc;
783710Sjacobs char *s;
793710Sjacobs
803710Sjacobs /*
813710Sjacobs * USB device nodes will have "compatible" propety values that
823710Sjacobs * begins with "usb".
833710Sjacobs */
846112Sqz150045 rc = di_prop_lookup_strings(DDI_DEV_T_ANY, node, "compatible", &s);
853710Sjacobs while (rc-- > 0) {
863710Sjacobs if (strncmp(s, "usb", 3) == 0) {
873710Sjacobs return (TRUE);
883710Sjacobs }
893710Sjacobs s += (strlen(s) + 1);
903710Sjacobs }
913710Sjacobs
923710Sjacobs return (FALSE);
933710Sjacobs }
943710Sjacobs
959608SLin.Guo@Sun.COM static char *
get_usb_devlink(char * devfs_path,const char * dir_name)969794SLin.Guo@Sun.COM get_usb_devlink(char *devfs_path, const char *dir_name)
979608SLin.Guo@Sun.COM {
989608SLin.Guo@Sun.COM char *result = NULL;
999608SLin.Guo@Sun.COM DIR *dp;
1009608SLin.Guo@Sun.COM
1019794SLin.Guo@Sun.COM if ((dp = opendir(dir_name)) != NULL) {
1029608SLin.Guo@Sun.COM struct dirent *ep;
1039608SLin.Guo@Sun.COM
1049608SLin.Guo@Sun.COM while ((ep = readdir(dp)) != NULL) {
1059608SLin.Guo@Sun.COM char path[MAXPATHLEN], lpath[MAXPATHLEN];
1069608SLin.Guo@Sun.COM
1079794SLin.Guo@Sun.COM strncpy(path, dir_name, strlen(dir_name));
1089794SLin.Guo@Sun.COM strncat(path, ep->d_name, strlen(ep->d_name));
1099608SLin.Guo@Sun.COM memset(lpath, 0, sizeof (lpath));
1109608SLin.Guo@Sun.COM if ((readlink(path, lpath, sizeof (lpath)) > 0) &&
1119608SLin.Guo@Sun.COM (strstr(lpath, devfs_path) != NULL)) {
1129608SLin.Guo@Sun.COM result = strdup(path);
1139608SLin.Guo@Sun.COM break;
1149608SLin.Guo@Sun.COM }
1159794SLin.Guo@Sun.COM memset(path, 0, sizeof (path));
1169608SLin.Guo@Sun.COM }
1179608SLin.Guo@Sun.COM closedir(dp);
1189608SLin.Guo@Sun.COM }
1199608SLin.Guo@Sun.COM
1209608SLin.Guo@Sun.COM return (result);
1219608SLin.Guo@Sun.COM }
1229608SLin.Guo@Sun.COM
1232912Sartem HalDevice *
devinfo_usb_add(HalDevice * parent,di_node_t node,char * devfs_path,char * device_type)1242912Sartem devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type)
1252912Sartem {
1262912Sartem HalDevice *d, *nd = NULL;
1272912Sartem char *s;
1283710Sjacobs int *i;
1292912Sartem char *driver_name, *binding_name;
1306112Sqz150045 char if_devfs_path[HAL_PATH_MAX];
1316112Sqz150045 di_devlink_handle_t hdl;
1326112Sqz150045 double k;
1332912Sartem
1346112Sqz150045 if (is_usb_node(node) == FALSE) {
1352912Sartem return (NULL);
1362912Sartem }
1372912Sartem
1386112Sqz150045 driver_name = di_driver_name (node);
1396112Sqz150045
1406112Sqz150045 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "interface", &i) < 0) {
1416112Sqz150045 /* It is a USB device node. */
1426112Sqz150045
1436112Sqz150045 d = hal_device_new ();
1442912Sartem
1456112Sqz150045 devinfo_set_default_properties (d, parent, node, devfs_path);
1466112Sqz150045 hal_device_property_set_string (d, "info.subsystem", "usb_device");
1476112Sqz150045 PROP_STR(d, node, s, "usb-product-name", "info.product");
1486112Sqz150045 PROP_STR(d, node, s, "usb-product-name", "usb_device.product");
1496112Sqz150045 PROP_STR(d, node, s, "usb-vendor-name", "usb_device.vendor");
1506112Sqz150045 PROP_INT(d, node, i, "usb-vendor-id", "usb_device.vendor_id");
1516112Sqz150045 PROP_INT(d, node, i, "usb-product-id", "usb_device.product_id");
1526112Sqz150045 PROP_INT(d, node, i, "usb-revision-id", "usb_device.device_revision_bcd");
1536112Sqz150045 PROP_STR(d, node, s, "usb-serialno", "usb_device.serial");
1546112Sqz150045 PROP_INT(d, node, i, "usb-port-count", "usb_device.num_ports");
1556112Sqz150045 PROP_INT(d, node, i, "usb-num-configs", "usb_device.num_configurations");
1566112Sqz150045 PROP_INT(d, node, i, "assigned-address", "usb_device.bus_number");
1576112Sqz150045
1586112Sqz150045 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "usb-release", &i) > 0) {
1596112Sqz150045 k = (double)bcd(*i);
1606112Sqz150045 hal_device_property_set_double (d, "usb_device.version", k / 100);
1616112Sqz150045 }
1626112Sqz150045
1636112Sqz150045 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "low-speed", &i) >= 0) {
1646112Sqz150045 k = 1.5;
1656112Sqz150045 } else if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "high-speed", &i) >= 0) {
1666112Sqz150045 k = 480.0;
1676112Sqz150045 } else {
1686112Sqz150045 /* It is the full speed device. */
1696112Sqz150045 k = 12.0;
1706112Sqz150045 }
1716112Sqz150045 hal_device_property_set_double (d, "usb_device.speed", k);
1726112Sqz150045
1736112Sqz150045 set_usb_properties (d, node, devfs_path, driver_name);
1742912Sartem
1756112Sqz150045 /* wait for the ugen node's creation */
1766112Sqz150045 if ((driver_name != NULL) && (strcmp (driver_name, "usb_mid") == 0)) {
1776112Sqz150045 if (hdl = di_devlink_init (devfs_path, DI_MAKE_LINK)) {
1786112Sqz150045 di_devlink_fini (&hdl);
1796112Sqz150045 }
1806112Sqz150045 }
1816112Sqz150045
1826112Sqz150045 devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler);
1836112Sqz150045
1846112Sqz150045 /* add to TDL so preprobing callouts and prober can access it */
1856112Sqz150045 hal_device_store_add (hald_get_tdl (), d);
1866112Sqz150045
1876112Sqz150045 if (((binding_name = di_binding_name (node)) != NULL) &&
1886112Sqz150045 (strncmp (binding_name, "usbif,", sizeof ("usbif,") - 1) == 0)) {
1896112Sqz150045
1906112Sqz150045 snprintf (if_devfs_path, sizeof (if_devfs_path), "%s:if%d",
1919608SLin.Guo@Sun.COM devfs_path, 0);
1926112Sqz150045 if ((nd = devinfo_usb_if_add (d, node, if_devfs_path,
1939608SLin.Guo@Sun.COM if_devfs_path, 0)) != NULL) {
1946112Sqz150045 d = nd;
1956112Sqz150045 nd = NULL;
1966112Sqz150045 devfs_path = if_devfs_path;
1976112Sqz150045 }
1982912Sartem }
1996112Sqz150045 } else {
2006112Sqz150045 /* It is a USB interface node or IA node. */
2016112Sqz150045 int *j;
2026112Sqz150045
2036112Sqz150045 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "interface-count", &j) > 0) {
2046112Sqz150045 /*
2056112Sqz150045 * The USB IA node properties are not defined in
2066112Sqz150045 * HAL spec so far. So IA node udi has "ia" sign
2076112Sqz150045 * now, different from the IF node udi with "if".
2086112Sqz150045 */
2096112Sqz150045 snprintf (if_devfs_path, sizeof (if_devfs_path),
2106112Sqz150045 "%s:ia%d", devfs_path, *i);
2116112Sqz150045 } else {
2126112Sqz150045 snprintf (if_devfs_path, sizeof (if_devfs_path),
2136112Sqz150045 "%s:if%d", devfs_path, *i);
2146112Sqz150045 }
2156112Sqz150045
2166112Sqz150045 d = devinfo_usb_if_add (parent, node, devfs_path, if_devfs_path, *i);
2172912Sartem }
2182912Sartem
2192912Sartem /* driver specific */
2209608SLin.Guo@Sun.COM if (driver_name != NULL) {
2219608SLin.Guo@Sun.COM if (strcmp (driver_name, "scsa2usb") == 0) {
2229608SLin.Guo@Sun.COM nd = devinfo_usb_scsa2usb_add (d, node);
2239608SLin.Guo@Sun.COM } else if (strcmp (driver_name, "usbprn") == 0) {
2249608SLin.Guo@Sun.COM nd = devinfo_usb_printer_add (d, node);
2259608SLin.Guo@Sun.COM } else if (strcmp(driver_name, "hid") == 0) {
2269608SLin.Guo@Sun.COM if (hdl = di_devlink_init(devfs_path, DI_MAKE_LINK)) {
2279608SLin.Guo@Sun.COM di_devlink_fini(&hdl);
2289608SLin.Guo@Sun.COM }
2299608SLin.Guo@Sun.COM nd = devinfo_usb_input_add(d, node);
2309794SLin.Guo@Sun.COM } else if (strcmp(driver_name, "usbvc") == 0) {
2319794SLin.Guo@Sun.COM if (hdl = di_devlink_init(devfs_path, DI_MAKE_LINK)) {
2329794SLin.Guo@Sun.COM di_devlink_fini(&hdl);
2339794SLin.Guo@Sun.COM }
2349794SLin.Guo@Sun.COM nd = devinfo_usb_video4linux_add(d, node);
2359608SLin.Guo@Sun.COM }
2362912Sartem }
2372912Sartem
2382912Sartem out:
2392912Sartem if (nd != NULL) {
2402912Sartem return (nd);
2412912Sartem } else {
2422912Sartem return (d);
2432912Sartem }
2442912Sartem }
2452912Sartem
2466112Sqz150045
2476112Sqz150045 static void
set_usb_properties(HalDevice * d,di_node_t node,gchar * devfs_path,char * driver_name)2486112Sqz150045 set_usb_properties(HalDevice *d, di_node_t node, gchar *devfs_path, char *driver_name)
2496112Sqz150045 {
2506112Sqz150045 usb_dev_descr_t *dev_descrp = NULL; /* device descriptor */
2516112Sqz150045 usb_cfg_descr_t *cfg_descrp = NULL; /* configuration descriptor */
2526112Sqz150045 unsigned char *rdata = NULL;
2536112Sqz150045 char *p;
2546112Sqz150045 int i = 0;
2556112Sqz150045
2566112Sqz150045 hal_device_property_set_int (d, "usb_device.port_number",
2576112Sqz150045 atoi (devfs_path + strlen (devfs_path) -1));
2586112Sqz150045
2596112Sqz150045 if (di_prop_lookup_bytes (DDI_DEV_T_ANY, node, "usb-dev-descriptor",
2606112Sqz150045 &rdata) > 0) {
2616112Sqz150045 dev_descrp = (usb_dev_descr_t *)rdata;
2626112Sqz150045
2636112Sqz150045 if (dev_descrp != NULL) {
2646112Sqz150045 hal_device_property_set_int (d, "usb_device.device_class",
2656112Sqz150045 dev_descrp->bDeviceClass);
2666112Sqz150045 hal_device_property_set_int (d, "usb_device.device_subclass",
2676112Sqz150045 dev_descrp->bDeviceSubClass);
2686112Sqz150045 hal_device_property_set_int (d, "usb_device.device_protocol",
2696112Sqz150045 dev_descrp->bDeviceProtocol);
2706112Sqz150045 }
2716112Sqz150045 }
2726112Sqz150045
2736112Sqz150045 if (di_prop_lookup_bytes (DDI_DEV_T_ANY, node, "usb-raw-cfg-descriptors",
2746112Sqz150045 &rdata) > 0) {
2756112Sqz150045 cfg_descrp = (usb_cfg_descr_t *)(rdata);
2766112Sqz150045
2776112Sqz150045 if (cfg_descrp != NULL) {
2786112Sqz150045 hal_device_property_set_int (d, "usb_device.configuration_value",
2796112Sqz150045 cfg_descrp->bConfigurationValue);
2806112Sqz150045 hal_device_property_set_int (d, "usb_device.max_power",
2816112Sqz150045 cfg_descrp->bMaxPower);
2826112Sqz150045 hal_device_property_set_int (d, "usb_device.num_interfaces",
2836112Sqz150045 cfg_descrp->bNumInterfaces);
2846112Sqz150045 hal_device_property_set_bool (d, "usb_device.can_wake_up",
2856112Sqz150045 (cfg_descrp->bmAttributes & 0x20) ? TRUE : FALSE);
2866112Sqz150045 hal_device_property_set_bool (d, "usb_device.is_self_powered",
2876112Sqz150045 (cfg_descrp->bmAttributes & 0x40) ? TRUE : FALSE);
2886112Sqz150045 }
2896112Sqz150045 }
2906112Sqz150045
2916112Sqz150045 /* get the node's usb tree level by counting hub numbers */
2926112Sqz150045 do {
2936112Sqz150045 if (p = strstr (devfs_path, "/hub@")) {
2946112Sqz150045 devfs_path = p + strlen ("/hub@");
2956112Sqz150045 i ++;
2966112Sqz150045 }
2976112Sqz150045 } while (p != NULL);
2986112Sqz150045
2996112Sqz150045 if ((driver_name != NULL) && (strcmp (driver_name, "hubd") == 0) && (i > 0))
3006112Sqz150045 i --;
3016112Sqz150045
3026112Sqz150045 hal_device_property_set_int (d, "usb_device.level_number", i);
3036112Sqz150045 }
3046112Sqz150045
3056112Sqz150045
3066112Sqz150045 static usb_if_descr_t *
parse_usb_if_descr(di_node_t node,int ifnum)3076112Sqz150045 parse_usb_if_descr(di_node_t node, int ifnum)
3082912Sartem {
3096112Sqz150045 unsigned char *rdata = NULL;
3106112Sqz150045 usb_if_descr_t *if_descrp=NULL; /* interface descriptor */
3119608SLin.Guo@Sun.COM di_node_t tmp_node = DI_NODE_NIL;
3126112Sqz150045 uint8_t num, length, type;
3136112Sqz150045 int rlen;
3146112Sqz150045 gchar *devpath = NULL;
3156112Sqz150045
3166112Sqz150045 if ((rlen = di_prop_lookup_bytes (DDI_DEV_T_ANY, node,
3176112Sqz150045 "usb-raw-cfg-descriptors", &rdata)) < 0) {
3186112Sqz150045
3196112Sqz150045 char *p;
3206112Sqz150045 int i;
3216112Sqz150045
3226112Sqz150045 if ((devpath = di_devfs_path (node)) == NULL)
3236112Sqz150045 goto out;
3246112Sqz150045
3256112Sqz150045 /* Look up its parent that may be a USB IA or USB mid. */
3266112Sqz150045 for (i = 0; i < 2; i++) {
3276112Sqz150045 p = strrchr (devpath, '/');
3286112Sqz150045 if (p == NULL)
3296112Sqz150045 goto out;
3306112Sqz150045 *p = '\0';
3319794SLin.Guo@Sun.COM
3326112Sqz150045 if ((tmp_node = di_init (devpath, DINFOCPYALL)) == DI_NODE_NIL)
3336112Sqz150045 goto out;
3346112Sqz150045
3356112Sqz150045 if ((rlen = di_prop_lookup_bytes (DDI_DEV_T_ANY, tmp_node,
3366112Sqz150045 "usb-raw-cfg-descriptors", &rdata)) > 0)
3376112Sqz150045 break;
3386112Sqz150045
3396112Sqz150045 di_fini (tmp_node);
3406112Sqz150045 }
3416112Sqz150045 }
3422912Sartem
3436112Sqz150045 if (rdata == NULL)
3446112Sqz150045 goto out;
3456112Sqz150045
3466112Sqz150045 do {
3476112Sqz150045 length = (uint8_t)*rdata;
3486112Sqz150045 type = (uint8_t)*(rdata + 1);
3496112Sqz150045 if (type == USB_DESCR_TYPE_IF) {
3506112Sqz150045 num = (uint8_t)*(rdata + 2);
3516112Sqz150045 if (num == ifnum) {
3526112Sqz150045 if_descrp = (usb_if_descr_t *)rdata;
3536112Sqz150045 break;
3546112Sqz150045 }
3556112Sqz150045 }
3566112Sqz150045 rdata += length;
3576112Sqz150045 rlen -= length;
3586112Sqz150045 } while ((length > 0 ) && (rlen > 0));
3596112Sqz150045
3606112Sqz150045 out:
3616112Sqz150045 if (devpath != NULL)
3626112Sqz150045 di_devfs_path_free (devpath);
3636112Sqz150045 if (tmp_node != DI_NODE_NIL)
3646112Sqz150045 di_fini (tmp_node);
3656112Sqz150045 return (if_descrp);
3666112Sqz150045 }
3676112Sqz150045
3686112Sqz150045
3696112Sqz150045 static HalDevice *
devinfo_usb_if_add(HalDevice * parent,di_node_t node,gchar * devfs_path,gchar * if_devfs_path,int ifnum)3706112Sqz150045 devinfo_usb_if_add(HalDevice *parent, di_node_t node, gchar *devfs_path,
3716112Sqz150045 gchar *if_devfs_path, int ifnum)
3726112Sqz150045 {
3736112Sqz150045 HalDevice *d = NULL;
3746112Sqz150045 char udi[HAL_PATH_MAX];
3756112Sqz150045 const char *parent_info;
3766112Sqz150045 usb_if_descr_t *if_descrp=NULL; /* interface descriptor */
3772912Sartem
3782912Sartem d = hal_device_new ();
3792912Sartem
3806112Sqz150045 devinfo_set_default_properties (d, parent, node, if_devfs_path);
3816112Sqz150045
3826112Sqz150045 /* Set the existed physical device path. */
3836112Sqz150045 hal_device_property_set_string (d, "solaris.devfs_path", devfs_path);
3846112Sqz150045 hal_device_property_set_string (d, "info.subsystem", "usb");
3856112Sqz150045 hal_device_property_set_string (d, "info.product", "USB Device Interface");
3866112Sqz150045
3876112Sqz150045 /* Set usb interface properties to interface node. */
3886112Sqz150045 if (strstr (if_devfs_path, ":ia") == NULL) {
3896112Sqz150045 if_descrp = parse_usb_if_descr (node, ifnum);
3906112Sqz150045
3916112Sqz150045 if (if_descrp != NULL) {
3926112Sqz150045 hal_device_property_set_int (d, "usb.interface.class",
3936112Sqz150045 if_descrp->bInterfaceClass);
3946112Sqz150045 hal_device_property_set_int (d, "usb.interface.subclass",
3956112Sqz150045 if_descrp->bInterfaceSubClass);
3966112Sqz150045 hal_device_property_set_int (d, "usb.interface.protocol",
3976112Sqz150045 if_descrp->bInterfaceProtocol);
3986112Sqz150045 hal_device_property_set_int (d, "usb.interface.number",
3996112Sqz150045 if_descrp->bInterfaceNumber);
4006112Sqz150045 }
4016112Sqz150045 }
4022912Sartem
4032912Sartem /* copy parent's usb_device.* properties */
4046112Sqz150045 parent_info = hal_device_property_get_string (parent, "info.subsystem");
4056112Sqz150045 if (parent_info != NULL) {
4066112Sqz150045 if (strcmp (parent_info, "usb_device") == 0) {
4076112Sqz150045 hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device.");
4086112Sqz150045 } else if (strcmp (parent_info, "usb") == 0) {
4096112Sqz150045 /* for the case that the parent is IA node */
4106112Sqz150045 hal_device_merge_with_rewrite (d, parent, "usb.", "usb.");
4116112Sqz150045 }
4126112Sqz150045 }
4136112Sqz150045
4146112Sqz150045 devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler);
4156112Sqz150045
4166112Sqz150045 /* add to TDL so preprobing callouts and prober can access it */
4176112Sqz150045 hal_device_store_add (hald_get_tdl (), d);
4182912Sartem
4192912Sartem return (d);
4202912Sartem }
4212912Sartem
4222912Sartem
4233536Sjacobs static void
get_dev_link_path(di_node_t node,char * nodetype,char * re,char ** devlink,char ** minor_path,char ** minor_name)4249608SLin.Guo@Sun.COM get_dev_link_path(di_node_t node, char *nodetype, char *re, char **devlink, char **minor_path, char **minor_name)
4253536Sjacobs {
4263536Sjacobs di_devlink_handle_t devlink_hdl;
4276112Sqz150045 int major;
4286112Sqz150045 di_minor_t minor;
4296112Sqz150045 dev_t devt;
4302912Sartem
4313536Sjacobs *devlink = NULL;
4326112Sqz150045 *minor_path = NULL;
4339608SLin.Guo@Sun.COM *minor_name = NULL;
4343536Sjacobs
4356112Sqz150045 if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) {
4366112Sqz150045 return;
4376112Sqz150045 }
4382912Sartem
4396112Sqz150045 major = di_driver_major(node);
4406112Sqz150045 minor = DI_MINOR_NIL;
4416112Sqz150045 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) {
4426112Sqz150045 devt = di_minor_devt(minor);
4436112Sqz150045 if (major != major(devt)) {
4446112Sqz150045 continue;
4456112Sqz150045 }
4463536Sjacobs
4476112Sqz150045 if (di_minor_type(minor) != DDM_MINOR) {
4486112Sqz150045 continue;
4496112Sqz150045 }
4502912Sartem
4516112Sqz150045 if ((*minor_path = di_devfs_minor_path(minor)) == NULL) {
4526112Sqz150045 continue;
4536112Sqz150045 }
4542912Sartem
4559608SLin.Guo@Sun.COM if (strcmp(di_minor_nodetype(minor), nodetype) == 0) {
4569608SLin.Guo@Sun.COM *devlink = get_devlink(devlink_hdl, re, *minor_path);
4579608SLin.Guo@Sun.COM /*
4589794SLin.Guo@Sun.COM * During hotplugging, devlink could be NULL for usb
4599608SLin.Guo@Sun.COM * devices due to devlink database has not yet been
4609608SLin.Guo@Sun.COM * updated when hal try to read from it although the
4619608SLin.Guo@Sun.COM * actually dev link path has been created. In such a
4629608SLin.Guo@Sun.COM * situation, we will read the devlink name from
4639608SLin.Guo@Sun.COM * /dev/usb directory.
4649608SLin.Guo@Sun.COM */
465*10975SRaymond.Chen@Sun.COM if ((*devlink == NULL) && (re != NULL) &&
4669794SLin.Guo@Sun.COM ((strstr(re, "hid") != NULL) || (strstr(re, "video") != NULL))) {
4679794SLin.Guo@Sun.COM *devlink = get_usb_devlink(*minor_path, "/dev/usb/");
4689608SLin.Guo@Sun.COM }
4699608SLin.Guo@Sun.COM
4709608SLin.Guo@Sun.COM if (*devlink != NULL) {
4719608SLin.Guo@Sun.COM *minor_name = di_minor_name(minor);
4729608SLin.Guo@Sun.COM break;
4739608SLin.Guo@Sun.COM }
4743536Sjacobs }
4759608SLin.Guo@Sun.COM
4763536Sjacobs di_devfs_path_free (*minor_path);
4773710Sjacobs *minor_path = NULL;
4783536Sjacobs }
4793536Sjacobs di_devlink_fini (&devlink_hdl);
4802912Sartem }
4812912Sartem
4822912Sartem static HalDevice *
devinfo_usb_video4linux_add(HalDevice * usbd,di_node_t node)4839794SLin.Guo@Sun.COM devinfo_usb_video4linux_add(HalDevice *usbd, di_node_t node)
4849794SLin.Guo@Sun.COM {
4859794SLin.Guo@Sun.COM HalDevice *d = NULL;
4869794SLin.Guo@Sun.COM int major;
4879794SLin.Guo@Sun.COM di_minor_t minor;
4889794SLin.Guo@Sun.COM dev_t devt;
4899794SLin.Guo@Sun.COM char *devlink = NULL;
4909794SLin.Guo@Sun.COM char *dev_videolink = NULL;
4919794SLin.Guo@Sun.COM char *minor_path = NULL;
4929794SLin.Guo@Sun.COM char *minor_name = NULL;
4939794SLin.Guo@Sun.COM char udi[HAL_PATH_MAX];
4949794SLin.Guo@Sun.COM char *s;
4959794SLin.Guo@Sun.COM
4969794SLin.Guo@Sun.COM get_dev_link_path(node, "usb_video",
497*10975SRaymond.Chen@Sun.COM "^usb/video[0-9]+", &devlink, &minor_path, &minor_name);
4989794SLin.Guo@Sun.COM
4999794SLin.Guo@Sun.COM if ((minor_path == NULL) || (devlink == NULL)) {
5009794SLin.Guo@Sun.COM
5019794SLin.Guo@Sun.COM goto out;
5029794SLin.Guo@Sun.COM }
5039794SLin.Guo@Sun.COM
5049794SLin.Guo@Sun.COM HAL_DEBUG(("devlink %s, minor_name %s", devlink, minor_name));
5059794SLin.Guo@Sun.COM if (strcmp(minor_name, "usbvc") != 0) {
5069794SLin.Guo@Sun.COM
5079794SLin.Guo@Sun.COM goto out;
5089794SLin.Guo@Sun.COM }
5099794SLin.Guo@Sun.COM
5109794SLin.Guo@Sun.COM d = hal_device_new();
5119794SLin.Guo@Sun.COM
5129794SLin.Guo@Sun.COM devinfo_set_default_properties(d, usbd, node, minor_path);
5139794SLin.Guo@Sun.COM hal_device_property_set_string(d, "info.subsystem", "video4linux");
5149794SLin.Guo@Sun.COM hal_device_property_set_string(d, "info.category", "video4linux");
5159794SLin.Guo@Sun.COM
5169794SLin.Guo@Sun.COM hal_device_add_capability(d, "video4linux");
5179794SLin.Guo@Sun.COM
5189794SLin.Guo@Sun.COM /* Get logic link under /dev (/dev/video+) */
5199794SLin.Guo@Sun.COM dev_videolink = get_usb_devlink(strstr(devlink, "usb"), "/dev/");
5209794SLin.Guo@Sun.COM
5219794SLin.Guo@Sun.COM hal_device_property_set_string(d, "video4linux.device", dev_videolink);
5229794SLin.Guo@Sun.COM
5239794SLin.Guo@Sun.COM hal_util_compute_udi(hald_get_gdl(), udi, sizeof (udi),
5249794SLin.Guo@Sun.COM "%s_video4linux", hal_device_get_udi(usbd));
5259794SLin.Guo@Sun.COM
5269794SLin.Guo@Sun.COM hal_device_set_udi(d, udi);
5279794SLin.Guo@Sun.COM hal_device_property_set_string(d, "info.udi", udi);
5289794SLin.Guo@Sun.COM PROP_STR(d, node, s, "usb-product-name", "info.product");
5299794SLin.Guo@Sun.COM
5309794SLin.Guo@Sun.COM devinfo_add_enqueue(d, minor_path, &devinfo_usb_handler);
5319794SLin.Guo@Sun.COM
5329794SLin.Guo@Sun.COM
5339794SLin.Guo@Sun.COM out:
5349794SLin.Guo@Sun.COM if (devlink) {
5359794SLin.Guo@Sun.COM free(devlink);
5369794SLin.Guo@Sun.COM }
5379794SLin.Guo@Sun.COM
5389794SLin.Guo@Sun.COM if (minor_path) {
5399794SLin.Guo@Sun.COM di_devfs_path_free(minor_path);
5409794SLin.Guo@Sun.COM }
5419794SLin.Guo@Sun.COM
5429794SLin.Guo@Sun.COM return (d);
5439794SLin.Guo@Sun.COM }
5449794SLin.Guo@Sun.COM
5459794SLin.Guo@Sun.COM static HalDevice *
devinfo_usb_input_add(HalDevice * usbd,di_node_t node)5469608SLin.Guo@Sun.COM devinfo_usb_input_add(HalDevice *usbd, di_node_t node)
5479608SLin.Guo@Sun.COM {
5489608SLin.Guo@Sun.COM HalDevice *d = NULL;
5499608SLin.Guo@Sun.COM int major;
5509608SLin.Guo@Sun.COM di_minor_t minor;
5519608SLin.Guo@Sun.COM dev_t devt;
5529608SLin.Guo@Sun.COM char *devlink = NULL;
5539608SLin.Guo@Sun.COM char *minor_path = NULL;
5549608SLin.Guo@Sun.COM char *minor_name = NULL;
5559608SLin.Guo@Sun.COM char udi[HAL_PATH_MAX];
5569608SLin.Guo@Sun.COM
5579608SLin.Guo@Sun.COM get_dev_link_path(node, "ddi_pseudo",
558*10975SRaymond.Chen@Sun.COM "^usb/hid[0-9]+", &devlink, &minor_path, &minor_name);
5599608SLin.Guo@Sun.COM
5609608SLin.Guo@Sun.COM if ((minor_path == NULL) || (devlink == NULL)) {
5619608SLin.Guo@Sun.COM
5629608SLin.Guo@Sun.COM goto out;
5639608SLin.Guo@Sun.COM }
5649608SLin.Guo@Sun.COM
5659608SLin.Guo@Sun.COM HAL_DEBUG(("devlink %s, minor_name %s", devlink, minor_name));
5669608SLin.Guo@Sun.COM if ((strcmp(minor_name, "keyboard") != 0) &&
5679608SLin.Guo@Sun.COM (strcmp(minor_name, "mouse") != 0)) {
5689608SLin.Guo@Sun.COM
5699608SLin.Guo@Sun.COM goto out;
5709608SLin.Guo@Sun.COM }
5719794SLin.Guo@Sun.COM
5729608SLin.Guo@Sun.COM d = hal_device_new();
5739608SLin.Guo@Sun.COM
5749608SLin.Guo@Sun.COM devinfo_set_default_properties(d, usbd, node, minor_path);
5759608SLin.Guo@Sun.COM hal_device_property_set_string(d, "info.subsystem", "input");
5769608SLin.Guo@Sun.COM hal_device_property_set_string(d, "info.category", "input");
5779608SLin.Guo@Sun.COM
5789608SLin.Guo@Sun.COM hal_device_add_capability(d, "input");
5799608SLin.Guo@Sun.COM
5809608SLin.Guo@Sun.COM if (strcmp(minor_name, "keyboard") == 0) {
5819608SLin.Guo@Sun.COM hal_device_add_capability(d, "input.keyboard");
5829608SLin.Guo@Sun.COM hal_device_add_capability(d, "input.keys");
5839608SLin.Guo@Sun.COM hal_device_add_capability(d, "button");
5849608SLin.Guo@Sun.COM } else if (strcmp(minor_name, "mouse") == 0) {
5859608SLin.Guo@Sun.COM hal_device_add_capability (d, "input.mouse");
5869608SLin.Guo@Sun.COM }
5879608SLin.Guo@Sun.COM
5889608SLin.Guo@Sun.COM hal_device_property_set_string(d, "input.device", devlink);
5899608SLin.Guo@Sun.COM hal_device_property_set_string(d, "input.originating_device",
5909608SLin.Guo@Sun.COM hal_device_get_udi(usbd));
5919608SLin.Guo@Sun.COM
5929608SLin.Guo@Sun.COM hal_util_compute_udi(hald_get_gdl(), udi, sizeof (udi),
5939608SLin.Guo@Sun.COM "%s_logicaldev_input", hal_device_get_udi(usbd));
5949794SLin.Guo@Sun.COM
5959608SLin.Guo@Sun.COM hal_device_set_udi(d, udi);
5969608SLin.Guo@Sun.COM hal_device_property_set_string(d, "info.udi", udi);
5979608SLin.Guo@Sun.COM
5989608SLin.Guo@Sun.COM if (strcmp(minor_name, "keyboard") == 0) {
5999608SLin.Guo@Sun.COM devinfo_add_enqueue(d, minor_path, &devinfo_usb_keyboard_handler);
6009608SLin.Guo@Sun.COM } else {
6019608SLin.Guo@Sun.COM devinfo_add_enqueue(d, minor_path, &devinfo_usb_handler);
6029608SLin.Guo@Sun.COM }
6039608SLin.Guo@Sun.COM
6049608SLin.Guo@Sun.COM /* add to TDL so preprobing callouts and prober can access it */
6059608SLin.Guo@Sun.COM hal_device_store_add(hald_get_tdl(), d);
6069608SLin.Guo@Sun.COM
6079608SLin.Guo@Sun.COM out:
6089608SLin.Guo@Sun.COM if (devlink) {
6099608SLin.Guo@Sun.COM free(devlink);
6109608SLin.Guo@Sun.COM }
6119608SLin.Guo@Sun.COM
6129608SLin.Guo@Sun.COM if (minor_path) {
6139608SLin.Guo@Sun.COM di_devfs_path_free(minor_path);
6149608SLin.Guo@Sun.COM }
6159608SLin.Guo@Sun.COM
6169608SLin.Guo@Sun.COM return (d);
6179608SLin.Guo@Sun.COM }
6189608SLin.Guo@Sun.COM
6199608SLin.Guo@Sun.COM static HalDevice *
devinfo_usb_scsa2usb_add(HalDevice * usbd,di_node_t node)6206112Sqz150045 devinfo_usb_scsa2usb_add(HalDevice *usbd, di_node_t node)
6212912Sartem {
6222912Sartem HalDevice *d = NULL;
6232912Sartem di_devlink_handle_t devlink_hdl;
6246112Sqz150045 int major;
6256112Sqz150045 di_minor_t minor;
6266112Sqz150045 dev_t devt;
6276112Sqz150045 char *minor_path = NULL;
6289608SLin.Guo@Sun.COM char *minor_name = NULL;
6292912Sartem char *devlink = NULL;
6306112Sqz150045 char udi[HAL_PATH_MAX];
6312912Sartem
632*10975SRaymond.Chen@Sun.COM get_dev_link_path(node, "ddi_ctl:devctl:scsi",
633*10975SRaymond.Chen@Sun.COM "^usb/mass-storage[0-9]+", &devlink, &minor_path, &minor_name);
6342912Sartem
6353536Sjacobs if ((devlink == NULL) || (minor_path == NULL)) {
6362912Sartem goto out;
6372912Sartem }
6382912Sartem
6392912Sartem d = hal_device_new ();
6402912Sartem
6412912Sartem devinfo_set_default_properties (d, usbd, node, minor_path);
6426112Sqz150045 hal_device_property_set_string (d, "scsi_host.solaris.device", devlink);
6436112Sqz150045 hal_device_property_set_string (d, "info.category", "scsi_host");
6446112Sqz150045 hal_device_property_set_int (d, "scsi_host.host", 0);
6452912Sartem
6466112Sqz150045 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi),
6476112Sqz150045 "%s/scsi_host%d", hal_device_get_udi (usbd),
6486112Sqz150045 hal_device_property_get_int (d, "scsi_host.host"));
6496112Sqz150045 hal_device_set_udi (d, udi);
6506112Sqz150045 hal_device_property_set_string (d, "info.udi", udi);
6516112Sqz150045 hal_device_property_set_string (d, "info.product", "SCSI Host Adapter");
6522912Sartem
6532912Sartem devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler);
6542912Sartem
6552912Sartem out:
6562912Sartem if (devlink) {
6572912Sartem free(devlink);
6582912Sartem }
6592912Sartem if (minor_path) {
6602912Sartem di_devfs_path_free (minor_path);
6612912Sartem }
6622912Sartem
6632912Sartem return (d);
6642912Sartem }
6652912Sartem
6663536Sjacobs static HalDevice *
devinfo_usb_printer_add(HalDevice * parent,di_node_t node)6676112Sqz150045 devinfo_usb_printer_add(HalDevice *parent, di_node_t node)
6683536Sjacobs {
6698529SNorm.Jacobs@Sun.COM char *properties[] = { "vendor", "product", "serial", NULL };
6708529SNorm.Jacobs@Sun.COM int i;
6713536Sjacobs HalDevice *d = NULL;
6726112Sqz150045 char udi[HAL_PATH_MAX];
6733536Sjacobs char *s;
6749608SLin.Guo@Sun.COM char *devlink = NULL, *minor_path = NULL, *minor_name = NULL;
6758529SNorm.Jacobs@Sun.COM const char *subsystem;
6763536Sjacobs
6779608SLin.Guo@Sun.COM get_dev_link_path(node, "ddi_printer", "printers/.+", &devlink, &minor_path, &minor_name);
6783536Sjacobs
6793536Sjacobs if ((devlink == NULL) || (minor_path == NULL)) {
6803536Sjacobs goto out;
6813536Sjacobs }
6823536Sjacobs
6833536Sjacobs d = hal_device_new ();
6843536Sjacobs
6853536Sjacobs devinfo_set_default_properties (d, parent, node, minor_path);
6866112Sqz150045 hal_device_property_set_string (d, "info.category", "printer");
6873536Sjacobs hal_device_add_capability (d, "printer");
6883536Sjacobs
6893536Sjacobs /* add printer properties */
6906112Sqz150045 hal_device_property_set_string (d, "printer.device", devlink);
6918529SNorm.Jacobs@Sun.COM
6928529SNorm.Jacobs@Sun.COM /* copy parent's selected usb* properties to printer properties */
6938529SNorm.Jacobs@Sun.COM subsystem = hal_device_property_get_string (parent, "info.subsystem");
6948529SNorm.Jacobs@Sun.COM for (i = 0; properties[i] != NULL; i++) {
6958529SNorm.Jacobs@Sun.COM char src[32], dst[32]; /* "subsystem.property" names */
6968529SNorm.Jacobs@Sun.COM
6978529SNorm.Jacobs@Sun.COM snprintf(src, sizeof (src), "%s.%s", subsystem, properties[i]);
6988529SNorm.Jacobs@Sun.COM snprintf(dst, sizeof (dst), "printer.%s", properties[i]);
6998529SNorm.Jacobs@Sun.COM hal_device_copy_property(parent, src, d, dst);
7008529SNorm.Jacobs@Sun.COM }
7013536Sjacobs
7023536Sjacobs devinfo_add_enqueue (d, minor_path, &devinfo_usb_printer_handler);
7033536Sjacobs
7043536Sjacobs out:
7053536Sjacobs if (devlink) {
7063536Sjacobs free(devlink);
7073536Sjacobs }
7083536Sjacobs if (minor_path) {
7093536Sjacobs di_devfs_path_free (minor_path);
7103536Sjacobs }
7113536Sjacobs
7123536Sjacobs return (d);
7133536Sjacobs }
7143536Sjacobs
7153536Sjacobs const gchar *
devinfo_printer_prnio_get_prober(HalDevice * d,int * timeout)7163536Sjacobs devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout)
7173536Sjacobs {
7183536Sjacobs *timeout = 5 * 1000; /* 5 second timeout */
7193536Sjacobs return ("hald-probe-printer");
7203536Sjacobs }
7219608SLin.Guo@Sun.COM
7229608SLin.Guo@Sun.COM const gchar *
devinfo_keyboard_get_prober(HalDevice * d,int * timeout)7239608SLin.Guo@Sun.COM devinfo_keyboard_get_prober(HalDevice *d, int *timeout)
7249608SLin.Guo@Sun.COM {
7259608SLin.Guo@Sun.COM *timeout = 5 * 1000; /* 5 second timeout */
7269608SLin.Guo@Sun.COM return ("hald-probe-xkb");
7279608SLin.Guo@Sun.COM }
728