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); 42*9794SLin.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 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 * 96*9794SLin.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 101*9794SLin.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 107*9794SLin.Guo@Sun.COM strncpy(path, dir_name, strlen(dir_name)); 108*9794SLin.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 } 115*9794SLin.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 * 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); 230*9794SLin.Guo@Sun.COM } else if (strcmp(driver_name, "usbvc") == 0) { 231*9794SLin.Guo@Sun.COM if (hdl = di_devlink_init(devfs_path, DI_MAKE_LINK)) { 232*9794SLin.Guo@Sun.COM di_devlink_fini(&hdl); 233*9794SLin.Guo@Sun.COM } 234*9794SLin.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 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 * 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'; 331*9794SLin.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 * 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 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 /* 458*9794SLin.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*9794SLin.Guo@Sun.COM if ((*devlink == NULL) && 466*9794SLin.Guo@Sun.COM ((strstr(re, "hid") != NULL) || (strstr(re, "video") != NULL))) { 467*9794SLin.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 * 483*9794SLin.Guo@Sun.COM devinfo_usb_video4linux_add(HalDevice *usbd, di_node_t node) 484*9794SLin.Guo@Sun.COM { 485*9794SLin.Guo@Sun.COM HalDevice *d = NULL; 486*9794SLin.Guo@Sun.COM int major; 487*9794SLin.Guo@Sun.COM di_minor_t minor; 488*9794SLin.Guo@Sun.COM dev_t devt; 489*9794SLin.Guo@Sun.COM char *devlink = NULL; 490*9794SLin.Guo@Sun.COM char *dev_videolink = NULL; 491*9794SLin.Guo@Sun.COM char *minor_path = NULL; 492*9794SLin.Guo@Sun.COM char *minor_name = NULL; 493*9794SLin.Guo@Sun.COM char udi[HAL_PATH_MAX]; 494*9794SLin.Guo@Sun.COM char *s; 495*9794SLin.Guo@Sun.COM 496*9794SLin.Guo@Sun.COM get_dev_link_path(node, "usb_video", 497*9794SLin.Guo@Sun.COM "^usb/video+", &devlink, &minor_path, &minor_name); 498*9794SLin.Guo@Sun.COM 499*9794SLin.Guo@Sun.COM if ((minor_path == NULL) || (devlink == NULL)) { 500*9794SLin.Guo@Sun.COM 501*9794SLin.Guo@Sun.COM goto out; 502*9794SLin.Guo@Sun.COM } 503*9794SLin.Guo@Sun.COM 504*9794SLin.Guo@Sun.COM HAL_DEBUG(("devlink %s, minor_name %s", devlink, minor_name)); 505*9794SLin.Guo@Sun.COM if (strcmp(minor_name, "usbvc") != 0) { 506*9794SLin.Guo@Sun.COM 507*9794SLin.Guo@Sun.COM goto out; 508*9794SLin.Guo@Sun.COM } 509*9794SLin.Guo@Sun.COM 510*9794SLin.Guo@Sun.COM d = hal_device_new(); 511*9794SLin.Guo@Sun.COM 512*9794SLin.Guo@Sun.COM devinfo_set_default_properties(d, usbd, node, minor_path); 513*9794SLin.Guo@Sun.COM hal_device_property_set_string(d, "info.subsystem", "video4linux"); 514*9794SLin.Guo@Sun.COM hal_device_property_set_string(d, "info.category", "video4linux"); 515*9794SLin.Guo@Sun.COM 516*9794SLin.Guo@Sun.COM hal_device_add_capability(d, "video4linux"); 517*9794SLin.Guo@Sun.COM 518*9794SLin.Guo@Sun.COM /* Get logic link under /dev (/dev/video+) */ 519*9794SLin.Guo@Sun.COM dev_videolink = get_usb_devlink(strstr(devlink, "usb"), "/dev/"); 520*9794SLin.Guo@Sun.COM 521*9794SLin.Guo@Sun.COM hal_device_property_set_string(d, "video4linux.device", dev_videolink); 522*9794SLin.Guo@Sun.COM 523*9794SLin.Guo@Sun.COM hal_util_compute_udi(hald_get_gdl(), udi, sizeof (udi), 524*9794SLin.Guo@Sun.COM "%s_video4linux", hal_device_get_udi(usbd)); 525*9794SLin.Guo@Sun.COM 526*9794SLin.Guo@Sun.COM hal_device_set_udi(d, udi); 527*9794SLin.Guo@Sun.COM hal_device_property_set_string(d, "info.udi", udi); 528*9794SLin.Guo@Sun.COM PROP_STR(d, node, s, "usb-product-name", "info.product"); 529*9794SLin.Guo@Sun.COM 530*9794SLin.Guo@Sun.COM devinfo_add_enqueue(d, minor_path, &devinfo_usb_handler); 531*9794SLin.Guo@Sun.COM 532*9794SLin.Guo@Sun.COM 533*9794SLin.Guo@Sun.COM out: 534*9794SLin.Guo@Sun.COM if (devlink) { 535*9794SLin.Guo@Sun.COM free(devlink); 536*9794SLin.Guo@Sun.COM } 537*9794SLin.Guo@Sun.COM 538*9794SLin.Guo@Sun.COM if (minor_path) { 539*9794SLin.Guo@Sun.COM di_devfs_path_free(minor_path); 540*9794SLin.Guo@Sun.COM } 541*9794SLin.Guo@Sun.COM 542*9794SLin.Guo@Sun.COM return (d); 543*9794SLin.Guo@Sun.COM } 544*9794SLin.Guo@Sun.COM 545*9794SLin.Guo@Sun.COM static HalDevice * 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", 5589608SLin.Guo@Sun.COM "^usb/hid+", &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 } 571*9794SLin.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)); 594*9794SLin.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 * 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 6329608SLin.Guo@Sun.COM get_dev_link_path(node, "ddi_ctl:devctl:scsi", NULL, &devlink, &minor_path, &minor_name); 6332912Sartem 6343536Sjacobs if ((devlink == NULL) || (minor_path == NULL)) { 6352912Sartem goto out; 6362912Sartem } 6372912Sartem 6382912Sartem d = hal_device_new (); 6392912Sartem 6402912Sartem devinfo_set_default_properties (d, usbd, node, minor_path); 6416112Sqz150045 hal_device_property_set_string (d, "scsi_host.solaris.device", devlink); 6426112Sqz150045 hal_device_property_set_string (d, "info.category", "scsi_host"); 6436112Sqz150045 hal_device_property_set_int (d, "scsi_host.host", 0); 6442912Sartem 6456112Sqz150045 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 6466112Sqz150045 "%s/scsi_host%d", hal_device_get_udi (usbd), 6476112Sqz150045 hal_device_property_get_int (d, "scsi_host.host")); 6486112Sqz150045 hal_device_set_udi (d, udi); 6496112Sqz150045 hal_device_property_set_string (d, "info.udi", udi); 6506112Sqz150045 hal_device_property_set_string (d, "info.product", "SCSI Host Adapter"); 6512912Sartem 6522912Sartem devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler); 6532912Sartem 6542912Sartem out: 6552912Sartem if (devlink) { 6562912Sartem free(devlink); 6572912Sartem } 6582912Sartem if (minor_path) { 6592912Sartem di_devfs_path_free (minor_path); 6602912Sartem } 6612912Sartem 6622912Sartem return (d); 6632912Sartem } 6642912Sartem 6653536Sjacobs static HalDevice * 6666112Sqz150045 devinfo_usb_printer_add(HalDevice *parent, di_node_t node) 6673536Sjacobs { 6688529SNorm.Jacobs@Sun.COM char *properties[] = { "vendor", "product", "serial", NULL }; 6698529SNorm.Jacobs@Sun.COM int i; 6703536Sjacobs HalDevice *d = NULL; 6716112Sqz150045 char udi[HAL_PATH_MAX]; 6723536Sjacobs char *s; 6739608SLin.Guo@Sun.COM char *devlink = NULL, *minor_path = NULL, *minor_name = NULL; 6748529SNorm.Jacobs@Sun.COM const char *subsystem; 6753536Sjacobs 6769608SLin.Guo@Sun.COM get_dev_link_path(node, "ddi_printer", "printers/.+", &devlink, &minor_path, &minor_name); 6773536Sjacobs 6783536Sjacobs if ((devlink == NULL) || (minor_path == NULL)) { 6793536Sjacobs goto out; 6803536Sjacobs } 6813536Sjacobs 6823536Sjacobs d = hal_device_new (); 6833536Sjacobs 6843536Sjacobs devinfo_set_default_properties (d, parent, node, minor_path); 6856112Sqz150045 hal_device_property_set_string (d, "info.category", "printer"); 6863536Sjacobs hal_device_add_capability (d, "printer"); 6873536Sjacobs 6883536Sjacobs /* add printer properties */ 6896112Sqz150045 hal_device_property_set_string (d, "printer.device", devlink); 6908529SNorm.Jacobs@Sun.COM 6918529SNorm.Jacobs@Sun.COM /* copy parent's selected usb* properties to printer properties */ 6928529SNorm.Jacobs@Sun.COM subsystem = hal_device_property_get_string (parent, "info.subsystem"); 6938529SNorm.Jacobs@Sun.COM for (i = 0; properties[i] != NULL; i++) { 6948529SNorm.Jacobs@Sun.COM char src[32], dst[32]; /* "subsystem.property" names */ 6958529SNorm.Jacobs@Sun.COM 6968529SNorm.Jacobs@Sun.COM snprintf(src, sizeof (src), "%s.%s", subsystem, properties[i]); 6978529SNorm.Jacobs@Sun.COM snprintf(dst, sizeof (dst), "printer.%s", properties[i]); 6988529SNorm.Jacobs@Sun.COM hal_device_copy_property(parent, src, d, dst); 6998529SNorm.Jacobs@Sun.COM } 7003536Sjacobs 7013536Sjacobs devinfo_add_enqueue (d, minor_path, &devinfo_usb_printer_handler); 7023536Sjacobs 7033536Sjacobs out: 7043536Sjacobs if (devlink) { 7053536Sjacobs free(devlink); 7063536Sjacobs } 7073536Sjacobs if (minor_path) { 7083536Sjacobs di_devfs_path_free (minor_path); 7093536Sjacobs } 7103536Sjacobs 7113536Sjacobs return (d); 7123536Sjacobs } 7133536Sjacobs 7143536Sjacobs const gchar * 7153536Sjacobs devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout) 7163536Sjacobs { 7173536Sjacobs *timeout = 5 * 1000; /* 5 second timeout */ 7183536Sjacobs return ("hald-probe-printer"); 7193536Sjacobs } 7209608SLin.Guo@Sun.COM 7219608SLin.Guo@Sun.COM const gchar * 7229608SLin.Guo@Sun.COM devinfo_keyboard_get_prober(HalDevice *d, int *timeout) 7239608SLin.Guo@Sun.COM { 7249608SLin.Guo@Sun.COM *timeout = 5 * 1000; /* 5 second timeout */ 7259608SLin.Guo@Sun.COM return ("hald-probe-xkb"); 7269608SLin.Guo@Sun.COM } 727