1 /*************************************************************************** 2 * 3 * devinfo_usb.h : USB devices 4 * 5 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 6 * Use is subject to license terms. 7 * 8 * Licensed under the Academic Free License version 2.1 9 * 10 **************************************************************************/ 11 12 #pragma ident "%Z%%M% %I% %E% SMI" 13 14 #include <stdio.h> 15 #include <string.h> 16 #include <libdevinfo.h> 17 #include <sys/types.h> 18 #include <sys/mkdev.h> 19 #include <sys/stat.h> 20 21 #include "../osspec.h" 22 #include "../logger.h" 23 #include "../hald.h" 24 #include "../hald_dbus.h" 25 #include "../device_info.h" 26 #include "../util.h" 27 #include "../ids.h" 28 #include "hotplug.h" 29 #include "devinfo.h" 30 #include "devinfo_usb.h" 31 32 HalDevice *devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type); 33 static HalDevice *devinfo_usb_if_add(HalDevice *d, di_node_t node, gchar *devfs_path, int ifnum); 34 static HalDevice *devinfo_usb_scsa2usb_add(HalDevice *d, di_node_t node, gchar *devfs_path); 35 36 DevinfoDevHandler devinfo_usb_handler = { 37 devinfo_usb_add, 38 NULL, 39 NULL, 40 NULL, 41 NULL, 42 NULL 43 }; 44 45 HalDevice * 46 devinfo_usb_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type) 47 { 48 HalDevice *d, *nd = NULL; 49 char *s; 50 int *i, *vid; 51 char *driver_name, *binding_name; 52 char if_devfs_path[HAL_PATH_MAX]; 53 54 /* 55 * we distinguish USB devices by presence of "usb-vendor-id" 56 * property. should USB devices have "device_type"? 57 */ 58 if (di_prop_lookup_ints(DDI_DEV_T_ANY, node, "usb-vendor-id", &vid) <= 0) { 59 return (NULL); 60 } 61 62 d = hal_device_new (); 63 64 devinfo_set_default_properties (d, parent, node, devfs_path); 65 hal_device_property_set_string (d, "info.bus", "usb_device"); 66 PROP_STR(d, node, s, "usb-product-name", "info.product"); 67 PROP_STR(d, node, s, "usb-product-name", "usb_device.product"); 68 PROP_STR(d, node, s, "usb-vendor-name", "usb_device.vendor"); 69 PROP_INT(d, node, i, "usb-vendor-id", "usb_device.vendor_id"); 70 PROP_INT(d, node, i, "usb-product-id", "usb_device.product_id"); 71 PROP_INT(d, node, i, "usb-revision-id", "usb_device.device_revision_bcd"); 72 PROP_INT(d, node, i, "usb-release-id", "usb_device.version_bcd"); 73 PROP_STR(d, node, s, "usb-serialno", "usb_device.serial"); 74 75 /* class, subclass */ 76 /* hal_device_property_set_int (d, "usb_device.device_class", 8); */ 77 78 /* binding name tells us if driver is bound to interface or device */ 79 if (((binding_name = di_binding_name(node)) != NULL) && 80 (strncmp(binding_name, "usbif,", sizeof ("usbif,") - 1) == 0)) { 81 snprintf(if_devfs_path, sizeof (if_devfs_path), "%s:if%d", devfs_path, 0); 82 if ((nd = devinfo_usb_if_add(d, node, if_devfs_path, 0)) != NULL) { 83 d = nd; 84 nd = NULL; 85 devfs_path = if_devfs_path; 86 } 87 } 88 89 /* driver specific */ 90 driver_name = di_driver_name (node); 91 if ((driver_name != NULL) && (strcmp (driver_name, "scsa2usb") == 0)) { 92 nd = devinfo_usb_scsa2usb_add (d, node, devfs_path); 93 } else { 94 devinfo_add_enqueue (d, devfs_path, &devinfo_usb_handler); 95 } 96 97 out: 98 if (nd != NULL) { 99 return (nd); 100 } else { 101 return (d); 102 } 103 } 104 105 static HalDevice * 106 devinfo_usb_if_add(HalDevice *parent, di_node_t node, gchar *devfs_path, int ifnum) 107 { 108 HalDevice *d = NULL; 109 char udi[HAL_PATH_MAX]; 110 111 devinfo_add_enqueue (parent, devfs_path, &devinfo_usb_handler); 112 113 d = hal_device_new (); 114 115 devinfo_set_default_properties (d, parent, node, devfs_path); 116 hal_device_property_set_string (d, "info.bus", "usb"); 117 118 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 119 "%s_if%d", parent->udi, ifnum); 120 hal_device_set_udi (d, udi); 121 hal_device_property_set_string (d, "info.udi", udi); 122 hal_device_property_set_string (d, "info.product", "USB Device Interface"); 123 124 /* copy parent's usb_device.* properties */ 125 hal_device_merge_with_rewrite (d, parent, "usb.", "usb_device."); 126 127 return (d); 128 } 129 130 static int 131 walk_devlinks(di_devlink_t devlink, void *arg) 132 { 133 char **path = (char **)arg; 134 135 *path = strdup(di_devlink_path(devlink)); 136 137 return (DI_WALK_TERMINATE); 138 } 139 140 static char * 141 get_devlink(di_devlink_handle_t devlink_hdl, char *path) 142 { 143 char *devlink = NULL; 144 145 (void) di_devlink_walk(devlink_hdl, NULL, path, 146 DI_PRIMARY_LINK, &devlink, walk_devlinks); 147 148 return (devlink); 149 } 150 151 static HalDevice * 152 devinfo_usb_scsa2usb_add(HalDevice *usbd, di_node_t node, gchar *devfs_path) 153 { 154 HalDevice *d = NULL; 155 di_devlink_handle_t devlink_hdl; 156 int major; 157 di_minor_t minor; 158 dev_t devt; 159 char *minor_path = NULL; 160 char *devlink = NULL; 161 char udi[HAL_PATH_MAX]; 162 163 devinfo_add_enqueue (usbd, devfs_path, &devinfo_usb_handler); 164 165 if ((devlink_hdl = di_devlink_init(NULL, 0)) == NULL) { 166 printf("di_devlink_init() failed\n"); 167 return (NULL); 168 } 169 170 major = di_driver_major(node); 171 minor = DI_MINOR_NIL; 172 while ((minor = di_minor_next(node, minor)) != DI_MINOR_NIL) { 173 devt = di_minor_devt(minor); 174 if (major != major(devt)) { 175 continue; 176 } 177 if ((minor_path = di_devfs_minor_path(minor)) == NULL) { 178 continue; 179 } 180 if (di_minor_type(minor) != DDM_MINOR) { 181 continue; 182 } 183 if (strcmp (di_minor_nodetype(minor), 184 "ddi_ctl:devctl:scsi") == 0) { 185 devlink = get_devlink(devlink_hdl, minor_path); 186 if (devlink == NULL) { 187 devlink = strdup(""); 188 } 189 break; 190 } 191 di_devfs_path_free (minor_path); 192 minor_path = NULL; 193 } 194 195 di_devlink_fini (&devlink_hdl); 196 197 if (devlink == NULL) { 198 goto out; 199 } 200 201 d = hal_device_new (); 202 203 devinfo_set_default_properties (d, usbd, node, minor_path); 204 hal_device_property_set_string (d, "scsi_host.solaris.device", devlink); 205 hal_device_property_set_string (d, "info.category", "scsi_host"); 206 hal_device_property_set_int (d, "scsi_host.host", 0); 207 208 hal_util_compute_udi (hald_get_gdl (), udi, sizeof (udi), 209 "%s/scsi_host%d", usbd->udi, 210 hal_device_property_get_int (d, "scsi_host.host")); 211 hal_device_set_udi (d, udi); 212 hal_device_property_set_string (d, "info.udi", udi); 213 hal_device_property_set_string (d, "info.product", "SCSI Host Adapter"); 214 215 devinfo_add_enqueue (d, minor_path, &devinfo_usb_handler); 216 217 out: 218 if (devlink) { 219 free(devlink); 220 } 221 if (minor_path) { 222 di_devfs_path_free (minor_path); 223 } 224 225 return (d); 226 } 227 228