From owner-svn-src-user@FreeBSD.ORG Wed Jul 16 16:30:31 2014 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [8.8.178.115]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 83F25B33; Wed, 16 Jul 2014 16:30:31 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 64EEA2954; Wed, 16 Jul 2014 16:30:31 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s6GGUVAc073709; Wed, 16 Jul 2014 16:30:31 GMT (envelope-from jceel@svn.freebsd.org) Received: (from jceel@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s6GGUU01073706; Wed, 16 Jul 2014 16:30:30 GMT (envelope-from jceel@svn.freebsd.org) Message-Id: <201407161630.s6GGUU01073706@svn.freebsd.org> From: Jakub Wojciech Klama Date: Wed, 16 Jul 2014 16:30:30 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r268768 - user/jceel/soc2014_evdev/head/sys/dev/terasic/mtl X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 16 Jul 2014 16:30:31 -0000 Author: jceel Date: Wed Jul 16 16:30:30 2014 New Revision: 268768 URL: http://svnweb.freebsd.org/changeset/base/268768 Log: Add Terasic MTL multitouch driver. Added: user/jceel/soc2014_evdev/head/sys/dev/terasic/mtl/terasic_mtl_touch.c (contents, props changed) Modified: user/jceel/soc2014_evdev/head/sys/dev/terasic/mtl/terasic_mtl.c user/jceel/soc2014_evdev/head/sys/dev/terasic/mtl/terasic_mtl.h Modified: user/jceel/soc2014_evdev/head/sys/dev/terasic/mtl/terasic_mtl.c ============================================================================== --- user/jceel/soc2014_evdev/head/sys/dev/terasic/mtl/terasic_mtl.c Wed Jul 16 15:57:17 2014 (r268767) +++ user/jceel/soc2014_evdev/head/sys/dev/terasic/mtl/terasic_mtl.c Wed Jul 16 16:30:30 2014 (r268768) @@ -80,6 +80,9 @@ terasic_mtl_attach(struct terasic_mtl_so error = terasic_mtl_text_attach(sc); if (error) goto error; + error = terasic_mtl_touch_attach(sc); + if (error) + goto error; /* * XXXRW: Once we've attached syscons, we can't detach it, so do it * last. Modified: user/jceel/soc2014_evdev/head/sys/dev/terasic/mtl/terasic_mtl.h ============================================================================== --- user/jceel/soc2014_evdev/head/sys/dev/terasic/mtl/terasic_mtl.h Wed Jul 16 15:57:17 2014 (r268767) +++ user/jceel/soc2014_evdev/head/sys/dev/terasic/mtl/terasic_mtl.h Wed Jul 16 16:30:30 2014 (r268768) @@ -33,6 +33,16 @@ #ifndef _DEV_TERASIC_MTL_H_ #define _DEV_TERASIC_MTL_H_ +struct terasic_mtl_touch_state +{ + int x1; + int y1; + int x2; + int y2; + uint16_t gesture; + uint32_t touchpoints; +}; + struct terasic_mtl_softc { /* * syscons requires that its video_adapter_t be at the front of the @@ -76,6 +86,14 @@ struct terasic_mtl_softc { struct resource *mtl_text_res; int mtl_text_rid; uint16_t *mtl_text_soft; + + /* + * evdev device + */ + struct evdev_dev *mtl_evdev; + struct terasic_mtl_touch_state mtl_evdev_state; + struct callout mtl_evdev_callout; + bool mtl_evdev_opened; }; #define TERASIC_MTL_LOCK(sc) mtx_lock(&(sc)->mtl_lock) @@ -154,6 +172,35 @@ struct terasic_mtl_softc { #define TERASIC_MTL_ALPHA_OPAQUE 255 /* + * Driver-recognized gestures. + */ + +#define TSG_NONE 0x00 +#define TSG_NORTH 0x10 +#define TSG_NORTHEAST 0x12 +#define TSG_EAST 0x14 +#define TSG_SOUTHEAST 0x16 +#define TSG_SOUTH 0x18 +#define TSG_SOUTHWEST 0x1A +#define TSG_WEST 0x1C +#define TSG_NORTHWEST 0x1E +#define TSG_ROTATE_CW 0x28 /* Clockwise */ +#define TSG_ROTATE_CCW 0x29 /* Counter Clockwise */ +#define TSG_CLICK 0x20 +#define TSG_DCLICK 0x22 /* Double Click */ +#define TSG2_NORTH 0x30 +#define TSG2_NORTHEAST 0x32 +#define TSG2_EAST 0x34 +#define TSG2_SOUTHEAST 0x36 +#define TSG2_SOUTH 0x38 +#define TSG2_SOUTHWEST 0x3A +#define TSG2_WEST 0x3C +#define TSG2_NORTHWEST 0x3E +#define TSG2_CLICK 0x40 +#define TSG2_ZOOM_IN 0x48 +#define TSG2_ZOOM_OUT 0x49 + +/* * Driver setup routines from the bus attachment/teardown. */ int terasic_mtl_attach(struct terasic_mtl_softc *sc); @@ -172,6 +219,8 @@ int terasic_mtl_syscons_attach(struct te void terasic_mtl_syscons_detach(struct terasic_mtl_softc *sc); int terasic_mtl_text_attach(struct terasic_mtl_softc *sc); void terasic_mtl_text_detach(struct terasic_mtl_softc *sc); +int terasic_mtl_touch_attach(struct terasic_mtl_softc *sc); +void terasic_mtl_touch_detach(struct terasic_mtl_softc *sc); /* * Control register I/O routines. Added: user/jceel/soc2014_evdev/head/sys/dev/terasic/mtl/terasic_mtl_touch.c ============================================================================== --- /dev/null 00:00:00 1970 (empty, because file is newly added) +++ user/jceel/soc2014_evdev/head/sys/dev/terasic/mtl/terasic_mtl_touch.c Wed Jul 16 16:30:30 2014 (r268768) @@ -0,0 +1,251 @@ + +/*- + * Copyright (c) 2014 Jakub Wojciech Klama + * 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. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include /* video_adapter_t */ +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +static void terasic_mtl_touch_intr(void *); +static evdev_open_t terasic_mtl_touch_open; +static evdev_close_t terasic_mtl_touch_close; + +struct evdev_methods terasic_mtl_ev_methods = { + .ev_open = &terasic_mtl_touch_open, + .ev_close = &terasic_mtl_touch_close, +}; + + +static uint16_t terasic_mtl_gestures[256] = { + /* Single finger gestures */ + [TSG_NONE] = KEY_RESERVED, + [TSG_NORTH] = BTN_NORTH, + [TSG_EAST] = BTN_EAST, + [TSG_WEST] = BTN_WEST, + [TSG_SOUTH] = BTN_SOUTH, + [TSG_CLICK] = BTN_TOUCH, + [TSG_DCLICK] = BTN_TOUCH, + [TSG_ROTATE_CW] = BTN_1, + [TSG_ROTATE_CCW] = BTN_2, + /* Two finger gestures */ + [TSG2_NORTH] = BTN_NORTH, + [TSG2_EAST] = BTN_EAST, + [TSG2_WEST] = BTN_WEST, + [TSG2_SOUTH] = BTN_SOUTH, + [TSG2_CLICK] = BTN_TOOL_DOUBLETAP, + [TSG2_ZOOM_IN] = KEY_ZOOMIN, + [TSG2_ZOOM_OUT] = KEY_ZOOMOUT, +}; + +int +terasic_mtl_touch_attach(struct terasic_mtl_softc *sc) +{ + struct input_absinfo absinfo; + sc->mtl_evdev = evdev_alloc(); + evdev_set_name(sc->mtl_evdev, device_get_desc(sc->mtl_dev)); + evdev_set_softc(sc->mtl_evdev, sc); + evdev_set_methods(sc->mtl_evdev, &terasic_mtl_ev_methods); + evdev_support_event(sc->mtl_evdev, EV_SYN); + evdev_support_event(sc->mtl_evdev, EV_KEY); + evdev_support_event(sc->mtl_evdev, EV_ABS); + evdev_support_abs(sc->mtl_evdev, ABS_MT_POSITION_X); + evdev_support_abs(sc->mtl_evdev, ABS_MT_POSITION_Y); + + /* Support gestures as a keys */ + evdev_support_key(sc->mtl_evdev, BTN_TOUCH); + evdev_support_key(sc->mtl_evdev, BTN_TOOL_DOUBLETAP); + evdev_support_key(sc->mtl_evdev, BTN_NORTH); + evdev_support_key(sc->mtl_evdev, BTN_SOUTH); + evdev_support_key(sc->mtl_evdev, BTN_WEST); + evdev_support_key(sc->mtl_evdev, BTN_EAST); + evdev_support_key(sc->mtl_evdev, BTN_1); + evdev_support_key(sc->mtl_evdev, BTN_2); + evdev_support_key(sc->mtl_evdev, KEY_ZOOMIN); + evdev_support_key(sc->mtl_evdev, KEY_ZOOMOUT); + + bzero(&absinfo, sizeof(struct input_absinfo)); + + /* Set X axis bounds */ + absinfo.minimum = 0; + absinfo.maximum = 1024; + evdev_set_absinfo(sc->mtl_evdev, ABS_MT_POSITION_X, &absinfo); + + /* Set Y axis bounds */ + absinfo.minimum = 0; + absinfo.maximum = 512; + evdev_set_absinfo(sc->mtl_evdev, ABS_MT_POSITION_Y, &absinfo); + + evdev_register(sc->mtl_dev, sc->mtl_evdev); + + callout_init(&sc->mtl_evdev_callout, 1); + return (0); +} + +void +terasic_mtl_touch_detach(struct terasic_mtl_softc *sc) +{ + + evdev_unregister(sc->mtl_dev, sc->mtl_evdev); +} + +static int +terasic_mtl_touch_open(struct evdev_dev *evdev, void *softc) +{ + struct terasic_mtl_softc *sc = (struct terasic_mtl_softc *)softc; + + /* Start polling */ + callout_reset(&sc->mtl_evdev_callout, hz / 10, + terasic_mtl_touch_intr, sc); + + sc->mtl_evdev_opened = true; + return (0); +} + +static void +terasic_mtl_touch_close(struct evdev_dev *evdev, void *softc) +{ + struct terasic_mtl_softc *sc = (struct terasic_mtl_softc *)softc; + + /* Stop polling */ + callout_stop(&sc->mtl_evdev_callout); + + sc->mtl_evdev_opened = false; +} + +static void +terasic_mtl_touch_intr(void *arg) +{ + struct terasic_mtl_softc *sc = (struct terasic_mtl_softc *)arg; + struct terasic_mtl_touch_state *state = &sc->mtl_evdev_state; + int32_t x1, y1, x2, y2; + bool sync = false; + + int tsg = le32toh(bus_read_4(sc->mtl_reg_res, + TERASIC_MTL_OFF_TOUCHGESTURE)); + int touchpoints = tsg >> 8; + int gesture = tsg & 0xff; + + if (touchpoints == 0 || touchpoints == 0xffffff) { + /* + * Check if it's a release and if so, push empty + * MT_SYNC event + */ + if (state->touchpoints != 0) { + evdev_mt_sync(sc->mtl_evdev); + evdev_sync(sc->mtl_evdev); + } + + state->touchpoints = 0; + + callout_reset(&sc->mtl_evdev_callout, hz / 10, + terasic_mtl_touch_intr, sc); + return; + } + + if (gesture != 0 && gesture != 0xff) { + uint16_t code = terasic_mtl_gestures[gesture]; + if (code != KEY_RESERVED) { + evdev_push_event(sc->mtl_evdev, EV_KEY, code, 1); + sync = true; + state->gesture = code; + } + } else { + if (state->gesture != 0) { + /* Push a release event */ + evdev_push_event(sc->mtl_evdev, EV_KEY, state->gesture, 0); + sync = true; + state->gesture = 0; + } + } + + if (touchpoints > 0) { + x1 = le32toh(bus_read_4(sc->mtl_reg_res, + TERASIC_MTL_OFF_TOUCHPOINT_X1)); + y1 = le32toh(bus_read_4(sc->mtl_reg_res, + TERASIC_MTL_OFF_TOUCHPOINT_Y1)); + + if (x1 != -1 && y1 != -1 && (x1 != state->x1) && + (y1 != state->y1)) { + evdev_push_event(sc->mtl_evdev, EV_ABS, + ABS_MT_POSITION_X, x1); + evdev_push_event(sc->mtl_evdev, EV_ABS, + ABS_MT_POSITION_Y, y1); + evdev_mt_sync(sc->mtl_evdev); + + state->x1 = x1; + state->y1 = y1; + sync = true; + } + } + + if (touchpoints > 1) { + x2 = le32toh(bus_read_4(sc->mtl_reg_res, + TERASIC_MTL_OFF_TOUCHPOINT_X2)); + y2 = le32toh(bus_read_4(sc->mtl_reg_res, + TERASIC_MTL_OFF_TOUCHPOINT_Y2)); + + if (x2 != -1 && y2 != -1 && (x2 != state->x2) && + (y2 != state->y2)) { + evdev_push_event(sc->mtl_evdev, EV_ABS, + ABS_MT_POSITION_X, x2); + evdev_push_event(sc->mtl_evdev, EV_ABS, + ABS_MT_POSITION_Y, y2); + evdev_mt_sync(sc->mtl_evdev); + + state->x2 = x2; + state->y2 = y2; + sync = true; + } + } + + state->touchpoints = touchpoints; + + if (sync) + evdev_sync(sc->mtl_evdev); + + callout_reset(&sc->mtl_evdev_callout, hz / 10, + terasic_mtl_touch_intr, sc); +}