1/*
2 * TSLIB based touchscreen driver for KDrive
3 * Porting to new input API and event queueing by Daniel Stone.
4 * Derived from ts.c by Keith Packard
5 * Derived from ps2.c by Jim Gettys
6 *
7 * Copyright � 1999 Keith Packard
8 * Copyright � 2000 Compaq Computer Corporation
9 * Copyright � 2002 MontaVista Software Inc.
10 * Copyright � 2005 OpenedHand Ltd.
11 * Copyright � 2006 Nokia Corporation
12 *
13 * Permission to use, copy, modify, distribute, and sell this software and its
14 * documentation for any purpose is hereby granted without fee, provided that
15 * the above copyright notice appear in all copies and that both that
16 * copyright notice and this permission notice appear in supporting
17 * documentation, and that the name of the authors and/or copyright holders
18 * not be used in advertising or publicity pertaining to distribution of the
19 * software without specific, written prior permission.  The authors and/or
20 * copyright holders make no representations about the suitability of this
21 * software for any purpose.  It is provided "as is" without express or
22 * implied warranty.
23 *
24 * THE AUTHORS AND/OR COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD
25 * TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
26 * AND FITNESS, IN NO EVENT SHALL THE AUTHORS AND/OR COPYRIGHT HOLDERS BE
27 * LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
28 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
29 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
30 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
31 */
32
33
34#ifdef HAVE_KDRIVE_CONFIG_H
35#include <kdrive-config.h>
36#endif
37
38#include <X11/X.h>
39#include <X11/Xproto.h>
40#include <X11/Xpoll.h>
41#include "inputstr.h"
42#include "scrnintstr.h"
43#include "kdrive.h"
44#include <sys/ioctl.h>
45#include <tslib.h>
46#include <dirent.h>
47#include <linux/input.h>
48
49struct TslibPrivate {
50    int fd;
51    int lastx, lasty;
52    struct tsdev *tsDev;
53    void (*raw_event_hook)(int x, int y, int pressure, void *closure);
54    void *raw_event_closure;
55    int phys_screen;
56};
57
58
59static void
60TsRead (int fd, void *closure)
61{
62    KdPointerInfo       *pi = closure;
63    struct TslibPrivate *private = pi->driverPrivate;
64    struct ts_sample    event;
65    long                x = 0, y = 0;
66    unsigned long       flags;
67
68    if (private->raw_event_hook) {
69        while (ts_read_raw(private->tsDev, &event, 1) == 1)
70            private->raw_event_hook (event.x, event.y, event.pressure,
71                                     private->raw_event_closure);
72        return;
73    }
74
75    while (ts_read(private->tsDev, &event, 1) == 1) {
76        if (event.pressure) {
77            flags = KD_BUTTON_1;
78
79            /*
80             * Here we test for the touch screen driver actually being on the
81             * touch screen, if it is we send absolute coordinates. If not,
82             * then we send delta's so that we can track the entire vga screen.
83             */
84            if (KdCurScreen == private->phys_screen) {
85                x = event.x;
86                y = event.y;
87            } else {
88                flags |= KD_MOUSE_DELTA;
89                if ((private->lastx == 0) || (private->lasty == 0)) {
90                    x = event.x;
91                    y = event.y;
92                } else {
93                    x = event.x - private->lastx;
94                    y = event.y - private->lasty;
95	    	}
96            }
97            private->lastx = event.x;
98            private->lasty = event.y;
99        } else {
100            flags = 0;
101            x = private->lastx;
102            y = private->lasty;
103        }
104
105        KdEnqueuePointerEvent (pi, flags, x, y, event.pressure);
106    }
107}
108
109static Status
110TslibEnable (KdPointerInfo *pi)
111{
112    struct TslibPrivate *private = pi->driverPrivate;
113
114    private->raw_event_hook = NULL;
115    private->raw_event_closure = NULL;
116    if (!pi->path) {
117        pi->path = strdup("/dev/input/touchscreen0");
118        ErrorF("[tslib/TslibEnable] no device path given, trying %s\n", pi->path);
119    }
120
121    private->tsDev = ts_open(pi->path, 0);
122    if (!private->tsDev) {
123        ErrorF("[tslib/TslibEnable] failed to open %s\n", pi->path);
124        return BadAlloc;
125    }
126
127    if (ts_config(private->tsDev)) {
128        ErrorF("[tslib/TslibEnable] failed to load configuration\n");
129        ts_close(private->tsDev);
130        private->tsDev = NULL;
131        return BadValue;
132    }
133
134    private->fd = ts_fd(private->tsDev);
135
136    KdRegisterFd(private->fd, TsRead, pi);
137
138    return Success;
139}
140
141
142static void
143TslibDisable (KdPointerInfo *pi)
144{
145    struct TslibPrivate *private = pi->driverPrivate;
146
147    if (private->fd)
148        KdUnregisterFd(pi, private->fd, TRUE);
149
150    if (private->tsDev)
151        ts_close(private->tsDev);
152
153    private->fd = 0;
154    private->tsDev = NULL;
155}
156
157
158static Status
159TslibInit (KdPointerInfo *pi)
160{
161    struct TslibPrivate *private = NULL;
162
163    if (!pi || !pi->dixdev)
164        return !Success;
165
166    pi->driverPrivate = (struct TslibPrivate *)
167                        calloc(sizeof(struct TslibPrivate), 1);
168    if (!pi->driverPrivate)
169        return !Success;
170
171    private = pi->driverPrivate;
172    /* hacktastic */
173    private->phys_screen = 0;
174    pi->nAxes = 3;
175    pi->name = strdup("Touchscreen");
176    pi->inputClass = KD_TOUCHSCREEN;
177
178    return Success;
179}
180
181
182static void
183TslibFini (KdPointerInfo *pi)
184{
185    free(pi->driverPrivate);
186    pi->driverPrivate = NULL;
187}
188
189
190KdPointerDriver TsDriver = {
191    "tslib",
192    TslibInit,
193    TslibEnable,
194    TslibDisable,
195    TslibFini,
196    NULL,
197};
198