[BACK]Return to usbdevs.c CVS log [TXT][DIR] Up to [local] / src / usr.sbin / usbdevs

File: [local] / src / usr.sbin / usbdevs / usbdevs.c (download)

Revision 1.36, Wed Dec 28 21:30:19 2022 UTC (17 months ago) by jmc
Branch: MAIN
CVS Tags: OPENBSD_7_5_BASE, OPENBSD_7_5, OPENBSD_7_4_BASE, OPENBSD_7_4, OPENBSD_7_3_BASE, OPENBSD_7_3, HEAD
Changes since 1.35: +2 -2 lines

spelling fixes; from paul tagliamonte
any parts of his diff not taken are noted on tech

/*	$OpenBSD: usbdevs.c,v 1.36 2022/12/28 21:30:19 jmc Exp $	*/
/*	$NetBSD: usbdevs.c,v 1.19 2002/02/21 00:34:31 christos Exp $	*/

/*
 * Copyright (c) 1998 The NetBSD Foundation, Inc.
 * All rights reserved.
 *
 * This code is derived from software contributed to The NetBSD Foundation
 * by Lennart Augustsson (augustss@netbsd.org).
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/types.h>
#include <dev/usb/usb.h>

#include <err.h>
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <vis.h>
#include <string.h>
#include <unistd.h>

#ifndef nitems
#define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
#endif

#define MINIMUM(a, b) (((a) < (b)) ? (a) : (b))

#define USBDEV "/dev/usb"

int verbose = 0;
char done[USB_MAX_DEVICES];

void usage(void);
void dump_device(int, uint8_t);
void dump_controller(char *, int, uint8_t);
int main(int, char **);

extern char *__progname;

void
usage(void)
{
	fprintf(stderr, "usage: %s [-v] [-a addr] [-d usbdev]\n", __progname);
	exit(1);
}

void
dump_device(int fd, uint8_t addr)
{
	struct usb_device_info di;
	int i;
	char vv[sizeof(di.udi_vendor)*4], vp[sizeof(di.udi_product)*4];
	char vr[sizeof(di.udi_release)*4], vs[sizeof(di.udi_serial)*4];

	di.udi_addr = addr;
	if (ioctl(fd, USB_DEVICEINFO, &di) == -1) {
		if (errno != ENXIO)
			warn("addr %u", addr);
		return;
	}

	done[addr] = 1;

	strvis(vv, di.udi_vendor, VIS_CSTYLE);
	strvis(vp, di.udi_product, VIS_CSTYLE);
	printf("addr %02u: %04x:%04x %s, %s", addr,
	    di.udi_vendorNo, di.udi_productNo,
	    vv, vp);

	if (verbose) {
		printf("\n\t ");
		switch (di.udi_speed) {
		case USB_SPEED_LOW:
			printf("low speed");
			break;
		case USB_SPEED_FULL:
			printf("full speed");
			break;
		case USB_SPEED_HIGH:
			printf("high speed");
			break;
		case USB_SPEED_SUPER:
			printf("super speed");
			break;
		default:
			break;
		}

		if (di.udi_power)
			printf(", power %d mA", di.udi_power);
		else
			printf(", self powered");

		if (di.udi_config)
			printf(", config %d", di.udi_config);
		else
			printf(", unconfigured");

		strvis(vr, di.udi_release, VIS_CSTYLE);
		printf(", rev %s", vr);

		if (di.udi_serial[0] != '\0') {
			strvis(vs, di.udi_serial, VIS_CSTYLE);
			printf(", iSerial %s", vs);
		}
	}
	printf("\n");

	if (verbose)
		for (i = 0; i < USB_MAX_DEVNAMES; i++)
			if (di.udi_devnames[i][0] != '\0')
				printf("\t driver: %s\n", di.udi_devnames[i]);

	if (verbose > 1) {
		int port, nports;

		nports = MINIMUM(di.udi_nports, nitems(di.udi_ports));
		for (port = 0; port < nports; port++) {
			uint16_t status, change;

			status = di.udi_ports[port] & 0xffff;
			change = di.udi_ports[port] >> 16;

			printf("\t port %02u: %04x.%04x", port+1, change,
			    status);

			if (status & UPS_CURRENT_CONNECT_STATUS)
				printf(" connect");

			if (status & UPS_PORT_ENABLED)
				printf(" enabled");

			if (status & UPS_SUSPEND)
				printf(" suspend");

			if (status & UPS_OVERCURRENT_INDICATOR)
				printf(" overcurrent");

			if (di.udi_speed < USB_SPEED_SUPER) {
				if (status & UPS_PORT_L1)
					printf(" l1");

				if (status & UPS_PORT_POWER)
					printf(" power");
			} else {
				if (status & UPS_PORT_POWER_SS)
					printf(" power");

				switch (UPS_PORT_LS_GET(status)) {
				case UPS_PORT_LS_U0:
					printf(" U0");
					break;
				case UPS_PORT_LS_U1:
					printf(" U1");
					break;
				case UPS_PORT_LS_U2:
					printf(" U2");
					break;
				case UPS_PORT_LS_U3:
					printf(" U3");
					break;
				case UPS_PORT_LS_SS_DISABLED:
					printf(" SS.disabled");
					break;
				case UPS_PORT_LS_RX_DETECT:
					printf(" Rx.detect");
					break;
				case UPS_PORT_LS_SS_INACTIVE:
					printf(" ss.inactive");
					break;
				case UPS_PORT_LS_POLLING:
					printf(" polling");
					break;
				case UPS_PORT_LS_RECOVERY:
					printf(" recovery");
					break;
				case UPS_PORT_LS_HOT_RESET:
					printf(" hot.reset");
					break;
				case UPS_PORT_LS_COMP_MOD:
					printf(" comp.mod");
					break;
				case UPS_PORT_LS_LOOPBACK:
					printf(" loopback");
					break;
				}
			}

			printf("\n");
		}
	}
}

void
dump_controller(char *name, int fd, uint8_t addr)
{
	memset(done, 0, sizeof(done));

	if (addr) {
		dump_device(fd, addr);
		return;
	}

	printf("Controller %s:\n", name);
	for (addr = 1; addr < USB_MAX_DEVICES; addr++)
		if (!done[addr])
			dump_device(fd, addr);
}

int
main(int argc, char **argv)
{
	int ch, fd;
	char *controller = NULL;
	uint8_t addr = 0;
	const char *errstr;

	while ((ch = getopt(argc, argv, "a:d:v")) != -1) {
		switch (ch) {
		case 'a':
			addr = strtonum(optarg, 1, USB_MAX_DEVICES-1, &errstr);
			if (errstr)
				errx(1, "addr %s", errstr);
			break;
		case 'd':
			controller = optarg;
			break;
		case 'v':
			verbose++;
			break;
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (argc != 0)
		usage();

	if (unveil("/dev", "r") == -1)
		err(1, "unveil /dev");
	if (unveil(NULL, NULL) == -1)
		err(1, "unveil");

	if (controller == NULL) {
		int i;
		int ncont = 0;

		for (i = 0; i < 10; i++) {
			char path[PATH_MAX];

			snprintf(path, sizeof(path), "%s%d", USBDEV, i);
			if ((fd = open(path, O_RDONLY)) < 0) {
				if (errno != ENOENT && errno != ENXIO)
					warn("%s", path);
				continue;
			}

			dump_controller(path, fd, addr);
			close(fd);
			ncont++;
		}
		if (verbose && ncont == 0)
			printf("%s: no USB controllers found\n",
			    __progname);
	} else {
		if ((fd = open(controller, O_RDONLY)) < 0)
			err(1, "%s", controller);

		dump_controller(controller, fd, addr);
		close(fd);
	}

	return 0;
}