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/