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: Benjamin Tissoires <benjamin.tissoires@enac.fr> Acked-by: Henrik Rydberg <rydberg@euromail.se> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
This commit is contained in:
Родитель
16b79bb8ec
Коммит
3ac36d1555
|
@ -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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
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,
|
||||||
/* 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)
|
||||||
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)
|
||||||
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)
|
||||||
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)
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче