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