1 /* $OpenBSD: usbdevs.c,v 1.34 2021/07/12 15:09:22 beck 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 * 20 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 21 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 24 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/types.h> 34 #include <dev/usb/usb.h> 35 36 #include <err.h> 37 #include <errno.h> 38 #include <fcntl.h> 39 #include <limits.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <vis.h> 43 #include <string.h> 44 #include <unistd.h> 45 46 #ifndef nitems 47 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 48 #endif 49 50 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 51 52 #define USBDEV "/dev/usb" 53 54 int verbose = 0; 55 char done[USB_MAX_DEVICES]; 56 57 void usage(void); 58 void dump_device(int, uint8_t); 59 void dump_controller(char *, int, uint8_t); 60 int main(int, char **); 61 62 extern char *__progname; 63 64 void 65 usage(void) 66 { 67 fprintf(stderr, "usage: %s [-v] [-a addr] [-d usbdev]\n", __progname); 68 exit(1); 69 } 70 71 void 72 dump_device(int fd, uint8_t addr) 73 { 74 struct usb_device_info di; 75 int i; 76 char vv[sizeof(di.udi_vendor)*4], vp[sizeof(di.udi_product)*4]; 77 char vr[sizeof(di.udi_release)*4], vs[sizeof(di.udi_serial)*4]; 78 79 di.udi_addr = addr; 80 if (ioctl(fd, USB_DEVICEINFO, &di) == -1) { 81 if (errno != ENXIO) 82 warn("addr %u", addr); 83 return; 84 } 85 86 done[addr] = 1; 87 88 strvis(vv, di.udi_vendor, VIS_CSTYLE); 89 strvis(vp, di.udi_product, VIS_CSTYLE); 90 printf("addr %02u: %04x:%04x %s, %s", addr, 91 di.udi_vendorNo, di.udi_productNo, 92 vv, vp); 93 94 if (verbose) { 95 printf("\n\t "); 96 switch (di.udi_speed) { 97 case USB_SPEED_LOW: 98 printf("low speed"); 99 break; 100 case USB_SPEED_FULL: 101 printf("full speed"); 102 break; 103 case USB_SPEED_HIGH: 104 printf("high speed"); 105 break; 106 case USB_SPEED_SUPER: 107 printf("super speed"); 108 break; 109 default: 110 break; 111 } 112 113 if (di.udi_power) 114 printf(", power %d mA", di.udi_power); 115 else 116 printf(", self powered"); 117 118 if (di.udi_config) 119 printf(", config %d", di.udi_config); 120 else 121 printf(", unconfigured"); 122 123 strvis(vr, di.udi_release, VIS_CSTYLE); 124 printf(", rev %s", vr); 125 126 if (di.udi_serial[0] != '\0') { 127 strvis(vs, di.udi_serial, VIS_CSTYLE); 128 printf(", iSerial %s", vs); 129 } 130 } 131 printf("\n"); 132 133 if (verbose) 134 for (i = 0; i < USB_MAX_DEVNAMES; i++) 135 if (di.udi_devnames[i][0] != '\0') 136 printf("\t driver: %s\n", di.udi_devnames[i]); 137 138 if (verbose > 1) { 139 int port, nports; 140 141 nports = MINIMUM(di.udi_nports, nitems(di.udi_ports)); 142 for (port = 0; port < nports; port++) { 143 uint16_t status, change; 144 145 status = di.udi_ports[port] & 0xffff; 146 change = di.udi_ports[port] >> 16; 147 148 printf("\t port %02u: %04x.%04x", port+1, change, 149 status); 150 151 if (status & UPS_CURRENT_CONNECT_STATUS) 152 printf(" connect"); 153 154 if (status & UPS_PORT_ENABLED) 155 printf(" enabled"); 156 157 if (status & UPS_SUSPEND) 158 printf(" supsend"); 159 160 if (status & UPS_OVERCURRENT_INDICATOR) 161 printf(" overcurrent"); 162 163 if (di.udi_speed < USB_SPEED_SUPER) { 164 if (status & UPS_PORT_L1) 165 printf(" l1"); 166 167 if (status & UPS_PORT_POWER) 168 printf(" power"); 169 } else { 170 if (status & UPS_PORT_POWER_SS) 171 printf(" power"); 172 173 switch (UPS_PORT_LS_GET(status)) { 174 case UPS_PORT_LS_U0: 175 printf(" U0"); 176 break; 177 case UPS_PORT_LS_U1: 178 printf(" U1"); 179 break; 180 case UPS_PORT_LS_U2: 181 printf(" U2"); 182 break; 183 case UPS_PORT_LS_U3: 184 printf(" U3"); 185 break; 186 case UPS_PORT_LS_SS_DISABLED: 187 printf(" SS.disabled"); 188 break; 189 case UPS_PORT_LS_RX_DETECT: 190 printf(" Rx.detect"); 191 break; 192 case UPS_PORT_LS_SS_INACTIVE: 193 printf(" ss.inactive"); 194 break; 195 case UPS_PORT_LS_POLLING: 196 printf(" polling"); 197 break; 198 case UPS_PORT_LS_RECOVERY: 199 printf(" recovery"); 200 break; 201 case UPS_PORT_LS_HOT_RESET: 202 printf(" hot.reset"); 203 break; 204 case UPS_PORT_LS_COMP_MOD: 205 printf(" comp.mod"); 206 break; 207 case UPS_PORT_LS_LOOPBACK: 208 printf(" loopback"); 209 break; 210 } 211 } 212 213 printf("\n"); 214 } 215 } 216 } 217 218 void 219 dump_controller(char *name, int fd, uint8_t addr) 220 { 221 memset(done, 0, sizeof(done)); 222 223 if (addr) { 224 dump_device(fd, addr); 225 return; 226 } 227 228 printf("Controller %s:\n", name); 229 for (addr = 1; addr < USB_MAX_DEVICES; addr++) 230 if (!done[addr]) 231 dump_device(fd, addr); 232 } 233 234 int 235 main(int argc, char **argv) 236 { 237 int ch, fd; 238 char *controller = NULL; 239 uint8_t addr = 0; 240 const char *errstr; 241 242 while ((ch = getopt(argc, argv, "a:d:v?")) != -1) { 243 switch (ch) { 244 case 'a': 245 addr = strtonum(optarg, 1, USB_MAX_DEVICES-1, &errstr); 246 if (errstr) 247 errx(1, "addr %s", errstr); 248 break; 249 case 'd': 250 controller = optarg; 251 break; 252 case 'v': 253 verbose++; 254 break; 255 default: 256 usage(); 257 } 258 } 259 argc -= optind; 260 argv += optind; 261 262 if (argc != 0) 263 usage(); 264 265 if (unveil("/dev", "r") == -1) 266 err(1, "unveil /dev"); 267 if (unveil(NULL, NULL) == -1) 268 err(1, "unveil"); 269 270 if (controller == NULL) { 271 int i; 272 int ncont = 0; 273 274 for (i = 0; i < 10; i++) { 275 char path[PATH_MAX]; 276 277 snprintf(path, sizeof(path), "%s%d", USBDEV, i); 278 if ((fd = open(path, O_RDONLY)) < 0) { 279 if (errno != ENOENT && errno != ENXIO) 280 warn("%s", path); 281 continue; 282 } 283 284 dump_controller(path, fd, addr); 285 close(fd); 286 ncont++; 287 } 288 if (verbose && ncont == 0) 289 printf("%s: no USB controllers found\n", 290 __progname); 291 } else { 292 if ((fd = open(controller, O_RDONLY)) < 0) 293 err(1, "%s", controller); 294 295 dump_controller(controller, fd, addr); 296 close(fd); 297 } 298 299 return 0; 300 } 301