1 /* $OpenBSD: usbdevs.c,v 1.36 2022/12/28 21:30:19 jmc 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
usage(void)65 usage(void)
66 {
67 fprintf(stderr, "usage: %s [-v] [-a addr] [-d usbdev]\n", __progname);
68 exit(1);
69 }
70
71 void
dump_device(int fd,uint8_t addr)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(" suspend");
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
dump_controller(char * name,int fd,uint8_t addr)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
main(int argc,char ** argv)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