diff options
author | Benjamin Tissoires <benjamin.tissoires@enac.fr> | 2012-05-04 08:53:46 -0400 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2012-05-10 05:35:43 -0400 |
commit | 3ac36d15557d1bedfb1151d9911b9587b2d40759 (patch) | |
tree | e69d4cfdd77ddeff31e9296a081d5bd502473184 /drivers/hid/hid-multitouch.c | |
parent | 16b79bb8ec4f20527525f8c063ae3e4d77388e97 (diff) |
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>
Diffstat (limited to 'drivers/hid/hid-multitouch.c')
-rw-r--r-- | drivers/hid/hid-multitouch.c | 58 |
1 files changed, 46 insertions, 12 deletions
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 25b94253e68f..6e3332a99976 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c | |||
@@ -70,9 +70,16 @@ struct mt_class { | |||
70 | bool is_indirect; /* true for touchpads */ | 70 | bool is_indirect; /* true for touchpads */ |
71 | }; | 71 | }; |
72 | 72 | ||
73 | struct mt_fields { | ||
74 | unsigned usages[HID_MAX_FIELDS]; | ||
75 | unsigned int length; | ||
76 | }; | ||
77 | |||
73 | struct mt_device { | 78 | struct mt_device { |
74 | struct mt_slot curdata; /* placeholder of incoming data */ | 79 | struct mt_slot curdata; /* placeholder of incoming data */ |
75 | struct mt_class mtclass; /* our mt device class */ | 80 | struct mt_class mtclass; /* our mt device class */ |
81 | struct mt_fields *fields; /* temporary placeholder for storing the | ||
82 | multitouch fields */ | ||
76 | unsigned last_field_index; /* last field index of the report */ | 83 | unsigned last_field_index; /* last field index of the report */ |
77 | unsigned last_slot_field; /* the last field of a slot */ | 84 | unsigned last_slot_field; /* the last field of a slot */ |
78 | __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ | 85 | __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 | input_set_abs_params(input, code, fmin, fmax, fuzz, 0); | 285 | input_set_abs_params(input, code, fmin, fmax, fuzz, 0); |
279 | } | 286 | } |
280 | 287 | ||
281 | static void set_last_slot_field(struct hid_usage *usage, struct mt_device *td, | 288 | static void mt_store_field(struct hid_usage *usage, struct mt_device *td, |
282 | struct hid_input *hi) | 289 | struct hid_input *hi) |
283 | { | 290 | { |
284 | if (!test_bit(usage->hid, hi->input->absbit)) | 291 | struct mt_fields *f = td->fields; |
285 | td->last_slot_field = usage->hid; | 292 | |
293 | if (f->length >= HID_MAX_FIELDS) | ||
294 | return; | ||
295 | |||
296 | f->usages[f->length++] = usage->hid; | ||
286 | } | 297 | } |
287 | 298 | ||
288 | static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | 299 | 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 | cls->sn_move); | 344 | cls->sn_move); |
334 | /* touchscreen emulation */ | 345 | /* touchscreen emulation */ |
335 | set_abs(hi->input, ABS_X, field, cls->sn_move); | 346 | set_abs(hi->input, ABS_X, field, cls->sn_move); |
336 | set_last_slot_field(usage, td, hi); | 347 | mt_store_field(usage, td, hi); |
337 | td->last_field_index = field->index; | 348 | td->last_field_index = field->index; |
338 | return 1; | 349 | return 1; |
339 | case HID_GD_Y: | 350 | case HID_GD_Y: |
@@ -343,7 +354,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
343 | cls->sn_move); | 354 | cls->sn_move); |
344 | /* touchscreen emulation */ | 355 | /* touchscreen emulation */ |
345 | set_abs(hi->input, ABS_Y, field, cls->sn_move); | 356 | set_abs(hi->input, ABS_Y, field, cls->sn_move); |
346 | set_last_slot_field(usage, td, hi); | 357 | mt_store_field(usage, td, hi); |
347 | td->last_field_index = field->index; | 358 | td->last_field_index = field->index; |
348 | return 1; | 359 | return 1; |
349 | } | 360 | } |
@@ -352,24 +363,24 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
352 | case HID_UP_DIGITIZER: | 363 | case HID_UP_DIGITIZER: |
353 | switch (usage->hid) { | 364 | switch (usage->hid) { |
354 | case HID_DG_INRANGE: | 365 | case HID_DG_INRANGE: |
355 | set_last_slot_field(usage, td, hi); | 366 | mt_store_field(usage, td, hi); |
356 | td->last_field_index = field->index; | 367 | td->last_field_index = field->index; |
357 | return 1; | 368 | return 1; |
358 | case HID_DG_CONFIDENCE: | 369 | case HID_DG_CONFIDENCE: |
359 | set_last_slot_field(usage, td, hi); | 370 | mt_store_field(usage, td, hi); |
360 | td->last_field_index = field->index; | 371 | td->last_field_index = field->index; |
361 | return 1; | 372 | return 1; |
362 | case HID_DG_TIPSWITCH: | 373 | case HID_DG_TIPSWITCH: |
363 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); | 374 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); |
364 | input_set_capability(hi->input, EV_KEY, BTN_TOUCH); | 375 | input_set_capability(hi->input, EV_KEY, BTN_TOUCH); |
365 | set_last_slot_field(usage, td, hi); | 376 | mt_store_field(usage, td, hi); |
366 | td->last_field_index = field->index; | 377 | td->last_field_index = field->index; |
367 | return 1; | 378 | return 1; |
368 | case HID_DG_CONTACTID: | 379 | case HID_DG_CONTACTID: |
369 | if (!td->maxcontacts) | 380 | if (!td->maxcontacts) |
370 | td->maxcontacts = MT_DEFAULT_MAXCONTACT; | 381 | td->maxcontacts = MT_DEFAULT_MAXCONTACT; |
371 | input_mt_init_slots(hi->input, td->maxcontacts); | 382 | input_mt_init_slots(hi->input, td->maxcontacts); |
372 | td->last_slot_field = usage->hid; | 383 | mt_store_field(usage, td, hi); |
373 | td->last_field_index = field->index; | 384 | td->last_field_index = field->index; |
374 | td->touches_by_report++; | 385 | td->touches_by_report++; |
375 | return 1; | 386 | return 1; |
@@ -378,7 +389,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
378 | EV_ABS, ABS_MT_TOUCH_MAJOR); | 389 | EV_ABS, ABS_MT_TOUCH_MAJOR); |
379 | set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, | 390 | set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, |
380 | cls->sn_width); | 391 | cls->sn_width); |
381 | set_last_slot_field(usage, td, hi); | 392 | mt_store_field(usage, td, hi); |
382 | td->last_field_index = field->index; | 393 | td->last_field_index = field->index; |
383 | return 1; | 394 | return 1; |
384 | case HID_DG_HEIGHT: | 395 | case HID_DG_HEIGHT: |
@@ -388,7 +399,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
388 | cls->sn_height); | 399 | cls->sn_height); |
389 | input_set_abs_params(hi->input, | 400 | input_set_abs_params(hi->input, |
390 | ABS_MT_ORIENTATION, 0, 1, 0, 0); | 401 | ABS_MT_ORIENTATION, 0, 1, 0, 0); |
391 | set_last_slot_field(usage, td, hi); | 402 | mt_store_field(usage, td, hi); |
392 | td->last_field_index = field->index; | 403 | td->last_field_index = field->index; |
393 | return 1; | 404 | return 1; |
394 | case HID_DG_TIPPRESSURE: | 405 | case HID_DG_TIPPRESSURE: |
@@ -399,7 +410,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
399 | /* touchscreen emulation */ | 410 | /* touchscreen emulation */ |
400 | set_abs(hi->input, ABS_PRESSURE, field, | 411 | set_abs(hi->input, ABS_PRESSURE, field, |
401 | cls->sn_pressure); | 412 | cls->sn_pressure); |
402 | set_last_slot_field(usage, td, hi); | 413 | mt_store_field(usage, td, hi); |
403 | td->last_field_index = field->index; | 414 | td->last_field_index = field->index; |
404 | return 1; | 415 | return 1; |
405 | case HID_DG_CONTACTCOUNT: | 416 | case HID_DG_CONTACTCOUNT: |
@@ -653,6 +664,16 @@ static void mt_post_parse_default_settings(struct mt_device *td) | |||
653 | td->mtclass.quirks = quirks; | 664 | td->mtclass.quirks = quirks; |
654 | } | 665 | } |
655 | 666 | ||
667 | static void mt_post_parse(struct mt_device *td) | ||
668 | { | ||
669 | struct mt_fields *f = td->fields; | ||
670 | |||
671 | if (td->touches_by_report > 0) { | ||
672 | int field_count_per_touch = f->length / td->touches_by_report; | ||
673 | td->last_slot_field = f->usages[field_count_per_touch - 1]; | ||
674 | } | ||
675 | } | ||
676 | |||
656 | static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | 677 | static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) |
657 | { | 678 | { |
658 | int ret, i; | 679 | int ret, i; |
@@ -683,6 +704,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
683 | td->maxcontact_report_id = -1; | 704 | td->maxcontact_report_id = -1; |
684 | hid_set_drvdata(hdev, td); | 705 | hid_set_drvdata(hdev, td); |
685 | 706 | ||
707 | td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL); | ||
708 | if (!td->fields) { | ||
709 | dev_err(&hdev->dev, "cannot allocate multitouch fields data\n"); | ||
710 | ret = -ENOMEM; | ||
711 | goto fail; | ||
712 | } | ||
713 | |||
686 | ret = hid_parse(hdev); | 714 | ret = hid_parse(hdev); |
687 | if (ret != 0) | 715 | if (ret != 0) |
688 | goto fail; | 716 | goto fail; |
@@ -691,6 +719,8 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
691 | if (ret) | 719 | if (ret) |
692 | goto fail; | 720 | goto fail; |
693 | 721 | ||
722 | mt_post_parse(td); | ||
723 | |||
694 | if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) | 724 | if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) |
695 | mt_post_parse_default_settings(td); | 725 | mt_post_parse_default_settings(td); |
696 | 726 | ||
@@ -708,9 +738,13 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
708 | mt_set_maxcontacts(hdev); | 738 | mt_set_maxcontacts(hdev); |
709 | mt_set_input_mode(hdev); | 739 | mt_set_input_mode(hdev); |
710 | 740 | ||
741 | kfree(td->fields); | ||
742 | td->fields = NULL; | ||
743 | |||
711 | return 0; | 744 | return 0; |
712 | 745 | ||
713 | fail: | 746 | fail: |
747 | kfree(td->fields); | ||
714 | kfree(td); | 748 | kfree(td); |
715 | return ret; | 749 | return ret; |
716 | } | 750 | } |