Instead of having to disable USB drivers to force some devices to attach
as ugen(4), we can whitelist them.  Diff below does that by adding a new
option to usbdevs(8):

# usbdevs -l 7047:04ca -l a001:1199 

The logic is currently limited to 16 devices.  usbdevs(8) output could
be improved but I'm not sure what people want.

This should remove the need for running config -e on GENERIC kernels to
disable ulpt(4).

Comments?

Index: usr.sbin/usbdevs/usbdevs.c
===================================================================
RCS file: /cvs/src/usr.sbin/usbdevs/usbdevs.c,v
retrieving revision 1.25
diff -u -p -r1.25 usbdevs.c
--- usr.sbin/usbdevs/usbdevs.c  22 Dec 2015 08:36:40 -0000      1.25
+++ usr.sbin/usbdevs/usbdevs.c  24 Apr 2018 11:54:57 -0000
@@ -30,15 +30,17 @@
  * 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 <string.h>
-#include <sys/types.h>
-#include <fcntl.h>
 #include <unistd.h>
-#include <err.h>
-#include <errno.h>
-#include <dev/usb/usb.h>
 
 #ifndef nitems
 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
@@ -48,6 +50,10 @@
 
 int verbose = 0;
 int showdevs = 0;
+int adddevs = 0;
+int gotlist = 0;
+
+struct usb_device_list dl;
 
 void usage(void);
 void usbdev(int f, int a, int rec);
@@ -110,14 +116,13 @@ usbdev(int f, int a, int rec)
                else
                        printf("unconfigured, ");
        }
+       printf("%04x:%04x %s, %s", di.udi_productNo, di.udi_vendorNo,
+           di.udi_product, di.udi_vendor);
        if (verbose) {
-               printf("%s(0x%04x), %s(0x%04x), rev %s",
-                   di.udi_product, di.udi_productNo,
-                   di.udi_vendor, di.udi_vendorNo, di.udi_release);
+               printf(", rev %s", di.udi_release);
                if (strlen(di.udi_serial))
                        printf(", iSerialNumber %s", di.udi_serial);
-       } else
-               printf("%s, %s", di.udi_product, di.udi_vendor);
+       }
        printf("\n");
        if (showdevs) {
                for (i = 0; i < USB_MAX_DEVNAMES; i++)
@@ -169,6 +174,13 @@ dumpone(char *name, int f, int addr)
 {
        if (verbose)
                printf("Controller %s:\n", name);
+
+       if (!gotlist) {
+               dl.udl_cmd = USB_DEVICE_LIST_GET;
+               if (ioctl(f, USB_DEVICE_LIST, &dl))
+                       /* nothing */;
+       }
+
        indent = 0;
        memset(done, 0, sizeof done);
        if (addr)
@@ -177,6 +189,44 @@ dumpone(char *name, int f, int addr)
                usbdump(f);
 }
 
+void
+addlist(char *optarg)
+{
+       long vendorNo, productNo;
+       char *str, *ids, *endptr;
+       int i;
+
+       ids = strdup(optarg);
+
+       str = strtok(ids, ":");
+       if (str == NULL)
+               errx(1, "product");
+       productNo = strtol(str, &endptr, 16);
+       if (str[0] == '\0' || endptr[0] != '\0' || productNo > 0xffff)
+               errx(1, "product '%s'", str);
+
+       str = strtok(NULL, ":");
+       if (str == NULL)
+               errx(1, "vendor");
+       vendorNo = strtol(str, &endptr, 16);
+       if (str[0] == '\0' || endptr[0] != '\0' || vendorNo > 0xffff)
+               errx(1, "vendor '%s'", str);
+
+       free(ids);
+
+       for (i = 0; i < USB_DEVICE_LIST_MAX; i++) {
+               if (dl.udl_productNo[i] != 0 || dl.udl_vendorNo[i] != 0)
+                       continue;
+
+               dl.udl_productNo[i] = productNo;
+               dl.udl_vendorNo[i] = vendorNo;
+               break;
+       }
+
+       if (i == USB_DEVICE_LIST_MAX)
+               errx(1, "too many listed devices");
+}
+
 int
 main(int argc, char **argv)
 {
@@ -187,7 +237,7 @@ main(int argc, char **argv)
        int addr = 0;
        int ncont;
 
-       while ((ch = getopt(argc, argv, "a:df:v?")) != -1) {
+       while ((ch = getopt(argc, argv, "a:cdf:l:v?")) != -1) {
                switch (ch) {
                case 'a':
                        addr = strtonum(optarg, 1, USB_MAX_DEVICES, &errstr);
@@ -200,6 +250,10 @@ main(int argc, char **argv)
                case 'f':
                        dev = optarg;
                        break;
+               case 'l':
+                       adddevs = 1;
+                       addlist(optarg);
+                       break;
                case 'v':
                        verbose = 1;
                        break;
@@ -210,6 +264,21 @@ main(int argc, char **argv)
        argc -= optind;
        argv += optind;
 
+       if (argc != 0)
+               usage();
+
+       if (adddevs) {
+               snprintf(buf, sizeof buf, "%s0", USBDEV);
+               f = open(buf, O_RDWR);
+               if (f >= 0) {
+                       dl.udl_cmd = USB_DEVICE_LIST_SET;
+                       if (ioctl(f, USB_DEVICE_LIST, &dl))
+                               err(1, "USB_DEVICE_LIST_SET");
+               } else
+                       err(1, "%s", buf);
+               return 0;
+       }
+
        if (dev == 0) {
                for (ncont = 0, i = 0; i < 10; i++) {
                        snprintf(buf, sizeof buf, "%s%d", USBDEV, i);
@@ -229,10 +298,24 @@ main(int argc, char **argv)
                            __progname);
        } else {
                f = open(dev, O_RDONLY);
-               if (f >= 0)
+               if (f >= 0) {
                        dumpone(dev, f, addr);
-               else
+                       close(f);
+               } else
                        err(1, "%s", dev);
        }
-       exit(0);
+
+       if (verbose) {
+               printf("Devices using generic driver:\n");
+
+               for (i = 0; i < USB_DEVICE_LIST_MAX; i++) {
+                       if (dl.udl_productNo[i] == 0 && dl.udl_vendorNo[i] == 0)
+                               continue;
+
+                       printf(" %04x:%04x\n", dl.udl_productNo[i],
+                           dl.udl_vendorNo[i]);
+               }
+       }
+
+       return 0;
 }
Index: sys/dev/usb/usb.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb.c,v
retrieving revision 1.118
diff -u -p -r1.118 usb.c
--- sys/dev/usb/usb.c   26 Feb 2018 13:06:49 -0000      1.118
+++ sys/dev/usb/usb.c   24 Apr 2018 11:53:55 -0000
@@ -110,6 +110,7 @@ static int usb_nbuses = 0;
 static int usb_run_tasks, usb_run_abort_tasks;
 int explore_pending;
 const char *usbrev_str[] = USBREV_STR;
+struct usb_device_list usb_udl;
 
 void            usb_explore(void *);
 void            usb_create_task_threads(void *);
@@ -158,6 +159,7 @@ usb_attach(struct device *parent, struct
                TAILQ_INIT(&usb_generic_tasks);
                usb_run_tasks = usb_run_abort_tasks = 1;
                kthread_create_deferred(usb_create_task_threads, NULL);
+               memset(&usb_udl, 0, sizeof(usb_udl));
        }
        usb_nbuses++;
 
@@ -813,6 +815,46 @@ usbioctl(dev_t devt, u_long cmd, caddr_t
                return (error);
        }
 
+       case USB_DEVICE_LIST:
+       {
+               struct usb_device_list *udl = (struct usb_device_list *)data;
+               struct usbd_device *dev;
+               int addr, i;
+
+               switch (udl->udl_cmd) {
+               case USB_DEVICE_LIST_GET:
+                       memcpy(udl, &usb_udl, sizeof(usb_udl));
+                       break;
+               case USB_DEVICE_LIST_SET:
+                       if ((error = suser(curproc)) != 0)
+                               return (error);
+                       if (!(flag & FWRITE))
+                               return (EBADF);
+
+                       memcpy(&usb_udl, udl, sizeof(usb_udl));
+                       for (i = 0; i < usb_cd.cd_ndevs; i ++) {
+                               sc = usb_cd.cd_devs[i];
+                               if (sc == NULL)
+                                       continue;
+
+                               for (addr = 1; addr < USB_MAX_DEVICES; addr++) {
+                                       dev = sc->sc_bus->devices[addr];
+                                       if (dev == NULL)
+                                               continue;
+
+                                       if (usb_match_ugen_list(dev)) {
+                                               printf("%s: reattach\n", 
__func__);
+                                               usb_needs_reattach(dev);
+                                       }
+                               }
+                       }
+                       break;
+               default:
+                       return (EINVAL);
+               }
+               return (0);
+       }
+
        default:
                return (EINVAL);
        }
@@ -914,6 +956,20 @@ usb_needs_reattach(struct usbd_device *d
        DPRINTFN(2,("usb_needs_reattach\n"));
        dev->powersrc->reattach = 1;
        usb_needs_explore(dev, 0);
+}
+
+int
+usb_match_ugen_list(struct usbd_device *dev)
+{
+       int i;
+
+       for (i = 0; i < USB_DEVICE_LIST_MAX; i++) {
+               if ((UGETW(dev->ddesc.idVendor) == usb_udl.udl_vendorNo[i]) &&
+                   (UGETW(dev->ddesc.idProduct) == usb_udl.udl_productNo[i]))
+                       return 1;
+       }
+
+       return 0;
 }
 
 void
Index: sys/dev/usb/usb.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb.h,v
retrieving revision 1.59
diff -u -p -r1.59 usb.h
--- sys/dev/usb/usb.h   1 Sep 2017 16:38:14 -0000       1.59
+++ sys/dev/usb/usb.h   23 Apr 2018 15:31:48 -0000
@@ -756,6 +756,15 @@ struct usb_device_stats {
        u_long  uds_requests[4];        /* indexed by transfer type UE_* */
 };
 
+#define USB_DEVICE_LIST_GET 0
+#define USB_DEVICE_LIST_SET 1
+#define USB_DEVICE_LIST_MAX 16
+struct usb_device_list {
+        int            udl_cmd;
+        u_int16_t      udl_vendorNo[USB_DEVICE_LIST_MAX];
+        u_int16_t      udl_productNo[USB_DEVICE_LIST_MAX];
+};
+
 /* USB controller */
 #define USB_REQUEST            _IOWR('U', 1, struct usb_ctl_request)
 #define USB_SETDEBUG           _IOW ('U', 2, unsigned int)
@@ -764,6 +773,7 @@ struct usb_device_stats {
 #define USB_DEVICE_GET_CDESC   _IOWR('U', 6, struct usb_device_cdesc)
 #define USB_DEVICE_GET_FDESC   _IOWR('U', 7, struct usb_device_fdesc)
 #define USB_DEVICE_GET_DDESC   _IOWR('U', 8, struct usb_device_ddesc)
+#define USB_DEVICE_LIST                _IOWR('U', 9, struct usb_device_list)
 
 /* Generic HID device */
 #define USB_GET_REPORT_DESC    _IOR ('U', 21, struct usb_ctl_report_desc)
Index: sys/dev/usb/usb_subr.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb_subr.c,v
retrieving revision 1.134
diff -u -p -r1.134 usb_subr.c
--- sys/dev/usb/usb_subr.c      8 Apr 2017 02:57:25 -0000       1.134
+++ sys/dev/usb/usb_subr.c      24 Apr 2018 11:22:25 -0000
@@ -887,6 +887,10 @@ usbd_probe_and_attach(struct device *par
        uaa.product = UGETW(dd->idProduct);
        uaa.release = UGETW(dd->bcdDevice);
 
+       /* Check if this device is in the ugen(4) list. */
+       if (usb_match_ugen_list(dev))
+               goto generic;
+
        /* First try with device specific drivers. */
        DPRINTF(("usbd_probe_and_attach trying device specific drivers\n"));
        dv = config_found(parent, &uaa, usbd_print);
Index: sys/dev/usb/usbdivar.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usbdivar.h,v
retrieving revision 1.73
diff -u -p -r1.73 usbdivar.h
--- sys/dev/usb/usbdivar.h      3 Feb 2018 13:37:37 -0000       1.73
+++ sys/dev/usb/usbdivar.h      24 Apr 2018 11:25:55 -0000
@@ -261,6 +261,7 @@ int         usbd_detach(struct usbd_device *, s
 /* Routines from usb.c */
 void           usb_needs_explore(struct usbd_device *, int);
 void           usb_needs_reattach(struct usbd_device *);
+int            usb_match_ugen_list(struct usbd_device *);
 void           usb_schedsoftintr(struct usbd_bus *);
 void           usb_tap(struct usbd_bus *, struct usbd_xfer *, uint8_t);
 

Reply via email to