From 8530dcc663bfc9ffe8edafb8dac18438a9b1efc4 Mon Sep 17 00:00:00 2001 From: miod Date: Mon, 2 Aug 2010 23:17:34 +0000 Subject: [PATCH] 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@ --- sys/dev/usb/uhid.c | 94 +++++++---------------------------- sys/dev/usb/uhidev.c | 71 +++++++++++++++++++++++++- sys/dev/usb/uhidev.h | 7 ++- sys/dev/usb/ukbd.c | 18 +++++-- sys/dev/usb/ums.c | 15 ++++-- usr.bin/usbhidctl/usbhidctl.1 | 10 ++-- 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 , -- 2.20.1