Commit 3ac36d15 authored by Benjamin Tissoires's avatar Benjamin Tissoires Committed by Jiri Kosina

HID: hid-multitouch: fix wrong protocol detection

The previous implementation introduced a randomness in the splitting
of the different touches reported by the device. This version is more
robust as we don't rely on hi->input->absbit, but on our own structure.

This also prepares hid-multitouch to better support Win8 devices.

[Jiri Kosina <jkosina@suse.cz>: fix build]
Signed-off-by: default avatarBenjamin Tissoires <benjamin.tissoires@enac.fr>
Acked-by: default avatarHenrik Rydberg <rydberg@euromail.se>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 16b79bb8
...@@ -70,9 +70,16 @@ struct mt_class { ...@@ -70,9 +70,16 @@ struct mt_class {
bool is_indirect; /* true for touchpads */ bool is_indirect; /* true for touchpads */
}; };
struct mt_fields {
unsigned usages[HID_MAX_FIELDS];
unsigned int length;
};
struct mt_device { struct mt_device {
struct mt_slot curdata; /* placeholder of incoming data */ struct mt_slot curdata; /* placeholder of incoming data */
struct mt_class mtclass; /* our mt device class */ struct mt_class mtclass; /* our mt device class */
struct mt_fields *fields; /* temporary placeholder for storing the
multitouch fields */
unsigned last_field_index; /* last field index of the report */ unsigned last_field_index; /* last field index of the report */
unsigned last_slot_field; /* the last field of a slot */ unsigned last_slot_field; /* the last field of a slot */
__s8 inputmode; /* InputMode HID feature, -1 if non-existent */ __s8 inputmode; /* InputMode HID feature, -1 if non-existent */
...@@ -278,11 +285,15 @@ static void set_abs(struct input_dev *input, unsigned int code, ...@@ -278,11 +285,15 @@ static void set_abs(struct input_dev *input, unsigned int code,
input_set_abs_params(input, code, fmin, fmax, fuzz, 0); input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
} }
static void set_last_slot_field(struct hid_usage *usage, struct mt_device *td, static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
struct hid_input *hi) struct hid_input *hi)
{ {
if (!test_bit(usage->hid, hi->input->absbit)) struct mt_fields *f = td->fields;
td->last_slot_field = usage->hid;
if (f->length >= HID_MAX_FIELDS)
return;
f->usages[f->length++] = usage->hid;
} }
static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
...@@ -333,7 +344,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -333,7 +344,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls->sn_move); cls->sn_move);
/* touchscreen emulation */ /* touchscreen emulation */
set_abs(hi->input, ABS_X, field, cls->sn_move); set_abs(hi->input, ABS_X, field, cls->sn_move);
set_last_slot_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
case HID_GD_Y: case HID_GD_Y:
...@@ -343,7 +354,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -343,7 +354,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls->sn_move); cls->sn_move);
/* touchscreen emulation */ /* touchscreen emulation */
set_abs(hi->input, ABS_Y, field, cls->sn_move); set_abs(hi->input, ABS_Y, field, cls->sn_move);
set_last_slot_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
} }
...@@ -352,24 +363,24 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -352,24 +363,24 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case HID_UP_DIGITIZER: case HID_UP_DIGITIZER:
switch (usage->hid) { switch (usage->hid) {
case HID_DG_INRANGE: case HID_DG_INRANGE:
set_last_slot_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
case HID_DG_CONFIDENCE: case HID_DG_CONFIDENCE:
set_last_slot_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
case HID_DG_TIPSWITCH: case HID_DG_TIPSWITCH:
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
input_set_capability(hi->input, EV_KEY, BTN_TOUCH); input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
set_last_slot_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
case HID_DG_CONTACTID: case HID_DG_CONTACTID:
if (!td->maxcontacts) if (!td->maxcontacts)
td->maxcontacts = MT_DEFAULT_MAXCONTACT; td->maxcontacts = MT_DEFAULT_MAXCONTACT;
input_mt_init_slots(hi->input, td->maxcontacts); input_mt_init_slots(hi->input, td->maxcontacts);
td->last_slot_field = usage->hid; mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
td->touches_by_report++; td->touches_by_report++;
return 1; return 1;
...@@ -378,7 +389,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -378,7 +389,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
EV_ABS, ABS_MT_TOUCH_MAJOR); EV_ABS, ABS_MT_TOUCH_MAJOR);
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
cls->sn_width); cls->sn_width);
set_last_slot_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
case HID_DG_HEIGHT: case HID_DG_HEIGHT:
...@@ -388,7 +399,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -388,7 +399,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
cls->sn_height); cls->sn_height);
input_set_abs_params(hi->input, input_set_abs_params(hi->input,
ABS_MT_ORIENTATION, 0, 1, 0, 0); ABS_MT_ORIENTATION, 0, 1, 0, 0);
set_last_slot_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
case HID_DG_TIPPRESSURE: case HID_DG_TIPPRESSURE:
...@@ -399,7 +410,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, ...@@ -399,7 +410,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
/* touchscreen emulation */ /* touchscreen emulation */
set_abs(hi->input, ABS_PRESSURE, field, set_abs(hi->input, ABS_PRESSURE, field,
cls->sn_pressure); cls->sn_pressure);
set_last_slot_field(usage, td, hi); mt_store_field(usage, td, hi);
td->last_field_index = field->index; td->last_field_index = field->index;
return 1; return 1;
case HID_DG_CONTACTCOUNT: case HID_DG_CONTACTCOUNT:
...@@ -653,6 +664,16 @@ static void mt_post_parse_default_settings(struct mt_device *td) ...@@ -653,6 +664,16 @@ static void mt_post_parse_default_settings(struct mt_device *td)
td->mtclass.quirks = quirks; td->mtclass.quirks = quirks;
} }
static void mt_post_parse(struct mt_device *td)
{
struct mt_fields *f = td->fields;
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];
}
}
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
{ {
int ret, i; int ret, i;
...@@ -683,6 +704,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -683,6 +704,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->maxcontact_report_id = -1; td->maxcontact_report_id = -1;
hid_set_drvdata(hdev, td); hid_set_drvdata(hdev, td);
td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
if (!td->fields) {
dev_err(&hdev->dev, "cannot allocate multitouch fields data\n");
ret = -ENOMEM;
goto fail;
}
ret = hid_parse(hdev); ret = hid_parse(hdev);
if (ret != 0) if (ret != 0)
goto fail; goto fail;
...@@ -691,6 +719,8 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -691,6 +719,8 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret) if (ret)
goto fail; goto fail;
mt_post_parse(td);
if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID)
mt_post_parse_default_settings(td); mt_post_parse_default_settings(td);
...@@ -708,9 +738,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) ...@@ -708,9 +738,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
mt_set_maxcontacts(hdev); mt_set_maxcontacts(hdev);
mt_set_input_mode(hdev); mt_set_input_mode(hdev);
kfree(td->fields);
td->fields = NULL;
return 0; return 0;
fail: fail:
kfree(td->fields);
kfree(td); kfree(td);
return ret; return ret;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment