summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMatthieu Herrb <matthieu@cvs.openbsd.org>2009-12-09 21:27:20 +0000
committerMatthieu Herrb <matthieu@cvs.openbsd.org>2009-12-09 21:27:20 +0000
commit7490d864e974184d55e7ad15e31ab481201413d7 (patch)
tree57e89ed90d124ed29e063b02f402095b34481754 /sys
parentf6dbc1b38f6ec140a2bba54729ea5f6ad24b22f6 (diff)
add uhts(4) a driver for USB HID touchscreens. ok miod@.
Man page advices by jmc@.
Diffstat (limited to 'sys')
-rw-r--r--sys/dev/usb/files.usb6
-rw-r--r--sys/dev/usb/uhts.c407
-rw-r--r--sys/dev/usb/usbhid.h5
3 files changed, 416 insertions, 2 deletions
diff --git a/sys/dev/usb/files.usb b/sys/dev/usb/files.usb
index 71e3b75e9f8..31638f380b0 100644
--- a/sys/dev/usb/files.usb
+++ b/sys/dev/usb/files.usb
@@ -1,4 +1,4 @@
-# $OpenBSD: files.usb,v 1.85 2009/11/23 19:35:54 yuo Exp $
+# $OpenBSD: files.usb,v 1.86 2009/12/09 21:27:19 matthieu 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.
@@ -95,6 +95,10 @@ device uts: wsmousedev
attach uts at uhub
file dev/usb/uts.c uts
+device uhts: wsmousedev
+attach uhts at uhidbus
+file dev/usb/uhts.c uhts
+
# Cypress microcontroller based serial adpaters
device ucycom: hid, ucombus
attach ucycom at uhidbus
diff --git a/sys/dev/usb/uhts.c b/sys/dev/usb/uhts.c
new file mode 100644
index 00000000000..b46d7a4d17d
--- /dev/null
+++ b/sys/dev/usb/uhts.c
@@ -0,0 +1,407 @@
+/* $OpenBSD: uhts.c,v 1.1 2009/12/09 21:27:19 matthieu Exp $ */
+/*
+ * Copyright (c) 2009 Matthieu Herrb <matthieu@herrb.eu>
+ * Copyright (c) 2007 Robert Nagy <robert@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.
+ */
+/*
+ * 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/kernel.h>
+#include <sys/device.h>
+#include <sys/ioctl.h>
+#include <sys/tty.h>
+#include <sys/file.h>
+#include <sys/selinfo.h>
+#include <sys/proc.h>
+#include <sys/vnode.h>
+#include <sys/poll.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbhid.h>
+
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbdevs.h>
+#include <dev/usb/uhidev.h>
+#include <dev/usb/hid.h>
+
+#include <dev/wscons/wsconsio.h>
+#include <dev/wscons/wsmousevar.h>
+
+#ifdef USB_DEBUG
+#define DPRINTF(x) do { if (uhtsdebug) printf x; } while (0)
+#define DPRINTFN(n,x) do { if (uhtsdebug>(n)) printf x; } while (0)
+int uhtsdebug = 0;
+#else
+#define DPRINTF(x)
+#define DPRINTFN(n,x)
+#endif
+
+#define UHTSUNIT(s) (minor(s))
+
+struct tsscale {
+ int minx, maxx;
+ int miny, maxy;
+ int swapxy;
+ int resx, resy;
+};
+
+struct uhts_softc {
+ struct uhidev sc_hdev;
+ struct hid_location sc_loc_x, sc_loc_y;
+ struct hid_location sc_loc_btn;
+ int sc_enabled;
+ u_int32_t sc_buttons; /* mouse button status */
+ int sc_rawmode;
+ int sc_oldx, sc_oldy;
+ struct tsscale sc_tsscale;
+ struct device *sc_wsmousedev;
+ char sc_dying;
+};
+
+struct uhts_pos {
+ int down;
+ int x, y;
+ int z; /* touch pressure */
+};
+
+void uhts_intr(struct uhidev *, void *, u_int);
+int uhts_enable(void *);
+void uhts_disable(void *);
+int uhts_ioctl(void *, u_long, caddr_t, int, struct proc *);
+
+const struct wsmouse_accessops uhts_accessops = {
+ uhts_enable,
+ uhts_ioctl,
+ uhts_disable
+};
+
+int uhts_match(struct device *, void *, void *);
+void uhts_attach(struct device *, struct device *, void *);
+int uhts_detach(struct device *, int);
+int uhts_activate(struct device *, int);
+void uhts_parse_desc(struct uhts_softc *);
+
+struct cfdriver uhts_cd = {
+ NULL, "uhts", DV_DULL
+};
+
+const struct cfattach uhts_ca = {
+ sizeof(struct uhts_softc),
+ uhts_match,
+ uhts_attach,
+ uhts_detach,
+ uhts_activate
+};
+
+int
+uhts_match(struct device *parent, void *match, void *aux)
+{
+ struct usb_attach_arg *uaa = aux;
+ struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
+ int size;
+ void *desc;
+
+ uhidev_get_report_desc(uha->parent, &desc, &size);
+ if (!hid_is_collection(desc, size, uha->reportid,
+ HID_USAGE2(HUP_DIGITIZERS, HUD_TOUCHSCREEN)))
+ return (UMATCH_NONE);
+ return (UMATCH_IFACECLASS);
+}
+
+void
+uhts_parse_desc(struct uhts_softc *sc)
+{
+ struct hid_data *d;
+ struct hid_item h;
+ int size;
+ void *desc;
+
+ uhidev_get_report_desc(sc->sc_hdev.sc_parent, &desc, &size);
+ d = hid_start_parse(desc, size, hid_input);
+ while (hid_get_item(d, &h)) {
+ if (h.kind != hid_input ||
+ HID_GET_USAGE_PAGE(h.usage) != HUP_GENERIC_DESKTOP ||
+ h.report_ID != sc->sc_hdev.sc_report_id)
+ continue;
+ DPRINTF(("uhts: usage=0x%x range %d..%d\n",
+ h.usage, h.logical_minimum, h.logical_maximum));
+ switch (HID_GET_USAGE(h.usage)) {
+ case HUG_X:
+ sc->sc_tsscale.minx = h.logical_minimum;
+ sc->sc_tsscale.maxx = h.logical_maximum;
+ break;
+ case HUG_Y:
+ sc->sc_tsscale.miny = h.logical_minimum;
+ sc->sc_tsscale.maxy = h.logical_maximum;
+ break;
+ }
+ }
+}
+
+void
+uhts_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct uhts_softc *sc = (struct uhts_softc *)self;
+ struct usb_attach_arg *uaa = aux;
+ struct uhidev_attach_arg *uha = (struct uhidev_attach_arg *)uaa;
+ struct wsmousedev_attach_args a;
+ void *desc;
+ int size;
+ u_int32_t flags;
+
+ sc->sc_hdev.sc_intr = uhts_intr;
+ sc->sc_hdev.sc_parent = uha->parent;
+ sc->sc_hdev.sc_report_id = uha->reportid;
+
+ uhidev_get_report_desc(uha->parent, &desc, &size);
+
+ if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
+ uha->reportid, hid_input, &sc->sc_loc_x, &flags)) {
+ printf("\n%s: touchscreen has no X report\n",
+ sc->sc_hdev.sc_dev.dv_xname);
+ return;
+ }
+ if (!hid_locate(desc, size, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
+ uha->reportid, hid_input, &sc->sc_loc_y, &flags)) {
+ printf("\n%s: touchscreen has no Y report\n",
+ sc->sc_hdev.sc_dev.dv_xname);
+ return;
+ }
+ if (!hid_locate(desc, size, HID_USAGE2(HUP_DIGITIZERS,
+ HUD_TIP_SWITCH), uha->reportid, hid_input,
+ &sc->sc_loc_btn, 0)){
+ printf("\n%s: touch screen has no button\n",
+ sc->sc_hdev.sc_dev.dv_xname);
+ return;
+ }
+ printf("\n");
+
+ a.accessops = &uhts_accessops;
+ a.accesscookie = sc;
+
+ uhts_parse_desc(sc);
+ sc->sc_rawmode = 0;
+ /* wild guess */
+ sc->sc_tsscale.swapxy = 0;
+ sc->sc_tsscale.resx = 1024;
+ sc->sc_tsscale.resy = 768;
+
+ sc->sc_wsmousedev = config_found(self, &a, wsmousedevprint);
+}
+
+int
+uhts_activate(struct device *self, int act)
+{
+ struct uhts_softc *sc = (struct uhts_softc *)self;
+ int rv = 0;
+
+ switch (act) {
+ case DVACT_ACTIVATE:
+ break;
+ case DVACT_DEACTIVATE:
+ if (sc->sc_wsmousedev != NULL)
+ rv = config_deactivate(sc->sc_wsmousedev);
+ sc->sc_dying = 1;
+ break;
+ }
+ return (rv);
+}
+
+int
+uhts_detach(struct device *self, int flags)
+{
+ struct uhts_softc *sc = (struct uhts_softc *)self;
+ int rv = 0;
+
+ DPRINTF(("uhts_detach: sc=%p flags=%d\n", sc, flags));
+
+ /* wsmouse takes care of reference counting */
+ if (sc->sc_wsmousedev != NULL)
+ rv = config_detach(sc->sc_wsmousedev, flags);
+ return (rv);
+}
+
+void
+uhts_intr(struct uhidev *addr, void *buf, u_int len)
+{
+ struct uhts_softc *sc = (struct uhts_softc *)addr;
+ u_char *ibuf = (u_char *)buf;
+ struct uhts_pos tp;
+ int x, y, s;
+ u_int32_t buttons = 0;
+
+ DPRINTFN(5, ("uhts_intr: len=%d\n", len));
+
+ x = hid_get_data(ibuf, &sc->sc_loc_x);
+ y = hid_get_data(ibuf, &sc->sc_loc_y);
+ if (hid_get_data(ibuf, &sc->sc_loc_btn))
+ buttons = 1;
+
+ DPRINTFN(10, ("uhts_intr: x:%d y:%d buttons:0x%x\n",
+ x, y, buttons));
+
+ if (buttons) {
+ if (sc->sc_tsscale.swapxy && !sc->sc_rawmode) {
+ /* Swap X/Y-Axis */
+ tp.y = x;
+ tp.x = y;
+ } else {
+ tp.x = x;
+ tp.y = y;
+ }
+ if (!sc->sc_rawmode) {
+ /* Scale down to the screen resolution. */
+ tp.x = ((tp.x - sc->sc_tsscale.minx) *
+ sc->sc_tsscale.resx) /
+ (sc->sc_tsscale.maxx - sc->sc_tsscale.minx);
+ tp.y = ((tp.y - sc->sc_tsscale.miny) *
+ sc->sc_tsscale.resy) /
+ (sc->sc_tsscale.maxy - sc->sc_tsscale.miny);
+ }
+ } else {
+ tp.x = sc->sc_oldx;
+ tp.y = sc->sc_oldy;
+ }
+
+ sc->sc_buttons = buttons;
+ tp.z = buttons;
+
+ if (sc->sc_wsmousedev != NULL) {
+ s = spltty();
+ wsmouse_input(sc->sc_wsmousedev, buttons, tp.x, tp.y, tp.z, 0,
+ WSMOUSE_INPUT_ABSOLUTE_X | WSMOUSE_INPUT_ABSOLUTE_Y |
+ WSMOUSE_INPUT_ABSOLUTE_Z);
+ sc->sc_oldx = tp.x;
+ sc->sc_oldy = tp.y;
+ splx(s);
+ }
+}
+
+int
+uhts_enable(void *v)
+{
+ struct uhts_softc *sc = v;
+
+ DPRINTFN(1, ("uhts_enable: sc=%p\n", sc));
+
+ if (sc->sc_dying)
+ return (EIO);
+
+ if (sc->sc_enabled)
+ return (EBUSY);
+
+ sc->sc_enabled = 1;
+ sc->sc_buttons = 0;
+
+ return (uhidev_open(&sc->sc_hdev));
+}
+
+void
+uhts_disable(void *v)
+{
+ struct uhts_softc *sc = v;
+
+ DPRINTFN(1, ("uhts_disable: sc=%p\n", sc));
+#ifdef DIAGNOSTIC
+ if (!sc->sc_enabled) {
+ printf("uhts_disable: not enabled\n");
+ return;
+ }
+#endif
+ sc->sc_enabled = 0;
+ uhidev_close(&sc->sc_hdev);
+}
+
+int
+uhts_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p)
+{
+ struct uhts_softc *sc = v;
+ struct wsmouse_calibcoords *wsmc = (struct wsmouse_calibcoords *)data;
+ int error = 0;
+
+ DPRINTF(("uhts_ioctl(%d, '%c', %d)\n",
+ IOCPARM_LEN(cmd), IOCGROUP(cmd), cmd & 0xff));
+
+ switch (cmd) {
+ case WSMOUSEIO_GTYPE:
+ *(u_int *)data = WSMOUSE_TYPE_TPANEL;
+ return (0);
+ 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->resx < 32768 && wsmc->resy < 32768 &&
+ wsmc->swapxy >= 0 && wsmc->swapxy <= 1 &&
+ wsmc->samplelen >= 0 && wsmc->samplelen <= 1))
+ return (EINVAL);
+
+ sc->sc_tsscale.minx = wsmc->minx;
+ sc->sc_tsscale.maxx = wsmc->maxx;
+ sc->sc_tsscale.miny = wsmc->miny;
+ sc->sc_tsscale.maxy = wsmc->maxy;
+ sc->sc_tsscale.swapxy = wsmc->swapxy;
+ sc->sc_tsscale.resx = wsmc->resx;
+ sc->sc_tsscale.resy = wsmc->resy;
+ sc->sc_rawmode = wsmc->samplelen;
+ break;
+ case WSMOUSEIO_GCALIBCOORDS:
+ wsmc->minx = sc->sc_tsscale.minx;
+ wsmc->maxx = sc->sc_tsscale.maxx;
+ wsmc->miny = sc->sc_tsscale.miny;
+ wsmc->maxy = sc->sc_tsscale.maxy;
+ wsmc->swapxy = sc->sc_tsscale.swapxy;
+ wsmc->resx = sc->sc_tsscale.resx;
+ wsmc->resy = sc->sc_tsscale.resy;
+ wsmc->samplelen = sc->sc_rawmode;
+ break;
+ default:
+ error = ENOTTY;
+ break;
+ }
+
+ return error;
+}
diff --git a/sys/dev/usb/usbhid.h b/sys/dev/usb/usbhid.h
index 3d095b91c54..8866e141d9a 100644
--- a/sys/dev/usb/usbhid.h
+++ b/sys/dev/usb/usbhid.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: usbhid.h,v 1.12 2008/06/26 05:42:19 ray Exp $ */
+/* $OpenBSD: usbhid.h,v 1.13 2009/12/09 21:27:19 matthieu Exp $ */
/* $NetBSD: usbhid.h,v 1.11 2001/12/28 00:20:24 augustss Exp $ */
/* $FreeBSD: src/sys/dev/usb/usbhid.h,v 1.7 1999/11/17 22:33:51 n_hibma Exp $ */
@@ -135,6 +135,9 @@ typedef struct usb_hid_descriptor {
/* Usages Digitizers */
#define HUD_UNDEFINED 0x0000
+#define HUD_DIGITIZER 0x0001
+#define HUD_PEN 0x0002
+#define HUD_TOUCHSCREEN 0x0004
#define HUD_TIP_PRESSURE 0x0030
#define HUD_BARREL_PRESSURE 0x0031
#define HUD_IN_RANGE 0x0032