It is mostly quick and dirty, but does the job.
It can be found there:
https://github.com/mickaeltorres/openbsd_ugenctl or
inlined at the end of this mail.
Cheers,
Mike.
Here is the kernel patch:
Index: usb.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb.c,v
retrieving revision 1.107
diff -u -p -r1.107 usb.c
--- usb.c 14 Mar 2015 03:38:50 -0000 1.107
+++ usb.c 6 Dec 2015 04:29:22 -0000
@@ -137,6 +137,8 @@ const struct cfattach usb_ca = {
usb_activate,
};
+struct usb_device_ugen_force usb_udf;
+
int
usb_match(struct device *parent, void *match, void *aux)
{
@@ -156,6 +158,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);
+ bzero(&usb_udf, sizeof(usb_udf));
}
usb_nbuses++;
@@ -792,6 +795,23 @@ usbioctl(dev_t devt, u_long cmd, caddr_t
return (error);
}
+ case USB_DEVICE_FORCE_UGEN:
+ {
+ struct usb_device_ugen_force *udf =
+ (struct usb_device_ugen_force *)data;
+
+ if (udf->udf_set) // replace our list
+ {
+ memcpy(&usb_udf, udf, sizeof(usb_udf));
+ return (0);
+ }
+ else // return the list
+ {
+ memcpy(udf, &usb_udf, sizeof(usb_udf));
+ return (0);
+ }
+ }
+
default:
return (EINVAL);
}
Index: usb.h
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb.h,v
retrieving revision 1.53
diff -u -p -r1.53 usb.h
--- usb.h 9 Jul 2015 05:40:44 -0000 1.53
+++ usb.h 6 Dec 2015 04:29:23 -0000
@@ -749,6 +749,13 @@ struct usb_device_stats {
u_long uds_requests[4]; /* indexed by transfer type
UE_* */
};
+#define USB_DEVICE_UGEN_FORCE_MAX 16
+struct usb_device_ugen_force {
+ int udf_set;
+ u_short udf_ven_id[USB_DEVICE_UGEN_FORCE_MAX];
+ u_short udf_dev_id[USB_DEVICE_UGEN_FORCE_MAX];
+};
+
/* USB controller */
#define USB_REQUEST _IOWR('U', 1, struct usb_ctl_request)
#define USB_SETDEBUG _IOW ('U', 2, unsigned int)
@@ -758,6 +765,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_FORCE_UGEN _IOWR('U', 9, struct
usb_device_ugen_force)
/* Generic HID device */
#define USB_GET_REPORT_DESC _IOR ('U', 21, struct
usb_ctl_report_desc)
Index: usb_subr.c
===================================================================
RCS file: /cvs/src/sys/dev/usb/usb_subr.c,v
retrieving revision 1.117
diff -u -p -r1.117 usb_subr.c
--- usb_subr.c 23 Mar 2015 22:26:01 -0000 1.117
+++ usb_subr.c 6 Dec 2015 04:29:23 -0000
@@ -840,6 +840,7 @@ usbd_probe_and_attach(struct device *par
struct device *dv;
struct usbd_interface **ifaces;
extern struct rwlock usbpalock;
+ extern struct usb_device_ugen_force usb_udf;
rw_enter_write(&usbpalock);
@@ -855,6 +856,14 @@ 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 force list */
+ for (i = 0; i < USB_DEVICE_UGEN_FORCE_MAX; i++)
+ if ((usb_udf.udf_ven_id[i] == uaa.vendor) &&
+ (usb_udf.udf_dev_id[i] == uaa.product))
+ break;
+ if (i != USB_DEVICE_UGEN_FORCE_MAX)
+ 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);
And here is the ugenctl utility:
Makefile:
# $OpenBSD: Makefile,v 1.1 2000/02/03 21:52:15 jakob Exp $
# $NetBSD: Makefile,v 1.2 1998/07/12 20:40:45 augustss Exp $
PROG= ugenctl
MAN= ugenctl.8
.include <bsd.prog.mk>
ugenctl.c:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <err.h>
#include <dev/usb/usb.h>
struct usb_change_list {
u_short vid[USB_DEVICE_UGEN_FORCE_MAX];
u_short pid[USB_DEVICE_UGEN_FORCE_MAX];
int rem[USB_DEVICE_UGEN_FORCE_MAX];
int end;
};
#define USB_PATH "/dev/usb0"
extern char *__progname;
void
usage(void)
{
fprintf(stderr, "usage: %s [-f dev] [-r vid:pid] [-s
vid:pid]\n",
__progname);
exit(EXIT_FAILURE);
}
void
usb_list_ioctl(int f, struct usb_device_ugen_force *udf, int set)
{
int e;
udf->udf_set = set;
e = ioctl(f, USB_DEVICE_FORCE_UGEN, udf);
if (e)
err(EXIT_FAILURE, "ioctl()");
}
unsigned short
usb_parse_id(char *usb_id, int dev)
{
unsigned short id;
char *pid;
id = 0;
if (!dev)
id = strtol(usb_id, NULL, 0);
else {
pid = strchr(usb_id, ':');
if (!pid)
errx(EXIT_FAILURE, "can't parse usb
vendor_id:device_id
'%s'",
usb_id);
id = strtol(pid + 1, NULL, 0);
}
if (!id)
errx(EXIT_FAILURE, "vid/pid can't be zero '%s'",
usb_id);
return id;
}
void
usb_list_mod(struct usb_change_list *u, char *usb_id, int i, int rem)
{
unsigned short vid, pid;
if (i >= USB_DEVICE_UGEN_FORCE_MAX)
errx(EXIT_FAILURE, "too many changes, max changes is
%d",
USB_DEVICE_UGEN_FORCE_MAX);
vid = usb_parse_id(usb_id, 0);
pid = usb_parse_id(usb_id, 1);
u->vid[i] = vid;
u->pid[i] = pid;
u->rem[i] = rem;
u->end = i;
}
void
usb_list_change(struct usb_device_ugen_force *udf, struct
usb_change_list
*u)
{
int i, j;
for (i = 0; i < u->end + 1; i++)
for (j = 0; j < USB_DEVICE_UGEN_FORCE_MAX; j++)
if (u->rem[i]) {
if ((u->vid[i] == udf->udf_ven_id[j])
&&
(u->pid[i] ==
udf->udf_dev_id[j]))
{
udf->udf_ven_id[j] = 0;
udf->udf_dev_id[j] = 0;
}
} else {
if ((!udf->udf_ven_id[j]) &&
(!udf->udf_dev_id[j])) {
udf->udf_ven_id[j] =
u->vid[i];
udf->udf_dev_id[j] =
u->pid[i];
break;
}
}
}
int
main(int argc, char **argv)
{
struct usb_device_ugen_force udf;
struct usb_change_list usb_change;
int ch, f, i;
char *dev;
bzero(&udf, sizeof(udf));
bzero(&usb_change, sizeof(usb_change));
dev = strdup(USB_PATH);
if (!dev)
err(EXIT_FAILURE, "strdup()");
i = 0;
while ((ch = getopt(argc, argv, "f:r:s:")) != -1) {
switch (ch) {
case 'f':
free(dev);
dev = optarg;
break;
case 'r':
udf.udf_set = 1;
usb_list_mod(&usb_change, optarg, i, 1);
i++;
break;
case 's':
udf.udf_set = 1;
usb_list_mod(&usb_change, optarg, i, 0);
i++;
break;
default:
usage();
}
}
argc -= optind;
argv += optind;
if (argc)
usage();
f = open(dev, O_RDONLY);
if (f == -1)
err(EXIT_FAILURE, "can't open usb device %s", dev);
if (udf.udf_set) {
usb_list_ioctl(f, &udf, 0);
usb_list_change(&udf, &usb_change);
usb_list_ioctl(f, &udf, 1);
}
usb_list_ioctl(f, &udf, 0);
printf("currently ugen forced devices:\n");
for (i = 0; i < USB_DEVICE_UGEN_FORCE_MAX; i++)
if (udf.udf_ven_id[i] && udf.udf_dev_id[i])
printf("VID:0x%04x PID:0x%04x\n",
udf.udf_ven_id[i],
udf.udf_dev_id[i]);
return (EXIT_SUCCESS);
}
And ugenctl.8:
.Dd $Mdocdate: December 6 2015 $
.Dt UGENCTL 8
.Os
.Sh NAME
.Nm ugenctl
.Nd select which usb devices are forced to attach to ugen
.Sh SYNOPSIS
.Nm
.Op Fl f Ar dev
.Op Fl r Ar vid:pid
.Op Fl s Ar vid:pid
.Sh DESCRIPTION
.Nm
permits to change the in-kernel list of devices that are forced to
attach
as
ugen(4), even if they have a more specific driver. The actual list is
printed
at the end of any operation. If no operation are specified, it only
prints
the list.
.Pp
The options are as follows:
.Bl -tag -width Fl
.It Fl f Ar dev
Select the usb controller device to use, instead of the default
(/dev/usb0).
It has no incidence on the operation, devices connected to ALL
controllers
will
be affected.
.It Fl r Ar vid:pid
Remove the device identified by the vid:pid pair from the list, if it
is on
it.
.It Fl s Ar vid:pid
Add the device identified by the vid:pid pair on the list.
.El
.Sh FILES
.Bl -tag -width Pa
.It Pa /dev/usb[0-9]
Default USB controllers.
.El
.Sh SEE ALSO
.Xr usb 4
.Xr ugen 4
.Sh HISTORY
The
.Nm
command appeared in
.Ox 5.9 .
.Sh BUGS
Actually the maximum number of forced devices is constant and defined
in
macro
USB_DEVICE_UGEN_FORCE_MAX in usb.h .