summaryrefslogtreecommitdiffstats
path: root/sys/dev/usb/uhidev.c
diff options
context:
space:
mode:
authormiod <miod@openbsd.org>2010-08-02 23:17:34 +0000
committermiod <miod@openbsd.org>2010-08-02 23:17:34 +0000
commit8530dcc663bfc9ffe8edafb8dac18438a9b1efc4 (patch)
tree968ce6779a87d6eec6cb443a231f8114e5b32415 /sys/dev/usb/uhidev.c
parentDon't refer to xs->cmd, even via a pointer to xs->cmd, after xs has (diff)
downloadwireguard-openbsd-8530dcc663bfc9ffe8edafb8dac18438a9b1efc4.tar.xz
wireguard-openbsd-8530dcc663bfc9ffe8edafb8dac18438a9b1efc4.zip
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@
Diffstat (limited to 'sys/dev/usb/uhidev.c')
-rw-r--r--sys/dev/usb/uhidev.c71
1 files changed, 70 insertions, 1 deletions
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;
+}