summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2010-12-16 09:17:48 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2010-12-16 09:17:48 -0800
commit67b989a0c17e34a7c2c095e58a2f3d1b4408e3cb (patch)
treec076d2f0b5d4ae8726a50206042d3e3a41620fe4 /drivers/input
parent56a8bd6dcf81693e61a712097216904f3a4ab536 (diff)
parent69479f8da68f1930b2078b2ebf6533fb00339918 (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rydberg/input-mt into next
Conflicts: drivers/input/Makefile
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/Makefile2
-rw-r--r--drivers/input/input-mt.c170
-rw-r--r--drivers/input/input.c48
-rw-r--r--drivers/input/misc/uinput.c4
-rw-r--r--drivers/input/tablet/wacom_wac.c26
-rw-r--r--drivers/input/tablet/wacom_wac.h4
-rw-r--r--drivers/input/touchscreen/wacom_w8001.c25
7 files changed, 188 insertions, 91 deletions
diff --git a/drivers/input/Makefile b/drivers/input/Makefile
index 9fd1cf2b705e..09614ce74961 100644
--- a/drivers/input/Makefile
+++ b/drivers/input/Makefile
@@ -5,7 +5,7 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_INPUT) += input-core.o
-input-core-y := input.o input-compat.o ff-core.o
+input-core-y := input.o input-compat.o input-mt.o ff-core.o
obj-$(CONFIG_INPUT_FF_MEMLESS) += ff-memless.o
obj-$(CONFIG_INPUT_POLLDEV) += input-polldev.o
diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
new file mode 100644
index 000000000000..c48c81f0308d
--- /dev/null
+++ b/drivers/input/input-mt.c
@@ -0,0 +1,170 @@
+/*
+ * Input Multitouch Library
+ *
+ * Copyright (c) 2008-2010 Henrik Rydberg
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ */
+
+#include <linux/input/mt.h>
+#include <linux/slab.h>
+
+#define TRKID_SGN ((TRKID_MAX + 1) >> 1)
+
+/**
+ * input_mt_init_slots() - initialize MT input slots
+ * @dev: input device supporting MT events and finger tracking
+ * @num_slots: number of slots used by the device
+ *
+ * This function allocates all necessary memory for MT slot handling
+ * in the input device, prepares the ABS_MT_SLOT and
+ * ABS_MT_TRACKING_ID events for use and sets up appropriate buffers.
+ * May be called repeatedly. Returns -EINVAL if attempting to
+ * reinitialize with a different number of slots.
+ */
+int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)
+{
+ int i;
+
+ if (!num_slots)
+ return 0;
+ if (dev->mt)
+ return dev->mtsize != num_slots ? -EINVAL : 0;
+
+ dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
+ if (!dev->mt)
+ return -ENOMEM;
+
+ dev->mtsize = num_slots;
+ input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
+ input_set_abs_params(dev, ABS_MT_TRACKING_ID, 0, TRKID_MAX, 0, 0);
+ input_set_events_per_packet(dev, 6 * num_slots);
+
+ /* Mark slots as 'unused' */
+ for (i = 0; i < num_slots; i++)
+ input_mt_set_value(&dev->mt[i], ABS_MT_TRACKING_ID, -1);
+
+ return 0;
+}
+EXPORT_SYMBOL(input_mt_init_slots);
+
+/**
+ * input_mt_destroy_slots() - frees the MT slots of the input device
+ * @dev: input device with allocated MT slots
+ *
+ * This function is only needed in error path as the input core will
+ * automatically free the MT slots when the device is destroyed.
+ */
+void input_mt_destroy_slots(struct input_dev *dev)
+{
+ kfree(dev->mt);
+ dev->mt = NULL;
+ dev->mtsize = 0;
+ dev->slot = 0;
+ dev->trkid = 0;
+}
+EXPORT_SYMBOL(input_mt_destroy_slots);
+
+/**
+ * input_mt_report_slot_state() - report contact state
+ * @dev: input device with allocated MT slots
+ * @tool_type: the tool type to use in this slot
+ * @active: true if contact is active, false otherwise
+ *
+ * Reports a contact via ABS_MT_TRACKING_ID, and optionally
+ * ABS_MT_TOOL_TYPE. If active is true and the slot is currently
+ * inactive, or if the tool type is changed, a new tracking id is
+ * assigned to the slot. The tool type is only reported if the
+ * corresponding absbit field is set.
+ */
+void input_mt_report_slot_state(struct input_dev *dev,
+ unsigned int tool_type, bool active)
+{
+ struct input_mt_slot *mt;
+ int id;
+
+ if (!dev->mt || !active) {
+ input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
+ return;
+ }
+
+ mt = &dev->mt[dev->slot];
+ id = input_mt_get_value(mt, ABS_MT_TRACKING_ID);
+ if (id < 0 || input_mt_get_value(mt, ABS_MT_TOOL_TYPE) != tool_type)
+ id = input_mt_new_trkid(dev);
+
+ input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
+ input_event(dev, EV_ABS, ABS_MT_TOOL_TYPE, tool_type);
+}
+EXPORT_SYMBOL(input_mt_report_slot_state);
+
+/**
+ * input_mt_report_finger_count() - report contact count
+ * @dev: input device with allocated MT slots
+ * @count: the number of contacts
+ *
+ * Reports the contact count via BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP,
+ * BTN_TOOL_TRIPLETAP and BTN_TOOL_QUADTAP.
+ *
+ * The input core ensures only the KEY events already setup for
+ * this device will produce output.
+ */
+void input_mt_report_finger_count(struct input_dev *dev, int count)
+{
+ input_event(dev, EV_KEY, BTN_TOOL_FINGER, count == 1);
+ input_event(dev, EV_KEY, BTN_TOOL_DOUBLETAP, count == 2);
+ input_event(dev, EV_KEY, BTN_TOOL_TRIPLETAP, count == 3);
+ input_event(dev, EV_KEY, BTN_TOOL_QUADTAP, count == 4);
+}
+EXPORT_SYMBOL(input_mt_report_finger_count);
+
+/**
+ * input_mt_report_pointer_emulation() - common pointer emulation
+ * @dev: input device with allocated MT slots
+ * @use_count: report number of active contacts as finger count
+ *
+ * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
+ * ABS_PRESSURE. Touchpad finger count is emulated if use_count is true.
+ *
+ * The input core ensures only the KEY and ABS axes already setup for
+ * this device will produce output.
+ */
+void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
+{
+ struct input_mt_slot *oldest = 0;
+ int oldid = dev->trkid;
+ int count = 0;
+ int i;
+
+ for (i = 0; i < dev->mtsize; ++i) {
+ struct input_mt_slot *ps = &dev->mt[i];
+ int id = input_mt_get_value(ps, ABS_MT_TRACKING_ID);
+
+ if (id < 0)
+ continue;
+ if ((id - oldid) & TRKID_SGN) {
+ oldest = ps;
+ oldid = id;
+ }
+ count++;
+ }
+
+ input_event(dev, EV_KEY, BTN_TOUCH, count > 0);
+ if (use_count)
+ input_mt_report_finger_count(dev, count);
+
+ if (oldest) {
+ int x = input_mt_get_value(oldest, ABS_MT_POSITION_X);
+ int y = input_mt_get_value(oldest, ABS_MT_POSITION_Y);
+ int p = input_mt_get_value(oldest, ABS_MT_PRESSURE);
+
+ input_event(dev, EV_ABS, ABS_X, x);
+ input_event(dev, EV_ABS, ABS_Y, y);
+ input_event(dev, EV_ABS, ABS_PRESSURE, p);
+ } else {
+ input_event(dev, EV_ABS, ABS_PRESSURE, 0);
+ }
+}
+EXPORT_SYMBOL(input_mt_report_pointer_emulation);
diff --git a/drivers/input/input.c b/drivers/input/input.c
index c7a1e826c580..3312e20016bf 100644
--- a/drivers/input/input.c
+++ b/drivers/input/input.c
@@ -14,7 +14,7 @@
#include <linux/init.h>
#include <linux/types.h>
-#include <linux/input.h>
+#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/random.h>
@@ -1726,52 +1726,6 @@ void input_free_device(struct input_dev *dev)
EXPORT_SYMBOL(input_free_device);
/**
- * input_mt_create_slots() - create MT input slots
- * @dev: input device supporting MT events and finger tracking
- * @num_slots: number of slots used by the device
- *
- * This function allocates all necessary memory for MT slot handling in the
- * input device, and adds ABS_MT_SLOT to the device capabilities. All slots
- * are initially marked as unused by setting ABS_MT_TRACKING_ID to -1.
- */
-int input_mt_create_slots(struct input_dev *dev, unsigned int num_slots)
-{
- int i;
-
- if (!num_slots)
- return 0;
-
- dev->mt = kcalloc(num_slots, sizeof(struct input_mt_slot), GFP_KERNEL);
- if (!dev->mt)
- return -ENOMEM;
-
- dev->mtsize = num_slots;
- input_set_abs_params(dev, ABS_MT_SLOT, 0, num_slots - 1, 0, 0);
-
- /* Mark slots as 'unused' */
- for (i = 0; i < num_slots; i++)
- dev->mt[i].abs[ABS_MT_TRACKING_ID - ABS_MT_FIRST] = -1;
-
- return 0;
-}
-EXPORT_SYMBOL(input_mt_create_slots);
-
-/**
- * input_mt_destroy_slots() - frees the MT slots of the input device
- * @dev: input device with allocated MT slots
- *
- * This function is only needed in error path as the input core will
- * automatically free the MT slots when the device is destroyed.
- */
-void input_mt_destroy_slots(struct input_dev *dev)
-{
- kfree(dev->mt);
- dev->mt = NULL;
- dev->mtsize = 0;
-}
-EXPORT_SYMBOL(input_mt_destroy_slots);
-
-/**
* input_set_capability - mark device as capable of a certain event
* @dev: device that is capable of emitting or accepting event
* @type: type of the event (EV_KEY, EV_REL, etc...)
diff --git a/drivers/input/misc/uinput.c b/drivers/input/misc/uinput.c
index b9410784e6a1..bea89722c4e9 100644
--- a/drivers/input/misc/uinput.c
+++ b/drivers/input/misc/uinput.c
@@ -37,6 +37,7 @@
#include <linux/fs.h>
#include <linux/miscdevice.h>
#include <linux/uinput.h>
+#include <linux/input/mt.h>
#include "../input-compat.h"
static int uinput_dev_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
@@ -406,8 +407,7 @@ static int uinput_setup_device(struct uinput_device *udev, const char __user *bu
goto exit;
if (test_bit(ABS_MT_SLOT, dev->absbit)) {
int nslot = input_abs_get_max(dev, ABS_MT_SLOT) + 1;
- input_mt_create_slots(dev, nslot);
- input_set_events_per_packet(dev, 6 * nslot);
+ input_mt_init_slots(dev, nslot);
} else if (test_bit(ABS_MT_POSITION_X, dev->absbit)) {
input_set_events_per_packet(dev, 60);
}
diff --git a/drivers/input/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
index b3252ef1e279..0b0525486711 100644
--- a/drivers/input/tablet/wacom_wac.c
+++ b/drivers/input/tablet/wacom_wac.c
@@ -14,6 +14,7 @@
#include "wacom_wac.h"
#include "wacom.h"
+#include <linux/input/mt.h>
static int wacom_penpartner_irq(struct wacom_wac *wacom)
{
@@ -862,19 +863,21 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
struct wacom_features *features = &wacom->features;
struct input_dev *input = wacom->input;
unsigned char *data = wacom->data;
- int sp = 0, sx = 0, sy = 0, count = 0;
int i;
for (i = 0; i < 2; i++) {
int p = data[9 * i + 2];
+ bool touch = p && !wacom->shared->stylus_in_proximity;
+
input_mt_slot(input, i);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, touch);
/*
* Touch events need to be disabled while stylus is
* in proximity because user's hand is resting on touchpad
* and sending unwanted events. User expects tablet buttons
* to continue working though.
*/
- if (p && !wacom->shared->stylus_in_proximity) {
+ if (touch) {
int x = get_unaligned_be16(&data[9 * i + 3]) & 0x7ff;
int y = get_unaligned_be16(&data[9 * i + 5]) & 0x7ff;
if (features->quirks & WACOM_QUIRK_BBTOUCH_LOWRES) {
@@ -884,23 +887,10 @@ static int wacom_bpt_touch(struct wacom_wac *wacom)
input_report_abs(input, ABS_MT_PRESSURE, p);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
- if (wacom->id[i] < 0)
- wacom->id[i] = wacom->trk_id++ & MAX_TRACKING_ID;
- if (!count++)
- sp = p, sx = x, sy = y;
- } else {
- wacom->id[i] = -1;
}
- input_report_abs(input, ABS_MT_TRACKING_ID, wacom->id[i]);
}
- input_report_key(input, BTN_TOUCH, count > 0);
- input_report_key(input, BTN_TOOL_FINGER, count == 1);
- input_report_key(input, BTN_TOOL_DOUBLETAP, count == 2);
-
- input_report_abs(input, ABS_PRESSURE, sp);
- input_report_abs(input, ABS_X, sx);
- input_report_abs(input, ABS_Y, sy);
+ input_mt_report_pointer_emulation(input, true);
input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
@@ -1272,7 +1262,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
- input_mt_create_slots(input_dev, 2);
+ input_mt_init_slots(input_dev, 2);
input_set_abs_params(input_dev, ABS_MT_POSITION_X,
0, features->x_max,
features->x_fuzz, 0);
@@ -1282,8 +1272,6 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev,
input_set_abs_params(input_dev, ABS_MT_PRESSURE,
0, features->pressure_max,
features->pressure_fuzz, 0);
- input_set_abs_params(input_dev, ABS_MT_TRACKING_ID, 0,
- MAX_TRACKING_ID, 0, 0);
} else if (features->device_type == BTN_TOOL_PEN) {
__set_bit(BTN_TOOL_RUBBER, input_dev->keybit);
__set_bit(BTN_TOOL_PEN, input_dev->keybit);
diff --git a/drivers/input/tablet/wacom_wac.h b/drivers/input/tablet/wacom_wac.h
index 00ca01541d89..b1310ec9720c 100644
--- a/drivers/input/tablet/wacom_wac.h
+++ b/drivers/input/tablet/wacom_wac.h
@@ -42,9 +42,6 @@
#define WACOM_QUIRK_MULTI_INPUT 0x0001
#define WACOM_QUIRK_BBTOUCH_LOWRES 0x0002
-/* largest reported tracking id */
-#define MAX_TRACKING_ID 0xfff
-
enum {
PENPARTNER = 0,
GRAPHIRE,
@@ -100,7 +97,6 @@ struct wacom_wac {
int id[3];
__u32 serial[2];
int last_finger;
- int trk_id;
struct wacom_features features;
struct wacom_shared *shared;
struct input_dev *input;
diff --git a/drivers/input/touchscreen/wacom_w8001.c b/drivers/input/touchscreen/wacom_w8001.c
index 9ae4c7b16ba7..2a0bec12d12a 100644
--- a/drivers/input/touchscreen/wacom_w8001.c
+++ b/drivers/input/touchscreen/wacom_w8001.c
@@ -15,7 +15,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/input.h>
+#include <linux/input/mt.h>
#include <linux/serio.h>
#include <linux/init.h>
#include <linux/ctype.h>
@@ -48,8 +48,6 @@ MODULE_LICENSE("GPL");
#define W8001_PKTLEN_TPCCTL 11 /* control packet */
#define W8001_PKTLEN_TOUCH2FG 13
-#define MAX_TRACKING_ID 0xFF /* arbitrarily chosen */
-
struct w8001_coord {
u8 rdy;
u8 tsw;
@@ -87,7 +85,6 @@ struct w8001 {
char phys[32];
int type;
unsigned int pktlen;
- int trkid[2];
};
static void parse_data(u8 *data, struct w8001_coord *coord)
@@ -116,28 +113,23 @@ static void parse_data(u8 *data, struct w8001_coord *coord)
static void parse_touch(struct w8001 *w8001)
{
- static int trkid;
struct input_dev *dev = w8001->dev;
unsigned char *data = w8001->data;
int i;
for (i = 0; i < 2; i++) {
- input_mt_slot(dev, i);
+ bool touch = data[0] & (1 << i);
- if (data[0] & (1 << i)) {
+ input_mt_slot(dev, i);
+ input_mt_report_slot_state(dev, MT_TOOL_FINGER, touch);
+ if (touch) {
int x = (data[6 * i + 1] << 7) | (data[6 * i + 2]);
int y = (data[6 * i + 3] << 7) | (data[6 * i + 4]);
/* data[5,6] and [11,12] is finger capacity */
input_report_abs(dev, ABS_MT_POSITION_X, x);
input_report_abs(dev, ABS_MT_POSITION_Y, y);
- input_report_abs(dev, ABS_MT_TOOL_TYPE, MT_TOOL_FINGER);
- if (w8001->trkid[i] < 0)
- w8001->trkid[i] = trkid++ & MAX_TRACKING_ID;
- } else {
- w8001->trkid[i] = -1;
}
- input_report_abs(dev, ABS_MT_TRACKING_ID, w8001->trkid[i]);
}
input_sync(dev);
@@ -318,15 +310,13 @@ static int w8001_setup(struct w8001 *w8001)
case 5:
w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
- input_mt_create_slots(dev, 2);
- input_set_abs_params(dev, ABS_MT_TRACKING_ID,
- 0, MAX_TRACKING_ID, 0, 0);
+ input_mt_init_slots(dev, 2);
input_set_abs_params(dev, ABS_MT_POSITION_X,
0, touch.x, 0, 0);
input_set_abs_params(dev, ABS_MT_POSITION_Y,
0, touch.y, 0, 0);
input_set_abs_params(dev, ABS_MT_TOOL_TYPE,
- 0, 0, 0, 0);
+ 0, MT_TOOL_MAX, 0, 0);
break;
}
}
@@ -372,7 +362,6 @@ static int w8001_connect(struct serio *serio, struct serio_driver *drv)
w8001->serio = serio;
w8001->id = serio->id.id;
w8001->dev = input_dev;
- w8001->trkid[0] = w8001->trkid[1] = -1;
init_completion(&w8001->cmd_done);
snprintf(w8001->phys, sizeof(w8001->phys), "%s/input0", serio->phys);