Skip site navigation (1)Skip section navigation (2)
Date:      Tue, 3 Jun 2014 20:27:08 +0000 (UTC)
From:      Jakub Wojciech Klama <jceel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r267025 - in user/jceel/soc2014_evdev/head/sys: amd64/conf conf dev/usb/input
Message-ID:  <201406032027.s53KR8Mo067067@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: jceel
Date: Tue Jun  3 20:27:07 2014
New Revision: 267025
URL: http://svnweb.freebsd.org/changeset/base/267025

Log:
  Add initial version of USB HID touchscreen driver, based on ums(4).

Added:
  user/jceel/soc2014_evdev/head/sys/dev/usb/input/utouch.c   (contents, props changed)
Modified:
  user/jceel/soc2014_evdev/head/sys/amd64/conf/EVDEV
  user/jceel/soc2014_evdev/head/sys/conf/files

Modified: user/jceel/soc2014_evdev/head/sys/amd64/conf/EVDEV
==============================================================================
--- user/jceel/soc2014_evdev/head/sys/amd64/conf/EVDEV	Tue Jun  3 20:09:39 2014	(r267024)
+++ user/jceel/soc2014_evdev/head/sys/amd64/conf/EVDEV	Tue Jun  3 20:27:07 2014	(r267025)
@@ -320,7 +320,8 @@ device		usb			# USB Bus (required)
 device		ukbd			# Keyboard
 device		umass			# Disks/Mass storage - Requires scbus and da
 device		ums
-device		ukbd
+device		uhid
+device		utouch
 
 # Sound support
 device		sound			# Generic sound driver (required)

Modified: user/jceel/soc2014_evdev/head/sys/conf/files
==============================================================================
--- user/jceel/soc2014_evdev/head/sys/conf/files	Tue Jun  3 20:09:39 2014	(r267024)
+++ user/jceel/soc2014_evdev/head/sys/conf/files	Tue Jun  3 20:27:07 2014	(r267025)
@@ -2476,6 +2476,7 @@ dev/usb/input/uhid.c		optional uhid
 dev/usb/input/ukbd.c		optional ukbd
 dev/usb/input/ums.c		optional ums
 dev/usb/input/wsp.c		optional wsp
+dev/usb/input/utouch.c		optional utouch
 #
 # USB quirks
 #

Added: user/jceel/soc2014_evdev/head/sys/dev/usb/input/utouch.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ user/jceel/soc2014_evdev/head/sys/dev/usb/input/utouch.c	Tue Jun  3 20:27:07 2014	(r267025)
@@ -0,0 +1,493 @@
+/*-
+ * Copyright (c) 2014 Jakub Wojciech Klama <jceel@FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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 AUTHOR 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 AUTHOR 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.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/stdint.h>
+#include <sys/stddef.h>
+#include <sys/param.h>
+#include <sys/queue.h>
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/sysctl.h>
+#include <sys/sx.h>
+#include <sys/unistd.h>
+#include <sys/callout.h>
+#include <sys/malloc.h>
+#include <sys/priv.h>
+#include <sys/conf.h>
+#include <sys/fcntl.h>
+#include <sys/sbuf.h>
+
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbdi_util.h>
+#include <dev/usb/usbhid.h>
+#include "usbdevs.h"
+
+#define	USB_DEBUG_VAR utouch_debug
+#include <dev/usb/usb_debug.h>
+
+#include <dev/usb/quirk/usb_quirk.h>
+
+#include <dev/evdev/input.h>
+#include <dev/evdev/evdev.h>
+
+#include <sys/ioccom.h>
+#include <sys/filio.h>
+#include <sys/tty.h>
+
+enum {
+	UTOUCH_INTR_DT,
+	UTOUCH_N_TRANSFER,
+};
+
+struct utouch_softc
+{
+	device_t sc_dev;
+	struct evdev_dev *sc_evdev;
+	struct mtx sc_mtx;
+	struct usb_xfer *sc_xfer[UTOUCH_N_TRANSFER];
+	struct hid_location sc_loc_x;
+	struct hid_location sc_loc_y;
+	struct hid_location sc_loc_z;
+#define	UTOUCH_BUTTON_MAX	8
+	struct hid_location sc_loc_btn[UTOUCH_BUTTON_MAX];
+	uint8_t sc_iid;
+	uint8_t	sc_iid_x;
+	uint8_t	sc_iid_y;
+	uint8_t	sc_iid_z;
+	uint8_t	sc_iid_btn[UTOUCH_BUTTON_MAX];
+	uint8_t	sc_nbuttons;
+	uint32_t sc_flags;
+#define	UTOUCH_FLAG_X_AXIS	0x0001
+#define	UTOUCH_FLAG_Y_AXIS	0x0002
+#define	UTOUCH_FLAG_Z_AXIS	0x0004
+#define	UTOUCH_FLAG_OPENED	0x0008
+
+
+	int sc_oldx;
+	int sc_oldy;
+	int sc_oldz;
+	int sc_oldbuttons;
+
+	uint8_t	sc_temp[64];
+};
+
+
+
+static usb_callback_t utouch_intr_callback;
+
+static device_probe_t utouch_probe;
+static device_attach_t utouch_attach;
+static device_detach_t utouch_detach;
+
+static evdev_open_t utouch_ev_open;
+static evdev_close_t utouch_ev_close;
+
+static int utouch_hid_test(void *, uint16_t);
+static void utouch_hid_parse(struct utouch_softc *, const void *, uint16_t);
+static void utouch_report_event(struct utouch_softc *, int, int, int, int);
+
+static struct evdev_methods utouch_evdev_methods = {
+	.ev_open = &utouch_ev_open,
+	.ev_close = &utouch_ev_close,
+};
+
+static const struct usb_config utouch_config[UTOUCH_N_TRANSFER] = {
+
+	[UTOUCH_INTR_DT] = {
+		.type = UE_INTERRUPT,
+		.endpoint = UE_ADDR_ANY,
+		.direction = UE_DIR_IN,
+		.flags = {.pipe_bof = 1,.short_xfer_ok = 1,},
+		.bufsize = 0,	/* use wMaxPacketSize */
+		.callback = &utouch_intr_callback,
+	},
+};
+
+static int
+utouch_probe(device_t dev)
+{
+	struct usb_attach_arg *uaa = device_get_ivars(dev);
+	void *d_ptr;
+	uint16_t d_len;
+	int err;
+
+	device_printf(dev, "utouch_probe()\n");
+
+	if (uaa->usb_mode != USB_MODE_HOST)
+		return (ENXIO);
+
+	if (uaa->info.bInterfaceClass != UICLASS_HID)
+		return (ENXIO);
+
+	err = usbd_req_get_hid_desc(uaa->device, NULL,
+	    &d_ptr, &d_len, M_TEMP, uaa->info.bIfaceIndex);
+
+	if (err)
+		return (ENXIO);
+
+	if (utouch_hid_test(d_ptr, d_len))
+		err = BUS_PROBE_DEFAULT;
+	else
+		err = ENXIO;
+
+	device_printf(dev, "probe: err = %d\n", err);
+
+	free(d_ptr, M_TEMP);
+	return (err);
+}
+
+static int
+utouch_attach(device_t dev)
+{
+	struct usb_attach_arg *uaa = device_get_ivars(dev);
+	struct utouch_softc *sc = device_get_softc(dev);
+	struct input_absinfo absinfo = { 0 };
+	void *d_ptr = NULL;
+	uint16_t d_len;
+	int isize, i, err;
+
+	device_printf(dev, "utouch_attach()\n");
+
+	device_set_usb_desc(dev);
+	sc->sc_dev = dev;
+
+	mtx_init(&sc->sc_mtx, "utouch lock", NULL, MTX_DEF | MTX_RECURSE);
+
+	err = usbd_req_set_protocol(uaa->device, NULL,
+	    uaa->info.bIfaceIndex, 1);
+
+	err = usbd_transfer_setup(uaa->device,
+	    &uaa->info.bIfaceIndex, sc->sc_xfer, utouch_config,
+	    UTOUCH_N_TRANSFER, sc, &sc->sc_mtx);
+	if (err) 
+		goto detach;
+
+	err = usbd_req_get_hid_desc(uaa->device, NULL, &d_ptr,
+	    &d_len, M_TEMP, uaa->info.bIfaceIndex);
+	if (err)
+		goto detach;
+
+	isize = hid_report_size(d_ptr, d_len, hid_input, &sc->sc_iid);
+
+	utouch_hid_parse(sc, d_ptr, d_len);
+
+	sc->sc_evdev = evdev_alloc();
+	evdev_set_name(sc->sc_evdev, device_get_desc(dev));
+	evdev_set_serial(sc->sc_evdev, "0");
+	evdev_set_softc(sc->sc_evdev, sc);
+	evdev_set_methods(sc->sc_evdev, &utouch_evdev_methods);
+	evdev_support_event(sc->sc_evdev, EV_SYN);
+	evdev_support_event(sc->sc_evdev, EV_ABS);
+	evdev_support_event(sc->sc_evdev, EV_REL);
+	evdev_support_event(sc->sc_evdev, EV_KEY);
+
+	if (sc->sc_flags & UTOUCH_FLAG_X_AXIS)
+		evdev_support_abs(sc->sc_evdev, ABS_X);
+
+	if (sc->sc_flags & UTOUCH_FLAG_Y_AXIS)
+		evdev_support_abs(sc->sc_evdev, ABS_Y);
+
+	if (sc->sc_flags & UTOUCH_FLAG_Z_AXIS)
+		evdev_support_rel(sc->sc_evdev, REL_Z);
+
+	for (i = 0; i < sc->sc_nbuttons; i++)
+		evdev_support_key(sc->sc_evdev, BTN_MOUSE + i);
+
+
+	/* Report absolute axes information */
+	absinfo.minimum = 0;
+	absinfo.maximum = 0x7fff; /* XXX should read from HID descriptor */
+	evdev_set_absinfo(sc->sc_evdev, ABS_X, &absinfo);
+	evdev_set_absinfo(sc->sc_evdev, ABS_Y, &absinfo);
+
+	err = evdev_register(dev, sc->sc_evdev);
+	if (err)
+		goto detach;
+
+	return (0);
+
+detach:
+	if (d_ptr)
+		free(d_ptr, M_TEMP);
+
+	utouch_detach(dev);
+	return (ENXIO);
+}
+
+static int
+utouch_detach(device_t dev)
+{
+	return (0);
+}
+
+static void
+utouch_intr_callback(struct usb_xfer *xfer, usb_error_t error)
+{
+	struct utouch_softc *sc = usbd_xfer_softc(xfer);
+	struct usb_page_cache *pc;
+	void *buf = sc->sc_temp;
+	int x, y, dz, buttons = 0, changed = 0;
+	int len, i;
+	usbd_xfer_status(xfer, &len, NULL, NULL, NULL);
+
+	switch (USB_GET_STATE(xfer)) {
+	case USB_ST_TRANSFERRED:
+		if (len == 0)
+			goto tr_setup;
+			
+		pc = usbd_xfer_get_frame(xfer, 0);
+		usbd_copy_out(pc, 0, buf, len);
+
+		if (sc->sc_flags & UTOUCH_FLAG_X_AXIS) {
+			x = hid_get_data(buf, len, &sc->sc_loc_x);
+			changed += x != sc->sc_oldx;
+		}
+
+		if (sc->sc_flags & UTOUCH_FLAG_Y_AXIS) {
+			y = hid_get_data(buf, len, &sc->sc_loc_y);
+			changed += y != sc->sc_oldy;
+		}
+
+		if (sc->sc_flags & UTOUCH_FLAG_Z_AXIS) {
+			dz = hid_get_data(buf, len, &sc->sc_loc_z);
+			changed += dz != 0;
+		}
+
+		for (i = 0; i < sc->sc_nbuttons; i++) {
+			if (hid_get_data(buf, len, &sc->sc_loc_btn[i]))
+				buttons |= (1 << i);
+
+			changed += buttons != 0;
+		}
+
+		if (changed) {
+			utouch_report_event(sc, x, y, dz, buttons);
+			sc->sc_oldx = x;
+			sc->sc_oldy = y;
+			sc->sc_oldbuttons = buttons;
+		}
+
+	case USB_ST_SETUP:
+tr_setup:
+		usbd_xfer_set_frame_len(xfer, 0, usbd_xfer_max_len(xfer));
+		usbd_transfer_submit(xfer);
+		break;
+	default:
+		if (error != USB_ERR_CANCELLED) {
+			/* try clear stall first */
+			usbd_xfer_set_stall(xfer);
+			goto tr_setup;
+		}
+		break;
+	}
+}
+
+static void
+utouch_ev_close(struct evdev_dev *evdev, void *ev_softc)
+{
+	struct utouch_softc *sc = (struct utouch_softc *)ev_softc;
+
+	mtx_lock(&sc->sc_mtx);
+	usbd_transfer_stop(sc->sc_xfer[UTOUCH_INTR_DT]);
+	mtx_unlock(&sc->sc_mtx);
+}
+
+static int
+utouch_ev_open(struct evdev_dev *evdev, void *ev_softc)
+{
+	struct utouch_softc *sc = (struct utouch_softc *)ev_softc;
+
+	mtx_lock(&sc->sc_mtx);
+
+	usbd_transfer_stop(sc->sc_xfer[UTOUCH_INTR_DT]);
+	usbd_xfer_set_interval(sc->sc_xfer[UTOUCH_INTR_DT], 100);
+	usbd_transfer_start(sc->sc_xfer[UTOUCH_INTR_DT]);
+
+	mtx_unlock(&sc->sc_mtx);
+
+	return (0);
+}
+
+static void
+utouch_report_event(struct utouch_softc *sc, int x, int y, int dz, int buttons)
+{
+	int i;
+
+	if (sc->sc_flags & UTOUCH_FLAG_X_AXIS)
+		evdev_push_event(sc->sc_evdev, EV_ABS, ABS_X, x);
+
+	if (sc->sc_flags & UTOUCH_FLAG_Y_AXIS)
+		evdev_push_event(sc->sc_evdev, EV_ABS, ABS_Y, y);
+
+	if (sc->sc_flags & UTOUCH_FLAG_Z_AXIS)
+		evdev_push_event(sc->sc_evdev, EV_REL, REL_Z, dz);
+
+	for (i = 0; i < sc->sc_nbuttons; i++) {
+		if (((buttons & (1 << i)) ^
+		    (sc->sc_oldbuttons & (1 << i))) == 0)
+			continue;
+
+		evdev_push_event(sc->sc_evdev, EV_KEY,
+		    BTN_MOUSE + i, !!(buttons & (1 << i)));
+	}
+
+	evdev_sync(sc->sc_evdev);
+
+}
+
+static int
+utouch_hid_test(void *d_ptr, uint16_t d_len)
+{
+	struct hid_data *hd;
+	struct hid_item hi;
+	int mdepth;
+	int found;
+
+	hd = hid_start_parse(d_ptr, d_len, 1 << hid_input);
+	if (hd == NULL)
+		return (0);
+
+	mdepth = 0;
+	found = 0;
+
+	while (hid_get_item(hd, &hi)) {
+		switch (hi.kind) {
+		case hid_collection:
+			if (mdepth != 0)
+				mdepth++;
+			else if (hi.collection == 1 &&
+			     hi.usage ==
+			      HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_POINTER))
+				mdepth++;
+			break;
+		case hid_endcollection:
+			if (mdepth != 0)
+				mdepth--;
+			break;
+		case hid_input:
+			if (mdepth == 0)
+				break;
+			if (hi.usage ==
+			     HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X) &&
+			    (hi.flags & (HIO_CONST|HIO_VARIABLE|HIO_RELATIVE)) == HIO_VARIABLE)
+				found++;
+			if (hi.usage ==
+			     HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y) &&
+			    (hi.flags & (HIO_CONST|HIO_VARIABLE|HIO_RELATIVE)) == HIO_VARIABLE)
+				found++;
+			break;
+		default:
+			break;
+		}
+	}
+	hid_end_parse(hd);
+	return (found);
+}
+
+static void
+utouch_hid_parse(struct utouch_softc *sc, const void *buf, uint16_t len)
+{
+	uint32_t flags;
+	uint8_t i;
+
+	if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_X),
+	    hid_input, 0, &sc->sc_loc_x, &flags, &sc->sc_iid_x)) {
+
+		if (flags & HIO_VARIABLE) {
+			sc->sc_flags |= UTOUCH_FLAG_X_AXIS;
+		}
+	}
+	if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP, HUG_Y),
+	    hid_input, 0, &sc->sc_loc_y, &flags, &sc->sc_iid_y)) {
+
+		if (flags & HIO_VARIABLE) {
+			sc->sc_flags |= UTOUCH_FLAG_Y_AXIS;
+		}
+	}
+	/* Try the wheel first as the Z activator since it's tradition. */
+	if (hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
+	    HUG_WHEEL), hid_input, 0, &sc->sc_loc_z, &flags,
+	    &sc->sc_iid_z) ||
+	    hid_locate(buf, len, HID_USAGE2(HUP_GENERIC_DESKTOP,
+	    HUG_TWHEEL), hid_input, 0, &sc->sc_loc_z, &flags,
+	    &sc->sc_iid_z)) {
+		if (flags & HIO_VARIABLE)
+			sc->sc_flags |= UTOUCH_FLAG_Z_AXIS;
+	}	
+
+	/* figure out the number of buttons */
+	for (i = 0; i < UTOUCH_BUTTON_MAX; i++) {
+		if (!hid_locate(buf, len, HID_USAGE2(HUP_BUTTON, (i + 1)),
+		    hid_input, 0, &sc->sc_loc_btn[i], NULL, 
+		    &sc->sc_iid_btn[i])) {
+			break;
+		}
+	}
+
+	sc->sc_nbuttons = i;
+
+	if (i > sc->sc_nbuttons)
+		sc->sc_nbuttons = i;
+
+	if (sc->sc_flags == 0)
+		return;
+
+	/* announce information about the mouse */
+	device_printf(sc->sc_dev, "%d buttons and [%s%s%s] axes\n",
+	    (sc->sc_nbuttons),
+	    (sc->sc_flags & UTOUCH_FLAG_X_AXIS) ? "X" : "",
+	    (sc->sc_flags & UTOUCH_FLAG_Y_AXIS) ? "Y" : "",
+	    (sc->sc_flags & UTOUCH_FLAG_Z_AXIS) ? "Z" : "");
+}
+
+static devclass_t utouch_devclass;
+
+static device_method_t utouch_methods[] = {
+	DEVMETHOD(device_probe, utouch_probe),
+	DEVMETHOD(device_attach, utouch_attach),
+	DEVMETHOD(device_detach, utouch_detach),
+
+	DEVMETHOD_END
+};
+
+static driver_t utouch_driver = {
+	.name = "utouch",
+	.methods = utouch_methods,
+	.size = sizeof(struct utouch_softc),
+};
+
+DRIVER_MODULE(utouch, uhub, utouch_driver, utouch_devclass, NULL, 0);
+MODULE_DEPEND(utouch, usb, 1, 1, 1);
+MODULE_VERSION(utouch, 1);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201406032027.s53KR8Mo067067>