diff options
| author | 2010-08-02 23:17:34 +0000 | |
|---|---|---|
| committer | 2010-08-02 23:17:34 +0000 | |
| commit | 8530dcc663bfc9ffe8edafb8dac18438a9b1efc4 (patch) | |
| tree | 968ce6779a87d6eec6cb443a231f8114e5b32415 /sys/dev/usb/uhidev.c | |
| parent | Don't refer to xs->cmd, even via a pointer to xs->cmd, after xs has (diff) | |
| download | wireguard-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.c | 71 |
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; +} |
