OSDN Git Service

HID: multitouch: Store per collection multitouch data
authorBenjamin Tissoires <benjamin.tissoires@redhat.com>
Fri, 13 Jul 2018 14:13:45 +0000 (16:13 +0200)
committerJiri Kosina <jkosina@suse.cz>
Tue, 17 Jul 2018 13:33:47 +0000 (15:33 +0200)
Currently, hid-multitouch can only handle one multitouch collection at
a time. This is an issue for the Dell Canvas, as the Totem (a dial tool)
is also using a multitouch-like collection.

Factor out the multitouch collection data in their own struct.

Acked-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-multitouch.c

index 91624a2..cd207e9 100644 (file)
  */
 
 /*
- * This driver is regularly tested thanks to the tool hid-test[1].
- * This tool relies on hid-replay[2] and a database of hid devices[3].
+ * This driver is regularly tested thanks to the test suite in hid-tools[1].
  * Please run these regression tests before patching this module so that
  * your patch won't break existing known devices.
  *
- * [1] https://github.com/bentiss/hid-test
- * [2] https://github.com/bentiss/hid-replay
- * [3] https://github.com/bentiss/hid-devices
+ * [1] https://gitlab.freedesktop.org/libevdev/hid-tools
  */
 
 #include <linux/device.h>
@@ -99,6 +96,37 @@ struct mt_slot {
        bool has_azimuth;       /* the contact reports azimuth */
 };
 
+struct mt_application {
+       struct list_head list;
+       unsigned int application;
+       struct mt_slot curdata;         /* placeholder of incoming data */
+
+       int cc_index;   /* contact count field index in the report */
+       int cc_value_index;     /* contact count value index in the field */
+       int scantime_index;     /* scantime field index in the report */
+       int scantime_val_index; /* scantime value index in the field */
+       unsigned int last_slot_field;   /* the last field of a slot */
+       bool curvalid;          /* is the current contact valid? */
+
+       int left_button_state;          /* left button state */
+       unsigned int mt_flags;          /* flags to pass to input-mt */
+
+       __u8 num_received;      /* how many contacts we received */
+       __u8 num_expected;      /* expected last contact index */
+       __u8 buttons_count;     /* number of physical buttons per touchpad */
+       __u8 touches_by_report; /* how many touches are present in one report:
+                                * 1 means we should use a serial protocol
+                                * > 1 means hybrid (multitouch) protocol
+                                */
+
+       __s32 dev_time;         /* the scan time provided by the device */
+       unsigned long jiffies;  /* the frame's jiffies */
+       int timestamp;          /* the timestamp to be sent */
+       int prev_scantime;              /* scantime reported previously */
+
+       bool have_contact_count;
+};
+
 struct mt_class {
        __s32 name;     /* MT_CLS */
        __s32 quirks;
@@ -117,40 +145,24 @@ struct mt_fields {
 };
 
 struct mt_device {
-       struct mt_slot curdata; /* placeholder of incoming data */
        struct mt_class mtclass;        /* our mt device class */
        struct timer_list release_timer;        /* to release sticky fingers */
        struct hid_device *hdev;        /* hid_device we're attached to */
        struct mt_fields *fields;       /* temporary placeholder for storing the
                                           multitouch fields */
        unsigned long mt_io_flags;      /* mt flags (MT_IO_FLAGS_*) */
-       int cc_index;   /* contact count field index in the report */
-       int cc_value_index;     /* contact count value index in the field */
-       int scantime_index;     /* scantime field index in the report */
-       int scantime_val_index; /* scantime value index in the field */
-       int prev_scantime;      /* scantime reported in the previous packet */
-       int left_button_state;  /* left button state */
-       unsigned last_slot_field;       /* the last field of a slot */
        unsigned mt_report_id;  /* the report ID of the multitouch device */
        __u8 inputmode_value;   /* InputMode HID feature value */
-       __u8 num_received;      /* how many contacts we received */
-       __u8 num_expected;      /* expected last contact index */
        __u8 maxcontacts;
-       __u8 touches_by_report; /* how many touches are present in one report:
-                               * 1 means we should use a serial protocol
-                               * > 1 means hybrid (multitouch) protocol */
-       __u8 buttons_count;     /* number of physical buttons per touchpad */
        bool is_buttonpad;      /* is this device a button pad? */
        bool serial_maybe;      /* need to check for serial protocol */
-       bool curvalid;          /* is the current contact valid? */
-       unsigned mt_flags;      /* flags to pass to input-mt */
-       __s32 dev_time;         /* the scan time provided by the device */
-       unsigned long jiffies;  /* the frame's jiffies */
-       int timestamp;          /* the timestamp to be sent */
+
+       struct list_head applications;
 };
 
-static void mt_post_parse_default_settings(struct mt_device *td);
-static void mt_post_parse(struct mt_device *td);
+static void mt_post_parse_default_settings(struct mt_device *td,
+                                          struct mt_application *app);
+static void mt_post_parse(struct mt_device *td, struct mt_application *app);
 
 /* classes of device behavior */
 #define MT_CLS_DEFAULT                         0x0001
@@ -203,10 +215,10 @@ static void mt_post_parse(struct mt_device *td);
  * to a valid contact that was just read.
  */
 
-static int cypress_compute_slot(struct mt_device *td)
+static int cypress_compute_slot(struct mt_application *app)
 {
-       if (td->curdata.contactid != 0 || td->num_received == 0)
-               return td->curdata.contactid;
+       if (app->curdata.contactid != 0 || app->num_received == 0)
+               return app->curdata.contactid;
        else
                return -1;
 }
@@ -353,15 +365,22 @@ static ssize_t mt_set_quirks(struct device *dev,
 {
        struct hid_device *hdev = to_hid_device(dev);
        struct mt_device *td = hid_get_drvdata(hdev);
+       struct mt_application *application;
 
        unsigned long val;
+       bool confidence_found = false;
 
        if (kstrtoul(buf, 0, &val))
                return -EINVAL;
 
        td->mtclass.quirks = val;
 
-       if (td->cc_index < 0)
+       list_for_each_entry(application, &td->applications, list) {
+               if (application->have_contact_count)
+                       confidence_found = true;
+       }
+
+       if (!confidence_found)
                td->mtclass.quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
 
        return count;
@@ -457,6 +476,55 @@ static void set_abs(struct input_dev *input, unsigned int code,
        input_abs_set_res(input, code, hidinput_calc_abs_res(field, code));
 }
 
+static struct mt_application *mt_allocate_application(struct mt_device *td,
+                                                     unsigned int application)
+{
+       struct mt_application *mt_application;
+
+       mt_application = devm_kzalloc(&td->hdev->dev, sizeof(*mt_application),
+                                     GFP_KERNEL);
+       if (!mt_application)
+               return NULL;
+
+       mt_application->application = application;
+
+       if (application == HID_DG_TOUCHSCREEN)
+               mt_application->mt_flags |= INPUT_MT_DIRECT;
+
+       /*
+        * Model touchscreens providing buttons as touchpads.
+        */
+       if (application == HID_DG_TOUCHPAD) {
+               mt_application->mt_flags |= INPUT_MT_POINTER;
+               td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
+       }
+
+       mt_application->cc_index = -1;
+       mt_application->scantime_index = -1;
+
+       list_add_tail(&mt_application->list, &td->applications);
+
+       return mt_application;
+}
+
+static struct mt_application *mt_find_application(struct mt_device *td,
+                                                 unsigned int application)
+{
+       struct mt_application *tmp, *mt_application = NULL;
+
+       list_for_each_entry(tmp, &td->applications, list) {
+               if (application == tmp->application) {
+                       mt_application = tmp;
+                       break;
+               }
+       }
+
+       if (!mt_application)
+               mt_application = mt_allocate_application(td, application);
+
+       return mt_application;
+}
+
 static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
                struct hid_input *hi)
 {
@@ -470,28 +538,24 @@ static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
 
 static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                struct hid_field *field, struct hid_usage *usage,
-               unsigned long **bit, int *max)
+               unsigned long **bit, int *max, struct mt_application *app)
 {
        struct mt_device *td = hid_get_drvdata(hdev);
        struct mt_class *cls = &td->mtclass;
        int code;
        struct hid_usage *prev_usage = NULL;
 
-       if (field->application == HID_DG_TOUCHSCREEN)
-               td->mt_flags |= INPUT_MT_DIRECT;
-
        /*
         * Model touchscreens providing buttons as touchpads.
         */
-       if (field->application == HID_DG_TOUCHPAD ||
-           (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
-               td->mt_flags |= INPUT_MT_POINTER;
+       if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) {
+               app->mt_flags |= INPUT_MT_POINTER;
                td->inputmode_value = MT_INPUTMODE_TOUCHPAD;
        }
 
        /* count the buttons on touchpads */
        if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
-               td->buttons_count++;
+               app->buttons_count++;
 
        if (usage->usage_index)
                prev_usage = &field->usage[usage->usage_index - 1];
@@ -501,33 +565,23 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        case HID_UP_GENDESK:
                switch (usage->hid) {
                case HID_GD_X:
-                       if (prev_usage && (prev_usage->hid == usage->hid)) {
-                               hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_TOOL_X);
-                               set_abs(hi->input, ABS_MT_TOOL_X, field,
-                                       cls->sn_move);
-                       } else {
-                               hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_POSITION_X);
-                               set_abs(hi->input, ABS_MT_POSITION_X, field,
-                                       cls->sn_move);
-                       }
+                       if (prev_usage && (prev_usage->hid == usage->hid))
+                               code = ABS_MT_TOOL_X;
+                       else
+                               code = ABS_MT_POSITION_X;
 
+                       hid_map_usage(hi, usage, bit, max, EV_ABS, code);
+                       set_abs(hi->input, code, field, cls->sn_move);
                        mt_store_field(usage, td, hi);
                        return 1;
                case HID_GD_Y:
-                       if (prev_usage && (prev_usage->hid == usage->hid)) {
-                               hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_TOOL_Y);
-                               set_abs(hi->input, ABS_MT_TOOL_Y, field,
-                                       cls->sn_move);
-                       } else {
-                               hid_map_usage(hi, usage, bit, max,
-                                       EV_ABS, ABS_MT_POSITION_Y);
-                               set_abs(hi->input, ABS_MT_POSITION_Y, field,
-                                       cls->sn_move);
-                       }
+                       if (prev_usage && (prev_usage->hid == usage->hid))
+                               code = ABS_MT_TOOL_Y;
+                       else
+                               code = ABS_MT_POSITION_Y;
 
+                       hid_map_usage(hi, usage, bit, max, EV_ABS, code);
+                       set_abs(hi->input, code, field, cls->sn_move);
                        mt_store_field(usage, td, hi);
                        return 1;
                }
@@ -558,7 +612,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        return 1;
                case HID_DG_CONTACTID:
                        mt_store_field(usage, td, hi);
-                       td->touches_by_report++;
+                       app->touches_by_report++;
                        td->mt_report_id = field->report->id;
                        return 1;
                case HID_DG_WIDTH:
@@ -602,20 +656,16 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                        if (field->index >= field->report->maxfield ||
                            usage->usage_index >= field->report_count)
                                return 1;
-                       td->scantime_index = field->index;
-                       td->scantime_val_index = usage->usage_index;
-                       /*
-                        * We don't set td->last_slot_field as scan time is
-                        * global to the report.
-                        */
+                       app->scantime_index = field->index;
+                       app->scantime_val_index = usage->usage_index;
                        return 1;
                case HID_DG_CONTACTCOUNT:
                        /* Ignore if indexes are out of bounds. */
                        if (field->index >= field->report->maxfield ||
                            usage->usage_index >= field->report_count)
                                return 1;
-                       td->cc_index = field->index;
-                       td->cc_value_index = usage->usage_index;
+                       app->cc_index = field->index;
+                       app->cc_value_index = usage->usage_index;
                        return 1;
                case HID_DG_AZIMUTH:
                        hid_map_usage(hi, usage, bit, max,
@@ -666,39 +716,41 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
        return 0;
 }
 
-static int mt_compute_slot(struct mt_device *td, struct input_dev *input)
+static int mt_compute_slot(struct mt_device *td, struct mt_application *app,
+                          struct input_dev *input)
 {
        __s32 quirks = td->mtclass.quirks;
 
        if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
-               return td->curdata.contactid;
+               return app->curdata.contactid;
 
        if (quirks & MT_QUIRK_CYPRESS)
-               return cypress_compute_slot(td);
+               return cypress_compute_slot(app);
 
        if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
-               return td->num_received;
+               return app->num_received;
 
        if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE)
-               return td->curdata.contactid - 1;
+               return app->curdata.contactid - 1;
 
-       return input_mt_get_slot_by_key(input, td->curdata.contactid);
+       return input_mt_get_slot_by_key(input, app->curdata.contactid);
 }
 
 /*
  * this function is called when a whole contact has been processed,
  * so that it can assign it to a slot and store the data there
  */
-static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
+static void mt_complete_slot(struct mt_device *td, struct mt_application *app,
+                            struct input_dev *input)
 {
        if ((td->mtclass.quirks & MT_QUIRK_CONTACT_CNT_ACCURATE) &&
-           td->num_received >= td->num_expected)
+           app->num_received >= app->num_expected)
                return;
 
-       if (td->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
+       if (app->curvalid || (td->mtclass.quirks & MT_QUIRK_ALWAYS_VALID)) {
                int active;
-               int slotnum = mt_compute_slot(td, input);
-               struct mt_slot *s = &td->curdata;
+               int slotnum = mt_compute_slot(td, app, input);
+               struct mt_slot *s = &app->curdata;
                struct input_mt *mt = input->mt;
 
                if (slotnum < 0 || slotnum >= td->maxcontacts)
@@ -753,23 +805,25 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input)
                }
        }
 
-       td->num_received++;
+       app->num_received++;
 }
 
 /*
  * this function is called when a whole packet has been received and processed,
  * so that it can decide what to send to the input layer.
  */
-static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
+static void mt_sync_frame(struct mt_device *td, struct mt_application *app,
+                         struct input_dev *input)
 {
        if (td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS)
-               input_event(input, EV_KEY, BTN_LEFT, td->left_button_state);
+               input_event(input, EV_KEY, BTN_LEFT, app->left_button_state);
 
        input_mt_sync_frame(input);
-       input_event(input, EV_MSC, MSC_TIMESTAMP, td->timestamp);
+       input_event(input, EV_MSC, MSC_TIMESTAMP, app->timestamp);
        input_sync(input);
-       td->num_received = 0;
-       td->left_button_state = 0;
+       app->num_received = 0;
+       app->left_button_state = 0;
+
        if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags))
                set_bit(MT_IO_FLAGS_PENDING_SLOTS, &td->mt_io_flags);
        else
@@ -777,14 +831,13 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
        clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags);
 }
 
-static int mt_compute_timestamp(struct mt_device *td, struct hid_field *field,
-               __s32 value)
+static int mt_compute_timestamp(struct mt_application *app,
+                               struct hid_field *field, __s32 value)
 {
-       long delta = value - td->dev_time;
-       unsigned long jdelta = jiffies_to_usecs(jiffies - td->jiffies);
+       long delta = value - app->prev_scantime;
+       unsigned long jdelta = jiffies_to_usecs(jiffies - app->jiffies);
 
-       td->jiffies = jiffies;
-       td->dev_time = value;
+       app->jiffies = jiffies;
 
        if (delta < 0)
                delta += field->logical_maximum;
@@ -796,7 +849,7 @@ static int mt_compute_timestamp(struct mt_device *td, struct hid_field *field,
                /* No data received for a while, resync the timestamp. */
                return 0;
        else
-               return td->timestamp + delta;
+               return app->timestamp + delta;
 }
 
 static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
@@ -811,7 +864,7 @@ static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
 
 static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
                                struct hid_usage *usage, __s32 value,
-                               bool first_packet)
+                               struct mt_application *app, bool first_packet)
 {
        struct mt_device *td = hid_get_drvdata(hid);
        __s32 quirks = td->mtclass.quirks;
@@ -821,47 +874,48 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
                switch (usage->hid) {
                case HID_DG_INRANGE:
                        if (quirks & MT_QUIRK_VALID_IS_INRANGE)
-                               td->curvalid = value;
+                               app->curvalid = value;
                        if (quirks & MT_QUIRK_HOVERING)
-                               td->curdata.inrange_state = value;
+                               app->curdata.inrange_state = value;
                        break;
                case HID_DG_TIPSWITCH:
                        if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
-                               td->curvalid = value;
-                       td->curdata.touch_state = value;
+                               app->curvalid = value;
+                       app->curdata.touch_state = value;
                        break;
                case HID_DG_CONFIDENCE:
                        if (quirks & MT_QUIRK_CONFIDENCE)
-                               td->curdata.confidence_state = value;
+                               app->curdata.confidence_state = value;
                        if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
-                               td->curvalid = value;
+                               app->curvalid = value;
                        break;
                case HID_DG_CONTACTID:
-                       td->curdata.contactid = value;
+                       app->curdata.contactid = value;
                        break;
                case HID_DG_TIPPRESSURE:
-                       td->curdata.p = value;
+                       app->curdata.p = value;
                        break;
                case HID_GD_X:
                        if (usage->code == ABS_MT_TOOL_X)
-                               td->curdata.cx = value;
+                               app->curdata.cx = value;
                        else
-                               td->curdata.x = value;
+                               app->curdata.x = value;
                        break;
                case HID_GD_Y:
                        if (usage->code == ABS_MT_TOOL_Y)
-                               td->curdata.cy = value;
+                               app->curdata.cy = value;
                        else
-                               td->curdata.y = value;
+                               app->curdata.y = value;
                        break;
                case HID_DG_WIDTH:
-                       td->curdata.w = value;
+                       app->curdata.w = value;
                        break;
                case HID_DG_HEIGHT:
-                       td->curdata.h = value;
+                       app->curdata.h = value;
                        break;
                case HID_DG_SCANTIME:
-                       td->timestamp = mt_compute_timestamp(td, field, value);
+                       app->timestamp = mt_compute_timestamp(app, field,
+                                                             value);
                        break;
                case HID_DG_CONTACTCOUNT:
                        break;
@@ -878,8 +932,8 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
                         */
                        if (value > field->logical_maximum / 2)
                                value -= field->logical_maximum;
-                       td->curdata.a = -value;
-                       td->curdata.has_azimuth = true;
+                       app->curdata.a = -value;
+                       app->curdata.has_azimuth = true;
                        break;
                case HID_DG_TOUCH:
                        /* do nothing */
@@ -904,7 +958,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
                         */
                        if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
                            usage->type == EV_KEY && usage->code == BTN_LEFT) {
-                               td->left_button_state |= value;
+                               app->left_button_state |= value;
                                return;
                        }
 
@@ -916,8 +970,9 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 
                if (usage->usage_index + 1 == field->report_count) {
                        /* we only take into account the last report. */
-                       if (usage->hid == td->last_slot_field)
-                               mt_complete_slot(td, field->hidinput->input);
+                       if (usage->hid == app->last_slot_field)
+                               mt_complete_slot(td, app,
+                                                field->hidinput->input);
                }
 
        }
@@ -926,26 +981,34 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
 static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
 {
        struct mt_device *td = hid_get_drvdata(hid);
+       struct mt_application *app;
        struct hid_field *field;
        bool first_packet;
        unsigned count;
-       int r, n, scantime = 0;
+       int r, n;
+       int scantime = 0;
+       int contact_count = -1;
 
        /* sticky fingers release in progress, abort */
        if (test_and_set_bit(MT_IO_FLAGS_RUNNING, &td->mt_io_flags))
                return;
 
+       app = mt_find_application(td, report->application);
+
+       if (!app)
+               return;
+
        /*
         * Includes multi-packet support where subsequent
         * packets are sent with zero contactcount.
         */
-       if (td->scantime_index >= 0) {
-               field = report->field[td->scantime_index];
-               scantime = field->value[td->scantime_val_index];
+       if (app->scantime_index >= 0) {
+               field = report->field[app->scantime_index];
+               scantime = field->value[app->scantime_val_index];
        }
-       if (td->cc_index >= 0) {
-               struct hid_field *field = report->field[td->cc_index];
-               int value = field->value[td->cc_value_index];
+       if (app->cc_index >= 0) {
+               field = report->field[app->cc_index];
+               contact_count = field->value[app->cc_value_index];
 
                /*
                 * For Win8 PTPs the first packet (td->num_received == 0) may
@@ -955,15 +1018,16 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
                 * timestamp has changed.
                 */
                if ((td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS) &&
-                   td->num_received == 0 && td->prev_scantime != scantime)
-                       td->num_expected = value;
+                   app->num_received == 0 &&
+                   app->prev_scantime != scantime)
+                       app->num_expected = contact_count;
                /* A non 0 contact count always indicates a first packet */
-               else if (value)
-                       td->num_expected = value;
+               else if (contact_count)
+                       app->num_expected = contact_count;
        }
-       td->prev_scantime = scantime;
+       app->prev_scantime = scantime;
 
-       first_packet = td->num_received == 0;
+       first_packet = app->num_received == 0;
        for (r = 0; r < report->maxfield; r++) {
                field = report->field[r];
                count = field->report_count;
@@ -973,11 +1037,11 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
 
                for (n = 0; n < count; n++)
                        mt_process_mt_event(hid, field, &field->usage[n],
-                                           field->value[n], first_packet);
+                                           field->value[n], app, first_packet);
        }
 
-       if (td->num_received >= td->num_expected)
-               mt_sync_frame(td, report->field[0]->hidinput->input);
+       if (app->num_received >= app->num_expected)
+               mt_sync_frame(td, app, report->field[0]->hidinput->input);
 
        /*
         * Windows 8 specs says 2 things:
@@ -1009,7 +1073,8 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
 }
 
 static int mt_touch_input_configured(struct hid_device *hdev,
-                                       struct hid_input *hi)
+                                    struct hid_input *hi,
+                                    struct mt_application *app)
 {
        struct mt_device *td = hid_get_drvdata(hdev);
        struct mt_class *cls = &td->mtclass;
@@ -1019,28 +1084,29 @@ static int mt_touch_input_configured(struct hid_device *hdev,
        if (!td->maxcontacts)
                td->maxcontacts = MT_DEFAULT_MAXCONTACT;
 
-       mt_post_parse(td);
+       mt_post_parse(td, app);
        if (td->serial_maybe)
-               mt_post_parse_default_settings(td);
+               mt_post_parse_default_settings(td, app);
 
        if (cls->is_indirect)
-               td->mt_flags |= INPUT_MT_POINTER;
+               app->mt_flags |= INPUT_MT_POINTER;
 
        if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
-               td->mt_flags |= INPUT_MT_DROP_UNUSED;
+               app->mt_flags |= INPUT_MT_DROP_UNUSED;
 
        /* check for clickpads */
-       if ((td->mt_flags & INPUT_MT_POINTER) && (td->buttons_count == 1))
+       if ((app->mt_flags & INPUT_MT_POINTER) &&
+           (app->buttons_count == 1))
                td->is_buttonpad = true;
 
        if (td->is_buttonpad)
                __set_bit(INPUT_PROP_BUTTONPAD, input->propbit);
 
-       ret = input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
+       ret = input_mt_init_slots(input, td->maxcontacts, app->mt_flags);
        if (ret)
                return ret;
 
-       td->mt_flags = 0;
+       app->mt_flags = 0;
        return 0;
 }
 
@@ -1051,6 +1117,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                unsigned long **bit, int *max)
 {
        struct mt_device *td = hid_get_drvdata(hdev);
+       struct mt_application *application;
 
        /*
         * If mtclass.export_all_inputs is not set, only map fields from
@@ -1093,6 +1160,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
                return 1;
        }
 
+       application = mt_find_application(td, field->application);
+
        /*
         * some egalax touchscreens have "application == HID_DG_TOUCHSCREEN"
         * for the stylus.
@@ -1109,7 +1178,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 
        if (field->application == HID_DG_TOUCHSCREEN ||
            field->application == HID_DG_TOUCHPAD)
-               return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
+               return mt_touch_input_mapping(hdev, hi, field, usage, bit, max,
+                                             application);
 
        /* let hid-core decide for the others */
        return 0;
@@ -1259,12 +1329,13 @@ static void mt_set_modes(struct hid_device *hdev, enum latency_mode latency,
        }
 }
 
-static void mt_post_parse_default_settings(struct mt_device *td)
+static void mt_post_parse_default_settings(struct mt_device *td,
+                                          struct mt_application *app)
 {
        __s32 quirks = td->mtclass.quirks;
 
        /* unknown serial device needs special quirks */
-       if (td->touches_by_report == 1) {
+       if (app->touches_by_report == 1) {
                quirks |= MT_QUIRK_ALWAYS_VALID;
                quirks &= ~MT_QUIRK_NOT_SEEN_MEANS_UP;
                quirks &= ~MT_QUIRK_VALID_IS_INRANGE;
@@ -1275,17 +1346,19 @@ static void mt_post_parse_default_settings(struct mt_device *td)
        td->mtclass.quirks = quirks;
 }
 
-static void mt_post_parse(struct mt_device *td)
+static void mt_post_parse(struct mt_device *td, struct mt_application *app)
 {
        struct mt_fields *f = td->fields;
        struct mt_class *cls = &td->mtclass;
 
-       if (td->touches_by_report > 0) {
-               int field_count_per_touch = f->length / td->touches_by_report;
-               td->last_slot_field = f->usages[field_count_per_touch - 1];
+       if (app->touches_by_report > 0) {
+               int field_count_per_touch;
+
+               field_count_per_touch = f->length / app->touches_by_report;
+               app->last_slot_field = f->usages[field_count_per_touch - 1];
        }
 
-       if (td->cc_index < 0)
+       if (app->cc_index < 0)
                cls->quirks &= ~MT_QUIRK_CONTACT_CNT_ACCURATE;
 }
 
@@ -1295,13 +1368,17 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
        char *name;
        const char *suffix = NULL;
        unsigned int application = 0;
+       struct mt_application *mt_application = NULL;
        struct hid_report *report;
        int ret;
 
        list_for_each_entry(report, &hi->reports, hidinput_list) {
                application = report->application;
+               mt_application = mt_find_application(td, application);
+
                if (report->id == td->mt_report_id) {
-                       ret = mt_touch_input_configured(hdev, hi);
+                       ret = mt_touch_input_configured(hdev, hi,
+                                                       mt_application);
                        if (ret)
                                return ret;
                }
@@ -1390,6 +1467,7 @@ static void mt_fix_const_fields(struct hid_device *hdev, unsigned int usage)
 static void mt_release_contacts(struct hid_device *hid)
 {
        struct hid_input *hidinput;
+       struct mt_application *application;
        struct mt_device *td = hid_get_drvdata(hid);
 
        list_for_each_entry(hidinput, &hid->inputs, list) {
@@ -1409,7 +1487,9 @@ static void mt_release_contacts(struct hid_device *hid)
                }
        }
 
-       td->num_received = 0;
+       list_for_each_entry(application, &td->applications, list) {
+               application->num_received = 0;
+       }
 }
 
 static void mt_expired_timeout(struct timer_list *t)
@@ -1449,11 +1529,11 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
        td->hdev = hdev;
        td->mtclass = *mtclass;
        td->inputmode_value = MT_INPUTMODE_TOUCHSCREEN;
-       td->cc_index = -1;
-       td->scantime_index = -1;
        td->mt_report_id = -1;
        hid_set_drvdata(hdev, td);
 
+       INIT_LIST_HEAD(&td->applications);
+
        td->fields = devm_kzalloc(&hdev->dev, sizeof(struct mt_fields),
                                  GFP_KERNEL);
        if (!td->fields) {