summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
authorMartin Pieuchot <mpi@cvs.openbsd.org>2016-09-12 08:12:07 +0000
committerMartin Pieuchot <mpi@cvs.openbsd.org>2016-09-12 08:12:07 +0000
commitb24f86f7ff2bc606be412870c5101ed318298605 (patch)
tree64615d34fb1710ae8af60a40a7ed0314e41fca7d /sys/dev
parentd351738eb532ad3e346f5e8e928f0c465e18ecce (diff)
Wacom USB tablet driver from Frank Groeneveld.
Currently attaches as a single child of uhidev(4) and offers basic pointer functionalities.
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/usb/files.usb7
-rw-r--r--sys/dev/usb/uwacom.c229
2 files changed, 235 insertions, 1 deletions
diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb
index efa13748f09..850f519db76 100644
--- a/sys/dev/usb/files.usb
+++ b/sys/dev/usb/files.usb
@@ -1,4 +1,4 @@
-# $OpenBSD: files.usb,v 1.130 2016/09/03 13:37:45 guenther Exp $
+# $OpenBSD: files.usb,v 1.131 2016/09/12 08:12:06 mpi Exp $
# $NetBSD: files.usb,v 1.16 2000/02/14 20:29:54 augustss Exp $
#
# Config file and device description for machine-independent USB code.
@@ -435,3 +435,8 @@ file dev/usb/uberry.c uberry
device upd: hid
attach upd at uhidbus
file dev/usb/upd.c upd
+
+# Wacom tablets
+device uwacom: hid, hidms, wsmousedev
+attach uwacom at uhidbus
+file dev/usb/uwacom.c uwacom
diff --git a/sys/dev/usb/uwacom.c b/sys/dev/usb/uwacom.c
new file mode 100644
index 00000000000..f93f18f220a
--- /dev/null
+++ b/sys/dev/usb/uwacom.c
@@ -0,0 +1,229 @@
+/* $OpenBSD: uwacom.c,v 1.1 2016/09/12 08:12:06 mpi Exp $ */
+
+/*
+ * Copyright (c) 2016 Frank Groeneveld <frank@frankgroeneveld.nl>
+ *
+ * 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 DISCAIMS 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.
+ */
+
+/* Driver for USB Wacom tablets */
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdevs.h>
+#include <dev/usb/uhidev.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsmousevar.h>
+
+#include <dev/hid/hidmsvar.h>
+
+struct uwacom_softc {
+ struct uhidev sc_hdev;
+ struct hidms sc_ms;
+ struct hid_location sc_loc_tip_press;
+};
+
+struct cfdriver uwacom_cd = {
+ NULL, "uwacom", DV_DULL
+};
+
+
+const struct usb_devno uwacom_devs[] = {
+ { USB_VENDOR_WACOM, USB_PRODUCT_WACOM_INTUOS_DRAW }
+};
+
+int uwacom_match(struct device *, void *, void *);
+void uwacom_attach(struct device *, struct device *, void *);
+int uwacom_detach(struct device *, int);
+void uwacom_intr(struct uhidev *, void *, u_int);
+int uwacom_enable(void *);
+void uwacom_disable(void *);
+int uwacom_ioctl(void *, u_long, caddr_t, int, struct proc *);
+
+const struct cfattach uwacom_ca = {
+ sizeof(struct uwacom_softc), uwacom_match, uwacom_attach, uwacom_detach
+};
+
+const struct wsmouse_accessops uwacom_accessops = {
+ uwacom_enable,
+ uwacom_ioctl,
+ uwacom_disable,
+};
+
+int
+uwacom_match(struct device *parent, void *match, void *aux)
+{
+ struct uhidev_attach_arg *uha = aux;
+ int size;
+ void *desc;
+
+ if (usb_lookup(uwacom_devs, uha->uaa->vendor,
+ uha->uaa->product) == NULL)
+ return (UMATCH_NONE);
+
+ uhidev_get_report_desc(uha->parent, &desc, &size);
+
+ if (!hid_locate(desc, size, HID_USAGE2(HUP_WACOM, HUG_POINTER),
+ uha->reportid, hid_input, NULL, NULL))
+ return (UMATCH_NONE);
+
+ return (UMATCH_IFACECLASS);
+}
+
+void
+uwacom_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct uwacom_softc *sc = (struct uwacom_softc *)self;
+ struct hidms *ms = &sc->sc_ms;
+ struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)aux;
+ struct usb_attach_arg *uaa = uha->uaa;
+ int size, repid;
+ void *desc;
+
+ sc->sc_hdev.sc_intr = uwacom_intr;
+ sc->sc_hdev.sc_parent = uha->parent;
+ sc->sc_hdev.sc_udev = uaa->device;
+ sc->sc_hdev.sc_report_id = uha->reportid;
+
+ uhidev_get_report_desc(uha->parent, &desc, &size);
+ repid = uha->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);
+
+ ms->sc_device = self;
+ ms->sc_rawmode = 1;
+ ms->sc_flags = HIDMS_ABSX | HIDMS_ABSY;
+ ms->sc_num_buttons = 3;
+ ms->sc_loc_x.pos = 8;
+ ms->sc_loc_x.size = 16;
+ ms->sc_loc_y.pos = 24;
+ ms->sc_loc_y.size = 16;
+
+ ms->sc_tsscale.minx = 0;
+ ms->sc_tsscale.maxx = 7600;
+ ms->sc_tsscale.miny = 0;
+ ms->sc_tsscale.maxy = 4750;
+
+ ms->sc_loc_btn[0].pos = 0;
+ ms->sc_loc_btn[0].size = 1;
+ ms->sc_loc_btn[1].pos = 1;
+ ms->sc_loc_btn[1].size = 1;
+ ms->sc_loc_btn[2].pos = 2;
+ ms->sc_loc_btn[2].size = 1;
+
+ sc->sc_loc_tip_press.pos = 43;
+ sc->sc_loc_tip_press.size = 8;
+
+ hidms_attach(ms, &uwacom_accessops);
+}
+
+int
+uwacom_detach(struct device *self, int flags)
+{
+ struct uwacom_softc *sc = (struct uwacom_softc *)self;
+ struct hidms *ms = &sc->sc_ms;
+
+ return hidms_detach(ms, flags);
+}
+
+void
+uwacom_intr(struct uhidev *addr, void *buf, u_int len)
+{
+ struct uwacom_softc *sc = (struct uwacom_softc *)addr;
+ struct hidms *ms = &sc->sc_ms;
+ u_int32_t buttons = 0;
+ uint8_t *data = (uint8_t *)buf;
+ int i, x, y, pressure;
+
+ if (ms->sc_enabled == 0)
+ return;
+
+ /* ignore proximity, it will cause invalid button 2 events */
+ if ((data[0] & 0xf0) == 0xc0)
+ return;
+
+ x = be16toh(hid_get_data(data, len, &ms->sc_loc_x));
+ y = be16toh(hid_get_data(data, len, &ms->sc_loc_y));
+ pressure = hid_get_data(data, len, &sc->sc_loc_tip_press);
+
+ for (i = 0; i < ms->sc_num_buttons; i++)
+ if (hid_get_data(data, len, &ms->sc_loc_btn[i]))
+ buttons |= (1 << i);
+
+ /* button 0 reporting is flaky, use tip pressure for it */
+ if (pressure > 10)
+ buttons |= 1;
+ else
+ buttons &= ~1;
+
+ if (x != 0 || y != 0 || buttons != ms->sc_buttons) {
+ wsmouse_position(ms->sc_wsmousedev, x, y);
+ wsmouse_buttons(ms->sc_wsmousedev, buttons);
+ wsmouse_input_sync(ms->sc_wsmousedev);
+ }
+}
+
+int
+uwacom_enable(void *v)
+{
+ struct uwacom_softc *sc = v;
+ struct hidms *ms = &sc->sc_ms;
+ int rv;
+
+ if (usbd_is_dying(sc->sc_hdev.sc_udev))
+ return EIO;
+
+ if ((rv = hidms_enable(ms)) != 0)
+ return rv;
+
+ return uhidev_open(&sc->sc_hdev);
+}
+
+void
+uwacom_disable(void *v)
+{
+ struct uwacom_softc *sc = v;
+ struct hidms *ms = &sc->sc_ms;
+
+ hidms_disable(ms);
+ uhidev_close(&sc->sc_hdev);
+}
+
+int
+uwacom_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct uwacom_softc *sc = v;
+ struct hidms *ms = &sc->sc_ms;
+ int rc;
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ *(u_int *)data = WSMOUSE_TYPE_TPANEL;
+ return 0;
+ }
+
+ rc = uhidev_ioctl(&sc->sc_hdev, cmd, data, flag, p);
+ if (rc != -1)
+ return rc;
+
+ return hidms_ioctl(ms, cmd, data, flag, p);
+}
+