summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2016-01-14 21:01:50 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2016-01-14 21:01:50 +0000
commit6f78afe452d424eb9bef0c7b65c8f0f6ca9fd0e8 (patch)
tree4e72ada246cf4b7db5580b2d4872e7b74379b067 /sys/dev
parent736724e00b3663dd6e0b689701ca916eb3836612 (diff)
Driver for HID-over-i2c keyboards.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/i2c/files.i2c7
-rw-r--r--sys/dev/i2c/ikbd.c172
2 files changed, 178 insertions, 1 deletions
diff --git a/sys/dev/i2c/files.i2c b/sys/dev/i2c/files.i2c
index 566a829edbd..2b2fb296422 100644
--- a/sys/dev/i2c/files.i2c
+++ b/sys/dev/i2c/files.i2c
@@ -1,4 +1,4 @@
-# $OpenBSD: files.i2c,v 1.52 2016/01/12 01:11:15 jcs Exp $
+# $OpenBSD: files.i2c,v 1.53 2016/01/14 21:01:49 kettenis Exp $
# $NetBSD: files.i2c,v 1.3 2003/10/20 16:24:10 briggs Exp $
define i2c {[addr = -1], [size = -1]}
@@ -180,6 +180,11 @@ device ihidev: hid, ihidbus
attach ihidev at i2c
file dev/i2c/ihidev.c ihidev
+# HID Keyboard
+device ikbd: hid, hidkbd, wskbddev
+attach ikbd at ihidbus
+file dev/i2c/ikbd.c ikbd
+
# HID Mouse/Trackpad
device ims: hid, hidms, wsmousedev
attach ims at ihidbus
diff --git a/sys/dev/i2c/ikbd.c b/sys/dev/i2c/ikbd.c
new file mode 100644
index 00000000000..7c95b03a5b5
--- /dev/null
+++ b/sys/dev/i2c/ikbd.c
@@ -0,0 +1,172 @@
+/* $OpenBSD: ikbd.c,v 1.1 2016/01/14 21:01:49 kettenis Exp $ */
+/*
+ * HID-over-i2c keyboard driver
+ *
+ * Copyright (c) 2016 Mark Kettenis <kettenis@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/timeout.h>
+
+#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/ihidev.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wskbdvar.h>
+#include <dev/wscons/wsksymdef.h>
+
+#include <dev/hid/hid.h>
+#include <dev/hid/hidkbdsc.h>
+
+struct ikbd_softc {
+ struct ihidev sc_hdev;
+ struct hidkbd sc_kbd;
+};
+
+void ikbd_intr(struct ihidev *addr, void *ibuf, u_int len);
+
+int ikbd_enable(void *, int);
+void ikbd_set_leds(void *, int);
+int ikbd_ioctl(void *, u_long, caddr_t, int, struct proc *);
+
+const struct wskbd_accessops ikbd_accessops = {
+ ikbd_enable,
+ ikbd_set_leds,
+ ikbd_ioctl,
+};
+
+int ikbd_match(struct device *, void *, void *);
+void ikbd_attach(struct device *, struct device *, void *);
+int ikbd_detach(struct device *, int);
+
+struct cfdriver ikbd_cd = {
+ NULL, "ikbd", DV_DULL
+};
+
+const struct cfattach ikbd_ca = {
+ sizeof(struct ikbd_softc),
+ ikbd_match,
+ ikbd_attach,
+ ikbd_detach
+};
+
+int
+ikbd_match(struct device *parent, void *match, void *aux)
+{
+ struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux;
+ int size;
+ void *desc;
+
+ ihidev_get_report_desc(iha->parent, &desc, &size);
+ if (!hid_is_collection(desc, size, iha->reportid,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_KEYBOARD)))
+ return (IMATCH_NONE);
+
+ return (IMATCH_IFACECLASS);
+}
+
+void
+ikbd_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct ikbd_softc *sc = (struct ikbd_softc *)self;
+ struct hidkbd *kbd = &sc->sc_kbd;
+ struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux;
+ int dlen, repid;
+ void *desc;
+
+ sc->sc_hdev.sc_intr = ikbd_intr;
+ sc->sc_hdev.sc_parent = iha->parent;
+ sc->sc_hdev.sc_report_id = iha->reportid;
+
+ ihidev_get_report_desc(iha->parent, &desc, &dlen);
+ repid = iha->reportid;
+ sc->sc_hdev.sc_isize = hid_report_size(desc, dlen, hid_input, repid);
+ sc->sc_hdev.sc_osize = hid_report_size(desc, dlen, hid_output, repid);
+ sc->sc_hdev.sc_fsize = hid_report_size(desc, dlen, hid_feature, repid);
+
+ if (hidkbd_attach(self, kbd, 0, 0, repid, desc, dlen) != 0)
+ return;
+
+ printf("\n");
+
+ hidkbd_attach_wskbd(kbd, KB_US | KB_DEFAULT, &ikbd_accessops);
+}
+
+int
+ikbd_detach(struct device *self, int flags)
+{
+ struct ikbd_softc *sc = (struct ikbd_softc *)self;
+ struct hidkbd *kbd = &sc->sc_kbd;
+
+ return hidkbd_detach(kbd, flags);
+}
+
+void
+ikbd_intr(struct ihidev *addr, void *ibuf, u_int len)
+{
+ struct ikbd_softc *sc = (struct ikbd_softc *)addr;
+ struct hidkbd *kbd = &sc->sc_kbd;
+
+ if (kbd->sc_enabled != 0)
+ hidkbd_input(kbd, (uint8_t *)ibuf, len);
+}
+
+int
+ikbd_enable(void *v, int on)
+{
+ struct ikbd_softc *sc = v;
+ struct hidkbd *kbd = &sc->sc_kbd;
+ int rv;
+
+ if ((rv = hidkbd_enable(kbd, on)) != 0)
+ return rv;
+
+ if (on) {
+ return ihidev_open(&sc->sc_hdev);
+ } else {
+ ihidev_close(&sc->sc_hdev);
+ return 0;
+ }
+}
+
+void
+ikbd_set_leds(void *v, int leds)
+{
+}
+
+int
+ikbd_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct ikbd_softc *sc = v;
+ struct hidkbd *kbd = &sc->sc_kbd;
+ int rc;
+
+ switch (cmd) {
+ case WSKBDIO_GTYPE:
+ /* XXX: should we set something else? */
+ *(u_int *)data = WSKBD_TYPE_USB;
+ return 0;
+ default:
+ rc = ihidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
+ if (rc != -1)
+ return rc;
+ else
+ return hidkbd_ioctl(kbd, cmd, data, flag, p);
+ }
+}