summaryrefslogtreecommitdiff
path: root/sys/dev/hid
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev/hid')
-rw-r--r--sys/dev/hid/files.hid18
-rw-r--r--sys/dev/hid/hid.c639
-rw-r--r--sys/dev/hid/hid.h404
-rw-r--r--sys/dev/hid/hidkbd.c642
-rw-r--r--sys/dev/hid/hidkbdsc.h105
-rw-r--r--sys/dev/hid/hidkbdvar.h34
-rw-r--r--sys/dev/hid/hidms.c478
-rw-r--r--sys/dev/hid/hidmsvar.h83
8 files changed, 2403 insertions, 0 deletions
diff --git a/sys/dev/hid/files.hid b/sys/dev/hid/files.hid
new file mode 100644
index 00000000000..c2bd1d2ce80
--- /dev/null
+++ b/sys/dev/hid/files.hid
@@ -0,0 +1,18 @@
+# $OpenBSD: files.hid,v 1.1 2016/01/08 15:54:13 jcs Exp $
+
+# Human Interface Devices
+
+# HID "bus"
+define hidbus {[reportid = -1]}
+
+# HID processing
+define hid
+file dev/hid/hid.c hid
+
+# Keyboards
+define hidkbd
+file dev/hid/hidkbd.c hidkbd needs-flag
+
+# Mice
+define hidms
+file dev/hid/hidms.c hidms
diff --git a/sys/dev/hid/hid.c b/sys/dev/hid/hid.c
new file mode 100644
index 00000000000..94a9bcf01f0
--- /dev/null
+++ b/sys/dev/hid/hid.c
@@ -0,0 +1,639 @@
+/* $OpenBSD: hid.c,v 1.1 2016/01/08 15:54:13 jcs Exp $ */
+/* $NetBSD: hid.c,v 1.23 2002/07/11 21:14:25 augustss Exp $ */
+/* $FreeBSD: src/sys/dev/usb/hid.c,v 1.11 1999/11/17 22:33:39 n_hibma Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net) at
+ * Carlstedt Research & Technology.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 <sys/systm.h>
+#include <sys/malloc.h>
+
+#include <dev/hid/hid.h>
+
+#ifdef USBHID_DEBUG
+#define DPRINTF(x...) do { printf(x); } while (0)
+#else
+#define DPRINTF(x...)
+#endif
+
+#define MAXUSAGE 64
+#define MAXPUSH 4
+#define MAXID 16
+
+struct hid_pos_data {
+ int32_t rid;
+ uint32_t pos;
+};
+
+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];
+ 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 */
+ enum hid_kind kind;
+ 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 */
+};
+
+static void
+hid_clear_local(struct hid_item *c)
+{
+ c->loc.count = 0;
+ c->loc.size = 0;
+ 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 nextid)
+{
+ uint8_t i;
+
+ if (c->report_ID == nextid)
+ 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;
+ s->last_pos[i].pos = c->loc.pos;
+ }
+
+ /* store next report ID */
+ c->report_ID = nextid;
+
+ /* lookup last position for next rID */
+ if (nextid == 0) {
+ i = 0;
+ } else {
+ for (i = 1; i != MAXID; i++) {
+ if (s->last_pos[i].rid == nextid)
+ break;
+ if (s->last_pos[i].rid == 0)
+ break;
+ }
+ }
+ if (i != MAXID) {
+ s->last_pos[i].rid = nextid;
+ c->loc.pos = s->last_pos[i].pos;
+ } else {
+ DPRINTF("Out of RID entries, position is set to zero!\n");
+ c->loc.pos = 0;
+ }
+}
+
+struct hid_data *
+hid_start_parse(const void *d, int len, enum hid_kind kind)
+{
+ struct hid_data *s;
+
+ s = malloc(sizeof(*s), M_TEMP, M_WAITOK | M_ZERO);
+
+ s->start = s->p = d;
+ s->end = ((const uint8_t *)d) + len;
+ s->kind = kind;
+ return (s);
+}
+
+void
+hid_end_parse(struct hid_data *s)
+{
+ if (s == NULL)
+ return;
+
+ free(s, M_TEMP, 0);
+}
+
+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);
+}
+
+int
+hid_get_item(struct hid_data *s, struct hid_item *h)
+{
+ struct hid_item *c;
+ unsigned int bTag, bType, bSize;
+ uint32_t oldpos;
+ 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 */
+ DPRINTF("%s: icount=%d ncount=%d\n", __func__,
+ s->icount, s->ncount);
+ 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 {
+ DPRINTF("Using last usage\n");
+ dval = s->usage_last;
+ }
+ s->icount ++;
+ /*
+ * Only copy HID item, increment position and return
+ * if correct kind!
+ */
+ if (s->kind == c->kind) {
+ *h = *c;
+ DPRINTF("%u,%u,%u\n", h->loc.pos,
+ h->loc.size, h->loc.count);
+ c->loc.pos += c->loc.size * c->loc.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 = hid_get_byte(s, 1);
+ mask = 0xFF;
+ break;
+ case 2:
+ dval = hid_get_byte(s, 1);
+ dval |= hid_get_byte(s, 1) << 8;
+ 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);
+ DPRINTF("bad length %u (data=0x%02x)\n",
+ bSize, dval);
+ continue;
+ }
+
+ DPRINTF("%s: bType=%d bTag=%d dval=%d\n", __func__,
+ bType, bTag, dval);
+ switch (bType) {
+ case 0: /* Main */
+ switch (bTag) {
+ case 8: /* Input */
+ c->kind = hid_input;
+ c->flags = dval;
+ ret:
+ c->loc.count = s->loc_count;
+ c->loc.size = s->loc_size;
+
+ if (c->flags & HIO_VARIABLE) {
+ /* range check usage count */
+ if (c->loc.count > 255) {
+ DPRINTF("Number of "
+ "items truncated to 255\n");
+ s->ncount = 255;
+ } else
+ s->ncount = c->loc.count;
+
+ /*
+ * The "top" loop will return
+ * one and one item:
+ */
+ c->loc.count = 1;
+ } 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) {
+ DPRINTF("invalid end collection\n");
+ return (0);
+ }
+ c->collevel--;
+ *h = *c;
+ return (1);
+ default:
+ DPRINTF("Main bTag=%d\n", bTag);
+ 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 */
+ s->pushlevel ++;
+ if (s->pushlevel < MAXPUSH) {
+ s->cur[s->pushlevel] = *c;
+ /* store size and count */
+ c->loc.size = s->loc_size;
+ c->loc.count = s->loc_count;
+ /* update current item pointer */
+ c = &s->cur[s->pushlevel];
+ } else {
+ DPRINTF("Cannot push "
+ "item @ %d\n", s->pushlevel);
+ }
+ break;
+ case 11: /* Pop */
+ s->pushlevel --;
+ if (s->pushlevel < MAXPUSH) {
+ /* preserve position */
+ oldpos = c->loc.pos;
+ c = &s->cur[s->pushlevel];
+ /* restore size and count */
+ s->loc_size = c->loc.size;
+ s->loc_count = c->loc.count;
+ /* set default item location */
+ c->loc.pos = oldpos;
+ c->loc.size = 0;
+ c->loc.count = 0;
+ } else {
+ DPRINTF("Cannot pop "
+ "item @ %d\n", s->pushlevel);
+ }
+ break;
+ default:
+ DPRINTF("Global bTag=%d\n", bTag);
+ 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 {
+ DPRINTF("max usage reached\n");
+ }
+
+ /* 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 {
+ DPRINTF("Usage set dropped\n");
+ }
+ 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:
+ DPRINTF("Local bTag=%d\n", bTag);
+ break;
+ }
+ break;
+ default:
+ DPRINTF("default bType=%d\n", bType);
+ break;
+ }
+ }
+ return (0);
+}
+
+int
+hid_report_size(const void *buf, int len, enum hid_kind k, u_int8_t id)
+{
+ struct hid_data *d;
+ struct hid_item h;
+ int lo, hi;
+
+ h.report_ID = 0;
+ lo = hi = -1;
+ DPRINTF("hid_report_size: kind=%d id=%d\n", k, id);
+ for (d = hid_start_parse(buf, len, k); hid_get_item(d, &h); ) {
+ DPRINTF("hid_report_size: item kind=%d id=%d pos=%d "
+ "size=%d count=%d\n",
+ h.kind, h.report_ID, h.loc.pos, h.loc.size,
+ h.loc.count);
+ if (h.report_ID == id && h.kind == k) {
+ if (lo < 0) {
+ lo = h.loc.pos;
+#ifdef DIAGNOSTIC
+ if (lo != 0) {
+ printf("hid_report_size: lo != 0\n");
+ }
+#endif
+ }
+ hi = h.loc.pos + h.loc.size * h.loc.count;
+ DPRINTF("hid_report_size: lo=%d hi=%d\n", lo, hi);
+
+ }
+ }
+ hid_end_parse(d);
+ return ((hi - lo + 7) / 8);
+}
+
+int
+hid_locate(const void *desc, int size, int32_t u, uint8_t id, enum hid_kind k,
+ struct hid_location *loc, uint32_t *flags)
+{
+ struct hid_data *d;
+ struct hid_item h;
+
+ h.report_ID = 0;
+ DPRINTF("hid_locate: enter usage=0x%x kind=%d id=%d\n", u, k, id);
+ for (d = hid_start_parse(desc, size, k); hid_get_item(d, &h); ) {
+ DPRINTF("hid_locate: usage=0x%x kind=%d id=%d flags=0x%x\n",
+ h.usage, h.kind, h.report_ID, h.flags);
+ if (h.kind == k && !(h.flags & HIO_CONST) &&
+ h.usage == u && h.report_ID == id) {
+ if (loc != NULL)
+ *loc = h.loc;
+ if (flags != NULL)
+ *flags = h.flags;
+ hid_end_parse(d);
+ return (1);
+ }
+ }
+ hid_end_parse(d);
+ if (loc != NULL)
+ loc->size = 0;
+ if (flags != NULL)
+ *flags = 0;
+ return (0);
+}
+
+int32_t
+hid_get_data(const uint8_t *buf, int len, struct hid_location *loc)
+{
+ uint32_t hpos = loc->pos;
+ uint32_t hsize = loc->size;
+ uint32_t data;
+ uint32_t rpos;
+ uint8_t n;
+
+ DPRINTF("hid_get_data: loc %d/%d\n", hpos, hsize);
+
+ /* Range check and limit */
+ if (hsize == 0)
+ return (0);
+ if (hsize > 32)
+ hsize = 32;
+
+ /* Get data in a safe way */
+ data = 0;
+ rpos = (hpos / 8);
+ n = (hsize + 7) / 8;
+ rpos += n;
+ while (n--) {
+ rpos--;
+ if (rpos < len)
+ data |= buf[rpos] << (8 * n);
+ }
+
+ /* Correctly shift down data */
+ data = (data >> (hpos % 8));
+ n = 32 - hsize;
+
+ data = (int32_t)((int32_t)data << n) >> n;
+
+ DPRINTF("hid_get_data: loc %d/%d = %lu\n",
+ loc->pos, loc->size, (long)data);
+ return (data);
+}
+
+int
+hid_is_collection(const void *desc, int size, uint8_t id, int32_t usage)
+{
+ struct hid_data *hd;
+ struct hid_item hi;
+ uint32_t coll_usage = ~0;
+
+ hd = hid_start_parse(desc, size, hid_none);
+
+ DPRINTF("%s: id=%d usage=0x%x\n", __func__, id, usage);
+ while (hid_get_item(hd, &hi)) {
+ DPRINTF("%s: kind=%d id=%d usage=0x%x(0x%x)\n", __func__,
+ hi.kind, hi.report_ID, hi.usage, coll_usage);
+ if (hi.kind == hid_collection &&
+ hi.collection == HCOLL_APPLICATION)
+ coll_usage = hi.usage;
+ if (hi.kind == hid_endcollection &&
+ coll_usage == usage && hi.report_ID == id) {
+ DPRINTF("%s: found\n", __func__);
+ hid_end_parse(hd);
+ return (1);
+ }
+ }
+ DPRINTF("%s: not found\n", __func__);
+ hid_end_parse(hd);
+ return (0);
+}
diff --git a/sys/dev/hid/hid.h b/sys/dev/hid/hid.h
new file mode 100644
index 00000000000..53af2bae669
--- /dev/null
+++ b/sys/dev/hid/hid.h
@@ -0,0 +1,404 @@
+/* $OpenBSD: hid.h,v 1.1 2016/01/08 15:54:13 jcs Exp $ */
+/* $NetBSD: hid.h,v 1.8 2002/07/11 21:14:25 augustss Exp $ */
+/* $FreeBSD: src/sys/dev/usb/hid.h,v 1.7 1999/11/17 22:33:40 n_hibma Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net) at
+ * Carlstedt Research & Technology.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 _HIDHID_H_
+#define _HIDHID_H_
+
+enum hid_kind {
+ hid_input,
+ hid_output,
+ hid_feature,
+ hid_collection,
+ hid_endcollection,
+ hid_none
+};
+
+struct hid_location {
+ u_int32_t size;
+ u_int32_t count;
+ u_int32_t pos;
+};
+
+struct hid_item {
+ /* Global */
+ int32_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_ID;
+ /* Local */
+ int32_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;
+ u_int32_t flags;
+ /* Location */
+ struct hid_location loc;
+ /* */
+ struct hid_item *next;
+};
+
+struct hid_data *hid_start_parse(const void *, int, enum hid_kind);
+void hid_end_parse(struct hid_data *);
+int hid_get_item(struct hid_data *, struct hid_item *);
+int hid_report_size(const void *, int, enum hid_kind, uint8_t);
+int hid_locate(const void *, int, int32_t, uint8_t, enum hid_kind,
+ struct hid_location *, uint32_t *);
+int32_t hid_get_data(const uint8_t *buf, int, struct hid_location *);
+int hid_is_collection(const void *, int, uint8_t, int32_t);
+
+/* Usage pages */
+#define HUP_UNDEFINED 0x0000
+#define HUP_GENERIC_DESKTOP 0x0001
+#define HUP_SIMULATION 0x0002
+#define HUP_VR_CONTROLS 0x0003
+#define HUP_SPORTS_CONTROLS 0x0004
+#define HUP_GAMING_CONTROLS 0x0005
+#define HUP_KEYBOARD 0x0007
+#define HUP_LED 0x0008
+#define HUP_BUTTON 0x0009
+#define HUP_ORDINALS 0x000a
+#define HUP_TELEPHONY 0x000b
+#define HUP_CONSUMER 0x000c
+#define HUP_DIGITIZERS 0x000d
+#define HUP_PHYSICAL_IFACE 0x000e
+#define HUP_UNICODE 0x0010
+#define HUP_ALPHANUM_DISPLAY 0x0014
+#define HUP_MONITOR 0x0080
+#define HUP_MONITOR_ENUM_VAL 0x0081
+#define HUP_VESA_VC 0x0082
+#define HUP_VESA_CMD 0x0083
+#define HUP_POWER 0x0084
+#define HUP_BATTERY 0x0085
+#define HUP_BARCODE_SCANNER 0x008b
+#define HUP_SCALE 0x008c
+#define HUP_CAMERA_CONTROL 0x0090
+#define HUP_ARCADE 0x0091
+#define HUP_APPLE 0x00ff
+#define HUP_MICROSOFT 0xff00
+
+/* Usages, Power Device */
+#define HUP_INAME 0x0001
+#define HUP_PRESENT_STATUS 0x0002
+#define HUP_CHANGED_STATUS 0x0003
+#define HUP_UPS 0x0004
+#define HUP_POWER_SUPPLY 0x0005
+#define HUP_BATTERY_SYSTEM 0x0010
+#define HUP_BATTERY_SYSTEM_ID 0x0011
+#define HUP_PD_BATTERY 0x0012
+#define HUP_BATTERY_ID 0x0013
+#define HUP_CHARGER 0x0014
+#define HUP_CHARGER_ID 0x0015
+#define HUP_POWER_CONVERTER 0x0016
+#define HUP_POWER_CONVERTER_ID 0x0017
+#define HUP_OUTLET_SYSTEM 0x0018
+#define HUP_OUTLET_SYSTEM_ID 0x0019
+#define HUP_INPUT 0x001a
+#define HUP_INPUT_ID 0x001b
+#define HUP_OUTPUT 0x001c
+#define HUP_OUTPUT_ID 0x001d
+#define HUP_FLOW 0x001e
+#define HUP_FLOW_ID 0x001f
+#define HUP_OUTLET 0x0020
+#define HUP_OUTLET_ID 0x0021
+#define HUP_GANG 0x0022
+#define HUP_GANG_ID 0x0023
+#define HUP_POWER_SUMMARY 0x0024
+#define HUP_POWER_SUMMARY_ID 0x0025
+#define HUP_VOLTAGE 0x0030
+#define HUP_CURRENT 0x0031
+#define HUP_FREQUENCY 0x0032
+#define HUP_APPARENT_POWER 0x0033
+#define HUP_ACTIVE_POWER 0x0034
+#define HUP_PERCENT_LOAD 0x0035
+#define HUP_TEMPERATURE 0x0036
+#define HUP_HUMIDITY 0x0037
+#define HUP_BADCOUNT 0x0038
+#define HUP_CONFIG_VOLTAGE 0x0040
+#define HUP_CONFIG_CURRENT 0x0041
+#define HUP_CONFIG_FREQUENCY 0x0042
+#define HUP_CONFIG_APP_POWER 0x0043
+#define HUP_CONFIG_ACT_POWER 0x0044
+#define HUP_CONFIG_PERCENT_LOAD 0x0045
+#define HUP_CONFIG_TEMPERATURE 0x0046
+#define HUP_CONFIG_HUMIDITY 0x0047
+#define HUP_SWITCHON_CONTROL 0x0050
+#define HUP_SWITCHOFF_CONTROL 0x0051
+#define HUP_TOGGLE_CONTROL 0x0052
+#define HUP_LOW_VOLT_TRANSF 0x0053
+#define HUP_HIGH_VOLT_TRANSF 0x0054
+#define HUP_DELAYBEFORE_REBOOT 0x0055
+#define HUP_DELAYBEFORE_STARTUP 0x0056
+#define HUP_DELAYBEFORE_SHUTDWN 0x0057
+#define HUP_TEST 0x0058
+#define HUP_MODULE_RESET 0x0059
+#define HUP_AUDIBLE_ALRM_CTL 0x005a
+#define HUP_PRESENT 0x0060
+#define HUP_GOOD 0x0061
+#define HUP_INTERNAL_FAILURE 0x0062
+#define HUP_PD_VOLT_OUTOF_RANGE 0x0063
+#define HUP_FREQ_OUTOFRANGE 0x0064
+#define HUP_OVERLOAD 0x0065
+#define HUP_OVERCHARGED 0x0066
+#define HUP_OVERTEMPERATURE 0x0067
+#define HUP_SHUTDOWN_REQUESTED 0x0068
+#define HUP_SHUTDOWN_IMMINENT 0x0069
+#define HUP_SWITCH_ON_OFF 0x006b
+#define HUP_SWITCHABLE 0x006c
+#define HUP_USED 0x006d
+#define HUP_BOOST 0x006e
+#define HUP_BUCK 0x006f
+#define HUP_INITIALIZED 0x0070
+#define HUP_TESTED 0x0071
+#define HUP_AWAITING_POWER 0x0072
+#define HUP_COMMUNICATION_LOST 0x0073
+#define HUP_IMANUFACTURER 0x00fd
+#define HUP_IPRODUCT 0x00fe
+#define HUP_ISERIALNUMBER 0x00ff
+
+/* Usages, Battery */
+#define HUB_SMB_BATTERY_MODE 0x0001
+#define HUB_SMB_BATTERY_STATUS 0x0002
+#define HUB_SMB_ALARM_WARNING 0x0003
+#define HUB_SMB_CHARGER_MODE 0x0004
+#define HUB_SMB_CHARGER_STATUS 0x0005
+#define HUB_SMB_CHARGER_SPECINF 0x0006
+#define HUB_SMB_SELECTR_STATE 0x0007
+#define HUB_SMB_SELECTR_PRESETS 0x0008
+#define HUB_SMB_SELECTR_INFO 0x0009
+#define HUB_SMB_OPT_MFGFUNC1 0x0010
+#define HUB_SMB_OPT_MFGFUNC2 0x0011
+#define HUB_SMB_OPT_MFGFUNC3 0x0012
+#define HUB_SMB_OPT_MFGFUNC4 0x0013
+#define HUB_SMB_OPT_MFGFUNC5 0x0014
+#define HUB_CONNECTIONTOSMBUS 0x0015
+#define HUB_OUTPUT_CONNECTION 0x0016
+#define HUB_CHARGER_CONNECTION 0x0017
+#define HUB_BATTERY_INSERTION 0x0018
+#define HUB_USENEXT 0x0019
+#define HUB_OKTOUSE 0x001a
+#define HUB_BATTERY_SUPPORTED 0x001b
+#define HUB_SELECTOR_REVISION 0x001c
+#define HUB_CHARGING_INDICATOR 0x001d
+#define HUB_MANUFACTURER_ACCESS 0x0028
+#define HUB_REM_CAPACITY_LIM 0x0029
+#define HUB_REM_TIME_LIM 0x002a
+#define HUB_ATRATE 0x002b
+#define HUB_CAPACITY_MODE 0x002c
+#define HUB_BCAST_TO_CHARGER 0x002d
+#define HUB_PRIMARY_BATTERY 0x002e
+#define HUB_CHANGE_CONTROLLER 0x002f
+#define HUB_TERMINATE_CHARGE 0x0040
+#define HUB_TERMINATE_DISCHARGE 0x0041
+#define HUB_BELOW_REM_CAP_LIM 0x0042
+#define HUB_REM_TIME_LIM_EXP 0x0043
+#define HUB_CHARGING 0x0044
+#define HUB_DISCHARGING 0x0045
+#define HUB_FULLY_CHARGED 0x0046
+#define HUB_FULLY_DISCHARGED 0x0047
+#define HUB_CONDITIONING_FLAG 0x0048
+#define HUB_ATRATE_OK 0x0049
+#define HUB_SMB_ERROR_CODE 0x004a
+#define HUB_NEED_REPLACEMENT 0x004b
+#define HUB_ATRATE_TIMETOFULL 0x0060
+#define HUB_ATRATE_TIMETOEMPTY 0x0061
+#define HUB_AVERAGE_CURRENT 0x0062
+#define HUB_MAXERROR 0x0063
+#define HUB_REL_STATEOF_CHARGE 0x0064
+#define HUB_ABS_STATEOF_CHARGE 0x0065
+#define HUB_REM_CAPACITY 0x0066
+#define HUB_FULLCHARGE_CAPACITY 0x0067
+#define HUB_RUNTIMETO_EMPTY 0x0068
+#define HUB_AVERAGETIMETO_EMPTY 0x0069
+#define HUB_AVERAGETIMETO_FULL 0x006a
+#define HUB_CYCLECOUNT 0x006b
+#define HUB_BATTPACKMODEL_LEVEL 0x0080
+#define HUB_INTERNAL_CHARGE_CTL 0x0081
+#define HUB_PRIMARY_BATTERY_SUP 0x0082
+#define HUB_DESIGN_CAPACITY 0x0083
+#define HUB_SPECIFICATION_INFO 0x0084
+#define HUB_MANUFACTURER_DATE 0x0085
+#define HUB_SERIAL_NUMBER 0x0086
+#define HUB_IMANUFACTURERNAME 0x0087
+#define HUB_IDEVICENAME 0x0088
+#define HUB_IDEVICECHEMISTERY 0x0089
+#define HUB_MANUFACTURERDATA 0x008a
+#define HUB_RECHARGABLE 0x008b
+#define HUB_WARN_CAPACITY_LIM 0x008c
+#define HUB_CAPACITY_GRANUL1 0x008d
+#define HUB_CAPACITY_GRANUL2 0x008e
+#define HUB_IOEM_INFORMATION 0x008f
+#define HUB_INHIBIT_CHARGE 0x00c0
+#define HUB_ENABLE_POLLING 0x00c1
+#define HUB_RESTORE_TO_ZERO 0x00c2
+#define HUB_AC_PRESENT 0x00d0
+#define HUB_BATTERY_PRESENT 0x00d1
+#define HUB_POWER_FAIL 0x00d2
+#define HUB_ALARM_INHIBITED 0x00d3
+#define HUB_THERMISTOR_UNDRANGE 0x00d4
+#define HUB_THERMISTOR_HOT 0x00d5
+#define HUB_THERMISTOR_COLD 0x00d6
+#define HUB_THERMISTOR_OVERANGE 0x00d7
+#define HUB_BS_VOLT_OUTOF_RANGE 0x00d8
+#define HUB_BS_CURR_OUTOF_RANGE 0x00d9
+#define HUB_BS_CURR_NOT_REGULTD 0x00da
+#define HUB_BS_VOLT_NOT_REGULTD 0x00db
+#define HUB_MASTER_MODE 0x00dc
+#define HUB_CHARGER_SELECTR_SUP 0x00f0
+#define HUB_CHARGER_SPEC 0x00f1
+#define HUB_LEVEL2 0x00f2
+#define HUB_LEVEL3 0x00f3
+
+/* Usages, generic desktop */
+#define HUG_POINTER 0x0001
+#define HUG_MOUSE 0x0002
+#define HUG_FN_KEY 0x0003
+#define HUG_JOYSTICK 0x0004
+#define HUG_GAME_PAD 0x0005
+#define HUG_KEYBOARD 0x0006
+#define HUG_KEYPAD 0x0007
+#define HUG_X 0x0030
+#define HUG_Y 0x0031
+#define HUG_Z 0x0032
+#define HUG_RX 0x0033
+#define HUG_RY 0x0034
+#define HUG_RZ 0x0035
+#define HUG_SLIDER 0x0036
+#define HUG_DIAL 0x0037
+#define HUG_WHEEL 0x0038
+#define HUG_HAT_SWITCH 0x0039
+#define HUG_COUNTED_BUFFER 0x003a
+#define HUG_BYTE_COUNT 0x003b
+#define HUG_MOTION_WAKEUP 0x003c
+#define HUG_VX 0x0040
+#define HUG_VY 0x0041
+#define HUG_VZ 0x0042
+#define HUG_VBRX 0x0043
+#define HUG_VBRY 0x0044
+#define HUG_VBRZ 0x0045
+#define HUG_VNO 0x0046
+#define HUG_TWHEEL 0x0048
+#define HUG_SYSTEM_CONTROL 0x0080
+#define HUG_SYSTEM_POWER_DOWN 0x0081
+#define HUG_SYSTEM_SLEEP 0x0082
+#define HUG_SYSTEM_WAKEUP 0x0083
+#define HUG_SYSTEM_CONTEXT_MENU 0x0084
+#define HUG_SYSTEM_MAIN_MENU 0x0085
+#define HUG_SYSTEM_APP_MENU 0x0086
+#define HUG_SYSTEM_MENU_HELP 0x0087
+#define HUG_SYSTEM_MENU_EXIT 0x0088
+#define HUG_SYSTEM_MENU_SELECT 0x0089
+#define HUG_SYSTEM_MENU_RIGHT 0x008a
+#define HUG_SYSTEM_MENU_LEFT 0x008b
+#define HUG_SYSTEM_MENU_UP 0x008c
+#define HUG_SYSTEM_MENU_DOWN 0x008d
+
+/* Usages, Digitizers */
+#define HUD_UNDEFINED 0x0000
+#define HUD_DIGITIZER 0x0001
+#define HUD_PEN 0x0002
+#define HUD_TOUCHSCREEN 0x0004
+#define HUD_TOUCHPAD 0x0005
+#define HUD_FINGER 0x0022
+#define HUD_TIP_PRESSURE 0x0030
+#define HUD_BARREL_PRESSURE 0x0031
+#define HUD_IN_RANGE 0x0032
+#define HUD_TOUCH 0x0033
+#define HUD_UNTOUCH 0x0034
+#define HUD_TAP 0x0035
+#define HUD_QUALITY 0x0036
+#define HUD_DATA_VALID 0x0037
+#define HUD_TRANSDUCER_INDEX 0x0038
+#define HUD_TABLET_FKEYS 0x0039
+#define HUD_PROGRAM_CHANGE_KEYS 0x003a
+#define HUD_BATTERY_STRENGTH 0x003b
+#define HUD_INVERT 0x003c
+#define HUD_X_TILT 0x003d
+#define HUD_Y_TILT 0x003e
+#define HUD_AZIMUTH 0x003f
+#define HUD_ALTITUDE 0x0040
+#define HUD_TWIST 0x0041
+#define HUD_TIP_SWITCH 0x0042
+#define HUD_SEC_TIP_SWITCH 0x0043
+#define HUD_BARREL_SWITCH 0x0044
+#define HUD_ERASER 0x0045
+#define HUD_TABLET_PICK 0x0046
+
+/* Usages, LED */
+#define HUL_NUM_LOCK 0x0001
+#define HUL_CAPS_LOCK 0x0002
+#define HUL_SCROLL_LOCK 0x0003
+#define HUL_COMPOSE 0x0004
+#define HUL_KANA 0x0005
+
+/* Usages, Consumer */
+#define HUC_AC_PAN 0x0238
+
+#define HID_USAGE2(p, u) (((p) << 16) | u)
+#define HID_GET_USAGE(u) ((u) & 0xffff)
+#define HID_GET_USAGE_PAGE(u) (((u) >> 16) & 0xffff)
+
+#define HCOLL_PHYSICAL 0
+#define HCOLL_APPLICATION 1
+#define HCOLL_LOGICAL 2
+
+/* Bits in the input/output/feature items */
+#define HIO_CONST 0x001
+#define HIO_VARIABLE 0x002
+#define HIO_RELATIVE 0x004
+#define HIO_WRAP 0x008
+#define HIO_NONLINEAR 0x010
+#define HIO_NOPREF 0x020
+#define HIO_NULLSTATE 0x040
+#define HIO_VOLATILE 0x080
+#define HIO_BUFBYTES 0x100
+
+/* Valid values for the country codes */
+#define HCC_UNDEFINED 0x00
+#define HCC_MAX 0x23
+
+#endif /* _HIDHID_H_ */
diff --git a/sys/dev/hid/hidkbd.c b/sys/dev/hid/hidkbd.c
new file mode 100644
index 00000000000..241ffc7bc3e
--- /dev/null
+++ b/sys/dev/hid/hidkbd.c
@@ -0,0 +1,642 @@
+/* $OpenBSD: hidkbd.c,v 1.1 2016/01/08 15:54:13 jcs Exp $ */
+/* $NetBSD: ukbd.c,v 1.85 2003/03/11 16:44:00 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net) at
+ * Carlstedt Research & Technology.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/timeout.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/malloc.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wskbdvar.h>
+#include <dev/wscons/wsksymdef.h>
+#include <dev/wscons/wsksymvar.h>
+
+#include <dev/hid/hid.h>
+#include <dev/hid/hidkbdsc.h>
+
+#ifdef HIDKBD_DEBUG
+#define DPRINTF(x) do { if (hidkbddebug) printf x; } while (0)
+#define DPRINTFN(n,x) do { if (hidkbddebug>(n)) printf x; } while (0)
+int hidkbddebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+#define PRESS 0x000
+#define RELEASE 0x100
+#define CODEMASK 0x0ff
+
+#if defined(WSDISPLAY_COMPAT_RAWKBD)
+#define NN 0 /* no translation */
+/*
+ * Translate USB keycodes to US keyboard XT scancodes.
+ * Scancodes >= 0x80 represent EXTENDED keycodes.
+ *
+ * See http://www.microsoft.com/whdc/archive/Scancode.mspx
+ */
+const u_int8_t hidkbd_trtab[256] = {
+ NN, NN, NN, NN, 0x1e, 0x30, 0x2e, 0x20, /* 00 - 07 */
+ 0x12, 0x21, 0x22, 0x23, 0x17, 0x24, 0x25, 0x26, /* 08 - 0f */
+ 0x32, 0x31, 0x18, 0x19, 0x10, 0x13, 0x1f, 0x14, /* 10 - 17 */
+ 0x16, 0x2f, 0x11, 0x2d, 0x15, 0x2c, 0x02, 0x03, /* 18 - 1f */
+ 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, /* 20 - 27 */
+ 0x1c, 0x01, 0x0e, 0x0f, 0x39, 0x0c, 0x0d, 0x1a, /* 28 - 2f */
+ 0x1b, 0x2b, 0x2b, 0x27, 0x28, 0x29, 0x33, 0x34, /* 30 - 37 */
+ 0x35, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, /* 38 - 3f */
+ 0x41, 0x42, 0x43, 0x44, 0x57, 0x58, 0xaa, 0x46, /* 40 - 47 */
+ 0x7f, 0xd2, 0xc7, 0xc9, 0xd3, 0xcf, 0xd1, 0xcd, /* 48 - 4f */
+ 0xcb, 0xd0, 0xc8, 0x45, 0xb5, 0x37, 0x4a, 0x4e, /* 50 - 57 */
+ 0x9c, 0x4f, 0x50, 0x51, 0x4b, 0x4c, 0x4d, 0x47, /* 58 - 5f */
+ 0x48, 0x49, 0x52, 0x53, 0x56, 0xdd, 0xde, 0x59, /* 60 - 67 */
+ 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, /* 68 - 6f */
+ 0x6c, 0x6d, 0x6e, 0x76, 0x97, NN, 0x93, 0x95, /* 70 - 77 */
+ 0x91, 0x92, 0x94, 0x9a, 0x96, 0x98, 0x99, 0xa0, /* 78 - 7f */
+ 0xb0, 0xae, NN, NN, NN, 0x7e, NN, 0x73, /* 80 - 87 */
+ 0x70, 0x7d, 0x79, 0x7b, 0x5c, NN, NN, NN, /* 88 - 8f */
+ NN, NN, 0x78, 0x77, 0x76, NN, NN, NN, /* 90 - 97 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* 98 - 9f */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* a0 - a7 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* a8 - af */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* b0 - b7 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* b8 - bf */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* c0 - c7 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* c8 - cf */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* d0 - d7 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* d8 - df */
+ 0x1d, 0x2a, 0x38, 0xdb, 0x9d, 0x36, 0xb8, 0xdc, /* e0 - e7 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* e8 - ef */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* f0 - f7 */
+ NN, NN, NN, NN, NN, NN, NN, NN, /* f8 - ff */
+};
+#endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */
+
+#define KEY_ERROR 0x01
+
+#ifdef HIDKBD_DEBUG
+#define HIDKBDTRACESIZE 64
+struct hidkbdtraceinfo {
+ int unit;
+ struct timeval tv;
+ struct hidkbd_data ud;
+};
+struct hidkbdtraceinfo hidkbdtracedata[HIDKBDTRACESIZE];
+int hidkbdtraceindex = 0;
+int hidkbdtrace = 0;
+void hidkbdtracedump(void);
+void
+hidkbdtracedump(void)
+{
+ int i;
+ for (i = 0; i < HIDKBDTRACESIZE; i++) {
+ struct hidkbdtraceinfo *p =
+ &hidkbdtracedata[(i+hidkbdtraceindex)%HIDKBDTRACESIZE];
+ printf("%lld.%06ld: mod=0x%02x key0=0x%02x key1=0x%02x "
+ "key2=0x%02x key3=0x%02x\n",
+ (long long)p->tv.tv_sec, p->tv.tv_usec,
+ p->ud.modifiers, p->ud.keycode[0], p->ud.keycode[1],
+ p->ud.keycode[2], p->ud.keycode[3]);
+ }
+}
+#endif
+
+int hidkbd_is_console;
+
+const char *hidkbd_parse_desc(struct hidkbd *, int, void *, int);
+
+void (*hidkbd_bell_fn)(void *, u_int, u_int, u_int, int);
+void *hidkbd_bell_fn_arg;
+
+void hidkbd_decode(struct hidkbd *, struct hidkbd_data *);
+void hidkbd_delayed_decode(void *addr);
+
+extern const struct wscons_keydesc ukbd_keydesctab[];
+
+struct wskbd_mapdata ukbd_keymapdata = {
+ ukbd_keydesctab
+};
+
+int
+hidkbd_attach(struct device *self, struct hidkbd *kbd, int console,
+ uint32_t qflags, int id, void *desc, int dlen)
+{
+ const char *parserr;
+
+ kbd->sc_var = NULL;
+
+ parserr = hidkbd_parse_desc(kbd, id, desc, dlen);
+ if (parserr != NULL) {
+ printf(": %s\n", parserr);
+ return ENXIO;
+ }
+
+#ifdef DIAGNOSTIC
+ printf(": %d variable keys, %d key codes",
+ kbd->sc_nvar, kbd->sc_nkeycode);
+#endif
+
+ kbd->sc_device = self;
+ kbd->sc_debounce = (qflags & HIDKBD_SPUR_BUT_UP) != 0;
+
+ /*
+ * Remember if we're the console keyboard.
+ *
+ * XXX This always picks the first (USB) keyboard to attach,
+ * but what else can we really do?
+ */
+ if (console) {
+ kbd->sc_console_keyboard = hidkbd_is_console;
+ /* Don't let any other keyboard have it. */
+ hidkbd_is_console = 0;
+ }
+
+ timeout_set(&kbd->sc_delay, hidkbd_delayed_decode, kbd);
+
+ return 0;
+}
+
+void
+hidkbd_attach_wskbd(struct hidkbd *kbd, kbd_t layout,
+ const struct wskbd_accessops *accessops)
+{
+ struct wskbddev_attach_args a;
+
+ ukbd_keymapdata.layout = layout;
+
+ a.console = kbd->sc_console_keyboard;
+ a.keymap = &ukbd_keymapdata;
+ a.accessops = accessops;
+ a.accesscookie = kbd->sc_device;
+ kbd->sc_wskbddev = config_found(kbd->sc_device, &a, wskbddevprint);
+}
+
+int
+hidkbd_detach(struct hidkbd *kbd, int flags)
+{
+ int rv = 0;
+
+ DPRINTF(("hidkbd_detach: sc=%p flags=%d\n", kbd->sc_device, flags));
+
+ if (kbd->sc_console_keyboard) {
+#if 0
+ /*
+ * XXX Should probably disconnect our consops,
+ * XXX and either notify some other keyboard that
+ * XXX it can now be the console, or if there aren't
+ * XXX any more USB keyboards, set hidkbd_is_console
+ * XXX back to 1 so that the next USB keyboard attached
+ * XXX to the system will get it.
+ */
+ panic("hidkbd_detach: console keyboard");
+#else
+ /*
+ * Disconnect our consops and set hidkbd_is_console
+ * back to 1 so that the next USB keyboard attached
+ * to the system will get it.
+ * XXX Should notify some other keyboard that it can be
+ * XXX console, if there are any other keyboards.
+ */
+ printf("%s: was console keyboard\n",
+ kbd->sc_device->dv_xname);
+ wskbd_cndetach();
+ hidkbd_is_console = 1;
+#endif
+ }
+ /* No need to do reference counting of hidkbd, wskbd has all the goo */
+ if (kbd->sc_wskbddev != NULL)
+ rv = config_detach(kbd->sc_wskbddev, flags);
+
+ if (kbd->sc_var != NULL)
+ free(kbd->sc_var, M_DEVBUF, 0);
+
+ return (rv);
+}
+
+void
+hidkbd_input(struct hidkbd *kbd, uint8_t *data, u_int len)
+{
+ struct hidkbd_data *ud = &kbd->sc_ndata;
+ int i;
+
+#ifdef HIDKBD_DEBUG
+ if (hidkbddebug > 5) {
+ printf("hidkbd_input: data");
+ for (i = 0; i < len; i++)
+ printf(" 0x%02x", data[i]);
+ printf("\n");
+ }
+#endif
+
+ /* extract variable keys */
+ for (i = 0; i < kbd->sc_nvar; i++)
+ ud->var[i] = (u_int8_t)hid_get_data(data, len,
+ &kbd->sc_var[i].loc);
+
+ /* extract keycodes */
+ memcpy(ud->keycode, data + kbd->sc_keycodeloc.pos / 8,
+ kbd->sc_nkeycode);
+
+ if (kbd->sc_debounce && !kbd->sc_polling) {
+ /*
+ * Some keyboards have a peculiar quirk. They sometimes
+ * generate a key up followed by a key down for the same
+ * key after about 10 ms.
+ * We avoid this bug by holding off decoding for 20 ms.
+ */
+ kbd->sc_data = *ud;
+ timeout_add_msec(&kbd->sc_delay, 20);
+#ifdef DDB
+ } else if (kbd->sc_console_keyboard && !kbd->sc_polling) {
+ /*
+ * For the console keyboard we can't deliver CTL-ALT-ESC
+ * from the interrupt routine. Doing so would start
+ * polling from inside the interrupt routine and that
+ * loses bigtime.
+ */
+ /* if (!timeout_pending(&kbd->sc_delay)) */ {
+ kbd->sc_data = *ud;
+ timeout_add(&kbd->sc_delay, 1);
+ }
+#endif
+ } else {
+ hidkbd_decode(kbd, ud);
+ }
+}
+
+void
+hidkbd_delayed_decode(void *addr)
+{
+ struct hidkbd *kbd = addr;
+
+ hidkbd_decode(kbd, &kbd->sc_data);
+}
+
+void
+hidkbd_decode(struct hidkbd *kbd, struct hidkbd_data *ud)
+{
+ u_int16_t ibuf[MAXKEYS]; /* chars events */
+ int s;
+ int nkeys, i, j;
+ int key;
+#define ADDKEY(c) ibuf[nkeys++] = (c)
+
+#ifdef HIDKBD_DEBUG
+ /*
+ * Keep a trace of the last events. Using printf changes the
+ * timing, so this can be useful sometimes.
+ */
+ if (hidkbdtrace) {
+ struct hidkbdtraceinfo *p = &hidkbdtracedata[hidkbdtraceindex];
+ p->unit = kbd->sc_device->dv_unit;
+ microtime(&p->tv);
+ p->ud = *ud;
+ if (++hidkbdtraceindex >= HIDKBDTRACESIZE)
+ hidkbdtraceindex = 0;
+ }
+ if (hidkbddebug > 5) {
+ struct timeval tv;
+ microtime(&tv);
+ DPRINTF((" at %lld.%06ld mod=0x%02x key0=0x%02x key1=0x%02x "
+ "key2=0x%02x key3=0x%02x\n",
+ (long long)tv.tv_sec, tv.tv_usec,
+ ud->modifiers, ud->keycode[0], ud->keycode[1],
+ ud->keycode[2], ud->keycode[3]));
+ }
+#endif
+
+ if (ud->keycode[0] == KEY_ERROR) {
+ DPRINTF(("hidkbd_input: KEY_ERROR\n"));
+ return; /* ignore */
+ }
+ nkeys = 0;
+
+ for (i = 0; i < kbd->sc_nvar; i++)
+ if ((kbd->sc_odata.var[i] & kbd->sc_var[i].mask) !=
+ (ud->var[i] & kbd->sc_var[i].mask)) {
+ ADDKEY(kbd->sc_var[i].key |
+ ((ud->var[i] & kbd->sc_var[i].mask) ?
+ PRESS : RELEASE));
+ }
+
+ if (memcmp(ud->keycode, kbd->sc_odata.keycode, kbd->sc_nkeycode) != 0) {
+ /* Check for released keys. */
+ for (i = 0; i < kbd->sc_nkeycode; i++) {
+ key = kbd->sc_odata.keycode[i];
+ if (key == 0)
+ continue;
+ for (j = 0; j < kbd->sc_nkeycode; j++)
+ if (key == ud->keycode[j])
+ goto rfound;
+ DPRINTFN(3,("hidkbd_decode: relse key=0x%02x\n", key));
+ ADDKEY(key | RELEASE);
+ rfound:
+ ;
+ }
+
+ /* Check for pressed keys. */
+ for (i = 0; i < kbd->sc_nkeycode; i++) {
+ key = ud->keycode[i];
+ if (key == 0)
+ continue;
+ for (j = 0; j < kbd->sc_nkeycode; j++)
+ if (key == kbd->sc_odata.keycode[j])
+ goto pfound;
+ DPRINTFN(2,("hidkbd_decode: press key=0x%02x\n", key));
+ ADDKEY(key | PRESS);
+ pfound:
+ ;
+ }
+ }
+ kbd->sc_odata = *ud;
+
+ if (nkeys == 0)
+ return;
+
+ if (kbd->sc_polling) {
+ DPRINTFN(1,("hidkbd_decode: pollchar = 0x%03x\n", ibuf[0]));
+ memcpy(kbd->sc_pollchars, ibuf, nkeys * sizeof(u_int16_t));
+ kbd->sc_npollchar = nkeys;
+ return;
+ }
+
+ if (kbd->sc_wskbddev == NULL)
+ return;
+
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+ if (kbd->sc_rawkbd) {
+ u_char cbuf[MAXKEYS * 2];
+ int c;
+
+ for (i = j = 0; i < nkeys; i++) {
+ key = ibuf[i];
+ c = hidkbd_trtab[key & CODEMASK];
+ if (c == NN)
+ continue;
+ if (c & 0x80)
+ cbuf[j++] = 0xe0;
+ cbuf[j] = c & 0x7f;
+ if (key & RELEASE)
+ cbuf[j] |= 0x80;
+ DPRINTFN(1,("hidkbd_decode: raw = %s0x%02x\n",
+ c & 0x80 ? "0xe0 " : "",
+ cbuf[j]));
+ j++;
+ }
+ s = spltty();
+ wskbd_rawinput(kbd->sc_wskbddev, cbuf, j);
+
+ /*
+ * Pass audio keys to wskbd_input anyway.
+ */
+ for (i = 0; i < nkeys; i++) {
+ key = ibuf[i];
+ switch (key & CODEMASK) {
+ case 127:
+ case 128:
+ case 129:
+ wskbd_input(kbd->sc_wskbddev,
+ key & RELEASE ? WSCONS_EVENT_KEY_UP :
+ WSCONS_EVENT_KEY_DOWN, key & CODEMASK);
+ break;
+ }
+ }
+ splx(s);
+
+ return;
+ }
+#endif
+
+ s = spltty();
+ for (i = 0; i < nkeys; i++) {
+ key = ibuf[i];
+ wskbd_input(kbd->sc_wskbddev,
+ key&RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN,
+ key&CODEMASK);
+ }
+ splx(s);
+#undef ADDKEY
+}
+
+int
+hidkbd_enable(struct hidkbd *kbd, int on)
+{
+ if (kbd->sc_enabled == on)
+ return EBUSY;
+
+ kbd->sc_enabled = on;
+ return 0;
+}
+
+int
+hidkbd_set_leds(struct hidkbd *kbd, int leds, uint8_t *report)
+{
+ if (kbd->sc_leds == leds)
+ return 0;
+
+ kbd->sc_leds = leds;
+
+ /*
+ * This is not totally correct, since we did not check the
+ * report size from the descriptor but for keyboards it should
+ * just be a single byte with the relevant bits set.
+ */
+ *report = 0;
+ if ((leds & WSKBD_LED_SCROLL) && kbd->sc_scroloc.size == 1)
+ *report |= 1 << kbd->sc_scroloc.pos;
+ if ((leds & WSKBD_LED_NUM) && kbd->sc_numloc.size == 1)
+ *report |= 1 << kbd->sc_numloc.pos;
+ if ((leds & WSKBD_LED_CAPS) && kbd->sc_capsloc.size == 1)
+ *report |= 1 << kbd->sc_capsloc.pos;
+ if ((leds & WSKBD_LED_COMPOSE) && kbd->sc_compose.size == 1)
+ *report |= 1 << kbd->sc_compose.pos;
+
+ return 1;
+}
+
+int
+hidkbd_ioctl(struct hidkbd *kbd, u_long cmd, caddr_t data, int flag,
+ struct proc *p)
+{
+ switch (cmd) {
+ case WSKBDIO_GETLEDS:
+ *(int *)data = kbd->sc_leds;
+ return (0);
+ case WSKBDIO_COMPLEXBELL:
+#define d ((struct wskbd_bell_data *)data)
+ hidkbd_bell(d->pitch, d->period, d->volume, 0);
+#undef d
+ return (0);
+#ifdef WSDISPLAY_COMPAT_RAWKBD
+ case WSKBDIO_SETMODE:
+ DPRINTF(("hidkbd_ioctl: set raw = %d\n", *(int *)data));
+ kbd->sc_rawkbd = *(int *)data == WSKBD_RAW;
+ return (0);
+#endif
+ }
+ return (-1);
+}
+
+void
+hidkbd_cngetc(struct hidkbd *kbd, u_int *type, int *data)
+{
+ int c;
+
+ c = kbd->sc_pollchars[0];
+ kbd->sc_npollchar--;
+ memcpy(kbd->sc_pollchars, kbd->sc_pollchars+1,
+ kbd->sc_npollchar * sizeof(u_int16_t));
+ *type = c & RELEASE ? WSCONS_EVENT_KEY_UP : WSCONS_EVENT_KEY_DOWN;
+ *data = c & CODEMASK;
+}
+
+void
+hidkbd_bell(u_int pitch, u_int period, u_int volume, int poll)
+{
+ if (hidkbd_bell_fn != NULL)
+ (*hidkbd_bell_fn)(hidkbd_bell_fn_arg, pitch, period,
+ volume, poll);
+}
+
+void
+hidkbd_hookup_bell(void (*fn)(void *, u_int, u_int, u_int, int), void *arg)
+{
+ if (hidkbd_bell_fn == NULL) {
+ hidkbd_bell_fn = fn;
+ hidkbd_bell_fn_arg = arg;
+ }
+}
+
+const char *
+hidkbd_parse_desc(struct hidkbd *kbd, int id, void *desc, int dlen)
+{
+ struct hid_data *d;
+ struct hid_item h;
+ unsigned int i, ivar = 0;
+
+ kbd->sc_nkeycode = 0;
+
+ d = hid_start_parse(desc, dlen, hid_input);
+ while (hid_get_item(d, &h)) {
+ if (h.kind != hid_input || (h.flags & HIO_CONST) ||
+ HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD ||
+ h.report_ID != id)
+ continue;
+ if (h.flags & HIO_VARIABLE)
+ ivar++;
+ }
+ hid_end_parse(d);
+
+ if (ivar > MAXVARS) {
+ DPRINTF((": too many variable keys\n"));
+ ivar = MAXVARS;
+ }
+
+ kbd->sc_nvar = ivar;
+ kbd->sc_var = (struct hidkbd_variable *)mallocarray(ivar,
+ sizeof(struct hidkbd_variable), M_DEVBUF, M_NOWAIT);
+
+ if (!kbd->sc_var)
+ return NULL;
+
+ i = 0;
+
+ d = hid_start_parse(desc, dlen, hid_input);
+ while (hid_get_item(d, &h)) {
+ if (h.kind != hid_input || (h.flags & HIO_CONST) ||
+ HID_GET_USAGE_PAGE(h.usage) != HUP_KEYBOARD ||
+ h.report_ID != id)
+ continue;
+
+ DPRINTF(("hidkbd: usage=0x%x flags=0x%x pos=%d size=%d cnt=%d",
+ h.usage, h.flags, h.loc.pos, h.loc.size, h.loc.count));
+ if (h.flags & HIO_VARIABLE) {
+ /* variable reports should be one bit each */
+ if (h.loc.size != 1) {
+ DPRINTF((": bad variable size\n"));
+ continue;
+ }
+
+ /* variable report */
+ if (i < MAXVARS) {
+ kbd->sc_var[i].loc = h.loc;
+ kbd->sc_var[i].mask = 1 << (i % 8);
+ kbd->sc_var[i].key = HID_GET_USAGE(h.usage);
+ i++;
+ }
+ } else {
+ /* keys array should be in bytes, on a byte boundary */
+ if (h.loc.size != 8) {
+ DPRINTF((": key code size != 8\n"));
+ continue;
+ }
+ if (h.loc.pos % 8 != 0) {
+ DPRINTF((": array not on byte boundary"));
+ continue;
+ }
+ if (kbd->sc_nkeycode != 0) {
+ DPRINTF((": ignoring multiple arrays\n"));
+ continue;
+ }
+ kbd->sc_keycodeloc = h.loc;
+ if (h.loc.count > MAXKEYCODE) {
+ DPRINTF((": ignoring extra key codes"));
+ kbd->sc_nkeycode = MAXKEYCODE;
+ } else
+ kbd->sc_nkeycode = h.loc.count;
+ }
+ DPRINTF(("\n"));
+ }
+ hid_end_parse(d);
+
+ /* don't attach if no keys... */
+ if (kbd->sc_nkeycode == 0 && ivar == 0)
+ return "no usable key codes array";
+
+ hid_locate(desc, dlen, HID_USAGE2(HUP_LED, HUL_NUM_LOCK),
+ id, hid_output, &kbd->sc_numloc, NULL);
+ hid_locate(desc, dlen, HID_USAGE2(HUP_LED, HUL_CAPS_LOCK),
+ id, hid_output, &kbd->sc_capsloc, NULL);
+ hid_locate(desc, dlen, HID_USAGE2(HUP_LED, HUL_SCROLL_LOCK),
+ id, hid_output, &kbd->sc_scroloc, NULL);
+ hid_locate(desc, dlen, HID_USAGE2(HUP_LED, HUL_COMPOSE),
+ id, hid_output, &kbd->sc_compose, NULL);
+
+ return (NULL);
+}
diff --git a/sys/dev/hid/hidkbdsc.h b/sys/dev/hid/hidkbdsc.h
new file mode 100644
index 00000000000..02c67fb2ff0
--- /dev/null
+++ b/sys/dev/hid/hidkbdsc.h
@@ -0,0 +1,105 @@
+/* $OpenBSD: hidkbdsc.h,v 1.1 2016/01/08 15:54:13 jcs Exp $ */
+/* $NetBSD: ukbd.c,v 1.85 2003/03/11 16:44:00 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net) at
+ * Carlstedt Research & Technology.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#define MAXKEYCODE 6
+#define MAXVARS 128
+
+#define MAXKEYS (MAXVARS+2*MAXKEYCODE)
+
+/* quirks */
+#define HIDKBD_SPUR_BUT_UP 0x001 /* spurious button up events */
+
+struct hidkbd_variable {
+ struct hid_location loc;
+ u_int8_t mask;
+ u_int8_t key;
+};
+
+struct hidkbd_data {
+ u_int8_t keycode[MAXKEYCODE];
+ u_int8_t var[MAXVARS];
+};
+
+struct hidkbd {
+ /* stored data */
+ struct hidkbd_data sc_ndata;
+ struct hidkbd_data sc_odata;
+
+ /* input reports */
+ u_int sc_nvar;
+ struct hidkbd_variable *sc_var;
+
+ struct hid_location sc_keycodeloc;
+ u_int sc_nkeycode;
+
+ /* output reports */
+ struct hid_location sc_numloc;
+ struct hid_location sc_capsloc;
+ struct hid_location sc_scroloc;
+ struct hid_location sc_compose;
+ int sc_leds;
+
+ /* state information */
+ struct device *sc_device;
+ struct device *sc_wskbddev;
+ char sc_enabled;
+
+ char sc_console_keyboard; /* we are the console keyboard */
+
+ char sc_debounce; /* for quirk handling */
+ struct timeout sc_delay; /* for quirk handling */
+ struct hidkbd_data sc_data; /* for quirk handling */
+
+ /* key repeat logic */
+#if defined(WSDISPLAY_COMPAT_RAWKBD)
+ int sc_rawkbd;
+#endif /* defined(WSDISPLAY_COMPAT_RAWKBD) */
+
+ int sc_polling;
+ int sc_npollchar;
+ u_int16_t sc_pollchars[MAXKEYS];
+};
+
+int hidkbd_attach(struct device *, struct hidkbd *, int, uint32_t,
+ int, void *, int);
+void hidkbd_attach_wskbd(struct hidkbd *, kbd_t,
+ const struct wskbd_accessops *);
+void hidkbd_bell(u_int, u_int, u_int, int);
+void hidkbd_cngetc(struct hidkbd *, u_int *, int *);
+int hidkbd_detach(struct hidkbd *, int);
+int hidkbd_enable(struct hidkbd *, int);
+void hidkbd_input(struct hidkbd *, uint8_t *, u_int);
+int hidkbd_ioctl(struct hidkbd *, u_long, caddr_t, int, struct proc *);
+int hidkbd_set_leds(struct hidkbd *, int, uint8_t *);
+
+extern int hidkbd_is_console;
diff --git a/sys/dev/hid/hidkbdvar.h b/sys/dev/hid/hidkbdvar.h
new file mode 100644
index 00000000000..17efebe3624
--- /dev/null
+++ b/sys/dev/hid/hidkbdvar.h
@@ -0,0 +1,34 @@
+/* $OpenBSD: hidkbdvar.h,v 1.1 2016/01/08 15:54:13 jcs Exp $ */
+/* $NetBSD: ukbd.c,v 1.85 2003/03/11 16:44:00 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net) at
+ * Carlstedt Research & Technology.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+void hidkbd_hookup_bell(void (*)(void *, u_int, u_int, u_int, int), void *);
diff --git a/sys/dev/hid/hidms.c b/sys/dev/hid/hidms.c
new file mode 100644
index 00000000000..e52c3cb7622
--- /dev/null
+++ b/sys/dev/hid/hidms.c
@@ -0,0 +1,478 @@
+/* $OpenBSD: hidms.c,v 1.1 2016/01/08 15:54:13 jcs Exp $ */
+/* $NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net) at
+ * Carlstedt Research & Technology.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+/*
+ * HID spec: http://www.usb.org/developers/devclass_docs/HID1_11.pdf
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsmousevar.h>
+
+#include <dev/hid/hid.h>
+#include <dev/hid/hidmsvar.h>
+
+#ifdef HIDMS_DEBUG
+#define DPRINTF(x) do { if (hidmsdebug) printf x; } while (0)
+#define DPRINTFN(n,x) do { if (hidmsdebug>(n)) printf x; } while (0)
+int hidmsdebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+#define HIDMS_BUT(i) ((i) == 1 || (i) == 2 ? 3 - (i) : i)
+
+#define MOUSE_FLAGS_MASK (HIO_CONST | HIO_RELATIVE)
+#define NOTMOUSE(f) (((f) & MOUSE_FLAGS_MASK) != HIO_RELATIVE)
+
+int
+hidms_setup(struct device *self, struct hidms *ms, uint32_t quirks,
+ int id, void *desc, int dlen)
+{
+ struct hid_item h;
+ struct hid_data *d;
+ uint32_t flags;
+ int i, wheel, twheel;
+
+ ms->sc_device = self;
+ ms->sc_rawmode = 1;
+
+ ms->sc_flags = quirks;
+
+ if (!hid_locate(desc, dlen, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X), id,
+ hid_input, &ms->sc_loc_x, &flags)) {
+ printf("\n%s: mouse has no X report\n", self->dv_xname);
+ return ENXIO;
+ }
+ switch(flags & MOUSE_FLAGS_MASK) {
+ case 0:
+ ms->sc_flags |= HIDMS_ABSX;
+ break;
+ case HIO_RELATIVE:
+ break;
+ default:
+ printf("\n%s: X report 0x%04x not supported\n",
+ self->dv_xname, flags);
+ return ENXIO;
+ }
+
+ if (!hid_locate(desc, dlen, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y), id,
+ hid_input, &ms->sc_loc_y, &flags)) {
+ printf("\n%s: mouse has no Y report\n", self->dv_xname);
+ return ENXIO;
+ }
+ switch(flags & MOUSE_FLAGS_MASK) {
+ case 0:
+ ms->sc_flags |= HIDMS_ABSY;
+ break;
+ case HIO_RELATIVE:
+ break;
+ default:
+ printf("\n%s: Y report 0x%04x not supported\n",
+ self->dv_xname, flags);
+ return ENXIO;
+ }
+
+ /*
+ * Try to guess the Z activator: check WHEEL, TWHEEL, and Z,
+ * in that order.
+ */
+
+ wheel = hid_locate(desc, dlen,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_WHEEL), id,
+ hid_input, &ms->sc_loc_z, &flags);
+ if (wheel == 0)
+ twheel = hid_locate(desc, dlen,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_TWHEEL), id,
+ hid_input, &ms->sc_loc_z, &flags);
+ else
+ twheel = 0;
+
+ if (wheel || twheel) {
+ if (NOTMOUSE(flags)) {
+ DPRINTF(("\n%s: Wheel report 0x%04x not supported\n",
+ self->dv_xname, flags));
+ ms->sc_loc_z.size = 0; /* Bad Z coord, ignore it */
+ } else {
+ ms->sc_flags |= HIDMS_Z;
+ /* Wheels need the Z axis reversed. */
+ ms->sc_flags ^= HIDMS_REVZ;
+ }
+ /*
+ * We might have both a wheel and Z direction; in this case,
+ * report the Z direction on the W axis.
+ *
+ * Otherwise, check for a W direction as an AC Pan input used
+ * on some newer mice.
+ */
+ if (hid_locate(desc, dlen,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), id,
+ hid_input, &ms->sc_loc_w, &flags)) {
+ if (NOTMOUSE(flags)) {
+ DPRINTF(("\n%s: Z report 0x%04x not supported\n",
+ self->dv_xname, flags));
+ /* Bad Z coord, ignore it */
+ ms->sc_loc_w.size = 0;
+ }
+ else
+ ms->sc_flags |= HIDMS_W;
+ } else if (hid_locate(desc, dlen,
+ HID_USAGE2(HUP_CONSUMER, HUC_AC_PAN), id, hid_input,
+ &ms->sc_loc_w, &flags)) {
+ ms->sc_flags |= HIDMS_W;
+ }
+ } else if (hid_locate(desc, dlen,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Z), id,
+ hid_input, &ms->sc_loc_z, &flags)) {
+ if (NOTMOUSE(flags)) {
+ DPRINTF(("\n%s: Z report 0x%04x not supported\n",
+ self->dv_xname, flags));
+ ms->sc_loc_z.size = 0; /* Bad Z coord, ignore it */
+ } else {
+ ms->sc_flags |= HIDMS_Z;
+ }
+ }
+
+ /*
+ * The Microsoft Wireless Intellimouse 2.0 reports its wheel
+ * using 0x0048 (I've called it HUG_TWHEEL) and seems to expect
+ * us to know that the byte after the wheel is the tilt axis.
+ * There are no other HID axis descriptors other than X, Y and
+ * TWHEEL, so we report TWHEEL on the W axis.
+ */
+ if (twheel) {
+ ms->sc_loc_w = ms->sc_loc_z;
+ ms->sc_loc_w.pos = ms->sc_loc_w.pos + 8;
+ ms->sc_flags |= HIDMS_W | HIDMS_LEADINGBYTE;
+ /* Wheels need their axis reversed. */
+ ms->sc_flags ^= HIDMS_REVW;
+ }
+
+ /* figure out the number of buttons */
+ for (i = 1; i <= MAX_BUTTONS; i++)
+ if (!hid_locate(desc, dlen, HID_USAGE2(HUP_BUTTON, i), id,
+ hid_input, &ms->sc_loc_btn[i - 1], NULL))
+ break;
+ ms->sc_num_buttons = i - 1;
+
+ if (hid_locate(desc, dlen, HID_USAGE2(HUP_DIGITIZERS,
+ HUD_TIP_SWITCH), id, hid_input,
+ &ms->sc_loc_btn[ms->sc_num_buttons], NULL)){
+ ms->sc_flags |= HIDMS_TIP;
+ ms->sc_num_buttons++;
+ }
+
+ if (hid_locate(desc, dlen, HID_USAGE2(HUP_DIGITIZERS,
+ HUD_ERASER), id, hid_input,
+ &ms->sc_loc_btn[ms->sc_num_buttons], NULL)){
+ ms->sc_flags |= HIDMS_ERASER;
+ ms->sc_num_buttons++;
+ }
+
+ if (hid_locate(desc, dlen, HID_USAGE2(HUP_DIGITIZERS,
+ HUD_BARREL_SWITCH), id, hid_input,
+ &ms->sc_loc_btn[ms->sc_num_buttons], NULL)){
+ ms->sc_flags |= HIDMS_BARREL;
+ ms->sc_num_buttons++;
+ }
+
+ /*
+ * The Microsoft Wireless Notebook Optical Mouse seems to be in worse
+ * shape than the Wireless Intellimouse 2.0, as its X, Y, wheel, and
+ * all of its other button positions are all off. It also reports that
+ * it has two addional buttons and a tilt wheel.
+ */
+ if (ms->sc_flags & HIDMS_MS_BAD_CLASS) {
+ /* HIDMS_LEADINGBYTE cleared on purpose */
+ ms->sc_flags = HIDMS_Z | HIDMS_SPUR_BUT_UP;
+ ms->sc_num_buttons = 3;
+ /* XXX change sc_hdev isize to 5? */
+ /* 1st byte of descriptor report contains garbage */
+ ms->sc_loc_x.pos = 16;
+ ms->sc_loc_y.pos = 24;
+ ms->sc_loc_z.pos = 32;
+ ms->sc_loc_btn[0].pos = 8;
+ ms->sc_loc_btn[1].pos = 9;
+ ms->sc_loc_btn[2].pos = 10;
+ }
+ /* Parse descriptors to get touch panel bounds */
+ d = hid_start_parse(desc, dlen, hid_input);
+ while (hid_get_item(d, &h)) {
+ if (h.kind != hid_input ||
+ HID_GET_USAGE_PAGE(h.usage) != HUP_GENERIC_DESKTOP)
+ continue;
+ DPRINTF(("hidms: usage=0x%x range %d..%d\n",
+ h.usage, h.logical_minimum, h.logical_maximum));
+ switch (HID_GET_USAGE(h.usage)) {
+ case HUG_X:
+ if (ms->sc_flags & HIDMS_ABSX) {
+ ms->sc_tsscale.minx = h.logical_minimum;
+ ms->sc_tsscale.maxx = h.logical_maximum;
+ }
+ break;
+ case HUG_Y:
+ if (ms->sc_flags & HIDMS_ABSY) {
+ ms->sc_tsscale.miny = h.logical_minimum;
+ ms->sc_tsscale.maxy = h.logical_maximum;
+ }
+ break;
+ }
+ }
+ hid_end_parse(d);
+ return 0;
+}
+
+void
+hidms_attach(struct hidms *ms, const struct wsmouse_accessops *ops)
+{
+ struct wsmousedev_attach_args a;
+#ifdef HIDMS_DEBUG
+ int i;
+#endif
+
+ printf(": %d button%s",
+ ms->sc_num_buttons, ms->sc_num_buttons <= 1 ? "" : "s");
+ switch (ms->sc_flags & (HIDMS_Z | HIDMS_W)) {
+ case HIDMS_Z:
+ printf(", Z dir");
+ break;
+ case HIDMS_W:
+ printf(", W dir");
+ break;
+ case HIDMS_Z | HIDMS_W:
+ printf(", Z and W dir");
+ break;
+ }
+
+ if (ms->sc_flags & HIDMS_TIP)
+ printf(", tip");
+ if (ms->sc_flags & HIDMS_BARREL)
+ printf(", barrel");
+ if (ms->sc_flags & HIDMS_ERASER)
+ printf(", eraser");
+
+ printf("\n");
+
+#ifdef HIDMS_DEBUG
+ DPRINTF(("hidms_attach: ms=%p\n", ms));
+ DPRINTF(("hidms_attach: X\t%d/%d\n",
+ ms->sc_loc_x.pos, ms->sc_loc_x.size));
+ DPRINTF(("hidms_attach: Y\t%d/%d\n",
+ ms->sc_loc_y.pos, ms->sc_loc_y.size));
+ if (ms->sc_flags & HIDMS_Z)
+ DPRINTF(("hidms_attach: Z\t%d/%d\n",
+ ms->sc_loc_z.pos, ms->sc_loc_z.size));
+ if (ms->sc_flags & HIDMS_W)
+ DPRINTF(("hidms_attach: W\t%d/%d\n",
+ ms->sc_loc_w.pos, ms->sc_loc_w.size));
+ for (i = 1; i <= ms->sc_num_buttons; i++) {
+ DPRINTF(("hidms_attach: B%d\t%d/%d\n",
+ i, ms->sc_loc_btn[i - 1].pos, ms->sc_loc_btn[i - 1].size));
+ }
+#endif
+
+ a.accessops = ops;
+ a.accesscookie = ms->sc_device;
+ ms->sc_wsmousedev = config_found(ms->sc_device, &a, wsmousedevprint);
+}
+
+int
+hidms_detach(struct hidms *ms, int flags)
+{
+ int rv = 0;
+
+ DPRINTF(("hidms_detach: ms=%p flags=%d\n", ms, flags));
+
+ /* No need to do reference counting of hidms, wsmouse has all the goo */
+ if (ms->sc_wsmousedev != NULL)
+ rv = config_detach(ms->sc_wsmousedev, flags);
+
+ return (rv);
+}
+
+void
+hidms_input(struct hidms *ms, uint8_t *data, u_int len)
+{
+ int dx, dy, dz, dw;
+ u_int32_t buttons = 0;
+ int flags;
+ int i, s;
+
+ DPRINTFN(5,("hidms_input: len=%d\n", len));
+
+ /*
+ * The Microsoft Wireless Intellimouse 2.0 sends one extra leading
+ * byte of data compared to most USB mice. This byte frequently
+ * switches from 0x01 (usual state) to 0x02. It may be used to
+ * report non-standard events (such as battery life). However,
+ * at the same time, it generates a left click event on the
+ * button byte, where there shouldn't be any. We simply discard
+ * the packet in this case.
+ *
+ * This problem affects the MS Wireless Notebook Optical Mouse, too.
+ * However, the leading byte for this mouse is normally 0x11, and
+ * the phantom mouse click occurs when it's 0x14.
+ */
+ if (ms->sc_flags & HIDMS_LEADINGBYTE) {
+ if (*data++ == 0x02)
+ return;
+ /* len--; */
+ } else if (ms->sc_flags & HIDMS_SPUR_BUT_UP) {
+ if (*data == 0x14 || *data == 0x15)
+ return;
+ }
+
+ flags = WSMOUSE_INPUT_DELTA;
+ if (ms->sc_flags & HIDMS_ABSX)
+ flags |= WSMOUSE_INPUT_ABSOLUTE_X;
+ if (ms->sc_flags & HIDMS_ABSY)
+ flags |= WSMOUSE_INPUT_ABSOLUTE_Y;
+
+ dx = hid_get_data(data, len, &ms->sc_loc_x);
+ dy = -hid_get_data(data, len, &ms->sc_loc_y);
+ dz = hid_get_data(data, len, &ms->sc_loc_z);
+ dw = hid_get_data(data, len, &ms->sc_loc_w);
+
+ if (ms->sc_flags & HIDMS_ABSY)
+ dy = -dy;
+ if (ms->sc_flags & HIDMS_REVZ)
+ dz = -dz;
+ if (ms->sc_flags & HIDMS_REVW)
+ dw = -dw;
+
+ if (ms->sc_tsscale.swapxy && !ms->sc_rawmode) {
+ int tmp = dx;
+ dx = dy;
+ dy = tmp;
+ }
+
+ if (!ms->sc_rawmode &&
+ (ms->sc_tsscale.maxx - ms->sc_tsscale.minx) != 0 &&
+ (ms->sc_tsscale.maxy - ms->sc_tsscale.miny) != 0) {
+ /* Scale down to the screen resolution. */
+ dx = ((dx - ms->sc_tsscale.minx) * ms->sc_tsscale.resx) /
+ (ms->sc_tsscale.maxx - ms->sc_tsscale.minx);
+ dy = ((dy - ms->sc_tsscale.miny) * ms->sc_tsscale.resy) /
+ (ms->sc_tsscale.maxy - ms->sc_tsscale.miny);
+ }
+
+ for (i = 0; i < ms->sc_num_buttons; i++)
+ if (hid_get_data(data, len, &ms->sc_loc_btn[i]))
+ buttons |= (1 << HIDMS_BUT(i));
+
+ if (dx != 0 || dy != 0 || dz != 0 || dw != 0 ||
+ buttons != ms->sc_buttons) {
+ DPRINTFN(10, ("hidms_input: x:%d y:%d z:%d w:%d buttons:0x%x\n",
+ dx, dy, dz, dw, buttons));
+ ms->sc_buttons = buttons;
+ if (ms->sc_wsmousedev != NULL) {
+ s = spltty();
+ wsmouse_input(ms->sc_wsmousedev, buttons,
+ dx, dy, dz, dw, flags);
+ splx(s);
+ }
+ }
+}
+
+int
+hidms_enable(struct hidms *ms)
+{
+ if (ms->sc_enabled)
+ return EBUSY;
+
+ ms->sc_enabled = 1;
+ ms->sc_buttons = 0;
+ return 0;
+}
+
+int
+hidms_ioctl(struct hidms *ms, u_long cmd, caddr_t data, int flag,
+ struct proc *p)
+{
+ struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
+
+ switch (cmd) {
+ case WSMOUSEIO_SCALIBCOORDS:
+ if (!(wsmc->minx >= 0 && wsmc->maxx >= 0 &&
+ wsmc->miny >= 0 && wsmc->maxy >= 0 &&
+ wsmc->resx >= 0 && wsmc->resy >= 0 &&
+ wsmc->minx < 32768 && wsmc->maxx < 32768 &&
+ wsmc->miny < 32768 && wsmc->maxy < 32768 &&
+ (wsmc->maxx - wsmc->minx) != 0 &&
+ (wsmc->maxy - wsmc->miny) != 0 &&
+ wsmc->resx < 32768 && wsmc->resy < 32768 &&
+ wsmc->swapxy >= 0 && wsmc->swapxy <= 1 &&
+ wsmc->samplelen >= 0 && wsmc->samplelen <= 1))
+ return (EINVAL);
+
+ ms->sc_tsscale.minx = wsmc->minx;
+ ms->sc_tsscale.maxx = wsmc->maxx;
+ ms->sc_tsscale.miny = wsmc->miny;
+ ms->sc_tsscale.maxy = wsmc->maxy;
+ ms->sc_tsscale.swapxy = wsmc->swapxy;
+ ms->sc_tsscale.resx = wsmc->resx;
+ ms->sc_tsscale.resy = wsmc->resy;
+ ms->sc_rawmode = wsmc->samplelen;
+ return 0;
+ case WSMOUSEIO_GCALIBCOORDS:
+ wsmc->minx = ms->sc_tsscale.minx;
+ wsmc->maxx = ms->sc_tsscale.maxx;
+ wsmc->miny = ms->sc_tsscale.miny;
+ wsmc->maxy = ms->sc_tsscale.maxy;
+ wsmc->swapxy = ms->sc_tsscale.swapxy;
+ wsmc->resx = ms->sc_tsscale.resx;
+ wsmc->resy = ms->sc_tsscale.resy;
+ wsmc->samplelen = ms->sc_rawmode;
+ return 0;
+ case WSMOUSEIO_GTYPE:
+ if (ms->sc_flags & HIDMS_ABSX && ms->sc_flags & HIDMS_ABSY) {
+ *(u_int *)data = WSMOUSE_TYPE_TPANEL;
+ return 0;
+ }
+ /* FALLTHROUGH */
+ default:
+ return -1;
+ }
+}
+
+void
+hidms_disable(struct hidms *ms)
+{
+ ms->sc_enabled = 0;
+}
diff --git a/sys/dev/hid/hidmsvar.h b/sys/dev/hid/hidmsvar.h
new file mode 100644
index 00000000000..355cb8b553d
--- /dev/null
+++ b/sys/dev/hid/hidmsvar.h
@@ -0,0 +1,83 @@
+/* $OpenBSD: hidmsvar.h,v 1.1 2016/01/08 15:54:13 jcs Exp $ */
+/* $NetBSD: ums.c,v 1.60 2003/03/11 16:44:00 augustss Exp $ */
+
+/*
+ * Copyright (c) 1998 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Lennart Augustsson (lennart@augustsson.net) at
+ * Carlstedt Research & Technology.
+ *
+ * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
+ */
+
+#define MAX_BUTTONS 31 /* must not exceed size of sc_buttons */
+
+struct tsscale {
+ int minx, maxx;
+ int miny, maxy;
+ int swapxy;
+ int resx, resy;
+};
+
+struct hidms {
+ int sc_enabled;
+ int sc_flags; /* device configuration */
+#define HIDMS_SPUR_BUT_UP 0x001 /* spurious button up events */
+#define HIDMS_Z 0x002 /* Z direction available */
+#define HIDMS_REVZ 0x004 /* Z-axis is reversed */
+#define HIDMS_W 0x008 /* W direction available */
+#define HIDMS_REVW 0x010 /* W-axis is reversed */
+#define HIDMS_LEADINGBYTE 0x020 /* Unknown leading byte */
+#define HIDMS_ABSX 0x040 /* X-axis is absolute */
+#define HIDMS_ABSY 0x080 /* Y-axis is absolute */
+#define HIDMS_TIP 0x100 /* Tip switch on a digitiser pen */
+#define HIDMS_BARREL 0x200 /* Barrel switch on a digitiser pen */
+#define HIDMS_ERASER 0x400 /* Eraser switch on a digitiser pen */
+#define HIDMS_MS_BAD_CLASS 0x800 /* Mouse doesn't identify properly */
+
+ int sc_num_buttons;
+ u_int32_t sc_buttons; /* mouse button status */
+
+ struct device *sc_device;
+ struct device *sc_wsmousedev;
+
+ /* locators */
+ struct hid_location sc_loc_x;
+ struct hid_location sc_loc_y;
+ struct hid_location sc_loc_z;
+ struct hid_location sc_loc_w;
+ struct hid_location sc_loc_btn[MAX_BUTTONS];
+
+ struct tsscale sc_tsscale;
+ int sc_rawmode;
+};
+
+void hidms_attach(struct hidms *, const struct wsmouse_accessops *);
+int hidms_detach(struct hidms *, int);
+void hidms_disable(struct hidms *);
+int hidms_enable(struct hidms *);
+void hidms_input(struct hidms *, uint8_t *, u_int);
+int hidms_ioctl(struct hidms *, u_long, caddr_t, int, struct proc *);
+int hidms_setup(struct device *, struct hidms *, uint32_t, int, void *,
+ int);