1 /* $OpenBSD: usbdevs.c,v 1.15 2008/03/17 16:30:05 sobrado Exp $ */ 2 /* $NetBSD: usbdevs.c,v 1.19 2002/02/21 00:34:31 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1998 The NetBSD Foundation, Inc. 6 * All rights reserved. 7 * 8 * This code is derived from software contributed to The NetBSD Foundation 9 * by Lennart Augustsson (augustss@netbsd.org). 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 3. All advertising materials mentioning features or use of this software 20 * must display the following acknowledgement: 21 * This product includes software developed by the NetBSD 22 * Foundation, Inc. and its contributors. 23 * 4. Neither the name of The NetBSD Foundation nor the names of its 24 * contributors may be used to endorse or promote products derived 25 * from this software without specific prior written permission. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 37 * POSSIBILITY OF SUCH DAMAGE. 38 */ 39 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <string.h> 43 #include <sys/types.h> 44 #include <fcntl.h> 45 #include <unistd.h> 46 #include <err.h> 47 #include <errno.h> 48 #include <dev/usb/usb.h> 49 50 #define USBDEV "/dev/usb" 51 52 int verbose = 0; 53 int showdevs = 0; 54 55 void usage(void); 56 void usbdev(int f, int a, int rec); 57 int getdevicedesc(int, int, usb_device_descriptor_t *); 58 void getstring(int, int, int, char *, int); 59 void usbdump(int f); 60 void dumpone(char *name, int f, int addr); 61 int main(int, char **); 62 63 extern char *__progname; 64 65 void 66 usage(void) 67 { 68 fprintf(stderr, "usage: %s [-dv] [-a addr] [-f dev]\n", __progname); 69 exit(1); 70 } 71 72 char done[USB_MAX_DEVICES]; 73 int indent; 74 75 void 76 usbdev(int f, int a, int rec) 77 { 78 struct usb_device_info di; 79 usb_device_descriptor_t dd; 80 char serialnum[USB_MAX_STRING_LEN]; 81 struct usb_ctl_request req; 82 usb_string_descriptor_t us; 83 int e, p, i; 84 int langid = 0; 85 86 di.udi_addr = a; 87 e = ioctl(f, USB_DEVICEINFO, &di); 88 if (e) { 89 if (errno != ENXIO) 90 printf("addr %d: I/O error\n", a); 91 return; 92 } 93 94 req.ucr_addr = a; 95 req.ucr_request.bmRequestType = UT_READ_DEVICE; 96 req.ucr_request.bRequest = UR_GET_DESCRIPTOR; 97 req.ucr_data = &us; 98 USETW2(req.ucr_request.wValue, UDESC_STRING, 0); 99 USETW(req.ucr_request.wIndex, 0); 100 USETW(req.ucr_request.wLength, 4); 101 req.ucr_flags = 0; 102 if (ioctl(f, USB_REQUEST, &req) >= 0) 103 langid = UGETW(us.bString[0]); 104 105 bzero(serialnum, sizeof serialnum); 106 if (getdevicedesc(f, a, &dd)) 107 getstring(f, a, dd.iSerialNumber, serialnum, langid); 108 109 printf("addr %d: ", a); 110 done[a] = 1; 111 if (verbose) { 112 switch (di.udi_speed) { 113 case USB_SPEED_LOW: 114 printf("low speed, "); 115 break; 116 case USB_SPEED_FULL: 117 printf("full speed, "); 118 break; 119 case USB_SPEED_HIGH: 120 printf("high speed, "); 121 break; 122 default: 123 break; 124 } 125 126 if (di.udi_power) 127 printf("power %d mA, ", di.udi_power); 128 else 129 printf("self powered, "); 130 if (di.udi_config) 131 printf("config %d, ", di.udi_config); 132 else 133 printf("unconfigured, "); 134 } 135 if (verbose) { 136 printf("%s(0x%04x), %s(0x%04x), rev %s", 137 di.udi_product, di.udi_productNo, 138 di.udi_vendor, di.udi_vendorNo, di.udi_release); 139 if (strlen(serialnum)) 140 printf(", iSerialNumber %s", serialnum); 141 } else 142 printf("%s, %s", di.udi_product, di.udi_vendor); 143 printf("\n"); 144 if (showdevs) { 145 for (i = 0; i < USB_MAX_DEVNAMES; i++) 146 if (di.udi_devnames[i][0]) 147 printf("%*s %s\n", indent, "", 148 di.udi_devnames[i]); 149 } 150 if (!rec) 151 return; 152 for (p = 0; p < di.udi_nports; p++) { 153 int s = di.udi_ports[p]; 154 155 if (s >= USB_MAX_DEVICES) { 156 if (verbose) { 157 printf("%*sport %d %s\n", indent+1, "", p+1, 158 s == USB_PORT_ENABLED ? "enabled" : 159 s == USB_PORT_SUSPENDED ? "suspended" : 160 s == USB_PORT_POWERED ? "powered" : 161 s == USB_PORT_DISABLED ? "disabled" : 162 "???"); 163 } 164 continue; 165 } 166 indent++; 167 printf("%*s", indent, ""); 168 if (verbose) 169 printf("port %d ", p+1); 170 if (s == 0) 171 printf("addr 0 should never happen!\n"); 172 else 173 usbdev(f, s, 1); 174 indent--; 175 } 176 } 177 178 int 179 getdevicedesc(int f, int addr, usb_device_descriptor_t *d) 180 { 181 struct usb_ctl_request req; 182 int r; 183 184 req.ucr_addr = addr; 185 req.ucr_request.bmRequestType = UT_READ_DEVICE; 186 req.ucr_request.bRequest = UR_GET_DESCRIPTOR; 187 USETW2(req.ucr_request.wValue, UDESC_DEVICE, 0); 188 USETW(req.ucr_request.wIndex, 0); 189 USETW(req.ucr_request.wLength, USB_DEVICE_DESCRIPTOR_SIZE); 190 req.ucr_data = d; 191 req.ucr_flags = 0; 192 if (r = ioctl(f, USB_REQUEST, &req)) 193 perror("getdevicedesc: ioctl"); 194 return 1; 195 return (r == 0); 196 } 197 198 void 199 getstring(int f, int addr, int si, char *s, int langid) 200 { 201 struct usb_ctl_request req; 202 usb_string_descriptor_t us; 203 int r, i, n; 204 u_int16_t c; 205 206 if (si == 0) { 207 *s = 0; 208 return; 209 } 210 req.ucr_addr = addr; 211 req.ucr_request.bmRequestType = UT_READ_DEVICE; 212 req.ucr_request.bRequest = UR_GET_DESCRIPTOR; 213 req.ucr_data = &us; 214 USETW2(req.ucr_request.wValue, UDESC_STRING, si); 215 USETW(req.ucr_request.wIndex, langid); 216 USETW(req.ucr_request.wLength, sizeof(usb_string_descriptor_t)); 217 req.ucr_flags = USBD_SHORT_XFER_OK; 218 219 if (ioctl(f, USB_REQUEST, &req) == -1){ 220 perror("getstring: ioctl"); 221 *s = 0; 222 return; 223 } 224 225 n = us.bLength / 2 - 1; 226 for (i = 0; i < n; i++) { 227 c = UGETW(us.bString[i]); 228 if ((c & 0xff00) == 0) 229 *s++ = c; 230 else if ((c & 0x00ff) == 0) 231 *s++ = c >> 8; 232 else { 233 snprintf(s, 6, "\\u%04x", c); 234 s += 6; 235 } 236 } 237 *s++ = 0; 238 } 239 240 void 241 usbdump(int f) 242 { 243 int a; 244 245 for (a = 1; a < USB_MAX_DEVICES; a++) { 246 if (!done[a]) 247 usbdev(f, a, 1); 248 } 249 } 250 251 void 252 dumpone(char *name, int f, int addr) 253 { 254 if (verbose) 255 printf("Controller %s:\n", name); 256 indent = 0; 257 memset(done, 0, sizeof done); 258 if (addr) 259 usbdev(f, addr, 0); 260 else 261 usbdump(f); 262 } 263 264 int 265 main(int argc, char **argv) 266 { 267 int ch, i, f; 268 char buf[50]; 269 char *dev = 0; 270 int addr = 0; 271 int ncont; 272 273 while ((ch = getopt(argc, argv, "a:df:v?")) != -1) { 274 switch (ch) { 275 case 'a': 276 addr = atoi(optarg); 277 break; 278 case 'd': 279 showdevs++; 280 break; 281 case 'f': 282 dev = optarg; 283 break; 284 case 'v': 285 verbose = 1; 286 break; 287 default: 288 usage(); 289 } 290 } 291 argc -= optind; 292 argv += optind; 293 294 if (dev == 0) { 295 for (ncont = 0, i = 0; i < 10; i++) { 296 snprintf(buf, sizeof buf, "%s%d", USBDEV, i); 297 f = open(buf, O_RDWR); 298 if (f >= 0) { 299 dumpone(buf, f, addr); 300 close(f); 301 } else { 302 if (errno == ENOENT || errno == ENXIO) 303 continue; 304 warn("%s", buf); 305 } 306 ncont++; 307 } 308 if (verbose && ncont == 0) 309 printf("%s: no USB controllers found\n", 310 __progname); 311 } else { 312 f = open(dev, O_RDWR); 313 if (f >= 0) 314 dumpone(dev, f, addr); 315 else 316 err(1, "%s", dev); 317 } 318 exit(0); 319 } 320