diff options
author | Zhang Qiang <qiang.z.zhang@intel.com> | 2012-05-18 19:55:31 +0800 |
---|---|---|
committer | Zhang Qiang <qiang.z.zhang@intel.com> | 2012-05-19 14:06:44 +0800 |
commit | 9fe619f25c5e7381596e1b5d4c26b1ddabf1c990 (patch) | |
tree | 7f2d64019b52e2fd04738b28994897d0241a260a /src | |
parent | d53d9359f35c72f861e8ba8a0f563931ed3a6823 (diff) | |
download | xorg-drv-mtev-9fe619f25c5e7381596e1b5d4c26b1ddabf1c990.tar.gz xorg-drv-mtev-9fe619f25c5e7381596e1b5d4c26b1ddabf1c990.tar.bz2 xorg-drv-mtev-9fe619f25c5e7381596e1b5d4c26b1ddabf1c990.zip |
Initial code release
Diffstat (limited to 'src')
-rw-r--r-- | src/caps.c | 143 | ||||
-rw-r--r-- | src/caps.h | 49 | ||||
-rw-r--r-- | src/common.h | 54 | ||||
-rw-r--r-- | src/hw.c | 105 | ||||
-rw-r--r-- | src/hw.h | 52 | ||||
-rw-r--r-- | src/mtouch.c | 110 | ||||
-rw-r--r-- | src/mtouch.h | 83 | ||||
-rw-r--r-- | src/multitouch.c | 434 |
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 +}; |