diff options
Diffstat (limited to 'sys/dev/hid/hidraw.c')
-rw-r--r-- | sys/dev/hid/hidraw.c | 93 |
1 files changed, 89 insertions, 4 deletions
diff --git a/sys/dev/hid/hidraw.c b/sys/dev/hid/hidraw.c index e71b2e2c7d5d..f359fe3e7e6f 100644 --- a/sys/dev/hid/hidraw.c +++ b/sys/dev/hid/hidraw.c @@ -41,6 +41,9 @@ __FBSDID("$FreeBSD$"); #include "opt_hid.h" #include <sys/param.h> +#ifdef COMPAT_FREEBSD32 +#include <sys/abi_compat.h> +#endif #include <sys/bus.h> #include <sys/conf.h> #include <sys/fcntl.h> @@ -115,6 +118,31 @@ struct hidraw_softc { struct cdev *dev; }; +#ifdef COMPAT_FREEBSD32 +struct hidraw_gen_descriptor32 { + uint32_t hgd_data; /* void * */ + uint16_t hgd_lang_id; + uint16_t hgd_maxlen; + uint16_t hgd_actlen; + uint16_t hgd_offset; + uint8_t hgd_config_index; + uint8_t hgd_string_index; + uint8_t hgd_iface_index; + uint8_t hgd_altif_index; + uint8_t hgd_endpt_index; + uint8_t hgd_report_type; + uint8_t reserved[8]; +}; +#define HIDRAW_GET_REPORT_DESC32 \ + _IOC_NEWTYPE(HIDRAW_GET_REPORT_DESC, struct hidraw_gen_descriptor32) +#define HIDRAW_GET_REPORT32 \ + _IOC_NEWTYPE(HIDRAW_GET_REPORT, struct hidraw_gen_descriptor32) +#define HIDRAW_SET_REPORT_DESC32 \ + _IOC_NEWTYPE(HIDRAW_SET_REPORT_DESC, struct hidraw_gen_descriptor32) +#define HIDRAW_SET_REPORT32 \ + _IOC_NEWTYPE(HIDRAW_SET_REPORT, struct hidraw_gen_descriptor32) +#endif + static d_open_t hidraw_open; static d_read_t hidraw_read; static d_write_t hidraw_write; @@ -507,11 +535,35 @@ hidraw_write(struct cdev *dev, struct uio *uio, int flag) return (error); } +#ifdef COMPAT_FREEBSD32 +static void +update_hgd32(const struct hidraw_gen_descriptor *hgd, + struct hidraw_gen_descriptor32 *hgd32) +{ + /* Don't update hgd_data pointer */ + CP(*hgd, *hgd32, hgd_lang_id); + CP(*hgd, *hgd32, hgd_maxlen); + CP(*hgd, *hgd32, hgd_actlen); + CP(*hgd, *hgd32, hgd_offset); + CP(*hgd, *hgd32, hgd_config_index); + CP(*hgd, *hgd32, hgd_string_index); + CP(*hgd, *hgd32, hgd_iface_index); + CP(*hgd, *hgd32, hgd_altif_index); + CP(*hgd, *hgd32, hgd_endpt_index); + CP(*hgd, *hgd32, hgd_report_type); + /* Don't update reserved */ +} +#endif + static int hidraw_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *td) { uint8_t local_buf[HIDRAW_LOCAL_BUFSIZE]; +#ifdef COMPAT_FREEBSD32 + struct hidraw_gen_descriptor local_hgd; + struct hidraw_gen_descriptor32 *hgd32 = NULL; +#endif void *buf; struct hidraw_softc *sc; struct hidraw_gen_descriptor *hgd; @@ -527,6 +579,32 @@ hidraw_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, if (sc == NULL) return (EIO); +#ifdef COMPAT_FREEBSD32 + hgd = (struct hidraw_gen_descriptor *)addr; + switch (cmd) { + case HIDRAW_GET_REPORT_DESC32: + case HIDRAW_GET_REPORT32: + case HIDRAW_SET_REPORT_DESC32: + case HIDRAW_SET_REPORT32: + cmd = _IOC_NEWTYPE(cmd, struct hidraw_gen_descriptor); + hgd32 = (struct hidraw_gen_descriptor32 *)addr; + hgd = &local_hgd; + PTRIN_CP(*hgd32, *hgd, hgd_data); + CP(*hgd32, *hgd, hgd_lang_id); + CP(*hgd32, *hgd, hgd_maxlen); + CP(*hgd32, *hgd, hgd_actlen); + CP(*hgd32, *hgd, hgd_offset); + CP(*hgd32, *hgd, hgd_config_index); + CP(*hgd32, *hgd, hgd_string_index); + CP(*hgd32, *hgd, hgd_iface_index); + CP(*hgd32, *hgd, hgd_altif_index); + CP(*hgd32, *hgd, hgd_endpt_index); + CP(*hgd32, *hgd, hgd_report_type); + /* Don't copy reserved */ + break; + } +#endif + /* fixed-length ioctls handling */ switch (cmd) { case FIONBIO: @@ -562,15 +640,19 @@ hidraw_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, mtx_lock(&sc->sc_mtx); sc->sc_state.uhid = true; mtx_unlock(&sc->sc_mtx); - hgd = (struct hidraw_gen_descriptor *)addr; if (sc->sc_rdesc->len > hgd->hgd_maxlen) { size = hgd->hgd_maxlen; } else { size = sc->sc_rdesc->len; } hgd->hgd_actlen = size; +#ifdef COMPAT_FREEBSD32 + if (hgd32 != NULL) + update_hgd32(hgd, hgd32); +#endif if (hgd->hgd_data == NULL) return (0); /* descriptor length only */ + return (copyout(sc->sc_rdesc->data, hgd->hgd_data, size)); @@ -593,7 +675,6 @@ hidraw_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, if (error != 0) return(error); - hgd = (struct hidraw_gen_descriptor *)addr; buf = HIDRAW_LOCAL_ALLOC(local_buf, hgd->hgd_maxlen); copyin(hgd->hgd_data, buf, hgd->hgd_maxlen); /* Lock newbus around set_report_descr call */ @@ -640,7 +721,6 @@ hidraw_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, case HIDRAW_GET_REPORT: if (!(sc->sc_fflags & FREAD)) return (EPERM); - hgd = (struct hidraw_gen_descriptor *)addr; switch (hgd->hgd_report_type) { case HID_INPUT_REPORT: size = sc->sc_rdesc->isize; @@ -666,12 +746,17 @@ hidraw_ioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, if (!error) error = copyout(buf, hgd->hgd_data, size); HIDRAW_LOCAL_FREE(local_buf, buf); +#ifdef COMPAT_FREEBSD32 + /* + * HIDRAW_GET_REPORT is declared _IOWR, but hgd is not written + * so we don't call update_hgd32(). + */ +#endif return (error); case HIDRAW_SET_REPORT: if (!(sc->sc_fflags & FWRITE)) return (EPERM); - hgd = (struct hidraw_gen_descriptor *)addr; switch (hgd->hgd_report_type) { case HID_INPUT_REPORT: size = sc->sc_rdesc->isize; |