The branch stable/14 has been updated by bz:

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

commit 7907a9276081e9b1ccac839af91fe096e6779e9f
Author:     Bjoern A. Zeeb <b...@freebsd.org>
AuthorDate: 2025-02-12 22:53:06 +0000
Commit:     Bjoern A. Zeeb <b...@freebsd.org>
CommitDate: 2025-02-26 23:45:57 +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
    Reviewed by:    bapt (LGTM), ziaee (man)
    Differential Revision: https://reviews.freebsd.org/D48974
    
    (cherry picked from commit c66308d7bcc3931b60a096bfe6ba0f50105e77de)
---
 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 <b...@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 7d257fea52cd..9337effd835d 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;

Reply via email to