diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-01-14 21:01:50 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2016-01-14 21:01:50 +0000 |
commit | 6f78afe452d424eb9bef0c7b65c8f0f6ca9fd0e8 (patch) | |
tree | 4e72ada246cf4b7db5580b2d4872e7b74379b067 /sys/dev | |
parent | 736724e00b3663dd6e0b689701ca916eb3836612 (diff) |
Driver for HID-over-i2c keyboards.
Diffstat (limited to 'sys/dev')
-rw-r--r-- | sys/dev/i2c/files.i2c | 7 | ||||
-rw-r--r-- | sys/dev/i2c/ikbd.c | 172 |
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); + } +} |