xref: /openbsd-src/usr.sbin/usbdevs/usbdevs.c (revision 3a50f0a93a2072911d0ba6ababa815fb04bf9a71)
1*3a50f0a9Sjmc /*	$OpenBSD: usbdevs.c,v 1.36 2022/12/28 21:30:19 jmc Exp $	*/
27517eab2Snate /*	$NetBSD: usbdevs.c,v 1.19 2002/02/21 00:34:31 christos Exp $	*/
3ad1b13fbSjakob 
4ad1b13fbSjakob /*
5ad1b13fbSjakob  * Copyright (c) 1998 The NetBSD Foundation, Inc.
6ad1b13fbSjakob  * All rights reserved.
7ad1b13fbSjakob  *
8ad1b13fbSjakob  * This code is derived from software contributed to The NetBSD Foundation
9ad1b13fbSjakob  * by Lennart Augustsson (augustss@netbsd.org).
10ad1b13fbSjakob  *
11ad1b13fbSjakob  * Redistribution and use in source and binary forms, with or without
12ad1b13fbSjakob  * modification, are permitted provided that the following conditions
13ad1b13fbSjakob  * are met:
14ad1b13fbSjakob  * 1. Redistributions of source code must retain the above copyright
15ad1b13fbSjakob  *    notice, this list of conditions and the following disclaimer.
16ad1b13fbSjakob  * 2. Redistributions in binary form must reproduce the above copyright
17ad1b13fbSjakob  *    notice, this list of conditions and the following disclaimer in the
18ad1b13fbSjakob  *    documentation and/or other materials provided with the distribution.
19ad1b13fbSjakob  *
20ad1b13fbSjakob  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21ad1b13fbSjakob  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22ad1b13fbSjakob  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23ad1b13fbSjakob  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24ad1b13fbSjakob  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25ad1b13fbSjakob  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26ad1b13fbSjakob  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27ad1b13fbSjakob  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28ad1b13fbSjakob  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29ad1b13fbSjakob  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30ad1b13fbSjakob  * POSSIBILITY OF SUCH DAMAGE.
31ad1b13fbSjakob  */
32ad1b13fbSjakob 
3345249121Smpi #include <sys/types.h>
3445249121Smpi #include <dev/usb/usb.h>
3545249121Smpi 
3645249121Smpi #include <err.h>
3745249121Smpi #include <errno.h>
3845249121Smpi #include <fcntl.h>
3945249121Smpi #include <limits.h>
40ad1b13fbSjakob #include <stdio.h>
41ad1b13fbSjakob #include <stdlib.h>
4244d2074cSderaadt #include <vis.h>
43ad1b13fbSjakob #include <string.h>
44ad1b13fbSjakob #include <unistd.h>
45ad1b13fbSjakob 
46b5cd11a0Smpi #ifndef nitems
47b5cd11a0Smpi #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
48b5cd11a0Smpi #endif
49b5cd11a0Smpi 
50d412bb60Smpi #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))
51d412bb60Smpi 
52ad1b13fbSjakob #define USBDEV "/dev/usb"
53ad1b13fbSjakob 
547517eab2Snate int verbose = 0;
555de804ecSsemarie char done[USB_MAX_DEVICES];
56ad1b13fbSjakob 
57c72b5b24Smillert void usage(void);
585de804ecSsemarie void dump_device(int, uint8_t);
595de804ecSsemarie void dump_controller(char *, int, uint8_t);
60c72b5b24Smillert int main(int, char **);
61ad1b13fbSjakob 
62ad1b13fbSjakob extern char *__progname;
63ad1b13fbSjakob 
64ad1b13fbSjakob void
usage(void)653dfbfc24Sderaadt usage(void)
66ad1b13fbSjakob {
6748ef7734Smpi 	fprintf(stderr, "usage: %s [-v] [-a addr] [-d usbdev]\n", __progname);
68ad1b13fbSjakob 	exit(1);
69ad1b13fbSjakob }
70ad1b13fbSjakob 
71ad1b13fbSjakob void
dump_device(int fd,uint8_t addr)725de804ecSsemarie dump_device(int fd, uint8_t addr)
73ad1b13fbSjakob {
74ad1b13fbSjakob 	struct usb_device_info di;
755de804ecSsemarie 	int i;
7644d2074cSderaadt 	char vv[sizeof(di.udi_vendor)*4], vp[sizeof(di.udi_product)*4];
7744d2074cSderaadt 	char vr[sizeof(di.udi_release)*4], vs[sizeof(di.udi_serial)*4];
78ad1b13fbSjakob 
79d412bb60Smpi 	di.udi_addr = addr;
805de804ecSsemarie 	if (ioctl(fd, USB_DEVICEINFO, &di) == -1) {
81ad1b13fbSjakob 		if (errno != ENXIO)
825de804ecSsemarie 			warn("addr %u", addr);
83ad1b13fbSjakob 		return;
84ad1b13fbSjakob 	}
85bcd0f9c7Swiniger 
86d412bb60Smpi 	done[addr] = 1;
875de804ecSsemarie 
8844d2074cSderaadt 	strvis(vv, di.udi_vendor, VIS_CSTYLE);
8944d2074cSderaadt 	strvis(vp, di.udi_product, VIS_CSTYLE);
905de804ecSsemarie 	printf("addr %02u: %04x:%04x %s, %s", addr,
915de804ecSsemarie 	    di.udi_vendorNo, di.udi_productNo,
9244d2074cSderaadt 	    vv, vp);
935cd7bad0Smpi 
94ad1b13fbSjakob 	if (verbose) {
95d412bb60Smpi 		printf("\n\t ");
967517eab2Snate 		switch (di.udi_speed) {
973dfbfc24Sderaadt 		case USB_SPEED_LOW:
985de804ecSsemarie 			printf("low speed");
993dfbfc24Sderaadt 			break;
1003dfbfc24Sderaadt 		case USB_SPEED_FULL:
1015de804ecSsemarie 			printf("full speed");
1023dfbfc24Sderaadt 			break;
1033dfbfc24Sderaadt 		case USB_SPEED_HIGH:
1045de804ecSsemarie 			printf("high speed");
1053dfbfc24Sderaadt 			break;
10642fdad5cSjsg 		case USB_SPEED_SUPER:
1075de804ecSsemarie 			printf("super speed");
10842fdad5cSjsg 			break;
1093dfbfc24Sderaadt 		default:
1103dfbfc24Sderaadt 			break;
1117517eab2Snate 		}
1127517eab2Snate 
1139f9e15b2Snate 		if (di.udi_power)
1145de804ecSsemarie 			printf(", power %d mA", di.udi_power);
115ad1b13fbSjakob 		else
1165de804ecSsemarie 			printf(", self powered");
1175de804ecSsemarie 
1189f9e15b2Snate 		if (di.udi_config)
1195de804ecSsemarie 			printf(", config %d", di.udi_config);
120ad1b13fbSjakob 		else
1215de804ecSsemarie 			printf(", unconfigured");
122d412bb60Smpi 
12344d2074cSderaadt 		strvis(vr, di.udi_release, VIS_CSTYLE);
1245de804ecSsemarie 		printf(", rev %s", vr);
1255de804ecSsemarie 
1265de804ecSsemarie 		if (di.udi_serial[0] != '\0') {
12744d2074cSderaadt 			strvis(vs, di.udi_serial, VIS_CSTYLE);
12844d2074cSderaadt 			printf(", iSerial %s", vs);
129d412bb60Smpi 		}
1305de804ecSsemarie 	}
131ad1b13fbSjakob 	printf("\n");
1325cd7bad0Smpi 
1335de804ecSsemarie 	if (verbose)
134fb99babbSmickey 		for (i = 0; i < USB_MAX_DEVNAMES; i++)
1355de804ecSsemarie 			if (di.udi_devnames[i][0] != '\0')
1365cd7bad0Smpi 				printf("\t driver: %s\n", di.udi_devnames[i]);
1373dfbfc24Sderaadt 
13845249121Smpi 	if (verbose > 1) {
1395de804ecSsemarie 		int port, nports;
1405de804ecSsemarie 
1415cd7bad0Smpi 		nports = MINIMUM(di.udi_nports, nitems(di.udi_ports));
1425cd7bad0Smpi 		for (port = 0; port < nports; port++) {
1435de804ecSsemarie 			uint16_t status, change;
1445de804ecSsemarie 
1455cd7bad0Smpi 			status = di.udi_ports[port] & 0xffff;
1465cd7bad0Smpi 			change = di.udi_ports[port] >> 16;
1475de804ecSsemarie 
1485cd7bad0Smpi 			printf("\t port %02u: %04x.%04x", port+1, change,
1495cd7bad0Smpi 			    status);
1505cd7bad0Smpi 
1515cd7bad0Smpi 			if (status & UPS_CURRENT_CONNECT_STATUS)
1525cd7bad0Smpi 				printf(" connect");
1535cd7bad0Smpi 
1545cd7bad0Smpi 			if (status & UPS_PORT_ENABLED)
1555cd7bad0Smpi 				printf(" enabled");
1565cd7bad0Smpi 
1575cd7bad0Smpi 			if (status & UPS_SUSPEND)
158*3a50f0a9Sjmc 				printf(" suspend");
1595cd7bad0Smpi 
1605cd7bad0Smpi 			if (status & UPS_OVERCURRENT_INDICATOR)
1615cd7bad0Smpi 				printf(" overcurrent");
1625cd7bad0Smpi 
1635cd7bad0Smpi 			if (di.udi_speed < USB_SPEED_SUPER) {
1645cd7bad0Smpi 				if (status & UPS_PORT_L1)
1655cd7bad0Smpi 					printf(" l1");
1665cd7bad0Smpi 
1675cd7bad0Smpi 				if (status & UPS_PORT_POWER)
1685cd7bad0Smpi 					printf(" power");
1695cd7bad0Smpi 			} else {
1705cd7bad0Smpi 				if (status & UPS_PORT_POWER_SS)
1715cd7bad0Smpi 					printf(" power");
1725cd7bad0Smpi 
1735cd7bad0Smpi 				switch (UPS_PORT_LS_GET(status)) {
1745cd7bad0Smpi 				case UPS_PORT_LS_U0:
1755cd7bad0Smpi 					printf(" U0");
1765cd7bad0Smpi 					break;
1775cd7bad0Smpi 				case UPS_PORT_LS_U1:
1785cd7bad0Smpi 					printf(" U1");
1795cd7bad0Smpi 					break;
1805cd7bad0Smpi 				case UPS_PORT_LS_U2:
1815cd7bad0Smpi 					printf(" U2");
1825cd7bad0Smpi 					break;
1835cd7bad0Smpi 				case UPS_PORT_LS_U3:
1845cd7bad0Smpi 					printf(" U3");
1855cd7bad0Smpi 					break;
1865cd7bad0Smpi 				case UPS_PORT_LS_SS_DISABLED:
1875cd7bad0Smpi 					printf(" SS.disabled");
1885cd7bad0Smpi 					break;
1895cd7bad0Smpi 				case UPS_PORT_LS_RX_DETECT:
1905cd7bad0Smpi 					printf(" Rx.detect");
1915cd7bad0Smpi 					break;
1925cd7bad0Smpi 				case UPS_PORT_LS_SS_INACTIVE:
1935cd7bad0Smpi 					printf(" ss.inactive");
1945cd7bad0Smpi 					break;
1955cd7bad0Smpi 				case UPS_PORT_LS_POLLING:
1965cd7bad0Smpi 					printf(" polling");
1975cd7bad0Smpi 					break;
1985cd7bad0Smpi 				case UPS_PORT_LS_RECOVERY:
1995cd7bad0Smpi 					printf(" recovery");
2005cd7bad0Smpi 					break;
2015cd7bad0Smpi 				case UPS_PORT_LS_HOT_RESET:
2025cd7bad0Smpi 					printf(" hot.reset");
2035cd7bad0Smpi 					break;
2045cd7bad0Smpi 				case UPS_PORT_LS_COMP_MOD:
2055cd7bad0Smpi 					printf(" comp.mod");
2065cd7bad0Smpi 					break;
2075cd7bad0Smpi 				case UPS_PORT_LS_LOOPBACK:
2085cd7bad0Smpi 					printf(" loopback");
2095cd7bad0Smpi 					break;
210ad1b13fbSjakob 				}
211d412bb60Smpi 			}
212d412bb60Smpi 
2135cd7bad0Smpi 			printf("\n");
2145cd7bad0Smpi 		}
215ad1b13fbSjakob 	}
216ad1b13fbSjakob }
217ad1b13fbSjakob 
2181c95a3ebSckuethe void
dump_controller(char * name,int fd,uint8_t addr)2195de804ecSsemarie dump_controller(char *name, int fd, uint8_t addr)
220ad1b13fbSjakob {
2215de804ecSsemarie 	memset(done, 0, sizeof(done));
222ad1b13fbSjakob 
2235de804ecSsemarie 	if (addr) {
2245de804ecSsemarie 		dump_device(fd, addr);
2255de804ecSsemarie 		return;
226ad1b13fbSjakob 	}
227ad1b13fbSjakob 
228ad1b13fbSjakob 	printf("Controller %s:\n", name);
2295de804ecSsemarie 	for (addr = 1; addr < USB_MAX_DEVICES; addr++)
2305de804ecSsemarie 		if (!done[addr])
2315de804ecSsemarie 			dump_device(fd, addr);
232ad1b13fbSjakob }
233ad1b13fbSjakob 
234ad1b13fbSjakob int
main(int argc,char ** argv)2357517eab2Snate main(int argc, char **argv)
236ad1b13fbSjakob {
2375de804ecSsemarie 	int ch, fd;
2385de804ecSsemarie 	char *controller = NULL;
2395de804ecSsemarie 	uint8_t addr = 0;
24048800d7bSderaadt 	const char *errstr;
241ad1b13fbSjakob 
242e7155720Sdlg 	while ((ch = getopt(argc, argv, "a:d:v")) != -1) {
243ad1b13fbSjakob 		switch (ch) {
244ad1b13fbSjakob 		case 'a':
2455de804ecSsemarie 			addr = strtonum(optarg, 1, USB_MAX_DEVICES-1, &errstr);
24648800d7bSderaadt 			if (errstr)
24748800d7bSderaadt 				errx(1, "addr %s", errstr);
248ad1b13fbSjakob 			break;
249fb99babbSmickey 		case 'd':
2505de804ecSsemarie 			controller = optarg;
251ad1b13fbSjakob 			break;
252ad1b13fbSjakob 		case 'v':
25345249121Smpi 			verbose++;
254ad1b13fbSjakob 			break;
255ad1b13fbSjakob 		default:
256ad1b13fbSjakob 			usage();
257ad1b13fbSjakob 		}
258ad1b13fbSjakob 	}
259ad1b13fbSjakob 	argc -= optind;
260ad1b13fbSjakob 	argv += optind;
261ad1b13fbSjakob 
26245249121Smpi 	if (argc != 0)
26345249121Smpi 		usage();
26445249121Smpi 
265544844c4Smestre 	if (unveil("/dev", "r") == -1)
266bc5a8259Sbeck 		err(1, "unveil /dev");
267544844c4Smestre 	if (unveil(NULL, NULL) == -1)
268544844c4Smestre 		err(1, "unveil");
269544844c4Smestre 
2705de804ecSsemarie 	if (controller == NULL) {
2715de804ecSsemarie 		int i;
2725de804ecSsemarie 		int ncont = 0;
2735de804ecSsemarie 
2745de804ecSsemarie 		for (i = 0; i < 10; i++) {
2755de804ecSsemarie 			char path[PATH_MAX];
2765de804ecSsemarie 
2775de804ecSsemarie 			snprintf(path, sizeof(path), "%s%d", USBDEV, i);
2785de804ecSsemarie 			if ((fd = open(path, O_RDONLY)) < 0) {
2795de804ecSsemarie 				if (errno != ENOENT && errno != ENXIO)
2805de804ecSsemarie 					warn("%s", path);
281ad1b13fbSjakob 				continue;
282ad1b13fbSjakob 			}
2835de804ecSsemarie 
2845de804ecSsemarie 			dump_controller(path, fd, addr);
2855de804ecSsemarie 			close(fd);
286ad1b13fbSjakob 			ncont++;
287ad1b13fbSjakob 		}
288ad1b13fbSjakob 		if (verbose && ncont == 0)
2897517eab2Snate 			printf("%s: no USB controllers found\n",
2907517eab2Snate 			    __progname);
291ad1b13fbSjakob 	} else {
2925de804ecSsemarie 		if ((fd = open(controller, O_RDONLY)) < 0)
2935de804ecSsemarie 			err(1, "%s", controller);
2945de804ecSsemarie 
2955de804ecSsemarie 		dump_controller(controller, fd, addr);
2965de804ecSsemarie 		close(fd);
297ad1b13fbSjakob 	}
29845249121Smpi 
29945249121Smpi 	return 0;
300ad1b13fbSjakob }
301