summaryrefslogtreecommitdiff
path: root/sys/dev/i2c/ims.c
diff options
context:
space:
mode:
authorJoshua Stein <jcs@cvs.openbsd.org>2016-01-12 01:11:16 +0000
committerJoshua Stein <jcs@cvs.openbsd.org>2016-01-12 01:11:16 +0000
commitaed4423c7d742eb53456cd5f7cfd25b67f684521 (patch)
treee4105dfd6022fcb1576a79fe91753fa8a5771aeb /sys/dev/i2c/ims.c
parent051eb318946cb49493d05cc3d8f3b20d33741552 (diff)
Add dwiic, a driver for the Synopsys DesignWare i2c controller found
on the Samsung ATIV Book 9 laptop. This initial version only supports ACPI config/attachment. Add ihidev, a HID-over-i2c driver largely based on uhidev. dwiic handles attaching ihidev devices found in ACPI. Add ims, a HID-over-i2c mouse/trackpad driver to get basic cursor and button functionality from HID-compliant i2c trackpads. ok kettenis deraadt
Diffstat (limited to 'sys/dev/i2c/ims.c')
-rw-r--r--sys/dev/i2c/ims.c183
1 files changed, 183 insertions, 0 deletions
diff --git a/sys/dev/i2c/ims.c b/sys/dev/i2c/ims.c
new file mode 100644
index 00000000000..c3bc81ed84b
--- /dev/null
+++ b/sys/dev/i2c/ims.c
@@ -0,0 +1,183 @@
+/* $OpenBSD: ims.c,v 1.1 2016/01/12 01:11:15 jcs Exp $ */
+/*
+ * HID-over-i2c mouse/trackpad driver
+ *
+ * Copyright (c) 2015, 2016 joshua stein <jcs@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 <dev/i2c/i2cvar.h>
+#include <dev/i2c/ihidev.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsmousevar.h>
+
+#include <dev/hid/hid.h>
+#include <dev/hid/hidmsvar.h>
+
+struct ims_softc {
+ struct ihidev sc_hdev;
+ struct hidms sc_ms;
+};
+
+void ims_intr(struct ihidev *addr, void *ibuf, u_int len);
+
+int ims_enable(void *);
+void ims_disable(void *);
+int ims_ioctl(void *, u_long, caddr_t, int, struct proc *);
+
+const struct wsmouse_accessops ims_accessops = {
+ ims_enable,
+ ims_ioctl,
+ ims_disable,
+};
+
+int ims_match(struct device *, void *, void *);
+void ims_attach(struct device *, struct device *, void *);
+int ims_detach(struct device *, int);
+
+struct cfdriver ims_cd = {
+ NULL, "ims", DV_DULL
+};
+
+const struct cfattach ims_ca = {
+ sizeof(struct ims_softc),
+ ims_match,
+ ims_attach,
+ ims_detach
+};
+
+int
+ims_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_POINTER)))
+ return (IMATCH_IFACECLASS);
+
+ if (hid_is_collection(desc, size, iha->reportid,
+ HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_MOUSE)))
+ return (IMATCH_IFACECLASS);
+
+ if (hid_is_collection(desc, size, iha->reportid,
+ HID_USAGE2(HUP_DIGITIZERS, HUD_PEN)))
+ return (IMATCH_IFACECLASS);
+
+ return (IMATCH_NONE);
+}
+
+void
+ims_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct ims_softc *sc = (struct ims_softc *)self;
+ struct hidms *ms = &sc->sc_ms;
+ struct ihidev_attach_arg *iha = (struct ihidev_attach_arg *)aux;
+ int size, repid;
+ void *desc;
+
+ sc->sc_hdev.sc_intr = ims_intr;
+ sc->sc_hdev.sc_parent = iha->parent;
+ sc->sc_hdev.sc_report_id = iha->reportid;
+
+ ihidev_get_report_desc(iha->parent, &desc, &size);
+ repid = iha->reportid;
+ sc->sc_hdev.sc_isize = hid_report_size(desc, size, hid_input, repid);
+ sc->sc_hdev.sc_osize = hid_report_size(desc, size, hid_output, repid);
+ sc->sc_hdev.sc_fsize = hid_report_size(desc, size, hid_feature, repid);
+
+ if (hidms_setup(self, ms, 0, iha->reportid, desc, size) != 0)
+ return;
+
+ hidms_attach(ms, &ims_accessops);
+}
+
+int
+ims_detach(struct device *self, int flags)
+{
+ struct ims_softc *sc = (struct ims_softc *)self;
+ struct hidms *ms = &sc->sc_ms;
+
+ return hidms_detach(ms, flags);
+}
+
+void
+ims_intr(struct ihidev *addr, void *buf, u_int len)
+{
+ struct ims_softc *sc = (struct ims_softc *)addr;
+ struct hidms *ms = &sc->sc_ms;
+
+ if (ms->sc_enabled != 0)
+ hidms_input(ms, (uint8_t *)buf, len);
+}
+
+int
+ims_enable(void *v)
+{
+ struct ims_softc *sc = v;
+ struct hidms *ms = &sc->sc_ms;
+ int rv;
+
+ if ((rv = hidms_enable(ms)) != 0)
+ return rv;
+
+ return ihidev_open(&sc->sc_hdev);
+}
+
+void
+ims_disable(void *v)
+{
+ struct ims_softc *sc = v;
+ struct hidms *ms = &sc->sc_ms;
+
+ hidms_disable(ms);
+ ihidev_close(&sc->sc_hdev);
+}
+
+int
+ims_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct ims_softc *sc = v;
+ struct hidms *ms = &sc->sc_ms;
+ int rc;
+
+#if 0
+ rc = ihidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
+ if (rc != -1)
+ return rc;
+#endif
+
+ rc = hidms_ioctl(ms, cmd, data, flag, p);
+ if (rc != -1)
+ return rc;
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ /* XXX: should we set something else? */
+ *(u_int *)data = WSMOUSE_TYPE_USB;
+ return 0;
+ default:
+ return -1;
+ }
+}