1 /* $OpenBSD: usbdevs.c,v 1.12 2007/12/04 05:05:46 ckuethe 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 *); 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", 69 __progname); 70 exit(1); 71 } 72 73 char done[USB_MAX_DEVICES]; 74 int indent; 75 76 void 77 usbdev(int f, int a, int rec) 78 { 79 struct usb_device_info di; 80 usb_device_descriptor_t dd; 81 char serialnum[USB_MAX_STRING_LEN]; 82 int e, p, i; 83 84 di.udi_addr = a; 85 e = ioctl(f, USB_DEVICEINFO, &di); 86 if (e) { 87 if (errno != ENXIO) 88 printf("addr %d: I/O error\n", a); 89 return; 90 } 91 if (getdevicedesc(f, a, &dd)) 92 getstring(f, a, dd.iSerialNumber, serialnum); 93 94 printf("addr %d: ", a); 95 done[a] = 1; 96 if (verbose) { 97 switch (di.udi_speed) { 98 case USB_SPEED_LOW: 99 printf("low speed, "); 100 break; 101 case USB_SPEED_FULL: 102 printf("full speed, "); 103 break; 104 case USB_SPEED_HIGH: 105 printf("high speed, "); 106 break; 107 default: 108 break; 109 } 110 111 if (di.udi_power) 112 printf("power %d mA, ", di.udi_power); 113 else 114 printf("self powered, "); 115 if (di.udi_config) 116 printf("config %d, ", di.udi_config); 117 else 118 printf("unconfigured, "); 119 } 120 if (verbose) { 121 printf("%s(0x%04x), %s(0x%04x), rev %s", 122 di.udi_product, di.udi_productNo, 123 di.udi_vendor, di.udi_vendorNo, di.udi_release); 124 if (strlen(serialnum)) 125 printf(", iSerialNumber %s", serialnum); 126 } else 127 printf("%s, %s", di.udi_product, di.udi_vendor); 128 printf("\n"); 129 if (showdevs) { 130 for (i = 0; i < USB_MAX_DEVNAMES; i++) 131 if (di.udi_devnames[i][0]) 132 printf("%*s %s\n", indent, "", 133 di.udi_devnames[i]); 134 } 135 if (!rec) 136 return; 137 for (p = 0; p < di.udi_nports; p++) { 138 int s = di.udi_ports[p]; 139 140 if (s >= USB_MAX_DEVICES) { 141 if (verbose) { 142 printf("%*sport %d %s\n", indent+1, "", p+1, 143 s == USB_PORT_ENABLED ? "enabled" : 144 s == USB_PORT_SUSPENDED ? "suspended" : 145 s == USB_PORT_POWERED ? "powered" : 146 s == USB_PORT_DISABLED ? "disabled" : 147 "???"); 148 } 149 continue; 150 } 151 indent++; 152 printf("%*s", indent, ""); 153 if (verbose) 154 printf("port %d ", p+1); 155 if (s == 0) 156 printf("addr 0 should never happen!\n"); 157 else 158 usbdev(f, s, 1); 159 indent--; 160 } 161 } 162 163 int 164 getdevicedesc(int f, int addr, usb_device_descriptor_t *d) 165 { 166 struct usb_ctl_request req; 167 int r; 168 169 req.ucr_addr = addr; 170 req.ucr_request.bmRequestType = UT_READ_DEVICE; 171 req.ucr_request.bRequest = UR_GET_DESCRIPTOR; 172 USETW2(req.ucr_request.wValue, UDESC_DEVICE, 0); 173 USETW(req.ucr_request.wIndex, 0); 174 USETW(req.ucr_request.wLength, USB_DEVICE_DESCRIPTOR_SIZE); 175 req.ucr_data = d; 176 req.ucr_flags = 0; 177 if (r = ioctl(f, USB_REQUEST, &req)) 178 perror("getdevicedesc: ioctl"); 179 return 1; 180 return (r == 0); 181 } 182 183 void 184 getstring(int f, int addr, int si, char *s) 185 { 186 struct usb_ctl_request req; 187 usb_string_descriptor_t us; 188 int r, i, n; 189 u_int16_t c; 190 191 if (si == 0) { 192 *s = 0; 193 return; 194 } 195 req.ucr_addr = addr; 196 req.ucr_request.bmRequestType = UT_READ_DEVICE; 197 req.ucr_request.bRequest = UR_GET_DESCRIPTOR; 198 req.ucr_data = &us; 199 USETW2(req.ucr_request.wValue, UDESC_STRING, si); 200 USETW(req.ucr_request.wIndex, 0); 201 USETW(req.ucr_request.wLength, sizeof(usb_string_descriptor_t)); 202 req.ucr_flags = USBD_SHORT_XFER_OK; 203 204 if (ioctl(f, USB_REQUEST, &req) == -1){ 205 perror("getstring: ioctl"); 206 *s = 0; 207 return; 208 } 209 210 n = us.bLength / 2 - 1; 211 for (i = 0; i < n; i++) { 212 c = UGETW(us.bString[i]); 213 if ((c & 0xff00) == 0) 214 *s++ = c; 215 else if ((c & 0x00ff) == 0) 216 *s++ = c >> 8; 217 else { 218 snprintf(s, 6, "\\u%04x", c); 219 s += 6; 220 } 221 } 222 *s++ = 0; 223 } 224 225 void 226 usbdump(int f) 227 { 228 int a; 229 230 for (a = 1; a < USB_MAX_DEVICES; a++) { 231 if (!done[a]) 232 usbdev(f, a, 1); 233 } 234 } 235 236 void 237 dumpone(char *name, int f, int addr) 238 { 239 if (verbose) 240 printf("Controller %s:\n", name); 241 indent = 0; 242 memset(done, 0, sizeof done); 243 if (addr) 244 usbdev(f, addr, 0); 245 else 246 usbdump(f); 247 } 248 249 int 250 main(int argc, char **argv) 251 { 252 int ch, i, f; 253 char buf[50]; 254 char *dev = 0; 255 int addr = 0; 256 int ncont; 257 258 while ((ch = getopt(argc, argv, "a:df:v?")) != -1) { 259 switch (ch) { 260 case 'a': 261 addr = atoi(optarg); 262 break; 263 case 'd': 264 showdevs++; 265 break; 266 case 'f': 267 dev = optarg; 268 break; 269 case 'v': 270 verbose = 1; 271 break; 272 default: 273 usage(); 274 } 275 } 276 argc -= optind; 277 argv += optind; 278 279 if (dev == 0) { 280 for (ncont = 0, i = 0; i < 10; i++) { 281 snprintf(buf, sizeof buf, "%s%d", USBDEV, i); 282 f = open(buf, O_RDWR); 283 if (f >= 0) { 284 dumpone(buf, f, addr); 285 close(f); 286 } else { 287 if (errno == ENOENT || errno == ENXIO) 288 continue; 289 warn("%s", buf); 290 } 291 ncont++; 292 } 293 if (verbose && ncont == 0) 294 printf("%s: no USB controllers found\n", 295 __progname); 296 } else { 297 f = open(dev, O_RDWR); 298 if (f >= 0) 299 dumpone(dev, f, addr); 300 else 301 err(1, "%s", dev); 302 } 303 exit(0); 304 } 305