Re: [PATCH 3/3] input: mt: Move tracking and pointer emulation toinput-mt (rev2)
From: Ping Cheng
Date: Wed Dec 01 2010 - 20:26:22 EST
On Wed, Dec 1, 2010 at 9:21 AM, Henrik Rydberg <rydberg@xxxxxxxxxxx> wrote:
> The drivers using the type B protocol all report tracking information
> the same way. The contact id is semantically equivalent to
> ABS_MT_SLOT, and the handling of ABS_MT_TRACKING_ID only complicates
> the driver. The situation can be improved upon by providing a common
> pointer emulation code, thereby removing the need for the tracking id
> in the driver. This patch moves all tracking event handling over to
> the input core, simplifying both the existing drivers and the ones
> currently in preparation.
>
> Signed-off-by: Henrik Rydberg <rydberg@xxxxxxxxxxx>
Acked-by: Ping Cheng <pingc@xxxxxxxxx>
The changes that are related to Wacom driver look sane to me.
Dmitry,
Please ignore "[PATCH v2] Input: wacom - allow both MT and pen data to
be reported". I'll make a new one based on Henrik's patch.
Ping
> ---
> Hi Dmitry,
>
> This is revision two of this patch, fixing the compilation problem and
> adding the pointer emulation comment. In addition, the fourth patch
> has been folded into this one, and touchpad finger count emulation has
> been added. The original idea was to add this later, but since the
> wacom driver is already touched in this patch, it makes sense to
> switch to pointer emulation here and now.
>
> Cheers,
> Henrik
>
> drivers/hid/hid-3m-pct.c | 30 +----------
> drivers/input/input-mt.c | 91 +++++++++++++++++++++++++++++--
> drivers/input/tablet/wacom_wac.c | 19 +------
> drivers/input/tablet/wacom_wac.h | 4 --
> drivers/input/touchscreen/wacom_w8001.c | 13 +----
> include/linux/input-mt.h | 11 ++++
> include/linux/input.h | 1 +
> 7 files changed, 105 insertions(+), 64 deletions(-)
>
> diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c
> index e3711c5..a9fc2c1 100644
> --- a/drivers/hid/hid-3m-pct.c
> +++ b/drivers/hid/hid-3m-pct.c
> @@ -28,7 +28,6 @@ MODULE_LICENSE("GPL");
> #include "hid-ids.h"
>
> #define MAX_SLOTS 60
> -#define MAX_TRKID USHRT_MAX
>
> /* estimated signal-to-noise ratios */
> #define SN_MOVE 2048
> @@ -36,14 +35,11 @@ MODULE_LICENSE("GPL");etter t
>
> struct mmm_finger {
> __s32 x, y, w, h;
> - __u16 id;
> - bool prev_touch;
> bool touch, valid;
> };
>
> struct mmm_data {
> struct mmm_finger f[MAX_SLOTS];
> - __u16 id;
> __u8 curid;
> __u8 nexp, nreal;
> bool touch, valid;
> @@ -117,11 +113,6 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
> 0, 1, 0, 0);
> return 1;
> case HID_DG_CONTACTID:
> - field->logical_maximum = MAX_TRKID;
> - hid_map_usage(hi, usage, bit, max,
> - EV_ABS, ABS_MT_TRACKING_ID);
> - input_set_abs_params(hi->input, ABS_MT_TRACKING_ID,
> - 0, MAX_TRKID, 0, 0);
> input_mt_init_slots(hi->input, MAX_SLOTS);
> return 1;
> }
> @@ -152,7 +143,6 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
> */
> static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
> {
> - struct mmm_finger *oldest = 0;
> int i;
> for (i = 0; i < MAX_SLOTS; ++i) {
> struct mmm_finger *f = &md->f[i];
> @@ -161,6 +151,7 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
> continue;
> }
> input_mt_slot(input, i);
> + input_mt_report_slot_state(input, f->touch);
> if (f->touch) {
> /* this finger is on the screen */
> int wide = (f->w > f->h);
> @@ -168,33 +159,16 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
> int major = max(f->w, f->h) >> 1;
> int minor = min(f->w, f->h) >> 1;
>
> - if (!f->prev_touch)
> - f->id = md->id++;
> - input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id);
> input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
> input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
> input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
> input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
> input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
> - /* touchscreen emulation: pick the oldest contact */
> - if (!oldest || ((f->id - oldest->id) & (SHRT_MAX + 1)))
> - oldest = f;
> - } else {
> - /* this finger took off the screen */
> - input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1);
> }
> - f->prev_touch = f->touch;
> f->valid = 0;
> }
>
> - /* touchscreen emulation */
> - if (oldest) {
> - input_event(input, EV_KEY, BTN_TOUCH, 1);
> - input_event(input, EV_ABS, ABS_X, oldest->x);
> - input_event(input, EV_ABS, ABS_Y, oldest->y);
> - } else {
> - input_event(input, EV_KEY, BTN_TOUCH, 0);
> - }
> + input_mt_report_pointer_emulation(input);
> input_sync(input);
> }
>
> diff --git a/drivers/input/input-mt.c b/drivers/input/input-mt.c
> index c4a9784..be7264d 100644
> --- a/drivers/input/input-mt.c
> +++ b/drivers/input/input-mt.c
> @@ -11,17 +11,18 @@
> #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, adds ABS_MT_SLOT to the device capabilities
> - * and sets up appropriate event buffers. All slots are initially
> - * marked as unused by setting ABS_MT_TRACKING_ID to -1. May be called
> - * repeatedly. Returns -EINVAL if attempting to reinitialize with a
> - * different number of slots.
> + * 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)
> {
> @@ -38,6 +39,7 @@ int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots)
>
> 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' */
> @@ -61,5 +63,84 @@ void input_mt_destroy_slots(struct input_dev *dev)
> dev->mt = NULL;
> dev->mtsize = 0;
> dev->slot = 0;
> + dev->trkid = 0;
> }
> EXPORT_SYMBOL(input_mt_destroy_slots);
> +
> +/**
> + * input_mt_report_state() - report contact state
> + * @dev: input device with allocated MT slots
> + * @active: true if contact is active, false otherwise
> + *
> + * Reports an active touch via ABS_MT_TRACKING_ID. If active is
> + * true and the slot is currently inactive, a new tracking id is
> + * assigned to the slot.
> + */
> +void input_mt_report_slot_state(struct input_dev *dev, bool active)
> +{
> + struct input_mt_slot *mt = dev->mt;
> + int id;
> +
> + if (!mt || !active) {
> + input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
> + return;
> + }
> +
> + id = input_mt_get_value(&mt[dev->slot], ABS_MT_TRACKING_ID);
> + if (id < 0)
> + id = input_mt_new_trkid(dev);
> + input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, id);
> +}
> +EXPORT_SYMBOL(input_mt_report_slot_state);
> +
> +/**
> + * input_mt_report_pointer_emulation() - common pointer emulation
> + * @dev: input device with allocated MT slots
> + *
> + * Performs legacy pointer emulation via BTN_TOUCH, ABS_X, ABS_Y and
> + * ABS_PRESSURE. Touchpad finger count is emulated using
> + * BTN_TOOL_FINGER, BTN_TOOL_DOUBLETAP, BTN_TOOL_TRIPLETAP and
> + * BTN_TOOL_QUADTAP.
> + *
> + * 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)
> +{
> + 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);
> + 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);
> +
> + 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/tablet/wacom_wac.c b/drivers/input/tablet/wacom_wac.c
> index 3f9e280..86d0be3 100644
> --- a/drivers/input/tablet/wacom_wac.c
> +++ b/drivers/input/tablet/wacom_wac.c
> @@ -863,7 +863,6 @@ 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++) {
> @@ -885,23 +884,13 @@ 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;
> + input_mt_report_slot_state(input, true);
> } else {
> - wacom->id[i] = -1;
> + input_mt_report_slot_state(input, false);
> }
> - 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);
>
> input_report_key(input, BTN_LEFT, (data[1] & 0x08) != 0);
> input_report_key(input, BTN_FORWARD, (data[1] & 0x04) != 0);
> @@ -1283,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 00ca015..b1310ec 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 b706cd5..abf4c6e 100644
> --- a/drivers/input/touchscreen/wacom_w8001.c
> +++ b/drivers/input/touchscreen/wacom_w8001.c
> @@ -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,7 +113,6 @@ 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;
> @@ -132,12 +128,10 @@ static void parse_touch(struct w8001 *w8001)
> 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;
> + input_mt_report_slot_state(dev, true);
> } else {
> - w8001->trkid[i] = -1;
> + input_mt_report_slot_state(dev, false);
> }
> - input_report_abs(dev, ABS_MT_TRACKING_ID, w8001->trkid[i]);
> }
>
> input_sync(dev);
> @@ -319,8 +313,6 @@ static int w8001_setup(struct w8001 *w8001)
> w8001->pktlen = W8001_PKTLEN_TOUCH2FG;
>
> input_mt_init_slots(dev, 2);
> - input_set_abs_params(dev, ABS_MT_TRACKING_ID,
> - 0, MAX_TRACKING_ID, 0, 0);
> input_set_abs_params(dev, ABS_MT_POSITION_X,
> 0, touch.x, 0, 0);
> input_set_abs_params(dev, ABS_MT_POSITION_Y,
> @@ -372,7 +364,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);
>
> diff --git a/include/linux/input-mt.h b/include/linux/input-mt.h
> index d7f6518..1a44567 100644
> --- a/include/linux/input-mt.h
> +++ b/include/linux/input-mt.h
> @@ -13,6 +13,8 @@
>
> #include <linux/input.h>
>
> +#define TRKID_MAX 0xffff
> +
> /**
> * struct input_mt_slot - represents the state of an input MT slot
> * @abs: holds current values of ABS_MT axes for this slot
> @@ -36,9 +38,18 @@ static inline int input_mt_get_value(const struct input_mt_slot *slot,
> int input_mt_init_slots(struct input_dev *dev, unsigned int num_slots);
> void input_mt_destroy_slots(struct input_dev *dev);
>
> +static inline int input_mt_new_trkid(struct input_dev *dev)
> +{
> + return dev->trkid++ & TRKID_MAX;
> +}
> +
> static inline void input_mt_slot(struct input_dev *dev, int slot)
> {
> input_event(dev, EV_ABS, ABS_MT_SLOT, slot);
> }
>
> +void input_mt_report_slot_state(struct input_dev *dev, bool active);
> +
> +void input_mt_report_pointer_emulation(struct input_dev *dev);
> +
> #endif
> diff --git a/include/linux/input.h b/include/linux/input.h
> index dd7c0fc..3b856d6 100644
> --- a/include/linux/input.h
> +++ b/include/linux/input.h
> @@ -1206,6 +1206,7 @@ struct input_dev {
> struct input_mt_slot *mt;
> int mtsize;
> int slot;
> + int trkid;
>
> struct input_absinfo *absinfo;
>
> --
> 1.7.1
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/