118c2aff7Sartem /*************************************************************************** 218c2aff7Sartem * 318c2aff7Sartem * devinfo_usb.h : USB devices 418c2aff7Sartem * 5d5c32991SNorm Jacobs * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 618c2aff7Sartem * Use is subject to license terms. 718c2aff7Sartem * 818c2aff7Sartem * Licensed under the Academic Free License version 2.1 918c2aff7Sartem * 1018c2aff7Sartem **************************************************************************/ 1118c2aff7Sartem 1200687e57Sartem #ifdef HAVE_CONFIG_H 1300687e57Sartem # include <config.h> 1400687e57Sartem #endif 1500687e57Sartem 1618c2aff7Sartem #include <stdio.h> 1718c2aff7Sartem #include <string.h> 1818c2aff7Sartem #include <libdevinfo.h> 19b453864fSLin Guo - Sun Microsystems #include <unistd.h> 20b453864fSLin Guo - Sun Microsystems #include <dirent.h> 2118c2aff7Sartem #include <sys/types.h> 2218c2aff7Sartem #include <sys/mkdev.h> 2318c2aff7Sartem #include <sys/stat.h> 24112cd14aSqz150045 #include <sys/usb/usbai.h> 2518c2aff7Sartem 2618c2aff7Sartem #include "../osspec.h" 2718c2aff7Sartem #include "../logger.h" 2818c2aff7Sartem #include "../hald.h" 2918c2aff7Sartem #include "../hald_dbus.h" 3018c2aff7Sartem #include "../device_info.h" 3118c2aff7Sartem #include "../util.h" 3218c2aff7Sartem #include "../ids.h" 3318c2aff7Sartem #include "hotplug.h" 3418c2aff7Sartem #include "devinfo.h" 3518c2aff7Sartem #include "devinfo_usb.h" 3618c2aff7Sartem 37112cd14aSqz150045 static HalDevice *devinfo_usb_if_add(HalDevice *d, di_node_t node, gchar *devfs_path, 38112cd14aSqz150045 gchar *if_devfs_path, int ifnum); 39112cd14aSqz150045 static HalDevice *devinfo_usb_scsa2usb_add(HalDevice *d, di_node_t node); 40112cd14aSqz150045 static HalDevice *devinfo_usb_printer_add(HalDevice *usbd, di_node_t node); 41b453864fSLin Guo - Sun Microsystems static HalDevice *devinfo_usb_input_add(HalDevice *usbd, di_node_t node); 423622ad5aSLin Guo - Sun Microsystems static HalDevice *devinfo_usb_video4linux_add(HalDevice *usbd, di_node_t node); 4342a7bdedSjacobs const gchar *devinfo_printer_prnio_get_prober(HalDevice *d, int *timeout); 44b453864fSLin Guo - Sun Microsystems const gchar *devinfo_keyboard_get_prober(HalDevice *d, int *timeout); 45112cd14aSqz150045 static void set_usb_properties(HalDevice *d, di_node_t node, gchar *devfs_path, char *driver_name); 4618c2aff7Sartem 4718c2aff7Sartem DevinfoDevHandler devinfo_usb_handler = { 4818c2aff7Sartem devinfo_usb_add, 4918c2aff7Sartem NULL, 5018c2aff7Sartem NULL, 5118c2aff7Sartem NULL, 5218c2aff7Sartem NULL, 5318c2aff7Sartem NULL 5418c2aff7Sartem }; 5518c2aff7Sartem 5642a7bdedSjacobs DevinfoDevHandler devinfo_usb_printer_handler = { 5742a7bdedSjacobs devinfo_usb_add, 5842a7bdedSjacobs NULL, 5942a7bdedSjacobs NULL, 6042a7bdedSjacobs NULL, 6142a7bdedSjacobs NULL, 6242a7bdedSjacobs devinfo_printer_prnio_get_prober 6342a7bdedSjacobs }; 6442a7bdedSjacobs 65b453864fSLin Guo - Sun Microsystems DevinfoDevHandler devinfo_usb_keyboard_handler = { 66b453864fSLin Guo - Sun Microsystems devinfo_usb_add, 67b453864fSLin Guo - Sun Microsystems NULL, 68b453864fSLin Guo - Sun Microsystems NULL, 69b453864fSLin Guo - Sun Microsystems NULL, 70b453864fSLin Guo - Sun Microsystems NULL, 71b453864fSLin Guo - Sun Microsystems devinfo_keyboard_get_prober 72b453864fSLin Guo - Sun Microsystems }; 73b453864fSLin Guo - Sun Microsystems 74c74d5d46Sjacobs static gboolean 75c74d5d46Sjacobs is_usb_node(di_node_t node) 76c74d5d46Sjacobs { 77c74d5d46Sjacobs int rc; 78c74d5d46Sjacobs char *s; 79c74d5d46Sjacobs 80c74d5d46Sjacobs /* 81c74d5d46Sjacobs * USB device nodes will have "compatible" propety values that 82c74d5d46Sjacobs * begins with "usb". 83c74d5d46Sjacobs */ 84c74d5d46Sjacobs rc = di_prop_lookup_strings(DDI_DEV_T_ANY, node, "compatible", &s); 85c74d5d46Sjacobs while (rc-- > 0) { 86c74d5d46Sjacobs if (strncmp(s, "usb", 3) == 0) { 87c74d5d46Sjacobs return (TRUE); 88c74d5d46Sjacobs } 89c74d5d46Sjacobs s += (strlen(s) + 1); 90c74d5d46Sjacobs } 91c74d5d46Sjacobs 92c74d5d46Sjacobs return (FALSE); 93c74d5d46Sjacobs } 94c74d5d46Sjacobs 95b453864fSLin Guo - Sun Microsystems static char * 963622ad5aSLin Guo - Sun Microsystems get_usb_devlink(char *devfs_path, const char *dir_name) 97b453864fSLin Guo - Sun Microsystems { 98b453864fSLin Guo - Sun Microsystems char *result = NULL; 99b453864fSLin Guo - Sun Microsystems DIR *dp; 100b453864fSLin Guo - Sun Microsystems 1013622ad5aSLin Guo - Sun Microsystems if ((dp = opendir(dir_name)) != NULL) { 102b453864fSLin Guo - Sun Microsystems struct dirent *ep; 103b453864fSLin Guo - Sun Microsystems 104b453864fSLin Guo - Sun Microsystems while ((ep = readdir(dp)) != NULL) { 105b453864fSLin Guo - Sun Microsystems char path[MAXPATHLEN], lpath[MAXPATHLEN]; 106b453864fSLin Guo - Sun Microsystems 1073622ad5aSLin Guo - Sun Microsystems strncpy(path, dir_name, strlen(dir_name)); 1083622ad5aSLin Guo - Sun Microsystems strncat(path, ep->d_name, strlen(ep->d_name)); 109b453864fSLin Guo - Sun Microsystems memset(lpath, 0, sizeof (lpath)); 110b453864fSLin Guo - Sun Microsystems if ((readlink(path, lpath, sizeof (lpath)) > 0) && 111b453864fSLin Guo - Sun Microsystems (strstr(lpath, devfs_path) != NULL)) { 112b453864fSLin Guo - Sun Microsystems result = strdup(path); 113b453864fSLin Guo - Sun Microsystems break; 114b453864fSLin Guo - Sun Microsystems } 1153622ad5aSLin Guo - Sun Microsystems memset(path, 0, sizeof (path)); 116b453864fSLin Guo - Sun Microsystems } 117b453864fSLin Guo - Sun Microsystems closedir(dp); 118b453864fSLin Guo - Sun Microsystems } 119b453864fSLin Guo - Sun Microsystems 120b453864fSLin Guo - Sun Microsystems return (result); 121b453864fSLin Guo - Sun Microsystems } 122b453864fSLin Guo - Sun Microsystems 12318c2aff7Sartem HalDevice * 12418c2aff7Sartem devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type) 12518c2aff7Sartem { 12618c2aff7Sartem HalDevice *d, *nd = NULL; 12718c2aff7Sartem char *s; 128c74d5d46Sjacobs int *i; 12918c2aff7Sartem char *driver_name, *binding_name; 13018c2aff7Sartem char if_devfs_path[HAL_PATH_MAX]; 131112cd14aSqz150045 di_devlink_handle_t hdl; 132112cd14aSqz150045 double k; 13318c2aff7Sartem 134c74d5d46Sjacobs if (is_usb_node(node) == FALSE) { 13518c2aff7Sartem return (NULL); 13618c2aff7Sartem } 13718c2aff7Sartem 138112cd14aSqz150045 driver_name = di_driver_name (node); 139112cd14aSqz150045 140112cd14aSqz150045 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "interface", &i) < 0) { 141112cd14aSqz150045 /* It is a USB device node. */ 142112cd14aSqz150045 14318c2aff7Sartem d = hal_device_new (); 14418c2aff7Sartem 14518c2aff7Sartem devinfo_set_default_properties (d, parent, node, devfs_path); 146112cd14aSqz150045 hal_device_property_set_string (d, "info.subsystem", "usb_device"); 14718c2aff7Sartem PROP_STR(d, node, s, "usb-product-name", "info.product"); 14818c2aff7Sartem PROP_STR(d, node, s, "usb-product-name", "usb_device.product"); 14918c2aff7Sartem PROP_STR(d, node, s, "usb-vendor-name", "usb_device.vendor"); 15018c2aff7Sartem PROP_INT(d, node, i, "usb-vendor-id", "usb_device.vendor_id"); 15118c2aff7Sartem PROP_INT(d, node, i, "usb-product-id", "usb_device.product_id"); 15218c2aff7Sartem PROP_INT(d, node, i, "usb-revision-id", "usb_device.device_revision_bcd"); 15318c2aff7Sartem PROP_STR(d, node, s, "usb-serialno", "usb_device.serial"); 154112cd14aSqz150045 PROP_INT(d, node, i, "usb-port-count", "usb_device.num_ports"); 155112cd14aSqz150045 PROP_INT(d, node, i, "usb-num-configs", "usb_device.num_configurations"); 156112cd14aSqz150045 PROP_INT(d, node, i, "assigned-address", "usb_device.bus_number"); 15718c2aff7Sartem 158112cd14aSqz150045 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "usb-release", &i) > 0) { 159112cd14aSqz150045 k = (double)bcd(*i); 160112cd14aSqz150045 hal_device_property_set_double (d, "usb_device.version", k / 100); 161112cd14aSqz150045 } 16218c2aff7Sartem 163112cd14aSqz150045 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "low-speed", &i) >= 0) { 164112cd14aSqz150045 k = 1.5; 165112cd14aSqz150045 } else if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "high-speed", &i) >= 0) { 166112cd14aSqz150045 k = 480.0; 167112cd14aSqz150045 } else { 168112cd14aSqz150045 /* It is the full speed device. */ 169112cd14aSqz150045 k = 12.0; 170112cd14aSqz150045 } 171112cd14aSqz150045 hal_device_property_set_double (d, "usb_device.speed", k); 172112cd14aSqz150045 173112cd14aSqz150045 set_usb_properties (d, node, devfs_path, driver_name); 174112cd14aSqz150045 175112cd14aSqz150045 /* wait for the ugen node's creation */ 176112cd14aSqz150045 if ((driver_name != NULL) && (strcmp (driver_name, "usb_mid") == 0)) { 177112cd14aSqz150045 if (hdl = di_devlink_init (devfs_path, DI_MAKE_LINK)) { 178112cd14aSqz150045 di_devlink_fini (&hdl); 179112cd14aSqz150045 } 180112cd14aSqz150045 } 181112cd14aSqz150045 182112cd14aSqz150045 devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler); 183112cd14aSqz150045 184112cd14aSqz150045 /* add to TDL so preprobing callouts and prober can access it */ 185112cd14aSqz150045 hal_device_store_add (hald_get_tdl (), d); 186112cd14aSqz150045 18718c2aff7Sartem if (((binding_name = di_binding_name (node)) != NULL) && 18818c2aff7Sartem (strncmp (binding_name, "usbif,", sizeof ("usbif,") - 1) == 0)) { 189112cd14aSqz150045 190112cd14aSqz150045 snprintf (if_devfs_path, sizeof (if_devfs_path), "%s:if%d", 191112cd14aSqz150045 devfs_path, 0); 192112cd14aSqz150045 if ((nd = devinfo_usb_if_add (d, node, if_devfs_path, 193112cd14aSqz150045 if_devfs_path, 0)) != NULL) { 19418c2aff7Sartem d = nd; 19518c2aff7Sartem nd = NULL; 19618c2aff7Sartem devfs_path = if_devfs_path; 19718c2aff7Sartem } 19818c2aff7Sartem } 199112cd14aSqz150045 } else { 200112cd14aSqz150045 /* It is a USB interface node or IA node. */ 201112cd14aSqz150045 int *j; 202112cd14aSqz150045 203112cd14aSqz150045 if (di_prop_lookup_ints (DDI_DEV_T_ANY, node, "interface-count", &j) > 0) { 204112cd14aSqz150045 /* 205112cd14aSqz150045 * The USB IA node properties are not defined in 206112cd14aSqz150045 * HAL spec so far. So IA node udi has "ia" sign 207112cd14aSqz150045 * now, different from the IF node udi with "if". 208112cd14aSqz150045 */ 209112cd14aSqz150045 snprintf (if_devfs_path, sizeof (if_devfs_path), 210112cd14aSqz150045 "%s:ia%d", devfs_path, *i); 211112cd14aSqz150045 } else { 212112cd14aSqz150045 snprintf (if_devfs_path, sizeof (if_devfs_path), 213112cd14aSqz150045 "%s:if%d", devfs_path, *i); 214112cd14aSqz150045 } 215112cd14aSqz150045 216112cd14aSqz150045 d = devinfo_usb_if_add (parent, node, devfs_path, if_devfs_path, *i); 217112cd14aSqz150045 } 21818c2aff7Sartem 21918c2aff7Sartem /* driver specific */ 220b453864fSLin Guo - Sun Microsystems if (driver_name != NULL) { 221b453864fSLin Guo - Sun Microsystems if (strcmp (driver_name, "scsa2usb") == 0) { 222112cd14aSqz150045 nd = devinfo_usb_scsa2usb_add (d, node); 223b453864fSLin Guo - Sun Microsystems } else if (strcmp (driver_name, "usbprn") == 0) { 224112cd14aSqz150045 nd = devinfo_usb_printer_add (d, node); 225b453864fSLin Guo - Sun Microsystems } else if (strcmp(driver_name, "hid") == 0) { 226b453864fSLin Guo - Sun Microsystems if (hdl = di_devlink_init(devfs_path, DI_MAKE_LINK)) { 227b453864fSLin Guo - Sun Microsystems di_devlink_fini(&hdl); 228b453864fSLin Guo - Sun Microsystems } 229b453864fSLin Guo - Sun Microsystems nd = devinfo_usb_input_add(d, node); 2303622ad5aSLin Guo - Sun Microsystems } else if (strcmp(driver_name, "usbvc") == 0) { 2313622ad5aSLin Guo - Sun Microsystems if (hdl = di_devlink_init(devfs_path, DI_MAKE_LINK)) { 2323622ad5aSLin Guo - Sun Microsystems di_devlink_fini(&hdl); 2333622ad5aSLin Guo - Sun Microsystems } 2343622ad5aSLin Guo - Sun Microsystems nd = devinfo_usb_video4linux_add(d, node); 235b453864fSLin Guo - Sun Microsystems } 23618c2aff7Sartem } 23718c2aff7Sartem 23818c2aff7Sartem out: 23918c2aff7Sartem if (nd != NULL) { 24018c2aff7Sartem return (nd); 24118c2aff7Sartem } else { 24218c2aff7Sartem return (d); 24318c2aff7Sartem } 24418c2aff7Sartem } 24518c2aff7Sartem 246112cd14aSqz150045 247112cd14aSqz150045 static void 248112cd14aSqz150045 set_usb_properties(HalDevice *d, di_node_t node, gchar *devfs_path, char *driver_name) 249112cd14aSqz150045 { 250112cd14aSqz150045 usb_dev_descr_t *dev_descrp = NULL; /* device descriptor */ 251112cd14aSqz150045 usb_cfg_descr_t *cfg_descrp = NULL; /* configuration descriptor */ 252112cd14aSqz150045 unsigned char *rdata = NULL; 253112cd14aSqz150045 char *p; 254112cd14aSqz150045 int i = 0; 255112cd14aSqz150045 256112cd14aSqz150045 hal_device_property_set_int (d, "usb_device.port_number", 257112cd14aSqz150045 atoi (devfs_path + strlen (devfs_path) -1)); 258112cd14aSqz150045 259112cd14aSqz150045 if (di_prop_lookup_bytes (DDI_DEV_T_ANY, node, "usb-dev-descriptor", 260112cd14aSqz150045 &rdata) > 0) { 261112cd14aSqz150045 dev_descrp = (usb_dev_descr_t *)rdata; 262112cd14aSqz150045 263112cd14aSqz150045 if (dev_descrp != NULL) { 264112cd14aSqz150045 hal_device_property_set_int (d, "usb_device.device_class", 265112cd14aSqz150045 dev_descrp->bDeviceClass); 266112cd14aSqz150045 hal_device_property_set_int (d, "usb_device.device_subclass", 267112cd14aSqz150045 dev_descrp->bDeviceSubClass); 268112cd14aSqz150045 hal_device_property_set_int (d, "usb_device.device_protocol", 269112cd14aSqz150045 dev_descrp->bDeviceProtocol); 270112cd14aSqz150045 } 271112cd14aSqz150045 } 272112cd14aSqz150045 273112cd14aSqz150045 if (di_prop_lookup_bytes (DDI_DEV_T_ANY, node, "usb-raw-cfg-descriptors", 274112cd14aSqz150045 &rdata) > 0) { 275112cd14aSqz150045 cfg_descrp = (usb_cfg_descr_t *)(rdata); 276112cd14aSqz150045 277112cd14aSqz150045 if (cfg_descrp != NULL) { 278112cd14aSqz150045 hal_device_property_set_int (d, "usb_device.configuration_value", 279112cd14aSqz150045 cfg_descrp->bConfigurationValue); 280112cd14aSqz150045 hal_device_property_set_int (d, "usb_device.max_power", 281112cd14aSqz150045 cfg_descrp->bMaxPower); 282112cd14aSqz150045 hal_device_property_set_int (d, "usb_device.num_interfaces", 283112cd14aSqz150045 cfg_descrp->bNumInterfaces); 284112cd14aSqz150045 hal_device_property_set_bool (d, "usb_device.can_wake_up", 285112cd14aSqz150045 (cfg_descrp->bmAttributes & 0x20) ? TRUE : FALSE); 286112cd14aSqz150045 hal_device_property_set_bool (d, "usb_device.is_self_powered", 287112cd14aSqz150045 (cfg_descrp->bmAttributes & 0x40) ? TRUE : FALSE); 288112cd14aSqz150045 } 289112cd14aSqz150045 } 290112cd14aSqz150045 291112cd14aSqz150045 /* get the node's usb tree level by counting hub numbers */ 292112cd14aSqz150045 do { 293112cd14aSqz150045 if (p = strstr (devfs_path, "/hub@")) { 294112cd14aSqz150045 devfs_path = p + strlen ("/hub@"); 295112cd14aSqz150045 i ++; 296112cd14aSqz150045 } 297112cd14aSqz150045 } while (p != NULL); 298112cd14aSqz150045 299112cd14aSqz150045 if ((driver_name != NULL) && (strcmp (driver_name, "hubd") == 0) && (i > 0)) 300112cd14aSqz150045 i --; 301112cd14aSqz150045 302112cd14aSqz150045 hal_device_property_set_int (d, "usb_device.level_number", i); 303112cd14aSqz150045 } 304112cd14aSqz150045 305112cd14aSqz150045 306112cd14aSqz150045 static usb_if_descr_t * 307112cd14aSqz150045 parse_usb_if_descr(di_node_t node, int ifnum) 308112cd14aSqz150045 { 309112cd14aSqz150045 unsigned char *rdata = NULL; 310112cd14aSqz150045 usb_if_descr_t *if_descrp=NULL; /* interface descriptor */ 311112cd14aSqz150045 di_node_t tmp_node = DI_NODE_NIL; 312112cd14aSqz150045 uint8_t num, length, type; 313112cd14aSqz150045 int rlen; 314112cd14aSqz150045 gchar *devpath = NULL; 315112cd14aSqz150045 316112cd14aSqz150045 if ((rlen = di_prop_lookup_bytes (DDI_DEV_T_ANY, node, 317112cd14aSqz150045 "usb-raw-cfg-descriptors", &rdata)) < 0) { 318112cd14aSqz150045 319112cd14aSqz150045 char *p; 320112cd14aSqz150045 int i; 321112cd14aSqz150045 322112cd14aSqz150045 if ((devpath = di_devfs_path (node)) == NULL) 323112cd14aSqz150045 goto out; 324112cd14aSqz150045 325112cd14aSqz150045 /* Look up its parent that may be a USB IA or USB mid. */ 326112cd14aSqz150045 for (i = 0; i < 2; i++) { 327112cd14aSqz150045 p = strrchr (devpath, '/'); 328112cd14aSqz150045 if (p == NULL) 329112cd14aSqz150045 goto out; 330112cd14aSqz150045 *p = '\0'; 331112cd14aSqz150045 332112cd14aSqz150045 if ((tmp_node = di_init (devpath, DINFOCPYALL)) == DI_NODE_NIL) 333112cd14aSqz150045 goto out; 334112cd14aSqz150045 335112cd14aSqz150045 if ((rlen = di_prop_lookup_bytes (DDI_DEV_T_ANY, tmp_node, 336112cd14aSqz150045 "usb-raw-cfg-descriptors", &rdata)) > 0) 337112cd14aSqz150045 break; 338112cd14aSqz150045 339112cd14aSqz150045 di_fini (tmp_node); 340112cd14aSqz150045 } 341112cd14aSqz150045 } 342112cd14aSqz150045 343112cd14aSqz150045 if (rdata == NULL) 344112cd14aSqz150045 goto out; 345112cd14aSqz150045 346112cd14aSqz150045 do { 347112cd14aSqz150045 length = (uint8_t)*rdata; 348112cd14aSqz150045 type = (uint8_t)*(rdata + 1); 349112cd14aSqz150045 if (type == USB_DESCR_TYPE_IF) { 350112cd14aSqz150045 num = (uint8_t)*(rdata + 2); 351112cd14aSqz150045 if (num == ifnum) { 352112cd14aSqz150045 if_descrp = (usb_if_descr_t *)rdata; 353112cd14aSqz150045 break; 354112cd14aSqz150045 } 355112cd14aSqz150045 } 356112cd14aSqz150045 rdata += length; 357112cd14aSqz150045 rlen -= length; 358112cd14aSqz150045 } while ((length > 0 ) && (rlen > 0)); 359112cd14aSqz150045 360112cd14aSqz150045 out: 361112cd14aSqz150045 if (devpath != NULL) 362112cd14aSqz150045 di_devfs_path_free (devpath); 363112cd14aSqz150045 if (tmp_node != DI_NODE_NIL) 364112cd14aSqz150045 di_fini (tmp_node); 365112cd14aSqz150045 return (if_descrp); 366112cd14aSqz150045 } 367112cd14aSqz150045 368112cd14aSqz150045 36918c2aff7Sartem static HalDevice * 370112cd14aSqz150045 devinfo_usb_if_add(HalDevice *parent, di_node_t node, gchar *devfs_path, 371112cd14aSqz150045 gchar *if_devfs_path, int ifnum) 37218c2aff7Sartem { 37318c2aff7Sartem HalDevice *d = NULL; 37418c2aff7Sartem char udi[HAL_PATH_MAX]; 375112cd14aSqz150045 const char *parent_info; 376112cd14aSqz150045 usb_if_descr_t *if_descrp=NULL; /* interface descriptor */ 37718c2aff7Sartem 37818c2aff7Sartem d = hal_device_new (); 37918c2aff7Sartem 380112cd14aSqz150045 devinfo_set_default_properties (d, parent, node, if_devfs_path); 381112cd14aSqz150045 382112cd14aSqz150045 /* Set the existed physical device path. */ 383112cd14aSqz150045 hal_device_property_set_string (d, "solaris.devfs_path", devfs_path); 384112cd14aSqz150045 hal_device_property_set_string (d, "info.subsystem", "usb"); 38518c2aff7Sartem hal_device_property_set_string (d, "info.product", "USB Device Interface"); 38618c2aff7Sartem 387112cd14aSqz150045 /* Set usb interface properties to interface node. */ 388112cd14aSqz150045 if (strstr (if_devfs_path, ":ia") == NULL) { 389112cd14aSqz150045 if_descrp = parse_usb_if_descr (node, ifnum); 390112cd14aSqz150045 391112cd14aSqz150045 if (if_descrp != NULL) { 392112cd14aSqz150045 hal_device_property_set_int (d, "usb.interface.class", 393112cd14aSqz150045 if_descrp->bInterfaceClass); 394112cd14aSqz150045 hal_device_property_set_int (d, "usb.interface.subclass", 395112cd14aSqz150045 if_descrp->bInterfaceSubClass); 396112cd14aSqz150045 hal_device_property_set_int (d, "usb.interface.protocol", 397112cd14aSqz150045 if_descrp->bInterfaceProtocol); 398112cd14aSqz150045 hal_device_property_set_int (d, "usb.interface.number", 399112cd14aSqz150045 if_descrp->bInterfaceNumber); 400112cd14aSqz150045 } 401112cd14aSqz150045 } 402112cd14aSqz150045 40318c2aff7Sartem /* copy parent's usb_device.* properties */ 404112cd14aSqz150045 parent_info = hal_device_property_get_string (parent, "info.subsystem"); 405112cd14aSqz150045 if (parent_info != NULL) { 406112cd14aSqz150045 if (strcmp (parent_info, "usb_device") == 0) { 40718c2aff7Sartem hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device."); 408112cd14aSqz150045 } else if (strcmp (parent_info, "usb") == 0) { 409112cd14aSqz150045 /* for the case that the parent is IA node */ 410112cd14aSqz150045 hal_device_merge_with_rewrite (d, parent, "usb.", "usb."); 411112cd14aSqz150045 } 412112cd14aSqz150045 } 413112cd14aSqz150045 414112cd14aSqz150045 devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler); 415112cd14aSqz150045 416112cd14aSqz150045 /* add to TDL so preprobing callouts and prober can access it */ 417112cd14aSqz150045 hal_device_store_add (hald_get_tdl (), d); 41818c2aff7Sartem 41918c2aff7Sartem return (d); 42018c2aff7Sartem } 42118c2aff7Sartem 42242a7bdedSjacobs 42342a7bdedSjacobs static void 424b453864fSLin Guo - Sun Microsystems get_dev_link_path(di_node_t node, char *nodetype, char *re, char **devlink, char **minor_path, char **minor_name) 42518c2aff7Sartem { 42642a7bdedSjacobs di_devlink_handle_t devlink_hdl; 42742a7bdedSjacobs int major; 42842a7bdedSjacobs di_minor_t minor; 42942a7bdedSjacobs dev_t devt; 43018c2aff7Sartem 43142a7bdedSjacobs *devlink = NULL; 43242a7bdedSjacobs *minor_path = NULL; 433b453864fSLin Guo - Sun Microsystems *minor_name = NULL; 43418c2aff7Sartem 43542a7bdedSjacobs if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) { 43642a7bdedSjacobs return; 43718c2aff7Sartem } 43818c2aff7Sartem 43942a7bdedSjacobs major = di_driver_major(node); 44042a7bdedSjacobs minor = DI_MINOR_NIL; 44142a7bdedSjacobs while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 44242a7bdedSjacobs devt = di_minor_devt(minor); 44342a7bdedSjacobs if (major != major(devt)) { 44442a7bdedSjacobs continue; 44542a7bdedSjacobs } 44618c2aff7Sartem 44742a7bdedSjacobs if (di_minor_type(minor) != DDM_MINOR) { 44842a7bdedSjacobs continue; 44942a7bdedSjacobs } 45018c2aff7Sartem 45142a7bdedSjacobs if ((*minor_path = di_devfs_minor_path(minor)) == NULL) { 45242a7bdedSjacobs continue; 45342a7bdedSjacobs } 45442a7bdedSjacobs 455b453864fSLin Guo - Sun Microsystems if (strcmp(di_minor_nodetype(minor), nodetype) == 0) { 456b453864fSLin Guo - Sun Microsystems *devlink = get_devlink(devlink_hdl, re, *minor_path); 457b453864fSLin Guo - Sun Microsystems /* 4583622ad5aSLin Guo - Sun Microsystems * During hotplugging, devlink could be NULL for usb 459b453864fSLin Guo - Sun Microsystems * devices due to devlink database has not yet been 460b453864fSLin Guo - Sun Microsystems * updated when hal try to read from it although the 461b453864fSLin Guo - Sun Microsystems * actually dev link path has been created. In such a 462b453864fSLin Guo - Sun Microsystems * situation, we will read the devlink name from 463b453864fSLin Guo - Sun Microsystems * /dev/usb directory. 464b453864fSLin Guo - Sun Microsystems */ 465*3fb52c73SRaymond Chen if ((*devlink == NULL) && (re != NULL) && 4663622ad5aSLin Guo - Sun Microsystems ((strstr(re, "hid") != NULL) || (strstr(re, "video") != NULL))) { 4673622ad5aSLin Guo - Sun Microsystems *devlink = get_usb_devlink(*minor_path, "/dev/usb/"); 468b453864fSLin Guo - Sun Microsystems } 469b453864fSLin Guo - Sun Microsystems 470b453864fSLin Guo - Sun Microsystems if (*devlink != NULL) { 471b453864fSLin Guo - Sun Microsystems *minor_name = di_minor_name(minor); 47242a7bdedSjacobs break; 47342a7bdedSjacobs } 474b453864fSLin Guo - Sun Microsystems } 475b453864fSLin Guo - Sun Microsystems 47642a7bdedSjacobs di_devfs_path_free (*minor_path); 477c74d5d46Sjacobs *minor_path = NULL; 47842a7bdedSjacobs } 47942a7bdedSjacobs di_devlink_fini (&devlink_hdl); 48018c2aff7Sartem } 48118c2aff7Sartem 48218c2aff7Sartem static HalDevice * 4833622ad5aSLin Guo - Sun Microsystems devinfo_usb_video4linux_add(HalDevice *usbd, di_node_t node) 4843622ad5aSLin Guo - Sun Microsystems { 4853622ad5aSLin Guo - Sun Microsystems HalDevice *d = NULL; 4863622ad5aSLin Guo - Sun Microsystems int major; 4873622ad5aSLin Guo - Sun Microsystems di_minor_t minor; 4883622ad5aSLin Guo - Sun Microsystems dev_t devt; 4893622ad5aSLin Guo - Sun Microsystems char *devlink = NULL; 4903622ad5aSLin Guo - Sun Microsystems char *dev_videolink = NULL; 4913622ad5aSLin Guo - Sun Microsystems char *minor_path = NULL; 4923622ad5aSLin Guo - Sun Microsystems char *minor_name = NULL; 4933622ad5aSLin Guo - Sun Microsystems char udi[HAL_PATH_MAX]; 4943622ad5aSLin Guo - Sun Microsystems char *s; 4953622ad5aSLin Guo - Sun Microsystems 4963622ad5aSLin Guo - Sun Microsystems get_dev_link_path(node, "usb_video", 497*3fb52c73SRaymond Chen "^usb/video[0-9]+", &devlink, &minor_path, &minor_name); 4983622ad5aSLin Guo - Sun Microsystems 4993622ad5aSLin Guo - Sun Microsystems if ((minor_path == NULL) || (devlink == NULL)) { 5003622ad5aSLin Guo - Sun Microsystems 5013622ad5aSLin Guo - Sun Microsystems goto out; 5023622ad5aSLin Guo - Sun Microsystems } 5033622ad5aSLin Guo - Sun Microsystems 5043622ad5aSLin Guo - Sun Microsystems HAL_DEBUG(("devlink %s, minor_name %s", devlink, minor_name)); 5053622ad5aSLin Guo - Sun Microsystems if (strcmp(minor_name, "usbvc") != 0) { 5063622ad5aSLin Guo - Sun Microsystems 5073622ad5aSLin Guo - Sun Microsystems goto out; 5083622ad5aSLin Guo - Sun Microsystems } 5093622ad5aSLin Guo - Sun Microsystems 5103622ad5aSLin Guo - Sun Microsystems d = hal_device_new(); 5113622ad5aSLin Guo - Sun Microsystems 5123622ad5aSLin Guo - Sun Microsystems devinfo_set_default_properties(d, usbd, node, minor_path); 5133622ad5aSLin Guo - Sun Microsystems hal_device_property_set_string(d, "info.subsystem", "video4linux"); 5143622ad5aSLin Guo - Sun Microsystems hal_device_property_set_string(d, "info.category", "video4linux"); 5153622ad5aSLin Guo - Sun Microsystems 5163622ad5aSLin Guo - Sun Microsystems hal_device_add_capability(d, "video4linux"); 5173622ad5aSLin Guo - Sun Microsystems 5183622ad5aSLin Guo - Sun Microsystems /* Get logic link under /dev (/dev/video+) */ 5193622ad5aSLin Guo - Sun Microsystems dev_videolink = get_usb_devlink(strstr(devlink, "usb"), "/dev/"); 5203622ad5aSLin Guo - Sun Microsystems 5213622ad5aSLin Guo - Sun Microsystems hal_device_property_set_string(d, "video4linux.device", dev_videolink); 5223622ad5aSLin Guo - Sun Microsystems 5233622ad5aSLin Guo - Sun Microsystems hal_util_compute_udi(hald_get_gdl(), udi, sizeof (udi), 5243622ad5aSLin Guo - Sun Microsystems "%s_video4linux", hal_device_get_udi(usbd)); 5253622ad5aSLin Guo - Sun Microsystems 5263622ad5aSLin Guo - Sun Microsystems hal_device_set_udi(d, udi); 5273622ad5aSLin Guo - Sun Microsystems hal_device_property_set_string(d, "info.udi", udi); 5283622ad5aSLin Guo - Sun Microsystems PROP_STR(d, node, s, "usb-product-name", "info.product"); 5293622ad5aSLin Guo - Sun Microsystems 5303622ad5aSLin Guo - Sun Microsystems devinfo_add_enqueue(d, minor_path, &devinfo_usb_handler); 5313622ad5aSLin Guo - Sun Microsystems 5323622ad5aSLin Guo - Sun Microsystems 5333622ad5aSLin Guo - Sun Microsystems out: 5343622ad5aSLin Guo - Sun Microsystems if (devlink) { 5353622ad5aSLin Guo - Sun Microsystems free(devlink); 5363622ad5aSLin Guo - Sun Microsystems } 5373622ad5aSLin Guo - Sun Microsystems 5383622ad5aSLin Guo - Sun Microsystems if (minor_path) { 5393622ad5aSLin Guo - Sun Microsystems di_devfs_path_free(minor_path); 5403622ad5aSLin Guo - Sun Microsystems } 5413622ad5aSLin Guo - Sun Microsystems 5423622ad5aSLin Guo - Sun Microsystems return (d); 5433622ad5aSLin Guo - Sun Microsystems } 5443622ad5aSLin Guo - Sun Microsystems 5453622ad5aSLin Guo - Sun Microsystems static HalDevice * 546b453864fSLin Guo - Sun Microsystems devinfo_usb_input_add(HalDevice *usbd, di_node_t node) 547b453864fSLin Guo - Sun Microsystems { 548b453864fSLin Guo - Sun Microsystems HalDevice *d = NULL; 549b453864fSLin Guo - Sun Microsystems int major; 550b453864fSLin Guo - Sun Microsystems di_minor_t minor; 551b453864fSLin Guo - Sun Microsystems dev_t devt; 552b453864fSLin Guo - Sun Microsystems char *devlink = NULL; 553b453864fSLin Guo - Sun Microsystems char *minor_path = NULL; 554b453864fSLin Guo - Sun Microsystems char *minor_name = NULL; 555b453864fSLin Guo - Sun Microsystems char udi[HAL_PATH_MAX]; 556b453864fSLin Guo - Sun Microsystems 557b453864fSLin Guo - Sun Microsystems get_dev_link_path(node, "ddi_pseudo", 558*3fb52c73SRaymond Chen "^usb/hid[0-9]+", &devlink, &minor_path, &minor_name); 559b453864fSLin Guo - Sun Microsystems 560b453864fSLin Guo - Sun Microsystems if ((minor_path == NULL) || (devlink == NULL)) { 561b453864fSLin Guo - Sun Microsystems 562b453864fSLin Guo - Sun Microsystems goto out; 563b453864fSLin Guo - Sun Microsystems } 564b453864fSLin Guo - Sun Microsystems 565b453864fSLin Guo - Sun Microsystems HAL_DEBUG(("devlink %s, minor_name %s", devlink, minor_name)); 566b453864fSLin Guo - Sun Microsystems if ((strcmp(minor_name, "keyboard") != 0) && 567b453864fSLin Guo - Sun Microsystems (strcmp(minor_name, "mouse") != 0)) { 568b453864fSLin Guo - Sun Microsystems 569b453864fSLin Guo - Sun Microsystems goto out; 570b453864fSLin Guo - Sun Microsystems } 571b453864fSLin Guo - Sun Microsystems 572b453864fSLin Guo - Sun Microsystems d = hal_device_new(); 573b453864fSLin Guo - Sun Microsystems 574b453864fSLin Guo - Sun Microsystems devinfo_set_default_properties(d, usbd, node, minor_path); 575b453864fSLin Guo - Sun Microsystems hal_device_property_set_string(d, "info.subsystem", "input"); 576b453864fSLin Guo - Sun Microsystems hal_device_property_set_string(d, "info.category", "input"); 577b453864fSLin Guo - Sun Microsystems 578b453864fSLin Guo - Sun Microsystems hal_device_add_capability(d, "input"); 579b453864fSLin Guo - Sun Microsystems 580b453864fSLin Guo - Sun Microsystems if (strcmp(minor_name, "keyboard") == 0) { 581b453864fSLin Guo - Sun Microsystems hal_device_add_capability(d, "input.keyboard"); 582b453864fSLin Guo - Sun Microsystems hal_device_add_capability(d, "input.keys"); 583b453864fSLin Guo - Sun Microsystems hal_device_add_capability(d, "button"); 584b453864fSLin Guo - Sun Microsystems } else if (strcmp(minor_name, "mouse") == 0) { 585b453864fSLin Guo - Sun Microsystems hal_device_add_capability (d, "input.mouse"); 586b453864fSLin Guo - Sun Microsystems } 587b453864fSLin Guo - Sun Microsystems 588b453864fSLin Guo - Sun Microsystems hal_device_property_set_string(d, "input.device", devlink); 589b453864fSLin Guo - Sun Microsystems hal_device_property_set_string(d, "input.originating_device", 590b453864fSLin Guo - Sun Microsystems hal_device_get_udi(usbd)); 591b453864fSLin Guo - Sun Microsystems 592b453864fSLin Guo - Sun Microsystems hal_util_compute_udi(hald_get_gdl(), udi, sizeof (udi), 593b453864fSLin Guo - Sun Microsystems "%s_logicaldev_input", hal_device_get_udi(usbd)); 594b453864fSLin Guo - Sun Microsystems 595b453864fSLin Guo - Sun Microsystems hal_device_set_udi(d, udi); 596b453864fSLin Guo - Sun Microsystems hal_device_property_set_string(d, "info.udi", udi); 597b453864fSLin Guo - Sun Microsystems 598b453864fSLin Guo - Sun Microsystems if (strcmp(minor_name, "keyboard") == 0) { 599b453864fSLin Guo - Sun Microsystems devinfo_add_enqueue(d, minor_path, &devinfo_usb_keyboard_handler); 600b453864fSLin Guo - Sun Microsystems } else { 601b453864fSLin Guo - Sun Microsystems devinfo_add_enqueue(d, minor_path, &devinfo_usb_handler); 602b453864fSLin Guo - Sun Microsystems } 603b453864fSLin Guo - Sun Microsystems 604b453864fSLin Guo - Sun Microsystems /* add to TDL so preprobing callouts and prober can access it */ 605b453864fSLin Guo - Sun Microsystems hal_device_store_add(hald_get_tdl(), d); 606b453864fSLin Guo - Sun Microsystems 607b453864fSLin Guo - Sun Microsystems out: 608b453864fSLin Guo - Sun Microsystems if (devlink) { 609b453864fSLin Guo - Sun Microsystems free(devlink); 610b453864fSLin Guo - Sun Microsystems } 611b453864fSLin Guo - Sun Microsystems 612b453864fSLin Guo - Sun Microsystems if (minor_path) { 613b453864fSLin Guo - Sun Microsystems di_devfs_path_free(minor_path); 614b453864fSLin Guo - Sun Microsystems } 615b453864fSLin Guo - Sun Microsystems 616b453864fSLin Guo - Sun Microsystems return (d); 617b453864fSLin Guo - Sun Microsystems } 618b453864fSLin Guo - Sun Microsystems 619b453864fSLin Guo - Sun Microsystems static HalDevice * 620112cd14aSqz150045 devinfo_usb_scsa2usb_add(HalDevice *usbd, di_node_t node) 62118c2aff7Sartem { 62218c2aff7Sartem HalDevice *d = NULL; 62318c2aff7Sartem di_devlink_handle_t devlink_hdl; 62418c2aff7Sartem int major; 62518c2aff7Sartem di_minor_t minor; 62618c2aff7Sartem dev_t devt; 62718c2aff7Sartem char *minor_path = NULL; 628b453864fSLin Guo - Sun Microsystems char *minor_name = NULL; 62918c2aff7Sartem char *devlink = NULL; 63018c2aff7Sartem char udi[HAL_PATH_MAX]; 63118c2aff7Sartem 632*3fb52c73SRaymond Chen get_dev_link_path(node, "ddi_ctl:devctl:scsi", 633*3fb52c73SRaymond Chen "^usb/mass-storage[0-9]+", &devlink, &minor_path, &minor_name); 63418c2aff7Sartem 63542a7bdedSjacobs if ((devlink == NULL) || (minor_path == NULL)) { 63618c2aff7Sartem goto out; 63718c2aff7Sartem } 63818c2aff7Sartem 63918c2aff7Sartem d = hal_device_new (); 64018c2aff7Sartem 64118c2aff7Sartem devinfo_set_default_properties (d, usbd, node, minor_path); 64218c2aff7Sartem hal_device_property_set_string (d, "scsi_host.solaris.device", devlink); 64318c2aff7Sartem hal_device_property_set_string (d, "info.category", "scsi_host"); 64418c2aff7Sartem hal_device_property_set_int (d, "scsi_host.host", 0); 64518c2aff7Sartem 64618c2aff7Sartem hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 64700687e57Sartem "%s/scsi_host%d", hal_device_get_udi (usbd), 64818c2aff7Sartem hal_device_property_get_int (d, "scsi_host.host")); 64918c2aff7Sartem hal_device_set_udi (d, udi); 65018c2aff7Sartem hal_device_property_set_string (d, "info.udi", udi); 65118c2aff7Sartem hal_device_property_set_string (d, "info.product", "SCSI Host Adapter"); 65218c2aff7Sartem 65318c2aff7Sartem devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler); 65418c2aff7Sartem 65518c2aff7Sartem out: 65618c2aff7Sartem if (devlink) { 65718c2aff7Sartem free(devlink); 65818c2aff7Sartem } 65918c2aff7Sartem if (minor_path) { 66018c2aff7Sartem di_devfs_path_free (minor_path); 66118c2aff7Sartem } 66218c2aff7Sartem 66318c2aff7Sartem return (d); 66418c2aff7Sartem } 66518c2aff7Sartem 66642a7bdedSjacobs static HalDevice * 667112cd14aSqz150045 devinfo_usb_printer_add(HalDevice *parent, di_node_t node) 66842a7bdedSjacobs { 669d5c32991SNorm Jacobs char *properties[] = { "vendor", "product", "serial", NULL }; 670d5c32991SNorm Jacobs int i; 67142a7bdedSjacobs HalDevice *d = NULL; 67242a7bdedSjacobs char udi[HAL_PATH_MAX]; 67342a7bdedSjacobs char *s; 674b453864fSLin Guo - Sun Microsystems char *devlink = NULL, *minor_path = NULL, *minor_name = NULL; 675d5c32991SNorm Jacobs const char *subsystem; 67642a7bdedSjacobs 677b453864fSLin Guo - Sun Microsystems get_dev_link_path(node, "ddi_printer", "printers/.+", &devlink, &minor_path, &minor_name); 67842a7bdedSjacobs 67942a7bdedSjacobs if ((devlink == NULL) || (minor_path == NULL)) { 68042a7bdedSjacobs goto out; 68142a7bdedSjacobs } 68242a7bdedSjacobs 68342a7bdedSjacobs d = hal_device_new (); 68442a7bdedSjacobs 68542a7bdedSjacobs devinfo_set_default_properties (d, parent, node, minor_path); 68642a7bdedSjacobs hal_device_property_set_string (d, "info.category", "printer"); 68742a7bdedSjacobs hal_device_add_capability (d, "printer"); 68842a7bdedSjacobs 68942a7bdedSjacobs /* add printer properties */ 69042a7bdedSjacobs hal_device_property_set_string (d, "printer.device", devlink); 691d5c32991SNorm Jacobs 692d5c32991SNorm Jacobs /* copy parent's selected usb* properties to printer properties */ 693d5c32991SNorm Jacobs subsystem = hal_device_property_get_string (parent, "info.subsystem"); 694d5c32991SNorm Jacobs for (i = 0; properties[i] != NULL; i++) { 695d5c32991SNorm Jacobs char src[32], dst[32]; /* "subsystem.property" names */ 696d5c32991SNorm Jacobs 697d5c32991SNorm Jacobs snprintf(src, sizeof (src), "%s.%s", subsystem, properties[i]); 698d5c32991SNorm Jacobs snprintf(dst, sizeof (dst), "printer.%s", properties[i]); 699d5c32991SNorm Jacobs hal_device_copy_property(parent, src, d, dst); 700d5c32991SNorm Jacobs } 70142a7bdedSjacobs 70242a7bdedSjacobs devinfo_add_enqueue (d, minor_path, &devinfo_usb_printer_handler); 70342a7bdedSjacobs 70442a7bdedSjacobs out: 70542a7bdedSjacobs if (devlink) { 70642a7bdedSjacobs free(devlink); 70742a7bdedSjacobs } 70842a7bdedSjacobs if (minor_path) { 70942a7bdedSjacobs di_devfs_path_free (minor_path); 71042a7bdedSjacobs } 71142a7bdedSjacobs 71242a7bdedSjacobs return (d); 71342a7bdedSjacobs } 71442a7bdedSjacobs 71542a7bdedSjacobs const gchar * 71642a7bdedSjacobs devinfo_printer_prnio_get_prober (HalDevice *d, int *timeout) 71742a7bdedSjacobs { 71842a7bdedSjacobs *timeout = 5 * 1000; /* 5 second timeout */ 71942a7bdedSjacobs return ("hald-probe-printer"); 72042a7bdedSjacobs } 721b453864fSLin Guo - Sun Microsystems 722b453864fSLin Guo - Sun Microsystems const gchar * 723b453864fSLin Guo - Sun Microsystems devinfo_keyboard_get_prober(HalDevice *d, int *timeout) 724b453864fSLin Guo - Sun Microsystems { 725b453864fSLin Guo - Sun Microsystems *timeout = 5 * 1000; /* 5 second timeout */ 726b453864fSLin Guo - Sun Microsystems return ("hald-probe-xkb"); 727b453864fSLin Guo - Sun Microsystems } 728