Handle USB_GET_REPORT, USB_GET_REPORT_DESC, USB_GET_REPORT_ID and
authormiod <miod@openbsd.org>
Mon, 2 Aug 2010 23:17:34 +0000 (23:17 +0000)
committermiod <miod@openbsd.org>
Mon, 2 Aug 2010 23:17:34 +0000 (23:17 +0000)
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
sys/dev/usb/uhidev.c
sys/dev/usb/uhidev.h
sys/dev/usb/ukbd.c
sys/dev/usb/ums.c
usr.bin/usbhidctl/usbhidctl.1

index 9955bca..3bf6476 100644 (file)
@@ -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);
 }
index 0bbf514..c15084b 100644 (file)
@@ -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;
+}
index ba08593..079b1f8 100644 (file)
@@ -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);
index 6f63447..d9b2588 100644 (file)
@@ -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);
        }
 }
 
index 2a72197..01bfd65 100644 (file)
@@ -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);
        }
 }
index 171c35a..70af793 100644 (file)
@@ -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 ,