aboutsummaryrefslogtreecommitdiff
path: root/sys/dev/hid/hidraw.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/hid/hidraw.c')
-rw-r--r--sys/dev/hid/hidraw.c93
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;