summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/caps.c143
-rw-r--r--src/caps.h49
-rw-r--r--src/common.h54
-rw-r--r--src/hw.c105
-rw-r--r--src/hw.h52
-rw-r--r--src/mtouch.c110
-rw-r--r--src/mtouch.h83
-rw-r--r--src/multitouch.c434
8 files changed, 1030 insertions, 0 deletions
diff --git a/src/caps.c b/src/caps.c
new file mode 100644
index 0000000..293e5b3
--- /dev/null
+++ b/src/caps.c
@@ -0,0 +1,143 @@
+/***************************************************************************
+ *
+ * Multitouch protocol X driver
+ * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (C) 2009,2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#include "caps.h"
+#include <errno.h>
+#include <string.h>
+#include <xf86.h>
+#include <xf86Xinput.h>
+
+#define SETABS(c, x, map, key, fd) \
+ c->has_##x = getbit(map, key) && getabs(&c->abs_##x, key, fd)
+
+#define ADDCAP(s, c, x) strcat(s, c->has_##x ? " " #x : "")
+
+static const int bits_per_long = 8 * sizeof(long);
+
+static inline int nlongs(int nbit)
+{
+ return (nbit + bits_per_long - 1) / bits_per_long;
+}
+
+static inline bool getbit(const unsigned long* map, int key)
+{
+ return (map[key / bits_per_long] >> (key % bits_per_long)) & 0x01;
+}
+
+static bool getabs(struct input_absinfo *abs, int key, int fd)
+{
+ int rc;
+ SYSCALL(rc = ioctl(fd, EVIOCGABS(key), abs));
+ return rc >= 0;
+}
+
+int caps_read(struct mtev_caps *caps, int fd)
+{
+ unsigned long evbits[nlongs(EV_MAX)];
+ unsigned long absbits[nlongs(ABS_MAX)];
+ unsigned long keybits[nlongs(KEY_MAX)];
+ int rc;
+
+ memset(caps, 0, sizeof(struct mtev_caps));
+
+ SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_SYN, sizeof(evbits)), evbits));
+ if (rc < 0) {
+ xf86Msg(X_ERROR, "mtev: EV_SYN needed but missing\n");
+ return rc;
+ }
+
+ SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybits)), keybits));
+ if (rc < 0) {
+ xf86Msg(X_ERROR, "mtev: EV_KEY needed but missing\n");
+ return rc;
+ }
+ SYSCALL(rc = ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbits)), absbits));
+ if (rc < 0) {
+ xf86Msg(X_ERROR, "mtev: EV_ABS needed but missing\n");
+ return rc;
+ }
+
+ caps->has_left = getbit(keybits, BTN_LEFT);
+ caps->has_middle = getbit(keybits, BTN_MIDDLE);
+ caps->has_right = getbit(keybits, BTN_RIGHT);
+
+ SETABS(caps, touch_major, absbits, ABS_MT_TOUCH_MAJOR, fd);
+ SETABS(caps, touch_minor, absbits, ABS_MT_TOUCH_MINOR, fd);
+ SETABS(caps, width_major, absbits, ABS_MT_WIDTH_MAJOR, fd);
+ SETABS(caps, width_minor, absbits, ABS_MT_WIDTH_MINOR, fd);
+ SETABS(caps, orientation, absbits, ABS_MT_ORIENTATION, fd);
+ SETABS(caps, position_x, absbits, ABS_MT_POSITION_X, fd);
+ SETABS(caps, position_y, absbits, ABS_MT_POSITION_Y, fd);
+ SETABS(caps, tracking_id, absbits, ABS_MT_TRACKING_ID, fd);
+
+ caps->has_mtdata = caps->has_position_x && caps->has_position_y;
+
+ return 0;
+}
+
+void caps_output(const struct mtev_caps *caps)
+{
+ char line[1024];
+ memset(line, 0, sizeof(line));
+ ADDCAP(line, caps, left);
+ ADDCAP(line, caps, middle);
+ ADDCAP(line, caps, right);
+ ADDCAP(line, caps, mtdata);
+ ADDCAP(line, caps, touch_major);
+ ADDCAP(line, caps, touch_minor);
+ ADDCAP(line, caps, width_major);
+ ADDCAP(line, caps, width_minor);
+ ADDCAP(line, caps, orientation);
+ ADDCAP(line, caps, tracking_id);
+ ADDCAP(line, caps, position_x);
+ ADDCAP(line, caps, position_y);
+
+ xf86Msg(X_INFO, "mtev: caps:%s\n", line);
+ if (caps->has_touch_major)
+ xf86Msg(X_INFO, "mtev: touch major: %d %d\n",
+ caps->abs_touch_major.minimum,
+ caps->abs_touch_major.maximum);
+ if (caps->has_touch_minor)
+ xf86Msg(X_INFO, "mtev: touch minor: %d %d\n",
+ caps->abs_touch_minor.minimum,
+ caps->abs_touch_minor.maximum);
+ if (caps->has_width_major)
+ xf86Msg(X_INFO, "mtev: width: %d %d\n",
+ caps->abs_width_major.minimum,
+ caps->abs_width_major.maximum);
+ if (caps->has_orientation)
+ xf86Msg(X_INFO, "mtev: orientation: %d %d\n",
+ caps->abs_orientation.minimum,
+ caps->abs_orientation.maximum);
+ if (caps->has_tracking_id)
+ xf86Msg(X_INFO, "mtev: tracking_id: %d %d\n",
+ caps->abs_tracking_id.minimum,
+ caps->abs_tracking_id.maximum);
+ if (caps->has_position_x)
+ xf86Msg(X_INFO, "mtev: position_x: %d %d\n",
+ caps->abs_position_x.minimum,
+ caps->abs_position_x.maximum);
+ if (caps->has_position_y)
+ xf86Msg(X_INFO, "mtev: position_y: %d %d\n",
+ caps->abs_position_y.minimum,
+ caps->abs_position_y.maximum);
+}
diff --git a/src/caps.h b/src/caps.h
new file mode 100644
index 0000000..bfc9c33
--- /dev/null
+++ b/src/caps.h
@@ -0,0 +1,49 @@
+/***************************************************************************
+ *
+ * Multitouch protocol X driver
+ * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (C) 2009,2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#ifndef CAPABILITIES_H
+#define CAPABILITIES_H
+
+#include "common.h"
+#include <linux/input.h>
+
+struct mtev_caps {
+ bool has_left, has_middle;
+ bool has_right, has_mtdata;
+ bool has_touch_major, has_touch_minor;
+ bool has_width_major, has_width_minor;
+ bool has_orientation, has_tracking_id;
+ bool has_position_x, has_position_y;
+ struct input_absinfo abs_touch_major;
+ struct input_absinfo abs_touch_minor;
+ struct input_absinfo abs_width_major;
+ struct input_absinfo abs_width_minor;
+ struct input_absinfo abs_orientation;
+ struct input_absinfo abs_position_x;
+ struct input_absinfo abs_position_y;
+ struct input_absinfo abs_tracking_id;
+};
+
+int caps_read(struct mtev_caps *caps, int fd);
+void caps_output(const struct mtev_caps *caps);
+
+#endif
diff --git a/src/common.h b/src/common.h
new file mode 100644
index 0000000..7cc4998
--- /dev/null
+++ b/src/common.h
@@ -0,0 +1,54 @@
+/***************************************************************************
+ *
+ * Multitouch protocol X driver
+ * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (C) 2009,2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#ifndef COMMON_H
+#define COMMON_H
+
+typedef unsigned char bool;
+
+// includes available in 2.6.30-rc5
+
+#ifndef ABS_MT_PRESSURE
+#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */
+#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
+#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
+#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
+#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
+#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
+#define ABS_MT_POSITION_X 0x35 /* Center X ellipse position */
+#define ABS_MT_POSITION_Y 0x36 /* Center Y ellipse position */
+#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
+#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
+#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
+#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
+#define SYN_MT_REPORT 2
+#define MT_TOOL_FINGER 0
+#define MT_TOOL_PEN 1
+#endif
+
+#define SYSCALL(call) while (((call) == -1) && (errno == EINTR))
+
+#define GETBIT(m, x) ((m>>(x))&1U)
+#define SETBIT(m, x) (m|=(1U<<(x)))
+#define CLEARBIT(m, x) (m&=~(1U<<(x)))
+
+#endif
diff --git a/src/hw.c b/src/hw.c
new file mode 100644
index 0000000..1afec1a
--- /dev/null
+++ b/src/hw.c
@@ -0,0 +1,105 @@
+/***************************************************************************
+ *
+ * Multitouch protocol X driver
+ * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (C) 2009,2010 Nokia Corporation
+ *
+ * Adaptation to libmtdev and Linux multi-touch-protocol B (slotted)
+ * Copyright (C) 2010 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#include <string.h>
+#include <linux/input.h>
+#include <xf86.h>
+#include <mtdev.h>
+
+#include "hw.h"
+
+void hw_init(struct mtev_hw_state *hw)
+{
+ int i;
+ memset(hw, 0, sizeof(struct mtev_hw_state));
+ for (i = 0; i < HW_MAX_SLOTS; i++)
+ hw->slot[i].tracking_id = INVALID_TRACKING_ID;
+}
+
+bool hw_read(struct mtev_hw_state *hw, const struct input_event* ev)
+{
+ // xf86Msg(X_INFO, "event: %d %d %d\n", ev->type, ev->code, ev->value);
+
+ switch (ev->type) {
+ case EV_SYN:
+ switch (ev->code) {
+ case SYN_REPORT:
+ return 1;
+
+ case SYN_MT_REPORT:
+ xf86Msg(X_ERROR, "libmtdev sent SYN_MT_REPORT");
+ break;
+ }
+ break;
+
+ case EV_ABS:
+ if (ev->code == ABS_MT_SLOT) {
+ if (ev->value >= HW_MAX_SLOTS) {
+ xf86Msg(X_ERROR, "Slot usage (%d) exceeds limit of %d", ev->value, HW_MAX_SLOTS);
+ hw->current_slot = INVALID_SLOT;
+ } else
+ hw->current_slot = ev->value;
+ break;
+ }
+
+ if (hw->current_slot == INVALID_SLOT)
+ break;
+
+ switch (ev->code) {
+ case ABS_MT_POSITION_X:
+ hw->slot[hw->current_slot].position_x = ev->value;
+ break;
+ case ABS_MT_POSITION_Y:
+ hw->slot[hw->current_slot].position_y = ev->value;
+ break;
+ case ABS_MT_TOUCH_MAJOR:
+ hw->slot[hw->current_slot].touch_major = ev->value;
+ break;
+ case ABS_MT_TOUCH_MINOR:
+ hw->slot[hw->current_slot].touch_minor = ev->value;
+ break;
+ case ABS_MT_WIDTH_MAJOR:
+ hw->slot[hw->current_slot].width_major = ev->value;
+ break;
+ case ABS_MT_WIDTH_MINOR:
+ hw->slot[hw->current_slot].width_minor = ev->value;
+ break;
+ case ABS_MT_ORIENTATION:
+ hw->slot[hw->current_slot].orientation = ev->value;
+ break;
+ case ABS_MT_PRESSURE:
+ hw->slot[hw->current_slot].pressure = ev->value;
+ break;
+ case ABS_MT_TRACKING_ID:
+ if (ev->value == -1) /* Slot contact has been released */
+ hw->slot[hw->current_slot].tracking_id = INVALID_TRACKING_ID;
+ else
+ hw->slot[hw->current_slot].tracking_id = hw->current_slot;//ev->value;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/src/hw.h b/src/hw.h
new file mode 100644
index 0000000..faba0f8
--- /dev/null
+++ b/src/hw.h
@@ -0,0 +1,52 @@
+/***************************************************************************
+ *
+ * Multitouch protocol X driver
+ * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (C) 2009,2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#ifndef HWDATA_H
+#define HWDATA_H
+
+#include "common.h"
+
+struct input_event;
+
+// Max touch points we gonna get out from kernel layer
+#define HW_MAX_SLOTS 10
+#define INVALID_SLOT -1
+#define INVALID_TRACKING_ID -1
+
+struct mtev_touch_point {
+ int touch_major, touch_minor;
+ int width_major, width_minor;
+ int orientation;
+ int position_x, position_y;
+ int pressure;
+ int tracking_id;
+};
+
+struct mtev_hw_state {
+ struct mtev_touch_point slot[HW_MAX_SLOTS];
+ int current_slot;
+};
+
+void hw_init(struct mtev_hw_state *hw);
+bool hw_read(struct mtev_hw_state *hw, const struct input_event* ev);
+
+#endif
diff --git a/src/mtouch.c b/src/mtouch.c
new file mode 100644
index 0000000..cf3add8
--- /dev/null
+++ b/src/mtouch.c
@@ -0,0 +1,110 @@
+/***************************************************************************
+ *
+ * Multitouch protocol X driver
+ * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (C) 2009,2010 Nokia Corporation
+ *
+ * Adaptation to libmtdev and Linux multi-touch-protocol B (slotted)
+ * Copyright (C) 2010 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <xf86.h>
+
+#include "mtouch.h"
+
+int mtouch_configure(struct mtev_mtouch *mt, int fd)
+{
+ int rc = caps_read(&mt->caps, fd);
+ if (rc < 0)
+ return rc;
+ caps_output(&mt->caps);
+ return 0;
+}
+
+int mtouch_open(struct mtev_mtouch *mt, int fd)
+{
+ memset(&mt->ev, 0, sizeof(mt->ev));
+ memset(&mt->dev, 0, sizeof(mt->dev));
+ mt->num_events = 0;
+ hw_init(&mt->hw_state);
+ return mtdev_open(&mt->dev, fd);
+}
+
+int mtouch_close(struct mtev_mtouch *mt, int fd)
+{
+ mtdev_close(&mt->dev);
+ memset(&mt->dev, 0, sizeof(mt->dev));
+ memset(&mt->ev, 0, sizeof(mt->ev));
+ mt->num_events = 0;
+ hw_init(&mt->hw_state);
+ return 0;
+}
+
+const struct input_event* mtouch_read_event(struct mtev_mtouch *mt, int fd)
+{
+ struct input_event *ev;
+
+ /* Read in bursts from input subsystem, then feed to caller one
+ * at a time, only reading the next burst when the queue is empty */
+ if (mt->num_events_read >= mt->num_events) {
+ int n;
+
+ SYSCALL(n = mtdev_get(&mt->dev, fd, mt->ev, MAX_EVENTS));
+ if (n <= 0)
+ return NULL;
+
+ mt->num_events = n;
+ mt->num_events_read = 0;
+ }
+
+ if (mt->num_events > mt->num_events_read) {
+ ev = &mt->ev[mt->num_events_read];
+ mt->num_events_read++;
+ return ev;
+ }
+
+ // This should not happen
+ xf86Msg(X_ERROR, "mtev: got read_event without event!\n");
+ return NULL;
+}
+
+bool mtouch_read_synchronized_event(struct mtev_mtouch *mt, int fd)
+{
+ const struct input_event* ev;
+
+ while ((ev = mtouch_read_event(mt, fd))) {
+ if (hw_read(&mt->hw_state, ev))
+ return 1;
+ }
+
+ return 0;
+}
+
+const struct mtev_touch_point* mtouch_get_contact(const struct mtev_mtouch *mt, int n)
+{
+ int i = 0;
+ do {
+ if (mt->hw_state.slot[i].tracking_id != INVALID_TRACKING_ID && (n--) == 0)
+ return &mt->hw_state.slot[i];
+ } while (++i < HW_MAX_SLOTS);
+
+ return NULL;
+}
diff --git a/src/mtouch.h b/src/mtouch.h
new file mode 100644
index 0000000..9745776
--- /dev/null
+++ b/src/mtouch.h
@@ -0,0 +1,83 @@
+/***************************************************************************
+ *
+ * Multitouch protocol X driver
+ * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (C) 2009,2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#ifndef MTOUCH_H
+#define MTOUCH_H
+
+#include <mtdev.h>
+#include <mtdev-mapping.h>
+
+#include "caps.h"
+#include "hw.h"
+
+#define MT_AXIS_PER_FINGER 5
+
+/*
+ * How many fingers we export to upwards
+ * The MAX_VALUATORS limits these.
+ * MT_NUM_VALUATORS needs to be less or equal than MAX_VALUATORS
+ */
+
+#define MT_NUM_FINGERS 6
+#define MT_NUM_VALUATORS (MT_NUM_FINGERS * MT_AXIS_PER_FINGER)
+
+#define MT_NUM_BUTTONS 1
+
+/* Axis labels */
+
+#define AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR "Abs MT Touch Major"
+#define AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR "Abs MT Touch Minor"
+#define AXIS_LABEL_PROP_ABS_MT_WIDTH_MAJOR "Abs MT Width Major"
+#define AXIS_LABEL_PROP_ABS_MT_WIDTH_MINOR "Abs MT Width Minor"
+#define AXIS_LABEL_PROP_ABS_MT_ORIENTATION "Abs MT Orientation"
+#define AXIS_LABEL_PROP_ABS_MT_POSITION_X "Abs MT Position X"
+#define AXIS_LABEL_PROP_ABS_MT_POSITION_Y "Abs MT Position Y"
+#define AXIS_LABEL_PROP_ABS_MT_TOOL_TYPE "Abs MT Tool Type"
+#define AXIS_LABEL_PROP_ABS_MT_BLOB_ID "Abs MT Blob ID"
+#define AXIS_LABEL_PROP_ABS_MT_TRACKING_ID "Abs MT Tracking ID"
+#define AXIS_LABEL_PROP_ABS_MT_PRESSURE "Abs MT Pressure"
+
+#define MAX_EVENTS 256
+
+struct mtev_mtouch {
+ struct input_event ev[MAX_EVENTS];
+ unsigned long num_events;
+ unsigned long num_events_read;
+
+ struct mtev_hw_state hw_state;
+ struct mtev_caps caps;
+
+ bool invert_x;
+ bool invert_y;
+ bool swap_xy;
+ struct mtdev dev;
+};
+
+int mtouch_configure(struct mtev_mtouch *mt, int fd);
+int mtouch_open(struct mtev_mtouch *mt, int fd);
+int mtouch_close(struct mtev_mtouch *mt, int fd);
+
+bool mtouch_read_synchronized_event(struct mtev_mtouch *mt, int fd);
+int mtouch_num_contacts(const struct mtev_mtouch *mt);
+const struct mtev_touch_point* mtouch_get_contact(const struct mtev_mtouch *mt, int n);
+
+#endif
diff --git a/src/multitouch.c b/src/multitouch.c
new file mode 100644
index 0000000..20fdf65
--- /dev/null
+++ b/src/multitouch.c
@@ -0,0 +1,434 @@
+/***************************************************************************
+ *
+ * Multitouch X driver
+ * Copyright (C) 2008 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (C) 2009,2010 Nokia Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ **************************************************************************/
+
+#define MODULEVENDORSTRING "Nokia"
+
+#include "xorg-server.h"
+#include <xorg/exevents.h>
+#include <xorg/xserver-properties.h>
+#include <X11/Xatom.h>
+#include <xf86.h>
+#include <xf86_OSproc.h>
+#include <xf86Xinput.h>
+
+#include "common.h"
+#include "mtouch.h"
+
+static const char* const axis_labels_str[] = {
+ AXIS_LABEL_PROP_ABS_MT_POSITION_X,
+ AXIS_LABEL_PROP_ABS_MT_POSITION_Y,
+ AXIS_LABEL_PROP_ABS_MT_TOUCH_MAJOR,
+ AXIS_LABEL_PROP_ABS_MT_TOUCH_MINOR,
+ AXIS_LABEL_PROP_ABS_MT_TRACKING_ID,
+};
+
+static void pointer_control(DeviceIntPtr dev, PtrCtrl *ctrl)
+{
+ xf86Msg(X_INFO, "pointer_control\n");
+}
+
+static int pointer_property(DeviceIntPtr dev,
+ Atom property,
+ XIPropertyValuePtr prop,
+ BOOL checkonly)
+{
+ xf86Msg(X_INFO, "pointer_property\n");
+ return Success;
+}
+
+static void init_axes_labels(Atom* labels, int num_labels)
+{
+ int i;
+
+ for (i = 0 ; i < num_labels; i++) {
+ labels[i] = MakeAtom(axis_labels_str[i % MT_AXIS_PER_FINGER],
+ strlen(axis_labels_str[i % MT_AXIS_PER_FINGER]),
+ TRUE);
+ }
+}
+
+static int init_properties(DeviceIntPtr dev)
+{
+ static const char* const strMaxContacts = "Max Contacts";
+ static const char* const strAxesPerContact = "Axes Per Contact";
+ int rc;
+
+ Atom labelMaxContacts;
+ Atom labelAxesPerContact;
+
+ int max_contacts = MT_NUM_FINGERS;
+ int axes_per_contact = MT_AXIS_PER_FINGER;
+
+ labelMaxContacts = MakeAtom(strMaxContacts,
+ strlen(strMaxContacts), TRUE);
+ labelAxesPerContact = MakeAtom(strAxesPerContact,
+ strlen(strAxesPerContact), TRUE);
+
+ rc = XIChangeDeviceProperty(dev,
+ labelMaxContacts,
+ XA_INTEGER,
+ 8,
+ PropModeReplace,
+ 1,
+ &max_contacts,
+ TRUE);
+ if (rc != Success)
+ return rc;
+
+ XISetDevicePropertyDeletable(dev, labelMaxContacts, FALSE);
+
+
+ rc = XIChangeDeviceProperty(dev,
+ labelAxesPerContact,
+ XA_INTEGER,
+ 8,
+ PropModeReplace,
+ 1,
+ &axes_per_contact,
+ TRUE);
+
+ if (rc != Success)
+ return rc;
+
+ XISetDevicePropertyDeletable(dev, labelAxesPerContact, FALSE);
+
+ return Success;
+}
+
+static int device_init(DeviceIntPtr dev, LocalDevicePtr local)
+{
+ struct mtev_mtouch *mt = local->private;
+ Atom atom;
+ int i;
+ int j;
+ unsigned char map[MT_NUM_BUTTONS + 1];
+ Atom btn_labels[MT_NUM_BUTTONS] = { 0 };
+ Atom axes_labels[MT_NUM_VALUATORS] = { 0, };
+ int r;
+
+ if (MT_NUM_VALUATORS > MAX_VALUATORS) {
+ xf86Msg(X_ERROR, "MT_NUM_VALUATORS(%d) > MAX_VALUATORS(%d)\n",
+ MT_NUM_VALUATORS, MAX_VALUATORS);
+ return BadValue;
+ }
+
+ for (i = 0; i < MT_NUM_BUTTONS; i++)
+ btn_labels[i] = XIGetKnownProperty(BTN_LABEL_PROP_BTN_UNKNOWN);
+
+ atom = XIGetKnownProperty(BTN_LABEL_PROP_BTN_LEFT);
+ btn_labels[0] = atom;
+
+ init_axes_labels(axes_labels, MT_NUM_VALUATORS);
+
+ r = init_properties(dev);
+ if (r != Success)
+ return r;
+
+ local->fd = xf86OpenSerial(local->options);
+ if (local->fd < 0) {
+ xf86Msg(X_ERROR, "mtev: cannot open device\n");
+ return !Success;
+ }
+ if (mtouch_configure(mt, local->fd)) {
+ xf86Msg(X_ERROR, "mtev: cannot configure device\n");
+ return !Success;
+ }
+ xf86CloseSerial(local->fd);
+
+ for (i = 0; i < MT_NUM_BUTTONS+1; i++)
+ map[i] = i;
+
+ InitPointerDeviceStruct((DevicePtr)dev,
+ map,
+ MT_NUM_BUTTONS,
+ btn_labels,
+ pointer_control,
+ GetMotionHistorySize(),
+ MT_NUM_VALUATORS,
+ axes_labels);
+
+ for (i = 0; i < MT_NUM_FINGERS; i++) {
+ for (j = 0; j < MT_AXIS_PER_FINGER; j++) {
+ const int val = (i * MT_AXIS_PER_FINGER) + j;
+ int min;
+ int max;
+
+ switch (j) {
+ case 0:
+ min = mt->caps.abs_position_x.minimum;
+ max = mt->caps.abs_position_x.maximum;
+ break;
+ case 1:
+ min = mt->caps.abs_position_y.minimum;
+ max = mt->caps.abs_position_y.maximum;
+ break;
+ case 2:
+ min = mt->caps.abs_touch_major.minimum;
+ max = mt->caps.abs_touch_major.maximum;
+ break;
+ case 3:
+ if (mt->caps.has_touch_minor) {
+ min = mt->caps.abs_touch_minor.minimum;
+ max = mt->caps.abs_touch_minor.maximum;
+ } else {
+ min = mt->caps.abs_touch_major.minimum;
+ max = mt->caps.abs_touch_major.maximum;
+ }
+ break;
+ case 4: // Tracking id
+ min = mt->caps.abs_tracking_id.minimum;
+ max = mt->caps.abs_tracking_id.maximum >
+ (MT_NUM_FINGERS-1) ?
+ (MT_NUM_FINGERS-1) :
+ mt->caps.abs_tracking_id.maximum;
+ break;
+ default:
+ return BadValue;
+ }
+
+ xf86InitValuatorAxisStruct(dev, val, axes_labels[val],
+ min,
+ max,
+ 1, 0, 1);
+ xf86InitValuatorDefaults(dev, val);
+ }
+ }
+
+ XIRegisterPropertyHandler(dev, pointer_property, NULL, NULL);
+
+ return Success;
+}
+
+static int device_on(LocalDevicePtr local)
+{
+ struct mtev_mtouch *mt = local->private;
+ local->fd = xf86OpenSerial(local->options);
+ if (local->fd < 0) {
+ xf86Msg(X_ERROR, "mtev: cannot open device\n");
+ return !Success;
+ }
+ if (mtouch_open(mt, local->fd)) {
+ xf86Msg(X_ERROR, "mtev: cannot grab device\n");
+ return !Success;
+ }
+ xf86AddEnabledDevice(local);
+ return Success;
+}
+
+static int device_off(LocalDevicePtr local)
+{
+ struct mtev_mtouch *mt = local->private;
+ xf86RemoveEnabledDevice(local);
+ if(mtouch_close(mt, local->fd)) {
+ xf86Msg(X_WARNING, "mtev: cannot ungrab device\n");
+ }
+ xf86CloseSerial(local->fd);
+ return Success;
+}
+
+static int device_close(LocalDevicePtr local)
+{
+ return Success;
+}
+
+static void process_state(LocalDevicePtr local,
+ const struct mtev_mtouch *mt)
+{
+
+ const struct mtev_touch_point *tp;
+ static int pdown = 0;
+ int valuators[MAX_VALUATORS];
+ int down;
+ int valix;
+ int contacts;
+
+ contacts = valix = down = 0;
+
+ while ((tp = mtouch_get_contact(mt, contacts)) != NULL) {
+ contacts++;
+
+ // We don't do remapping of tracking id's so
+ // make sure clients don't see too high tracking_id numbers
+ if (tp->tracking_id < MT_NUM_FINGERS) {
+ int x;
+ int y;
+
+ x = tp->position_x;
+ y = tp->position_y;
+
+ if (mt->invert_x)
+ x = mt->caps.abs_position_x.maximum - x +
+ mt->caps.abs_position_x.minimum;
+
+ if (mt->invert_y)
+ y = mt->caps.abs_position_y.maximum - y
+ + mt->caps.abs_position_y.minimum;
+
+ if (mt->swap_xy) {
+ const int tmp = y;
+ y = x;
+ x = tmp;
+ }
+
+ valuators[valix++] = x;
+ valuators[valix++] = y;
+ valuators[valix++] = tp->touch_major;
+
+ if (mt->caps.has_touch_minor)
+ valuators[valix++] = tp->touch_minor;
+ else
+ valuators[valix++] = tp->touch_major;
+
+ valuators[valix++] = tp->tracking_id;
+
+ down++;
+ }
+
+ // Don't deliver more than MaxContacts
+ if (down >= MT_NUM_FINGERS)
+ break;
+ }
+
+ /* Some x-clients assume they get motion events before button down */
+ if (down)
+ xf86PostMotionEventP(local->dev, TRUE,
+ 0, down * MT_AXIS_PER_FINGER, valuators);
+
+ if(down && pdown == 0)
+ xf86PostButtonEventP(local->dev, TRUE,
+ 1, 1,
+ 0, down * MT_AXIS_PER_FINGER, valuators);
+ else if (down == 0 && pdown)
+ xf86PostButtonEvent(local->dev, TRUE, 1, 0, 0, 0);
+
+ pdown = !!down;
+}
+
+/* called for each full received packet from the touchpad */
+static void read_input(LocalDevicePtr local)
+{
+ struct mtev_mtouch *mt = local->private;
+ while (mtouch_read_synchronized_event(mt, local->fd)) {
+ process_state(local, mt);
+ }
+}
+
+static Bool device_control(DeviceIntPtr dev, int mode)
+{
+ LocalDevicePtr local = dev->public.devicePrivate;
+ switch (mode) {
+ case DEVICE_INIT:
+ xf86Msg(X_INFO, "device control: init\n");
+ return device_init(dev, local);
+ case DEVICE_ON:
+ xf86Msg(X_INFO, "device control: on\n");
+ return device_on(local);
+ case DEVICE_OFF:
+ xf86Msg(X_INFO, "device control: off\n");
+ return device_off(local);
+ case DEVICE_CLOSE:
+ xf86Msg(X_INFO, "device control: close\n");
+ return device_close(local);
+ default:
+ xf86Msg(X_INFO, "device control: default\n");
+ return BadValue;
+ }
+}
+
+static InputInfoPtr preinit(InputDriverPtr drv, IDevPtr dev, int flags)
+{
+ struct mtev_mtouch *mt;
+ InputInfoPtr local = xf86AllocateInput(drv, 0);
+ if (!local)
+ goto error;
+ mt = calloc(1, sizeof(struct mtev_mtouch));
+ if (!mt)
+ goto error;
+
+ local->name = dev->identifier;
+ local->type_name = XI_TOUCHSCREEN;
+ local->device_control = device_control;
+ local->read_input = read_input;
+ local->private = mt;
+ local->flags = XI86_POINTER_CAPABLE |
+ XI86_SEND_DRAG_EVENTS;
+
+ local->conf_idev = dev;
+
+ xf86CollectInputOptions(local, NULL, NULL);
+ //xf86OptionListReport(local->options);
+ xf86ProcessCommonOptions(local, local->options);
+
+
+ mt->swap_xy = xf86SetBoolOption(local->options, "SwapAxes", FALSE);
+ mt->invert_x = xf86SetBoolOption(local->options, "InvertX", FALSE);
+ mt->invert_y = xf86SetBoolOption(local->options, "InvertY", FALSE);
+
+ local->flags |= XI86_CONFIGURED;
+
+error:
+ return local;
+}
+
+static void uninit(InputDriverPtr drv, InputInfoPtr local, int flags)
+{
+ free(local->private);
+ local->private = NULL;
+ xf86DeleteInput(local, 0);
+}
+
+static InputDriverRec MTEV = {
+ .driverVersion = 1,
+ .driverName = "mtev",
+ .Identify = NULL,
+ .PreInit = preinit,
+ .UnInit = uninit,
+ .module = NULL,
+ .refCount = 0
+};
+
+static XF86ModuleVersionInfo VERSION = {
+ .modname = "mtev",
+ .vendor = "Nokia",
+ ._modinfo1_ = MODINFOSTRING1,
+ ._modinfo2_ = MODINFOSTRING2,
+ .xf86version = XORG_VERSION_CURRENT,
+ .majorversion = 0,
+ .minorversion = 1,
+ .patchlevel = 12,
+ .abiclass = ABI_CLASS_XINPUT,
+ .abiversion = ABI_XINPUT_VERSION,
+ .moduleclass = MOD_CLASS_XINPUT,
+ .checksum = {0, 0, 0, 0}
+};
+
+static pointer setup(pointer module, pointer options, int *errmaj, int *errmin)
+{
+ xf86AddInputDriver(&MTEV, module, 0);
+ return module;
+}
+
+XF86ModuleData mtevModuleData = {
+ .vers = &VERSION,
+ .setup = &setup,
+ .teardown = NULL
+};