Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 24 Feb 2025 00:59:57 GMT
From:      "Bjoern A. Zeeb" <bz@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: c66308d7bcc3 - main - usbconfig: add -l option to dump_device_desc for single line output
Message-ID:  <202502240059.51O0xvPY039757@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by bz:

URL: https://cgit.FreeBSD.org/src/commit/?id=c66308d7bcc3931b60a096bfe6ba0f50105e77de

commit c66308d7bcc3931b60a096bfe6ba0f50105e77de
Author:     Bjoern A. Zeeb <bz@FreeBSD.org>
AuthorDate: 2025-02-12 22:53:06 +0000
Commit:     Bjoern A. Zeeb <bz@FreeBSD.org>
CommitDate: 2025-02-24 00:59:06 +0000

    usbconfig: add -l option to dump_device_desc for single line output
    
    Like pciconf -l add a -l to dump_device_desc for usbconfig which will
    fold most fields into a single line.  We do filter out some we think
    will not be interesting in this case.
    
    While mangling with string output in ways not always anticipated when
    the program was initially written this should help to parse the
    available devices for programs like fwget(8).  While I had this in
    mind for other bits for a while I got prompted by D48678 to finally
    do it.
    
    Sponsored by:   The FreebSD Foundation
    MFC after:      3 days
    Reviewed by:    bapt (LGTM), ziaee (man)
    Differential Revision: https://reviews.freebsd.org/D48974
---
 usr.sbin/usbconfig/dump.c      | 145 +++++++++++++++++++++++++++++++++++------
 usr.sbin/usbconfig/dump.h      |   5 +-
 usr.sbin/usbconfig/usbconfig.8 |   6 +-
 usr.sbin/usbconfig/usbconfig.c |  20 ++++--
 4 files changed, 148 insertions(+), 28 deletions(-)

diff --git a/usr.sbin/usbconfig/dump.c b/usr.sbin/usbconfig/dump.c
index 36f026bfc2fb..2a4a5300efeb 100644
--- a/usr.sbin/usbconfig/dump.c
+++ b/usr.sbin/usbconfig/dump.c
@@ -3,6 +3,10 @@
  *
  * Copyright (c) 2008 Hans Petter Selasky. All rights reserved.
  * Copyright (c) 2024 Baptiste Daroussin <bapt@FreeBSD.org>
+ * Copyright (c) 2025 The FreeBSD Foundation
+ *
+ * Portions of this software were developed by Björn Zeeb
+ * under sponsorship from the FreeBSD Foundation.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -28,22 +32,32 @@
 
 #include <sys/queue.h>
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <unistd.h>
 #include <err.h>
 #include <string.h>
 #include <pwd.h>
 #include <grp.h>
 #include <ctype.h>
+#include <fcntl.h>
 
 #include <libusb20.h>
 #include <libusb20_desc.h>
 
+#include <dev/usb/usb_ioctl.h>
+
 #include "dump.h"
 #include "pathnames.h"
 
+#ifndef IOUSB
+#define IOUSB(a) a
+#endif
+
 #define	DUMP0(n,type,field,...) dump_field(pdev, "  ", #field, n->field);
+#define	DUMP0L(n,type,field,...) dump_fieldl(pdev, "  ", #field, n->field);
 #define	DUMP1(n,type,field,...) dump_field(pdev, "    ", #field, n->field);
 #define	DUMP2(n,type,field,...) dump_field(pdev, "      ", #field, n->field);
 #define	DUMP3(n,type,field,...) dump_field(pdev, "        ", #field, n->field);
@@ -113,11 +127,21 @@ dump_power_mode(uint8_t value)
 }
 
 static void
-dump_field(struct libusb20_device *pdev, const char *plevel,
-    const char *field, uint32_t value)
+_dump_field(struct libusb20_device *pdev, const char *plevel,
+    const char *field, uint32_t value, bool list_mode)
 {
 	uint8_t temp_string[256];
 
+	if (list_mode) {
+		/* Skip fields we are not interested in. */
+		if (strcmp(field, "bLength") == 0 ||
+		    strcmp(field, "bDescriptorType") == 0 ||
+		    strcmp(field, "bMaxPacketSize0") == 0)
+			return;
+
+		printf("%s=%#06x ", field, value);
+		return;
+	}
 	printf("%s%s = 0x%04x ", plevel, field, value);
 
 	if (strlen(plevel) == 8) {
@@ -257,6 +281,20 @@ dump_field(struct libusb20_device *pdev, const char *plevel,
 	printf("\n");
 }
 
+static void
+dump_field(struct libusb20_device *pdev, const char *plevel,
+    const char *field, uint32_t value)
+{
+	_dump_field(pdev, plevel, field, value, false);
+}
+
+static void
+dump_fieldl(struct libusb20_device *pdev, const char *plevel,
+    const char *field, uint32_t value)
+{
+	_dump_field(pdev, plevel, field, value, true);
+}
+
 static void
 dump_extra(struct libusb20_me_struct *str, const char *plevel)
 {
@@ -396,16 +434,34 @@ load_vendors(void)
 	return (usb_vendors);
 }
 
+enum _device_descr_list_type {
+	_DEVICE_DESCR_LIST_TYPE_DEFAULT		= 0,
+	_DEVICE_DESCR_LIST_TYPE_UGEN		= 1,
+	_DEVICE_DESCR_LIST_TYPE_PRODUCT_VENDOR	= 2,
+};
+
 static char *
-_device_desc(struct libusb20_device *pdev)
+_device_desc(struct libusb20_device *pdev,
+    enum _device_descr_list_type list_type)
 {
 	static struct usb_vendors *usb_vendors = NULL;
 	char *desc = NULL;
 	const char *vendor = NULL, *product = NULL;
-	uint16_t vid = libusb20_dev_get_device_desc(pdev)->idVendor;
-	uint16_t pid = libusb20_dev_get_device_desc(pdev)->idProduct;
+	uint16_t vid;
+	uint16_t pid;
 	struct usb_vendor_info *vi;
 	struct usb_product_info *pi;
+	struct usb_device_info devinfo;
+
+	if (list_type == _DEVICE_DESCR_LIST_TYPE_UGEN) {
+		asprintf(&desc, "ugen%u.%u",
+				libusb20_dev_get_bus_number(pdev),
+				libusb20_dev_get_address(pdev));
+		return (desc);
+	}
+
+	vid = libusb20_dev_get_device_desc(pdev)->idVendor;
+	pid = libusb20_dev_get_device_desc(pdev)->idProduct;
 
 	if (usb_vendors == NULL)
 		usb_vendors = load_vendors();
@@ -424,6 +480,44 @@ _device_desc(struct libusb20_device *pdev)
 			}
 		}
 	}
+
+	/*
+	 * Try to gather the information; libusb2 unfortunately seems to
+	 * only build an entire string but not save vendor/product individually.
+	 */
+	if (vendor == NULL || product == NULL) {
+		char buf[64];
+		int f;
+
+		snprintf(buf, sizeof(buf), "/dev/" USB_GENERIC_NAME "%u.%u",
+		    libusb20_dev_get_bus_number(pdev),
+		    libusb20_dev_get_address(pdev));
+
+		f = open(buf, O_RDWR);
+		if (f < 0)
+			goto skip_vp_recovery;
+
+		if (ioctl(f, IOUSB(USB_GET_DEVICEINFO), &devinfo))
+			goto skip_vp_recovery;
+
+
+		if (vendor == NULL)
+			vendor = devinfo.udi_vendor;
+		if (product == NULL)
+			product = devinfo.udi_product;
+
+skip_vp_recovery:
+		if (f >= 0)
+			close(f);
+	}
+
+	if (list_type == _DEVICE_DESCR_LIST_TYPE_PRODUCT_VENDOR) {
+		asprintf(&desc, "vendor='%s' product='%s'",
+		    (vendor != NULL) ? vendor : "",
+		    (product != NULL) ? product : "");
+		return (desc);
+	}
+
 	if (vendor == NULL || product == NULL)
 		return (NULL);
 
@@ -433,12 +527,12 @@ _device_desc(struct libusb20_device *pdev)
 			product, vendor,
 			libusb20_dev_get_bus_number(pdev));
 
-
 	return (desc);
 }
 
 void
-dump_device_info(struct libusb20_device *pdev, uint8_t show_ifdrv)
+dump_device_info(struct libusb20_device *pdev, uint8_t show_ifdrv,
+    bool list_mode)
 {
 	char buf[128];
 	uint8_t n;
@@ -447,18 +541,22 @@ dump_device_info(struct libusb20_device *pdev, uint8_t show_ifdrv)
 
 	usage = libusb20_dev_get_power_usage(pdev);
 
-	desc = _device_desc(pdev);
-
-	printf("%s, cfg=%u md=%s spd=%s pwr=%s (%umA)\n",
-	    desc ? desc : libusb20_dev_get_desc(pdev),
-	    libusb20_dev_get_config_index(pdev),
-	    dump_mode(libusb20_dev_get_mode(pdev)),
-	    dump_speed(libusb20_dev_get_speed(pdev)),
-	    dump_power_mode(libusb20_dev_get_power_mode(pdev)),
-	    usage);
+	desc = _device_desc(pdev, (list_mode) ? _DEVICE_DESCR_LIST_TYPE_UGEN :
+	    _DEVICE_DESCR_LIST_TYPE_DEFAULT);
+
+	if (list_mode)
+		printf("%s: ", desc);
+	else
+		printf("%s, cfg=%u md=%s spd=%s pwr=%s (%umA)\n",
+		    desc ? desc : libusb20_dev_get_desc(pdev),
+		    libusb20_dev_get_config_index(pdev),
+		    dump_mode(libusb20_dev_get_mode(pdev)),
+		    dump_speed(libusb20_dev_get_speed(pdev)),
+		    dump_power_mode(libusb20_dev_get_power_mode(pdev)),
+		    usage);
 	free(desc);
 
-	if (!show_ifdrv)
+	if (list_mode || !show_ifdrv)
 		return;
 
 	for (n = 0; n != 255; n++) {
@@ -531,12 +629,21 @@ dump_be_dev_quirks(struct libusb20_backend *pbe)
 }
 
 void
-dump_device_desc(struct libusb20_device *pdev)
+dump_device_desc(struct libusb20_device *pdev, bool list_mode)
 {
 	struct LIBUSB20_DEVICE_DESC_DECODED *ddesc;
 
 	ddesc = libusb20_dev_get_device_desc(pdev);
-	LIBUSB20_DEVICE_DESC(DUMP0, ddesc);
+	if (list_mode) {
+		char *desc;
+
+		LIBUSB20_DEVICE_DESC(DUMP0L, ddesc);
+		desc = _device_desc(pdev, _DEVICE_DESCR_LIST_TYPE_PRODUCT_VENDOR);
+		printf("%s\n", (desc != NULL) ? desc : "");
+		free(desc);
+	} else {
+		LIBUSB20_DEVICE_DESC(DUMP0, ddesc);
+	}
 }
 
 void
diff --git a/usr.sbin/usbconfig/dump.h b/usr.sbin/usbconfig/dump.h
index 71adb47262ea..6adc8e54e5a9 100644
--- a/usr.sbin/usbconfig/dump.h
+++ b/usr.sbin/usbconfig/dump.h
@@ -32,10 +32,11 @@ const char *dump_mode(uint8_t value);
 const char *dump_speed(uint8_t value);
 const char *dump_power_mode(uint8_t value);
 void	dump_string_by_index(struct libusb20_device *pdev, uint8_t index);
-void	dump_device_info(struct libusb20_device *pdev, uint8_t show_drv);
+void	dump_device_info(struct libusb20_device *pdev, uint8_t show_drv,
+	    bool list_mode);
 void	dump_be_quirk_names(struct libusb20_backend *pbe);
 void	dump_be_dev_quirks(struct libusb20_backend *pbe);
-void	dump_device_desc(struct libusb20_device *pdev);
+void	dump_device_desc(struct libusb20_device *pdev, bool list_mode);
 void	dump_device_stats(struct libusb20_device *pdev);
 void	dump_config(struct libusb20_device *pdev, uint8_t all_cfg);
 
diff --git a/usr.sbin/usbconfig/usbconfig.8 b/usr.sbin/usbconfig/usbconfig.8
index 3926b03747e5..511fa9c5dddb 100644
--- a/usr.sbin/usbconfig/usbconfig.8
+++ b/usr.sbin/usbconfig/usbconfig.8
@@ -22,7 +22,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd January 29, 2022
+.Dd February 12, 2025
 .Dt USBCONFIG 8
 .Os
 .Sh NAME
@@ -30,6 +30,7 @@
 .Nd configure the USB subsystem
 .Sh SYNOPSIS
 .Nm
+.Op Fl l
 .Op Fl v
 .Op Fl a Ar addr
 .Op Fl i Ar interface_index
@@ -40,6 +41,7 @@
 .Sm off
 .Oo Oo Cm /dev/ Oc Cm ugen Oc Ar unit Cm \&. Ar addr
 .Sm on
+.Op Fl l
 .Op Fl v
 .Op Fl i Ar interface_index
 .Op Ar cmds ...
@@ -70,6 +72,8 @@ Show help and available commands.
 Specify interface index as indicated by the command description.
 If this argument is not specified
 a value of zero will be used for the interface index.
+.It Fl l Cm dump_device_desc
+Show numeral only key=value output as one long line.
 .It Fl u Ar unit
 Limit device range to USB devices connected to the given USBUS unit.
 .It Fl v
diff --git a/usr.sbin/usbconfig/usbconfig.c b/usr.sbin/usbconfig/usbconfig.c
index e28f8de9f75c..7cab4a1354b1 100644
--- a/usr.sbin/usbconfig/usbconfig.c
+++ b/usr.sbin/usbconfig/usbconfig.c
@@ -25,6 +25,7 @@
  * SUCH DAMAGE.
  */
 
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdint.h>
@@ -91,6 +92,7 @@ struct options {
 	uint8_t	got_dump_string:1;
 	uint8_t	got_do_request:1;
 	uint8_t	got_detach_kernel_driver:1;
+	uint8_t opt_dump_in_list_mode:1;
 };
 
 struct token {
@@ -504,11 +506,13 @@ flush_command(struct libusb20_backend *pbe, struct options *opt)
 
 		if (opt->got_list || dump_any) {
 			dump_device_info(pdev,
-			    opt->got_show_iface_driver);
+			    opt->got_show_iface_driver,
+			    opt->opt_dump_in_list_mode && opt->got_dump_device_desc);
 		}
 		if (opt->got_dump_device_desc) {
-			printf("\n");
-			dump_device_desc(pdev);
+			if (!opt->opt_dump_in_list_mode)
+				printf("\n");
+			dump_device_desc(pdev, opt->opt_dump_in_list_mode);
 		}
 		if (opt->got_dump_all_config) {
 			printf("\n");
@@ -518,14 +522,14 @@ flush_command(struct libusb20_backend *pbe, struct options *opt)
 			dump_config(pdev, 0);
 		} else if (opt->got_dump_all_desc) {
 			printf("\n");
-			dump_device_desc(pdev);
+			dump_device_desc(pdev, false);
 			dump_config(pdev, 1);
 		}
 		if (opt->got_dump_stats) {
 			printf("\n");
 			dump_device_stats(pdev);
 		}
-		if (dump_any) {
+		if (dump_any && !opt->opt_dump_in_list_mode) {
 			printf("\n");
 		}
 		if (libusb20_dev_close(pdev)) {
@@ -559,7 +563,7 @@ main(int argc, char **argv)
 	if (pbe == NULL)
 		err(1, "could not access USB backend\n");
 
-	while ((ch = getopt(argc, argv, "a:d:hi:u:v")) != -1) {
+	while ((ch = getopt(argc, argv, "a:d:hi:lu:v")) != -1) {
 		switch (ch) {
 		case 'a':
 			opt->addr = num_id(optarg, "addr");
@@ -596,6 +600,10 @@ main(int argc, char **argv)
 			opt->iface = num_id(optarg, "iface");
 			break;
 
+		case 'l':
+			opt->opt_dump_in_list_mode = 1;
+			break;
+
 		case 'u':
 			opt->bus = num_id(optarg, "busnum");
 			opt->got_bus = 1;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202502240059.51O0xvPY039757>