xref: /openbsd-src/usr.sbin/usbdevs/usbdevs.c (revision 7350f337b9e3eb4461d99580e625c7ef148d107c)
1 /*	$OpenBSD: usbdevs.c,v 1.31 2019/04/14 18:16:19 deraadt 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 
56 void usage(void);
57 void usbdev(int f, uint8_t);
58 void usbdump(int f);
59 void dumpone(char *name, int f, int addr);
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 char done[USB_MAX_DEVICES];
72 
73 void
74 usbdev(int f, uint8_t addr)
75 {
76 	struct usb_device_info di;
77 	int e, i, port, nports;
78 	uint16_t change, status;
79 	char vv[sizeof(di.udi_vendor)*4], vp[sizeof(di.udi_product)*4];
80 	char vr[sizeof(di.udi_release)*4], vs[sizeof(di.udi_serial)*4];
81 
82 	di.udi_addr = addr;
83 	e = ioctl(f, USB_DEVICEINFO, &di);
84 	if (e) {
85 		if (errno != ENXIO)
86 			printf("addr %d: I/O error\n", addr);
87 		return;
88 	}
89 
90 	printf("addr %02u: ", addr);
91 	done[addr] = 1;
92 	strvis(vv, di.udi_vendor, VIS_CSTYLE);
93 	strvis(vp, di.udi_product, VIS_CSTYLE);
94 	printf("%04x:%04x %s, %s", di.udi_vendorNo, di.udi_productNo,
95 	    vv, vp);
96 
97 	if (verbose) {
98 		printf("\n\t ");
99 		switch (di.udi_speed) {
100 		case USB_SPEED_LOW:
101 			printf("low speed, ");
102 			break;
103 		case USB_SPEED_FULL:
104 			printf("full speed, ");
105 			break;
106 		case USB_SPEED_HIGH:
107 			printf("high speed, ");
108 			break;
109 		case USB_SPEED_SUPER:
110 			printf("super speed, ");
111 			break;
112 		default:
113 			break;
114 		}
115 
116 		if (di.udi_power)
117 			printf("power %d mA, ", di.udi_power);
118 		else
119 			printf("self powered, ");
120 		if (di.udi_config)
121 			printf("config %d, ", di.udi_config);
122 		else
123 			printf("unconfigured, ");
124 
125 		strvis(vr, di.udi_release, VIS_CSTYLE);
126 		strvis(vs, di.udi_serial, VIS_CSTYLE);
127 		printf("rev %s", vr);
128 		if (strlen(di.udi_serial))
129 			printf(", iSerial %s", vs);
130 	}
131 	printf("\n");
132 
133 	if (verbose) {
134 		for (i = 0; i < USB_MAX_DEVNAMES; i++)
135 			if (di.udi_devnames[i][0])
136 				printf("\t driver: %s\n", di.udi_devnames[i]);
137 	}
138 
139 	if (verbose > 1) {
140 		nports = MINIMUM(di.udi_nports, nitems(di.udi_ports));
141 		for (port = 0; port < nports; port++) {
142 			status = di.udi_ports[port] & 0xffff;
143 			change = di.udi_ports[port] >> 16;
144 			printf("\t port %02u: %04x.%04x", port+1, change,
145 			    status);
146 
147 			if (status & UPS_CURRENT_CONNECT_STATUS)
148 				printf(" connect");
149 
150 			if (status & UPS_PORT_ENABLED)
151 				printf(" enabled");
152 
153 			if (status & UPS_SUSPEND)
154 				printf(" supsend");
155 
156 			if (status & UPS_OVERCURRENT_INDICATOR)
157 				printf(" overcurrent");
158 
159 			if (di.udi_speed < USB_SPEED_SUPER) {
160 				if (status & UPS_PORT_L1)
161 					printf(" l1");
162 
163 				if (status & UPS_PORT_POWER)
164 					printf(" power");
165 			} else {
166 				if (status & UPS_PORT_POWER_SS)
167 					printf(" power");
168 
169 				switch (UPS_PORT_LS_GET(status)) {
170 				case UPS_PORT_LS_U0:
171 					printf(" U0");
172 					break;
173 				case UPS_PORT_LS_U1:
174 					printf(" U1");
175 					break;
176 				case UPS_PORT_LS_U2:
177 					printf(" U2");
178 					break;
179 				case UPS_PORT_LS_U3:
180 					printf(" U3");
181 					break;
182 				case UPS_PORT_LS_SS_DISABLED:
183 					printf(" SS.disabled");
184 					break;
185 				case UPS_PORT_LS_RX_DETECT:
186 					printf(" Rx.detect");
187 					break;
188 				case UPS_PORT_LS_SS_INACTIVE:
189 					printf(" ss.inactive");
190 					break;
191 				case UPS_PORT_LS_POLLING:
192 					printf(" polling");
193 					break;
194 				case UPS_PORT_LS_RECOVERY:
195 					printf(" recovery");
196 					break;
197 				case UPS_PORT_LS_HOT_RESET:
198 					printf(" hot.reset");
199 					break;
200 				case UPS_PORT_LS_COMP_MOD:
201 					printf(" comp.mod");
202 					break;
203 				case UPS_PORT_LS_LOOPBACK:
204 					printf(" loopback");
205 					break;
206 				}
207 			}
208 
209 			printf("\n");
210 		}
211 	}
212 }
213 
214 void
215 usbdump(int f)
216 {
217 	uint8_t addr;
218 
219 	for (addr = 1; addr < USB_MAX_DEVICES; addr++) {
220 		if (!done[addr])
221 			usbdev(f, addr);
222 	}
223 }
224 
225 void
226 dumpone(char *name, int f, int addr)
227 {
228 	if (!addr)
229 		printf("Controller %s:\n", name);
230 	memset(done, 0, sizeof done);
231 	if (addr)
232 		usbdev(f, addr);
233 	else
234 		usbdump(f);
235 }
236 
237 int
238 main(int argc, char **argv)
239 {
240 	int ch, i, f;
241 	char buf[50];
242 	char *dev = NULL;
243 	const char *errstr;
244 	int addr = 0;
245 	int ncont;
246 
247 	while ((ch = getopt(argc, argv, "a:d:v?")) != -1) {
248 		switch (ch) {
249 		case 'a':
250 			addr = strtonum(optarg, 1, USB_MAX_DEVICES, &errstr);
251 			if (errstr)
252 				errx(1, "addr %s", errstr);
253 			break;
254 		case 'd':
255 			dev = optarg;
256 			break;
257 		case 'v':
258 			verbose++;
259 			break;
260 		default:
261 			usage();
262 		}
263 	}
264 	argc -= optind;
265 	argv += optind;
266 
267 	if (argc != 0)
268 		usage();
269 
270 	if (dev == 0) {
271 		for (ncont = 0, i = 0; i < 10; i++) {
272 			snprintf(buf, sizeof buf, "%s%d", USBDEV, i);
273 			f = open(buf, O_RDONLY);
274 			if (f >= 0) {
275 				dumpone(buf, f, addr);
276 				close(f);
277 			} else {
278 				if (errno == ENOENT || errno == ENXIO)
279 					continue;
280 				warn("%s", buf);
281 			}
282 			ncont++;
283 		}
284 		if (verbose && ncont == 0)
285 			printf("%s: no USB controllers found\n",
286 			    __progname);
287 	} else {
288 		f = open(dev, O_RDONLY);
289 		if (f >= 0) {
290 			dumpone(dev, f, addr);
291 			close(f);
292 		} else
293 			err(1, "%s", dev);
294 	}
295 
296 	return 0;
297 }
298