summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2010-08-02 23:17:37 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2010-08-02 23:17:37 +0000
commitd80928d3ec3eddf90d037391b62808bef72a7347 (patch)
treeef71742bd29fe4b095907dcecbb3d71706bcb644
parent3cda75f5bff339df3272b31a3de9141f3229d816 (diff)
Handle USB_GET_REPORT, USB_GET_REPORT_DESC, USB_GET_REPORT_ID and
USB_SET_REPORT ioctls in ukbd and ums. This allows usbhidctl to be used on these devices e.g. to dump the report descriptor of troublesome models. ok deraadt@
-rw-r--r--sys/dev/usb/uhid.c94
-rw-r--r--sys/dev/usb/uhidev.c71
-rw-r--r--sys/dev/usb/uhidev.h7
-rw-r--r--sys/dev/usb/ukbd.c18
-rw-r--r--sys/dev/usb/ums.c15
-rw-r--r--usr.bin/usbhidctl/usbhidctl.110
6 files changed, 126 insertions, 89 deletions
diff --git a/sys/dev/usb/uhid.c b/sys/dev/usb/uhid.c
index 9955bca0a97..3bf6476e824 100644
--- a/sys/dev/usb/uhid.c
+++ b/sys/dev/usb/uhid.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uhid.c,v 1.48 2010/07/26 01:56:27 guenther Exp $ */
+/* $OpenBSD: uhid.c,v 1.49 2010/08/02 23:17:34 miod Exp $ */
/* $NetBSD: uhid.c,v 1.57 2003/03/11 16:44:00 augustss Exp $ */
/*
@@ -73,10 +73,6 @@ int uhiddebug = 0;
struct uhid_softc {
struct uhidev sc_hdev;
- int sc_isize;
- int sc_osize;
- int sc_fsize;
-
u_char *sc_obuf;
struct clist sc_q;
@@ -146,12 +142,12 @@ uhid_attach(struct device *parent, struct device *self, void *aux)
uhidev_get_report_desc(uha->parent, &desc, &size);
repid = uha->reportid;
- sc->sc_isize = hid_report_size(desc, size, hid_input, repid);
- sc->sc_osize = hid_report_size(desc, size, hid_output, repid);
- sc->sc_fsize = hid_report_size(desc, size, hid_feature, repid);
+ sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid);
+ sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid);
+ sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid);
printf(": input=%d, output=%d, feature=%d\n",
- sc->sc_isize, sc->sc_osize, sc->sc_fsize);
+ sc->sc_hdev.sc_isize, sc->sc_hdev.sc_osize, sc->sc_hdev.sc_fsize);
}
int
@@ -263,7 +259,7 @@ uhidopen(dev_t dev, int flag, int mode, struct proc *p)
clalloc(&sc->sc_q, UHID_BSIZE, 0);
- sc->sc_obuf = malloc(sc->sc_osize, M_USBDEV, M_WAITOK);
+ sc->sc_obuf = malloc(sc->sc_hdev.sc_osize, M_USBDEV, M_WAITOK);
sc->sc_state &= ~UHID_IMMED;
sc->sc_async = NULL;
@@ -302,10 +298,10 @@ uhid_do_read(struct uhid_softc *sc, struct uio *uio, int flag)
DPRINTFN(1, ("uhidread immed\n"));
extra = sc->sc_hdev.sc_report_id != 0;
err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT,
- buffer, sc->sc_isize + extra);
+ buffer, sc->sc_hdev.sc_isize + extra);
if (err)
return (EIO);
- return (uiomove(buffer+extra, sc->sc_isize, uio));
+ return (uiomove(buffer+extra, sc->sc_hdev.sc_isize, uio));
}
s = splusb();
@@ -372,7 +368,7 @@ uhid_do_write(struct uhid_softc *sc, struct uio *uio, int flag)
if (sc->sc_dying)
return (EIO);
- size = sc->sc_osize;
+ size = sc->sc_hdev.sc_osize;
error = 0;
if (uio->uio_resid != size)
return (EINVAL);
@@ -406,12 +402,10 @@ int
uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr,
int flag, struct proc *p)
{
- struct usb_ctl_report_desc *rd;
- struct usb_ctl_report *re;
u_char buffer[UHID_CHUNK];
int size, extra;
usbd_status err;
- void *desc;
+ int rc;
DPRINTFN(2, ("uhidioctl: cmd=%lx\n", cmd));
@@ -441,19 +435,11 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr,
return (EPERM);
break;
- case USB_GET_REPORT_DESC:
- uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size);
- rd = (struct usb_ctl_report_desc *)addr;
- size = min(size, sizeof rd->ucrd_data);
- rd->ucrd_size = size;
- memcpy(rd->ucrd_data, desc, size);
- break;
-
case USB_SET_IMMED:
if (*(int *)addr) {
extra = sc->sc_hdev.sc_report_id != 0;
err = uhidev_get_report(&sc->sc_hdev, UHID_INPUT_REPORT,
- buffer, sc->sc_isize + extra);
+ buffer, sc->sc_hdev.sc_isize + extra);
if (err)
return (EOPNOTSUPP);
@@ -462,55 +448,6 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr,
sc->sc_state &= ~UHID_IMMED;
break;
- case USB_GET_REPORT:
- re = (struct usb_ctl_report *)addr;
- switch (re->ucr_report) {
- case UHID_INPUT_REPORT:
- size = sc->sc_isize;
- break;
- case UHID_OUTPUT_REPORT:
- size = sc->sc_osize;
- break;
- case UHID_FEATURE_REPORT:
- size = sc->sc_fsize;
- break;
- default:
- return (EINVAL);
- }
- extra = sc->sc_hdev.sc_report_id != 0;
- err = uhidev_get_report(&sc->sc_hdev, re->ucr_report,
- re->ucr_data, size + extra);
- if (extra)
- memcpy(re->ucr_data, re->ucr_data+1, size);
- if (err)
- return (EIO);
- break;
-
- case USB_SET_REPORT:
- re = (struct usb_ctl_report *)addr;
- switch (re->ucr_report) {
- case UHID_INPUT_REPORT:
- size = sc->sc_isize;
- break;
- case UHID_OUTPUT_REPORT:
- size = sc->sc_osize;
- break;
- case UHID_FEATURE_REPORT:
- size = sc->sc_fsize;
- break;
- default:
- return (EINVAL);
- }
- err = uhidev_set_report(&sc->sc_hdev, re->ucr_report,
- re->ucr_data, size);
- if (err)
- return (EIO);
- break;
-
- case USB_GET_REPORT_ID:
- *(int *)addr = sc->sc_hdev.sc_report_id;
- break;
-
case USB_GET_DEVICEINFO:
usbd_fill_deviceinfo(sc->sc_hdev.sc_parent->sc_udev,
(struct usb_device_info *)addr, 1);
@@ -527,8 +464,15 @@ uhid_do_ioctl(struct uhid_softc *sc, u_long cmd, caddr_t addr,
break;
}
+ case USB_GET_REPORT_DESC:
+ case USB_GET_REPORT:
+ case USB_SET_REPORT:
+ case USB_GET_REPORT_ID:
default:
- return (EINVAL);
+ rc = uhidev_ioctl(&sc->sc_hdev, cmd, addr, flag, p);
+ if (rc == -1)
+ rc = EINVAL;
+ return rc;
}
return (0);
}
diff --git a/sys/dev/usb/uhidev.c b/sys/dev/usb/uhidev.c
index 0bbf5142b9e..c15084b7cf6 100644
--- a/sys/dev/usb/uhidev.c
+++ b/sys/dev/usb/uhidev.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uhidev.c,v 1.37 2009/11/23 19:26:54 yuo Exp $ */
+/* $OpenBSD: uhidev.c,v 1.38 2010/08/02 23:17:34 miod Exp $ */
/* $NetBSD: uhidev.c,v 1.14 2003/03/11 16:44:00 augustss Exp $ */
/*
@@ -660,3 +660,72 @@ uhidev_write(struct uhidev_softc *sc, void *data, int len)
return usbd_intr_transfer(sc->sc_owxfer, sc->sc_opipe, 0,
USBD_NO_TIMEOUT, data, &len, "uhidevwi");
}
+
+int
+uhidev_ioctl(struct uhidev *sc, u_long cmd, caddr_t addr, int flag,
+ struct proc *p)
+{
+ struct usb_ctl_report_desc *rd;
+ struct usb_ctl_report *re;
+ int size, extra;
+ usbd_status err;
+ void *desc;
+
+ switch (cmd) {
+ case USB_GET_REPORT_DESC:
+ uhidev_get_report_desc(sc->sc_parent, &desc, &size);
+ rd = (struct usb_ctl_report_desc *)addr;
+ size = min(size, sizeof rd->ucrd_data);
+ rd->ucrd_size = size;
+ memcpy(rd->ucrd_data, desc, size);
+ break;
+ case USB_GET_REPORT:
+ re = (struct usb_ctl_report *)addr;
+ switch (re->ucr_report) {
+ case UHID_INPUT_REPORT:
+ size = sc->sc_isize;
+ break;
+ case UHID_OUTPUT_REPORT:
+ size = sc->sc_osize;
+ break;
+ case UHID_FEATURE_REPORT:
+ size = sc->sc_fsize;
+ break;
+ default:
+ return EINVAL;
+ }
+ extra = sc->sc_report_id != 0;
+ err = uhidev_get_report(sc, re->ucr_report, re->ucr_data,
+ size + extra);
+ if (extra)
+ memcpy(re->ucr_data, re->ucr_data + 1, size);
+ if (err)
+ return EIO;
+ break;
+ case USB_SET_REPORT:
+ re = (struct usb_ctl_report *)addr;
+ switch (re->ucr_report) {
+ case UHID_INPUT_REPORT:
+ size = sc->sc_isize;
+ break;
+ case UHID_OUTPUT_REPORT:
+ size = sc->sc_osize;
+ break;
+ case UHID_FEATURE_REPORT:
+ size = sc->sc_fsize;
+ break;
+ default:
+ return EINVAL;
+ }
+ err = uhidev_set_report(sc, re->ucr_report, re->ucr_data, size);
+ if (err)
+ return EIO;
+ break;
+ case USB_GET_REPORT_ID:
+ *(int *)addr = sc->sc_report_id;
+ break;
+ default:
+ return -1;
+ }
+ return 0;
+}
diff --git a/sys/dev/usb/uhidev.h b/sys/dev/usb/uhidev.h
index ba08593a324..079b1f839e4 100644
--- a/sys/dev/usb/uhidev.h
+++ b/sys/dev/usb/uhidev.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: uhidev.h,v 1.10 2008/06/26 05:42:18 ray Exp $ */
+/* $OpenBSD: uhidev.h,v 1.11 2010/08/02 23:17:34 miod Exp $ */
/* $NetBSD: uhidev.h,v 1.3 2002/10/08 09:56:17 dan Exp $ */
/*
@@ -71,6 +71,10 @@ struct uhidev {
int sc_in_rep_size;
#define UHIDEV_OPEN 0x01 /* device is open */
void (*sc_intr)(struct uhidev *, void *, u_int);
+
+ int sc_isize;
+ int sc_osize;
+ int sc_fsize;
};
struct uhidev_attach_arg {
@@ -84,6 +88,7 @@ struct uhidev_attach_arg {
void uhidev_get_report_desc(struct uhidev_softc *, void **, int *);
int uhidev_open(struct uhidev *);
void uhidev_close(struct uhidev *);
+int uhidev_ioctl(struct uhidev *, u_long, caddr_t, int, struct proc *);
usbd_status uhidev_set_report(struct uhidev *scd, int type, void *data,int len);
void uhidev_set_report_async(struct uhidev *scd, int type, void *data, int len);
usbd_status uhidev_get_report(struct uhidev *scd, int type, void *data,int len);
diff --git a/sys/dev/usb/ukbd.c b/sys/dev/usb/ukbd.c
index 6f63447b085..d9b258890e9 100644
--- a/sys/dev/usb/ukbd.c
+++ b/sys/dev/usb/ukbd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ukbd.c,v 1.52 2010/07/31 16:04:50 miod Exp $ */
+/* $OpenBSD: ukbd.c,v 1.53 2010/08/02 23:17:34 miod Exp $ */
/* $NetBSD: ukbd.c,v 1.85 2003/03/11 16:44:00 augustss Exp $ */
/*
@@ -180,7 +180,7 @@ ukbd_attach(struct device *parent, struct device *self, void *aux)
struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
usb_hid_descriptor_t *hid;
u_int32_t qflags;
- int dlen;
+ int dlen, repid;
void *desc;
kbd_t layout = (kbd_t)-1;
@@ -189,8 +189,13 @@ ukbd_attach(struct device *parent, struct device *self, void *aux)
sc->sc_hdev.sc_report_id = uha->reportid;
uhidev_get_report_desc(uha->parent, &desc, &dlen);
+ repid = uha->reportid;
+ sc->sc_hdev.sc_isize = hid_report_size(desc, dlen, hid_input, repid);
+ sc->sc_hdev.sc_osize = hid_report_size(desc, dlen, hid_output, repid);
+ sc->sc_hdev.sc_fsize = hid_report_size(desc, dlen, hid_feature, repid);
+
qflags = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
- if (hidkbd_attach(self, kbd, 1, qflags, uha->reportid, desc, dlen) != 0)
+ if (hidkbd_attach(self, kbd, 1, qflags, repid, desc, dlen) != 0)
return;
if (uha->uaa->vendor == USB_VENDOR_TOPRE &&
@@ -320,6 +325,7 @@ ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
struct ukbd_softc *sc = v;
struct hidkbd *kbd = &sc->sc_kbd;
+ int rc;
switch (cmd) {
case WSKBDIO_GTYPE:
@@ -329,7 +335,11 @@ ukbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
ukbd_set_leds(v, *(int *)data);
return (0);
default:
- return hidkbd_ioctl(kbd, cmd, data, flag, p);
+ rc = uhidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
+ if (rc != -1)
+ return rc;
+ else
+ return hidkbd_ioctl(kbd, cmd, data, flag, p);
}
}
diff --git a/sys/dev/usb/ums.c b/sys/dev/usb/ums.c
index 2a72197acb1..01bfd659423 100644
--- a/sys/dev/usb/ums.c
+++ b/sys/dev/usb/ums.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ums.c,v 1.32 2010/07/31 16:04:50 miod Exp $ */
+/* $OpenBSD: ums.c,v 1.33 2010/08/02 23:17:34 miod Exp $ */
/* $NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $ */
/*
@@ -114,7 +114,7 @@ ums_attach(struct device *parent, struct device *self, void *aux)
struct hidms *ms = &sc->sc_ms;
struct usb_attach_arg *uaa = aux;
struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
- int size;
+ int size, repid;
void *desc;
u_int32_t quirks;
@@ -124,6 +124,10 @@ ums_attach(struct device *parent, struct device *self, void *aux)
quirks = usbd_get_quirks(uha->parent->sc_udev)->uq_flags;
uhidev_get_report_desc(uha->parent, &desc, &size);
+ repid = uha->reportid;
+ sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid);
+ sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid);
+ sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid);
if (hidms_setup(self, ms, quirks, uha->reportid, desc, size) != 0)
return;
@@ -221,12 +225,17 @@ ums_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
{
struct ums_softc *sc = v;
struct hidms *ms = &sc->sc_ms;
+ int rc;
switch (cmd) {
case WSMOUSEIO_GTYPE:
*(u_int *)data = WSMOUSE_TYPE_USB;
return 0;
default:
- return hidms_ioctl(ms, cmd, data, flag, p);
+ rc = uhidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
+ if (rc != -1)
+ return rc;
+ else
+ return hidms_ioctl(ms, cmd, data, flag, p);
}
}
diff --git a/usr.bin/usbhidctl/usbhidctl.1 b/usr.bin/usbhidctl/usbhidctl.1
index 171c35a6179..70af793e369 100644
--- a/usr.bin/usbhidctl/usbhidctl.1
+++ b/usr.bin/usbhidctl/usbhidctl.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: usbhidctl.1,v 1.12 2008/10/16 18:37:19 jakemsr Exp $
+.\" $OpenBSD: usbhidctl.1,v 1.13 2010/08/02 23:17:36 miod Exp $
.\" $NetBSD: usbhidctl.1,v 1.14 2001/12/28 17:49:32 augustss Exp $
.\"
.\" Copyright (c) 2001 The NetBSD Foundation, Inc.
@@ -28,7 +28,7 @@
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: October 16 2008 $
+.Dd $Mdocdate: August 2 2010 $
.Dt USBHIDCTL 1
.Os
.Sh NAME
@@ -162,7 +162,7 @@ For example the
.Qq button 2
item would usually just be referred to on the command line as:
.Pp
-.Dl $ usbhidctl -f /dev/mouse Mouse.Pointer.Button_2
+.Dl $ usbhidctl -f /dev/wsmouse0 Mouse.Pointer.Button_2
.Pp
Items can also be named by referring to parts of the item name with the
numeric representation of the native HID usage identifiers.
@@ -175,7 +175,7 @@ is 2, so the following can be used to refer to the
.Qq button 2
item:
.Pp
-.Dl $ usbhidctl -f /dev/mouse 1:Mouse.1:Pointer.Button:2
+.Dl $ usbhidctl -f /dev/wsmouse0 1:Mouse.1:Pointer.Button:2
.Pp
Devices with human interface outputs can be manipulated with the
.Fl w
@@ -186,7 +186,7 @@ control as usage 2 under page 0xffff, in the
collection.
The following can be used to switch this LED off:
.Pp
-.Dl $ usbhidctl -f /dev/mouse -w Mouse.0xffff:2=0
+.Dl $ usbhidctl -f /dev/wsmouse0 -w Mouse.0xffff:2=0
.Sh SEE ALSO
.Xr usbhidaction 1 ,
.Xr usbhid 3 ,