aboutsummaryrefslogtreecommitdiff
path: root/lib/libusbhid
diff options
context:
space:
mode:
Diffstat (limited to 'lib/libusbhid')
-rw-r--r--lib/libusbhid/Makefile21
-rw-r--r--lib/libusbhid/Makefile.depend15
-rw-r--r--lib/libusbhid/data.c142
-rw-r--r--lib/libusbhid/descr.c175
-rw-r--r--lib/libusbhid/descr_compat.c78
-rw-r--r--lib/libusbhid/parse.c583
-rw-r--r--lib/libusbhid/usage.c238
-rw-r--r--lib/libusbhid/usbhid.3246
-rw-r--r--lib/libusbhid/usbhid.h118
-rw-r--r--lib/libusbhid/usbvar.h48
10 files changed, 1664 insertions, 0 deletions
diff --git a/lib/libusbhid/Makefile b/lib/libusbhid/Makefile
new file mode 100644
index 000000000000..cb5de55883bb
--- /dev/null
+++ b/lib/libusbhid/Makefile
@@ -0,0 +1,21 @@
+# $NetBSD: Makefile,v 1.5 1999/07/23 09:44:38 mrg Exp $
+
+LIB= usbhid
+MAN= usbhid.3
+
+SHLIB_MAJOR= 4
+
+MLINKS= usbhid.3 libusbhid.3 usbhid.3 hid_get_report_desc.3 \
+ usbhid.3 hid_dispose_report_desc.3 \
+ usbhid.3 hid_start_parse.3 usbhid.3 hid_end_parse.3 \
+ usbhid.3 hid_get_item.3 usbhid.3 hid_report_size.3 \
+ usbhid.3 hid_locate.3 \
+ usbhid.3 hid_usage_page.3 usbhid.3 hid_usage_in_page.3 \
+ usbhid.3 hid_init.3 \
+ usbhid.3 hid_get_data.3 usbhid.3 hid_set_data.3
+
+SRCS= descr.c descr_compat.c parse.c usage.c data.c
+
+INCS= usbhid.h
+
+.include <bsd.lib.mk>
diff --git a/lib/libusbhid/Makefile.depend b/lib/libusbhid/Makefile.depend
new file mode 100644
index 000000000000..6ef78fac5cbf
--- /dev/null
+++ b/lib/libusbhid/Makefile.depend
@@ -0,0 +1,15 @@
+# Autogenerated - do NOT edit!
+
+DIRDEPS = \
+ include \
+ include/xlocale \
+ lib/${CSU_DIR} \
+ lib/libc \
+ lib/libcompiler_rt \
+
+
+.include <dirdeps.mk>
+
+.if ${DEP_RELDIR} == ${_DEP_RELDIR}
+# local dependencies - needed for -jN in clean tree
+.endif
diff --git a/lib/libusbhid/data.c b/lib/libusbhid/data.c
new file mode 100644
index 000000000000..0fc2f4e4d840
--- /dev/null
+++ b/lib/libusbhid/data.c
@@ -0,0 +1,142 @@
+/* $NetBSD: data.c,v 1.8 2000/04/02 11:10:53 augustss Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dev/usb/usb_ioctl.h>
+#include "usbhid.h"
+#include "usbvar.h"
+
+int32_t
+hid_get_data(const void *p, const hid_item_t *h)
+{
+ const uint8_t *buf;
+ uint32_t hpos;
+ uint32_t hsize;
+ uint32_t data;
+ int i, end, offs;
+
+ buf = p;
+
+ /* Skip report ID byte. */
+ if (h->report_ID > 0)
+ buf++;
+
+ hpos = h->pos; /* bit position of data */
+ hsize = h->report_size; /* bit length of data */
+
+ /* Range check and limit */
+ if (hsize == 0)
+ return (0);
+ if (hsize > 32)
+ hsize = 32;
+
+ offs = hpos / 8;
+ end = (hpos + hsize) / 8 - offs;
+ data = 0;
+ for (i = 0; i <= end; i++)
+ data |= buf[offs + i] << (i*8);
+
+ /* Correctly shift down data */
+ data >>= hpos % 8;
+ hsize = 32 - hsize;
+
+ /* Mask and sign extend in one */
+ if ((h->logical_minimum < 0) || (h->logical_maximum < 0))
+ data = (int32_t)((int32_t)data << hsize) >> hsize;
+ else
+ data = (uint32_t)((uint32_t)data << hsize) >> hsize;
+
+ return (data);
+}
+
+void
+hid_set_data(void *p, const hid_item_t *h, int32_t data)
+{
+ uint8_t *buf;
+ uint32_t hpos;
+ uint32_t hsize;
+ uint32_t mask;
+ int i;
+ int end;
+ int offs;
+
+ buf = p;
+
+ /* Set report ID byte. */
+ if (h->report_ID > 0)
+ *buf++ = h->report_ID & 0xff;
+
+ hpos = h->pos; /* bit position of data */
+ hsize = h->report_size; /* bit length of data */
+
+ if (hsize != 32) {
+ mask = (1 << hsize) - 1;
+ data &= mask;
+ } else
+ mask = ~0;
+
+ data <<= (hpos % 8);
+ mask <<= (hpos % 8);
+ mask = ~mask;
+
+ offs = hpos / 8;
+ end = (hpos + hsize) / 8 - offs;
+
+ for (i = 0; i <= end; i++)
+ buf[offs + i] = (buf[offs + i] & (mask >> (i*8))) |
+ ((data >> (i*8)) & 0xff);
+}
+
+int
+hid_get_report(int fd, enum hid_kind k, unsigned char *data, unsigned int size)
+{
+ struct usb_gen_descriptor ugd;
+
+ memset(&ugd, 0, sizeof(ugd));
+ ugd.ugd_data = data;
+ ugd.ugd_maxlen = size;
+ ugd.ugd_report_type = k + 1;
+ return (ioctl(fd, USB_GET_REPORT, &ugd));
+}
+
+int
+hid_set_report(int fd, enum hid_kind k, unsigned char *data, unsigned int size)
+{
+ struct usb_gen_descriptor ugd;
+
+ memset(&ugd, 0, sizeof(ugd));
+ ugd.ugd_data = data;
+ ugd.ugd_maxlen = size;
+ ugd.ugd_report_type = k + 1;
+ return (ioctl(fd, USB_SET_REPORT, &ugd));
+}
diff --git a/lib/libusbhid/descr.c b/lib/libusbhid/descr.c
new file mode 100644
index 000000000000..74491df53f6c
--- /dev/null
+++ b/lib/libusbhid/descr.c
@@ -0,0 +1,175 @@
+/* $NetBSD: descr.c,v 1.9 2000/09/24 02:13:24 augustss Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+#include <dev/usb/usb_ioctl.h>
+
+#include "usbhid.h"
+#include "usbvar.h"
+
+int
+hid_set_immed(int fd, int enable)
+{
+ int ret;
+ ret = ioctl(fd, USB_SET_IMMED, &enable);
+#ifdef HID_COMPAT7
+ if (ret < 0)
+ ret = hid_set_immed_compat7(fd, enable);
+#endif
+ return (ret);
+}
+
+int
+hid_get_report_id(int fd)
+{
+ report_desc_t rep;
+ hid_data_t d;
+ hid_item_t h;
+ int kindset;
+ int temp = -1;
+ int ret;
+
+ if ((rep = hid_get_report_desc(fd)) == NULL)
+ goto use_ioctl;
+ kindset = 1 << hid_input | 1 << hid_output | 1 << hid_feature;
+ for (d = hid_start_parse(rep, kindset, -1); hid_get_item(d, &h); ) {
+ /* Return the first report ID we met. */
+ if (h.report_ID != 0) {
+ temp = h.report_ID;
+ break;
+ }
+ }
+ hid_end_parse(d);
+ hid_dispose_report_desc(rep);
+
+ if (temp > 0)
+ return (temp);
+
+use_ioctl:
+ ret = ioctl(fd, USB_GET_REPORT_ID, &temp);
+#ifdef HID_COMPAT7
+ if (ret < 0)
+ ret = hid_get_report_id_compat7(fd);
+ else
+#endif
+ ret = temp;
+
+ return (ret);
+}
+
+report_desc_t
+hid_get_report_desc(int fd)
+{
+ struct usb_gen_descriptor ugd;
+ report_desc_t rep;
+ void *data;
+
+ memset(&ugd, 0, sizeof(ugd));
+
+ /* get actual length first */
+ ugd.ugd_data = NULL;
+ ugd.ugd_maxlen = 65535;
+ if (ioctl(fd, USB_GET_REPORT_DESC, &ugd) < 0) {
+#ifdef HID_COMPAT7
+ /* could not read descriptor */
+ /* try FreeBSD 7 compat code */
+ return (hid_get_report_desc_compat7(fd));
+#else
+ return (NULL);
+#endif
+ }
+
+ /*
+ * NOTE: The kernel will return a failure if
+ * "ugd_actlen" is zero.
+ */
+ data = malloc(ugd.ugd_actlen);
+ if (data == NULL)
+ return (NULL);
+
+ /* fetch actual descriptor */
+ ugd.ugd_data = data;
+ ugd.ugd_maxlen = ugd.ugd_actlen;
+ if (ioctl(fd, USB_GET_REPORT_DESC, &ugd) < 0) {
+ /* could not read descriptor */
+ free(data);
+ return (NULL);
+ }
+
+ /* sanity check */
+ if (ugd.ugd_actlen < 1) {
+ /* invalid report descriptor */
+ free(data);
+ return (NULL);
+ }
+
+ /* check END_COLLECTION */
+ if (((unsigned char *)data)[ugd.ugd_actlen -1] != 0xC0) {
+ /* invalid end byte */
+ free(data);
+ return (NULL);
+ }
+
+ rep = hid_use_report_desc(data, ugd.ugd_actlen);
+
+ free(data);
+
+ return (rep);
+}
+
+report_desc_t
+hid_use_report_desc(unsigned char *data, unsigned int size)
+{
+ report_desc_t r;
+
+ r = malloc(sizeof(*r) + size);
+ if (r == NULL) {
+ errno = ENOMEM;
+ return (NULL);
+ }
+ r->size = size;
+ memcpy(r->data, data, size);
+ return (r);
+}
+
+void
+hid_dispose_report_desc(report_desc_t r)
+{
+
+ free(r);
+}
diff --git a/lib/libusbhid/descr_compat.c b/lib/libusbhid/descr_compat.c
new file mode 100644
index 000000000000..c861d2f4d253
--- /dev/null
+++ b/lib/libusbhid/descr_compat.c
@@ -0,0 +1,78 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This file contains fallback-compatibility code for the old FreeBSD
+ * USB stack.
+ */
+#ifdef HID_COMPAT7
+
+#include <sys/types.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/ioctl.h>
+
+#include <dev/usb/usb.h>
+
+#include "usbhid.h"
+#include "usbvar.h"
+
+int
+hid_set_immed_compat7(int fd, int enable)
+{
+ return (ioctl(fd, USB_SET_IMMED, &enable));
+}
+
+int
+hid_get_report_id_compat7(int fd)
+{
+ int temp = -1;
+
+ if (ioctl(fd, USB_GET_REPORT_ID, &temp) < 0)
+ return (-1);
+
+ return (temp);
+}
+
+report_desc_t
+hid_get_report_desc_compat7(int fd)
+{
+ struct usb_ctl_report_desc rep;
+
+ rep.ucrd_size = 0;
+ if (ioctl(fd, USB_GET_REPORT_DESC, &rep) < 0)
+ return (NULL);
+
+ return (hid_use_report_desc(rep.ucrd_data, (unsigned int)rep.ucrd_size));
+}
+#endif /* HID_COMPAT7 */
diff --git a/lib/libusbhid/parse.c b/lib/libusbhid/parse.c
new file mode 100644
index 000000000000..8eb94ab82fc8
--- /dev/null
+++ b/lib/libusbhid/parse.c
@@ -0,0 +1,583 @@
+/* $NetBSD: parse.c,v 1.11 2000/09/24 02:19:54 augustss Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1999, 2001 Lennart Augustsson <augustss@netbsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+
+#include "usbhid.h"
+#include "usbvar.h"
+
+#define MAXUSAGE 100
+#define MAXPUSH 4
+#define MAXID 64
+#define ITEMTYPES 3
+
+struct hid_pos_data {
+ int32_t rid;
+ uint32_t pos[ITEMTYPES];
+};
+
+struct hid_data {
+ const uint8_t *start;
+ const uint8_t *end;
+ const uint8_t *p;
+ struct hid_item cur[MAXPUSH];
+ struct hid_pos_data last_pos[MAXID];
+ uint32_t pos[ITEMTYPES];
+ int32_t usages_min[MAXUSAGE];
+ int32_t usages_max[MAXUSAGE];
+ int32_t usage_last; /* last seen usage */
+ uint32_t loc_size; /* last seen size */
+ uint32_t loc_count; /* last seen count */
+ uint8_t kindset; /* we have 5 kinds so 8 bits are enough */
+ uint8_t pushlevel; /* current pushlevel */
+ uint8_t ncount; /* end usage item count */
+ uint8_t icount; /* current usage item count */
+ uint8_t nusage; /* end "usages_min/max" index */
+ uint8_t iusage; /* current "usages_min/max" index */
+ uint8_t ousage; /* current "usages_min/max" offset */
+ uint8_t susage; /* usage set flags */
+ int32_t reportid; /* requested report ID */
+};
+
+/*------------------------------------------------------------------------*
+ * hid_clear_local
+ *------------------------------------------------------------------------*/
+static void
+hid_clear_local(hid_item_t *c)
+{
+
+ c->usage = 0;
+ c->usage_minimum = 0;
+ c->usage_maximum = 0;
+ c->designator_index = 0;
+ c->designator_minimum = 0;
+ c->designator_maximum = 0;
+ c->string_index = 0;
+ c->string_minimum = 0;
+ c->string_maximum = 0;
+ c->set_delimiter = 0;
+}
+
+static void
+hid_switch_rid(struct hid_data *s, struct hid_item *c, int32_t next_rID)
+{
+ uint8_t i, j;
+
+ /* check for same report ID - optimise */
+
+ if (c->report_ID == next_rID)
+ return;
+
+ /* save current position for current rID */
+
+ if (c->report_ID == 0) {
+ i = 0;
+ } else {
+ for (i = 1; i != MAXID; i++) {
+ if (s->last_pos[i].rid == c->report_ID)
+ break;
+ if (s->last_pos[i].rid == 0)
+ break;
+ }
+ }
+ if (i != MAXID) {
+ s->last_pos[i].rid = c->report_ID;
+ for (j = 0; j < ITEMTYPES; j++)
+ s->last_pos[i].pos[j] = s->pos[j];
+ }
+
+ /* store next report ID */
+
+ c->report_ID = next_rID;
+
+ /* lookup last position for next rID */
+
+ if (next_rID == 0) {
+ i = 0;
+ } else {
+ for (i = 1; i != MAXID; i++) {
+ if (s->last_pos[i].rid == next_rID)
+ break;
+ if (s->last_pos[i].rid == 0)
+ break;
+ }
+ }
+ if (i != MAXID) {
+ s->last_pos[i].rid = next_rID;
+ for (j = 0; j < ITEMTYPES; j++)
+ s->pos[j] = s->last_pos[i].pos[j];
+ } else {
+ for (j = 0; j < ITEMTYPES; j++)
+ s->pos[j] = 0; /* Out of RID entries. */
+ }
+}
+
+/*------------------------------------------------------------------------*
+ * hid_start_parse
+ *------------------------------------------------------------------------*/
+hid_data_t
+hid_start_parse(report_desc_t d, int kindset, int id)
+{
+ struct hid_data *s;
+
+ s = malloc(sizeof *s);
+ memset(s, 0, sizeof *s);
+ s->start = s->p = d->data;
+ s->end = d->data + d->size;
+ s->kindset = kindset;
+ s->reportid = id;
+ return (s);
+}
+
+/*------------------------------------------------------------------------*
+ * hid_end_parse
+ *------------------------------------------------------------------------*/
+void
+hid_end_parse(hid_data_t s)
+{
+
+ if (s == NULL)
+ return;
+
+ free(s);
+}
+
+/*------------------------------------------------------------------------*
+ * get byte from HID descriptor
+ *------------------------------------------------------------------------*/
+static uint8_t
+hid_get_byte(struct hid_data *s, const uint16_t wSize)
+{
+ const uint8_t *ptr;
+ uint8_t retval;
+
+ ptr = s->p;
+
+ /* check if end is reached */
+ if (ptr == s->end)
+ return (0);
+
+ /* read out a byte */
+ retval = *ptr;
+
+ /* check if data pointer can be advanced by "wSize" bytes */
+ if ((s->end - ptr) < wSize)
+ ptr = s->end;
+ else
+ ptr += wSize;
+
+ /* update pointer */
+ s->p = ptr;
+
+ return (retval);
+}
+
+/*------------------------------------------------------------------------*
+ * hid_get_item
+ *------------------------------------------------------------------------*/
+static int
+hid_get_item_raw(hid_data_t s, hid_item_t *h)
+{
+ hid_item_t *c;
+ unsigned int bTag, bType, bSize;
+ int32_t mask;
+ int32_t dval;
+
+ if (s == NULL)
+ return (0);
+
+ c = &s->cur[s->pushlevel];
+
+ top:
+ /* check if there is an array of items */
+ if (s->icount < s->ncount) {
+ /* get current usage */
+ if (s->iusage < s->nusage) {
+ dval = s->usages_min[s->iusage] + s->ousage;
+ c->usage = dval;
+ s->usage_last = dval;
+ if (dval == s->usages_max[s->iusage]) {
+ s->iusage ++;
+ s->ousage = 0;
+ } else {
+ s->ousage ++;
+ }
+ } else {
+ /* Using last usage */
+ dval = s->usage_last;
+ }
+ s->icount ++;
+ /*
+ * Only copy HID item, increment position and return
+ * if correct kindset!
+ */
+ if (s->kindset & (1 << c->kind)) {
+ *h = *c;
+ h->pos = s->pos[c->kind];
+ s->pos[c->kind] += c->report_size * c->report_count;
+ return (1);
+ }
+ }
+
+ /* reset state variables */
+ s->icount = 0;
+ s->ncount = 0;
+ s->iusage = 0;
+ s->nusage = 0;
+ s->susage = 0;
+ s->ousage = 0;
+ hid_clear_local(c);
+
+ /* get next item */
+ while (s->p != s->end) {
+
+ bSize = hid_get_byte(s, 1);
+ if (bSize == 0xfe) {
+ /* long item */
+ bSize = hid_get_byte(s, 1);
+ bSize |= hid_get_byte(s, 1) << 8;
+ bTag = hid_get_byte(s, 1);
+ bType = 0xff; /* XXX what should it be */
+ } else {
+ /* short item */
+ bTag = bSize >> 4;
+ bType = (bSize >> 2) & 3;
+ bSize &= 3;
+ if (bSize == 3)
+ bSize = 4;
+ }
+
+ switch(bSize) {
+ case 0:
+ dval = 0;
+ mask = 0;
+ break;
+ case 1:
+ dval = (int8_t)hid_get_byte(s, 1);
+ mask = 0xFF;
+ break;
+ case 2:
+ dval = hid_get_byte(s, 1);
+ dval |= hid_get_byte(s, 1) << 8;
+ dval = (int16_t)dval;
+ mask = 0xFFFF;
+ break;
+ case 4:
+ dval = hid_get_byte(s, 1);
+ dval |= hid_get_byte(s, 1) << 8;
+ dval |= hid_get_byte(s, 1) << 16;
+ dval |= hid_get_byte(s, 1) << 24;
+ mask = 0xFFFFFFFF;
+ break;
+ default:
+ dval = hid_get_byte(s, bSize);
+ continue;
+ }
+
+ switch (bType) {
+ case 0: /* Main */
+ switch (bTag) {
+ case 8: /* Input */
+ c->kind = hid_input;
+ c->flags = dval;
+ ret:
+ c->report_count = s->loc_count;
+ c->report_size = s->loc_size;
+
+ if (c->flags & HIO_VARIABLE) {
+ /* range check usage count */
+ if (c->report_count > 255) {
+ s->ncount = 255;
+ } else
+ s->ncount = c->report_count;
+
+ /*
+ * The "top" loop will return
+ * one and one item:
+ */
+ c->report_count = 1;
+ c->usage_minimum = 0;
+ c->usage_maximum = 0;
+ } else {
+ s->ncount = 1;
+ }
+ goto top;
+
+ case 9: /* Output */
+ c->kind = hid_output;
+ c->flags = dval;
+ goto ret;
+ case 10: /* Collection */
+ c->kind = hid_collection;
+ c->collection = dval;
+ c->collevel++;
+ c->usage = s->usage_last;
+ *h = *c;
+ return (1);
+ case 11: /* Feature */
+ c->kind = hid_feature;
+ c->flags = dval;
+ goto ret;
+ case 12: /* End collection */
+ c->kind = hid_endcollection;
+ if (c->collevel == 0) {
+ /* Invalid end collection. */
+ return (0);
+ }
+ c->collevel--;
+ *h = *c;
+ return (1);
+ default:
+ break;
+ }
+ break;
+
+ case 1: /* Global */
+ switch (bTag) {
+ case 0:
+ c->_usage_page = dval << 16;
+ break;
+ case 1:
+ c->logical_minimum = dval;
+ break;
+ case 2:
+ c->logical_maximum = dval;
+ break;
+ case 3:
+ c->physical_minimum = dval;
+ break;
+ case 4:
+ c->physical_maximum = dval;
+ break;
+ case 5:
+ c->unit_exponent = dval;
+ break;
+ case 6:
+ c->unit = dval;
+ break;
+ case 7:
+ /* mask because value is unsigned */
+ s->loc_size = dval & mask;
+ break;
+ case 8:
+ hid_switch_rid(s, c, dval & mask);
+ break;
+ case 9:
+ /* mask because value is unsigned */
+ s->loc_count = dval & mask;
+ break;
+ case 10: /* Push */
+ /* stop parsing, if invalid push level */
+ if ((s->pushlevel + 1) >= MAXPUSH)
+ return (0);
+ s->pushlevel ++;
+ s->cur[s->pushlevel] = *c;
+ /* store size and count */
+ c->report_size = s->loc_size;
+ c->report_count = s->loc_count;
+ /* update current item pointer */
+ c = &s->cur[s->pushlevel];
+ break;
+ case 11: /* Pop */
+ /* stop parsing, if invalid push level */
+ if (s->pushlevel == 0)
+ return (0);
+ s->pushlevel --;
+ c = &s->cur[s->pushlevel];
+ /* restore size and count */
+ s->loc_size = c->report_size;
+ s->loc_count = c->report_count;
+ c->report_size = 0;
+ c->report_count = 0;
+ break;
+ default:
+ break;
+ }
+ break;
+ case 2: /* Local */
+ switch (bTag) {
+ case 0:
+ if (bSize != 4)
+ dval = (dval & mask) | c->_usage_page;
+
+ /* set last usage, in case of a collection */
+ s->usage_last = dval;
+
+ if (s->nusage < MAXUSAGE) {
+ s->usages_min[s->nusage] = dval;
+ s->usages_max[s->nusage] = dval;
+ s->nusage ++;
+ }
+ /* else XXX */
+
+ /* clear any pending usage sets */
+ s->susage = 0;
+ break;
+ case 1:
+ s->susage |= 1;
+
+ if (bSize != 4)
+ dval = (dval & mask) | c->_usage_page;
+ c->usage_minimum = dval;
+
+ goto check_set;
+ case 2:
+ s->susage |= 2;
+
+ if (bSize != 4)
+ dval = (dval & mask) | c->_usage_page;
+ c->usage_maximum = dval;
+
+ check_set:
+ if (s->susage != 3)
+ break;
+
+ /* sanity check */
+ if ((s->nusage < MAXUSAGE) &&
+ (c->usage_minimum <= c->usage_maximum)) {
+ /* add usage range */
+ s->usages_min[s->nusage] =
+ c->usage_minimum;
+ s->usages_max[s->nusage] =
+ c->usage_maximum;
+ s->nusage ++;
+ }
+ /* else XXX */
+
+ s->susage = 0;
+ break;
+ case 3:
+ c->designator_index = dval;
+ break;
+ case 4:
+ c->designator_minimum = dval;
+ break;
+ case 5:
+ c->designator_maximum = dval;
+ break;
+ case 7:
+ c->string_index = dval;
+ break;
+ case 8:
+ c->string_minimum = dval;
+ break;
+ case 9:
+ c->string_maximum = dval;
+ break;
+ case 10:
+ c->set_delimiter = dval;
+ break;
+ default:
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return (0);
+}
+
+int
+hid_get_item(hid_data_t s, hid_item_t *h)
+{
+ int r;
+
+ for (;;) {
+ r = hid_get_item_raw(s, h);
+ if (r <= 0 || s->reportid == -1 || h->report_ID == s->reportid)
+ break;
+ }
+ return (r);
+}
+
+int
+hid_report_size(report_desc_t r, enum hid_kind k, int id)
+{
+ struct hid_data *d;
+ struct hid_item h;
+ uint32_t temp;
+ uint32_t hpos;
+ uint32_t lpos;
+ int report_id = 0;
+
+ hpos = 0;
+ lpos = 0xFFFFFFFF;
+
+ memset(&h, 0, sizeof h);
+ for (d = hid_start_parse(r, 1 << k, id); hid_get_item(d, &h); ) {
+ if (h.kind == k) {
+ /* compute minimum */
+ if (lpos > h.pos)
+ lpos = h.pos;
+ /* compute end position */
+ temp = h.pos + (h.report_size * h.report_count);
+ /* compute maximum */
+ if (hpos < temp)
+ hpos = temp;
+ if (h.report_ID != 0)
+ report_id = 1;
+ }
+ }
+ hid_end_parse(d);
+
+ /* safety check - can happen in case of currupt descriptors */
+ if (lpos > hpos)
+ temp = 0;
+ else
+ temp = hpos - lpos;
+
+ /* return length in bytes rounded up */
+ return ((temp + 7) / 8 + report_id);
+}
+
+int
+hid_locate(report_desc_t desc, unsigned int u, enum hid_kind k,
+ hid_item_t *h, int id)
+{
+ struct hid_data *d;
+
+ for (d = hid_start_parse(desc, 1 << k, id); hid_get_item(d, h); ) {
+ if (h->kind == k && !(h->flags & HIO_CONST) && h->usage == u) {
+ hid_end_parse(d);
+ return (1);
+ }
+ }
+ hid_end_parse(d);
+ h->report_size = 0;
+ return (0);
+}
diff --git a/lib/libusbhid/usage.c b/lib/libusbhid/usage.c
new file mode 100644
index 000000000000..3233044b5bff
--- /dev/null
+++ b/lib/libusbhid/usage.c
@@ -0,0 +1,238 @@
+/* $NetBSD: usage.c,v 1.8 2000/10/10 19:23:58 is Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/param.h>
+#include <assert.h>
+#include <ctype.h>
+#include <err.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "usbhid.h"
+
+#define _PATH_HIDTABLE "/usr/share/misc/usb_hid_usages"
+
+struct usage_in_page {
+ const char *name;
+ int usage;
+};
+
+static struct usage_page {
+ const char *name;
+ int usage;
+ struct usage_in_page *page_contents;
+ int pagesize, pagesizemax;
+} *pages;
+static int npages, npagesmax;
+
+#ifdef DEBUG
+void
+dump_hid_table(void)
+{
+ int i, j;
+
+ for (i = 0; i < npages; i++) {
+ printf("%d\t%s\n", pages[i].usage, pages[i].name);
+ for (j = 0; j < pages[i].pagesize; j++) {
+ printf("\t%d\t%s\n", pages[i].page_contents[j].usage,
+ pages[i].page_contents[j].name);
+ }
+ }
+}
+#endif
+
+void
+hid_init(const char *hidname)
+{
+ FILE *f;
+ char line[100], name[100], *p, *n;
+ int no;
+ int lineno;
+ struct usage_page *curpage = NULL;
+
+ if (hidname == NULL)
+ hidname = _PATH_HIDTABLE;
+
+ f = fopen(hidname, "r");
+ if (f == NULL)
+ err(1, "%s", hidname);
+ for (lineno = 1; ; lineno++) {
+ if (fgets(line, sizeof line, f) == NULL)
+ break;
+ if (line[0] == '#')
+ continue;
+ for (p = line; *p && isspace(*p); p++)
+ ;
+ if (!*p)
+ continue;
+ if (sscanf(line, " * %[^\n]", name) == 1)
+ no = -1;
+ else if (sscanf(line, " 0x%x %[^\n]", &no, name) != 2 &&
+ sscanf(line, " %d %[^\n]", &no, name) != 2)
+ errx(1, "file %s, line %d, syntax error",
+ hidname, lineno);
+ for (p = name; *p; p++)
+ if (isspace(*p) || *p == '.')
+ *p = '_';
+ n = strdup(name);
+ if (!n)
+ err(1, "strdup");
+ if (isspace(line[0])) {
+ if (!curpage)
+ errx(1, "file %s, line %d, syntax error",
+ hidname, lineno);
+ if (curpage->pagesize >= curpage->pagesizemax) {
+ curpage->pagesizemax += 10;
+ curpage->page_contents =
+ realloc(curpage->page_contents,
+ curpage->pagesizemax *
+ sizeof (struct usage_in_page));
+ if (!curpage->page_contents)
+ err(1, "realloc");
+ }
+ curpage->page_contents[curpage->pagesize].name = n;
+ curpage->page_contents[curpage->pagesize].usage = no;
+ curpage->pagesize++;
+ } else {
+ if (npages >= npagesmax) {
+ if (pages == NULL) {
+ npagesmax = 5;
+ pages = malloc(npagesmax *
+ sizeof (struct usage_page));
+ } else {
+ npagesmax += 5;
+ pages = realloc(pages,
+ npagesmax *
+ sizeof (struct usage_page));
+ }
+ if (!pages)
+ err(1, "alloc");
+ }
+ curpage = &pages[npages++];
+ curpage->name = n;
+ curpage->usage = no;
+ curpage->pagesize = 0;
+ curpage->pagesizemax = 10;
+ curpage->page_contents =
+ malloc(curpage->pagesizemax *
+ sizeof (struct usage_in_page));
+ if (!curpage->page_contents)
+ err(1, "malloc");
+ }
+ }
+ fclose(f);
+#ifdef DEBUG
+ dump_hid_table();
+#endif
+}
+
+const char *
+hid_usage_page(int i)
+{
+ static char b[10];
+ int k;
+
+ if (!pages)
+ errx(1, "no hid table");
+
+ for (k = 0; k < npages; k++)
+ if (pages[k].usage == i)
+ return pages[k].name;
+ sprintf(b, "0x%04x", i);
+ return b;
+}
+
+const char *
+hid_usage_in_page(unsigned int u)
+{
+ int page = HID_PAGE(u);
+ int i = HID_USAGE(u);
+ static char b[100];
+ int j, k, us;
+
+ for (k = 0; k < npages; k++)
+ if (pages[k].usage == page)
+ break;
+ if (k >= npages)
+ goto bad;
+ for (j = 0; j < pages[k].pagesize; j++) {
+ us = pages[k].page_contents[j].usage;
+ if (us == -1) {
+ sprintf(b,
+ fmtcheck(pages[k].page_contents[j].name, "%d"),
+ i);
+ return b;
+ }
+ if (us == i)
+ return pages[k].page_contents[j].name;
+ }
+ bad:
+ sprintf(b, "0x%04x", i);
+ return b;
+}
+
+int
+hid_parse_usage_page(const char *name)
+{
+ int k;
+
+ if (!pages)
+ errx(1, "no hid table");
+
+ for (k = 0; k < npages; k++)
+ if (strcmp(pages[k].name, name) == 0)
+ return pages[k].usage;
+ return -1;
+}
+
+/* XXX handle hex */
+int
+hid_parse_usage_in_page(const char *name)
+{
+ const char *sep;
+ int k, j;
+ unsigned int l;
+
+ sep = strchr(name, ':');
+ if (sep == NULL)
+ return -1;
+ l = sep - name;
+ for (k = 0; k < npages; k++)
+ if (strncmp(pages[k].name, name, l) == 0)
+ goto found;
+ return -1;
+ found:
+ sep++;
+ for (j = 0; j < pages[k].pagesize; j++)
+ if (strcmp(pages[k].page_contents[j].name, sep) == 0)
+ return (pages[k].usage << 16) | pages[k].page_contents[j].usage;
+ return (-1);
+}
diff --git a/lib/libusbhid/usbhid.3 b/lib/libusbhid/usbhid.3
new file mode 100644
index 000000000000..27a84402c279
--- /dev/null
+++ b/lib/libusbhid/usbhid.3
@@ -0,0 +1,246 @@
+.\" $NetBSD: usb.3,v 1.13 2000/09/24 02:17:52 augustss Exp $
+.\"
+.\" Copyright (c) 1999, 2001 Lennart Augustsson <augustss@NetBSD.org>
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.Dd January 27, 2009
+.Dt USBHID 3
+.Os
+.Sh NAME
+.Nm usbhid ,
+.Nm hid_get_report_desc ,
+.Nm hid_get_report_id ,
+.Nm hid_use_report_desc ,
+.Nm hid_dispose_report_desc ,
+.Nm hid_start_parse ,
+.Nm hid_end_parse ,
+.Nm hid_get_item ,
+.Nm hid_report_size ,
+.Nm hid_locate ,
+.Nm hid_usage_page ,
+.Nm hid_usage_in_page ,
+.Nm hid_init ,
+.Nm hid_get_data ,
+.Nm hid_set_data ,
+.Nm hid_get_report ,
+.Nm hid_set_report
+.Nd USB HID access routines
+.Sh LIBRARY
+.Lb libusbhid
+.Sh SYNOPSIS
+.In usbhid.h
+.Ft report_desc_t
+.Fn hid_get_report_desc "int file"
+.Ft int
+.Fn hid_get_report_id "int file"
+.Ft int
+.Fn hid_set_immed "int fd" "int enable"
+.Ft report_desc_t
+.Fn hid_use_report_desc "unsigned char *data" "unsigned int size"
+.Ft void
+.Fn hid_dispose_report_desc "report_desc_t d"
+.Ft hid_data_t
+.Fn hid_start_parse "report_desc_t d" "int kindset" "int id"
+.Ft void
+.Fn hid_end_parse "hid_data_t s"
+.Ft int
+.Fn hid_get_item "hid_data_t s" "hid_item_t *h"
+.Ft int
+.Fn hid_report_size "report_desc_t d" "hid_kind_t k" "int id"
+.Ft int
+.Fn hid_locate "report_desc_t d" "u_int usage" "hid_kind_t k" "hid_item_t *h" "int id"
+.Ft "const char *"
+.Fn hid_usage_page "int i"
+.Ft "const char *"
+.Fn hid_usage_in_page "u_int u"
+.Ft int
+.Fn hid_parse_usage_page "const char *"
+.Ft int
+.Fn hid_parse_usage_in_page "const char *"
+.Ft void
+.Fn hid_init "const char *file"
+.Ft int
+.Fn hid_get_data "const void *data" "const hid_item_t *h"
+.Ft void
+.Fn hid_set_data "void *buf" "const hid_item_t *h" "int data"
+.Ft int
+.Fn hid_get_report "int fd" "enum hid_kind k" "unsigned char *data" "unsigned int size"
+.Ft int
+.Fn hid_set_report "int fd" "enum hid_kind k" "unsigned char *data" "unsigned int size"
+.Sh DESCRIPTION
+The
+.Nm
+library provides routines to extract data from USB Human Interface Devices.
+.Ss Introduction
+USB HID devices send and receive data laid out in a device dependent way.
+The
+.Nm
+library contains routines to extract the
+.Em "report descriptor"
+which contains the data layout information and then use this information.
+.Pp
+The routines can be divided into four parts: extraction of the descriptor,
+parsing of the descriptor, translating to/from symbolic names, and
+data manipulation.
+.Ss Synchronous HID operation
+Synchronous HID operation can be enabled or disabled by a call to
+.Fn hid_set_immed .
+If the second argument is zero synchronous HID operation is disabled.
+Else synchronous HID operation is enabled.
+The function returns a negative value on failure.
+.Pp
+.Fn hid_get_report
+and
+.Fn hid_set_report
+functions allow to synchronously get and set specific report if device
+supports it.
+For devices with multiple report IDs, wanted ID should be provided in the
+first byte of the buffer for both get and set.
+.Ss Descriptor Functions
+The report descriptor ID can be obtained by calling
+.Fn hid_get_report_id .
+A report descriptor can be obtained by calling
+.Fn hid_get_report_desc
+with a file descriptor obtained by opening a
+.Xr uhid 4
+device.
+Alternatively a data buffer containing the report descriptor can be
+passed into
+.Fn hid_use_report_desc .
+The data is copied into an internal structure.
+When the report descriptor
+is no longer needed it should be freed by calling
+.Fn hid_dispose_report_desc .
+The type
+.Vt report_desc_t
+is opaque and should be used when calling the parsing functions.
+If
+.Fn hid_dispose_report_desc
+fails it will return
+.Dv NULL .
+.Ss Descriptor Parsing Functions
+To parse the report descriptor the
+.Fn hid_start_parse
+function should be called with a report descriptor, a set that
+describes which items that are interesting, and the desired report
+ID (or -1 to obtain items of all report IDs).
+The set is obtained by OR-ing together values
+.Fa "(1 << k)"
+where
+.Fa k
+is an item of type
+.Vt hid_kind_t .
+The function returns
+.Dv NULL
+if the initialization fails, otherwise an opaque value to be used
+in subsequent calls.
+After parsing the
+.Fn hid_end_parse
+function should be called to free internal data structures.
+.Pp
+To iterate through all the items in the report descriptor
+.Fn hid_get_item
+should be called while it returns a value greater than 0.
+When the report descriptor ends it will returns 0; a syntax
+error within the report descriptor will cause a return value less
+than 0.
+The struct pointed to by
+.Fa h
+will be filled with the relevant data for the item.
+The definition of
+.Vt hid_item_t
+can be found in
+.In usbhid.h
+and the meaning of the components in the USB HID documentation.
+.Pp
+Data should be read/written to the device in the size of
+the report.
+The size of a report (of a certain kind) can be computed by the
+.Fn hid_report_size
+function.
+If the report is prefixed by an ID byte it is given by
+.Fa id .
+.Pp
+To locate a single item the
+.Fn hid_locate
+function can be used.
+It should be given the usage code of
+the item and its kind and it will fill the item and return
+non-zero if the item was found.
+.Ss Name Translation Functions
+The function
+.Fn hid_usage_page
+will return the symbolic name of a usage page, and the function
+.Fn hid_usage_in_page
+will return the symbolic name of the usage within the page.
+Both these functions may return a pointer to static data.
+.Pp
+The functions
+.Fn hid_parse_usage_page
+and
+.Fn hid_parse_usage_in_page
+are the inverses of
+.Fn hid_usage_page
+and
+.Fn hid_usage_in_page .
+They take a usage string and return the number of the usage, or \-1
+if it cannot be found.
+.Pp
+Before any of these functions can be called the usage table
+must be parsed, this is done by calling
+.Fn hid_init
+with the name of the table.
+Passing
+.Dv NULL
+to this function will cause it to use the default table.
+.Ss Data Extraction Functions
+Given the data obtained from a HID device and an item in the
+report descriptor the
+.Fn hid_get_data
+function extracts the value of the item.
+Conversely
+.Fn hid_set_data
+can be used to put data into a report (which must be zeroed first).
+.Sh FILES
+.Bl -tag -width ".Pa /usr/share/misc/usb_hid_usages"
+.It Pa /usr/share/misc/usb_hid_usages
+The default HID usage table.
+.El
+.Sh EXAMPLES
+Not yet.
+.Sh SEE ALSO
+The
+.Tn USB
+specifications can be found at
+.Pa http://www.usb.org/developers/docs/ .
+.Pp
+.Xr uhid 4 ,
+.Xr usb 4
+.Sh HISTORY
+The
+.Nm
+library first appeared in
+.Nx 1.5 .
+.Sh BUGS
+This man page is woefully incomplete.
diff --git a/lib/libusbhid/usbhid.h b/lib/libusbhid/usbhid.h
new file mode 100644
index 000000000000..637fb3d846f7
--- /dev/null
+++ b/lib/libusbhid/usbhid.h
@@ -0,0 +1,118 @@
+/* $NetBSD: usb.h,v 1.8 2000/08/13 22:22:02 augustss Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _USBHID_H_
+#define _USBHID_H_
+
+#include <stdint.h>
+
+typedef struct report_desc *report_desc_t;
+
+typedef struct hid_data *hid_data_t;
+
+typedef enum hid_kind {
+ hid_input, hid_output, hid_feature, hid_collection, hid_endcollection
+} hid_kind_t;
+
+typedef struct hid_item {
+ /* Global */
+ uint32_t _usage_page;
+ int32_t logical_minimum;
+ int32_t logical_maximum;
+ int32_t physical_minimum;
+ int32_t physical_maximum;
+ int32_t unit_exponent;
+ int32_t unit;
+ int32_t report_size;
+ int32_t report_ID;
+#define NO_REPORT_ID 0
+ int32_t report_count;
+ /* Local */
+ uint32_t usage;
+ int32_t usage_minimum;
+ int32_t usage_maximum;
+ int32_t designator_index;
+ int32_t designator_minimum;
+ int32_t designator_maximum;
+ int32_t string_index;
+ int32_t string_minimum;
+ int32_t string_maximum;
+ int32_t set_delimiter;
+ /* Misc */
+ int32_t collection;
+ int collevel;
+ enum hid_kind kind;
+ uint32_t flags;
+ /* Location */
+ uint32_t pos;
+ /* unused */
+ struct hid_item *next;
+} hid_item_t;
+
+#define HID_PAGE(u) (((u) >> 16) & 0xffff)
+#define HID_USAGE(u) ((u) & 0xffff)
+#define HID_HAS_GET_SET_REPORT 1
+
+__BEGIN_DECLS
+
+/* Obtaining a report descriptor, descr.c: */
+report_desc_t hid_get_report_desc(int file);
+report_desc_t hid_use_report_desc(unsigned char *data, unsigned int size);
+void hid_dispose_report_desc(report_desc_t);
+int hid_get_report_id(int file);
+int hid_set_immed(int fd, int enable);
+
+/* Parsing of a HID report descriptor, parse.c: */
+hid_data_t hid_start_parse(report_desc_t d, int kindset, int id);
+void hid_end_parse(hid_data_t s);
+int hid_get_item(hid_data_t s, hid_item_t *h);
+int hid_report_size(report_desc_t d, enum hid_kind k, int id);
+int hid_locate(report_desc_t d, unsigned int usage, enum hid_kind k,
+ hid_item_t *h, int id);
+
+/* Conversion to/from usage names, usage.c: */
+const char *hid_usage_page(int i);
+const char *hid_usage_in_page(unsigned int u);
+void hid_init(const char *file);
+int hid_parse_usage_in_page(const char *name);
+int hid_parse_usage_page(const char *name);
+
+/* Extracting/insertion of data, data.c: */
+int32_t hid_get_data(const void *p, const hid_item_t *h);
+void hid_set_data(void *p, const hid_item_t *h, int32_t data);
+int hid_get_report(int fd, enum hid_kind k,
+ unsigned char *data, unsigned int size);
+int hid_set_report(int fd, enum hid_kind k,
+ unsigned char *data, unsigned int size);
+
+__END_DECLS
+
+#endif /* !_USBHID_H_ */
diff --git a/lib/libusbhid/usbvar.h b/lib/libusbhid/usbvar.h
new file mode 100644
index 000000000000..d23f580f1679
--- /dev/null
+++ b/lib/libusbhid/usbvar.h
@@ -0,0 +1,48 @@
+/* $NetBSD: usbvar.h,v 1.2 1999/05/11 21:15:46 augustss Exp $ */
+
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) 1999 Lennart Augustsson <augustss@netbsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _USBVAR_H_
+#define _USBVAR_H_
+
+struct report_desc {
+ uint32_t size;
+ uint8_t data[1];
+};
+
+/* internal backwards compatibility functions */
+
+#ifdef HID_COMPAT7
+int hid_set_immed_compat7(int fd, int enable);
+int hid_get_report_id_compat7(int fd);
+report_desc_t hid_get_report_desc_compat7(int fd);
+#endif
+
+#endif /* _USBVAR_H_ */