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