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);