Commit 3ac36d15557d1bedfb1151d9911b9587b2d40759
Committed by
Jiri Kosina
1 parent
16b79bb8ec
Exists in
smarc-l5.0.0_1.0.0-ga
and in
5 other branches
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>
Showing 1 changed file with 46 additions and 12 deletions Side-by-side Diff
drivers/hid/hid-multitouch.c
... | ... | @@ -70,9 +70,16 @@ |
70 | 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 | 78 | struct mt_device { |
74 | 79 | struct mt_slot curdata; /* placeholder of incoming data */ |
75 | 80 | struct mt_class mtclass; /* our mt device class */ |
81 | + struct mt_fields *fields; /* temporary placeholder for storing the | |
82 | + multitouch fields */ | |
76 | 83 | unsigned last_field_index; /* last field index of the report */ |
77 | 84 | unsigned last_slot_field; /* the last field of a slot */ |
78 | 85 | __s8 inputmode; /* InputMode HID feature, -1 if non-existent */ |
79 | 86 | |
... | ... | @@ -278,11 +285,15 @@ |
278 | 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 | 289 | struct hid_input *hi) |
283 | 290 | { |
284 | - if (!test_bit(usage->hid, hi->input->absbit)) | |
285 | - td->last_slot_field = usage->hid; | |
291 | + struct mt_fields *f = td->fields; | |
292 | + | |
293 | + if (f->length >= HID_MAX_FIELDS) | |
294 | + return; | |
295 | + | |
296 | + f->usages[f->length++] = usage->hid; | |
286 | 297 | } |
287 | 298 | |
288 | 299 | static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, |
... | ... | @@ -333,7 +344,7 @@ |
333 | 344 | cls->sn_move); |
334 | 345 | /* touchscreen emulation */ |
335 | 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 | 348 | td->last_field_index = field->index; |
338 | 349 | return 1; |
339 | 350 | case HID_GD_Y: |
... | ... | @@ -343,7 +354,7 @@ |
343 | 354 | cls->sn_move); |
344 | 355 | /* touchscreen emulation */ |
345 | 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 | 358 | td->last_field_index = field->index; |
348 | 359 | return 1; |
349 | 360 | } |
350 | 361 | |
351 | 362 | |
352 | 363 | |
... | ... | @@ -352,24 +363,24 @@ |
352 | 363 | case HID_UP_DIGITIZER: |
353 | 364 | switch (usage->hid) { |
354 | 365 | case HID_DG_INRANGE: |
355 | - set_last_slot_field(usage, td, hi); | |
366 | + mt_store_field(usage, td, hi); | |
356 | 367 | td->last_field_index = field->index; |
357 | 368 | return 1; |
358 | 369 | case HID_DG_CONFIDENCE: |
359 | - set_last_slot_field(usage, td, hi); | |
370 | + mt_store_field(usage, td, hi); | |
360 | 371 | td->last_field_index = field->index; |
361 | 372 | return 1; |
362 | 373 | case HID_DG_TIPSWITCH: |
363 | 374 | hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH); |
364 | 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 | 377 | td->last_field_index = field->index; |
367 | 378 | return 1; |
368 | 379 | case HID_DG_CONTACTID: |
369 | 380 | if (!td->maxcontacts) |
370 | 381 | td->maxcontacts = MT_DEFAULT_MAXCONTACT; |
371 | 382 | input_mt_init_slots(hi->input, td->maxcontacts); |
372 | - td->last_slot_field = usage->hid; | |
383 | + mt_store_field(usage, td, hi); | |
373 | 384 | td->last_field_index = field->index; |
374 | 385 | td->touches_by_report++; |
375 | 386 | return 1; |
... | ... | @@ -378,7 +389,7 @@ |
378 | 389 | EV_ABS, ABS_MT_TOUCH_MAJOR); |
379 | 390 | set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, |
380 | 391 | cls->sn_width); |
381 | - set_last_slot_field(usage, td, hi); | |
392 | + mt_store_field(usage, td, hi); | |
382 | 393 | td->last_field_index = field->index; |
383 | 394 | return 1; |
384 | 395 | case HID_DG_HEIGHT: |
... | ... | @@ -388,7 +399,7 @@ |
388 | 399 | cls->sn_height); |
389 | 400 | input_set_abs_params(hi->input, |
390 | 401 | ABS_MT_ORIENTATION, 0, 1, 0, 0); |
391 | - set_last_slot_field(usage, td, hi); | |
402 | + mt_store_field(usage, td, hi); | |
392 | 403 | td->last_field_index = field->index; |
393 | 404 | return 1; |
394 | 405 | case HID_DG_TIPPRESSURE: |
... | ... | @@ -399,7 +410,7 @@ |
399 | 410 | /* touchscreen emulation */ |
400 | 411 | set_abs(hi->input, ABS_PRESSURE, field, |
401 | 412 | cls->sn_pressure); |
402 | - set_last_slot_field(usage, td, hi); | |
413 | + mt_store_field(usage, td, hi); | |
403 | 414 | td->last_field_index = field->index; |
404 | 415 | return 1; |
405 | 416 | case HID_DG_CONTACTCOUNT: |
... | ... | @@ -653,6 +664,16 @@ |
653 | 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 | 677 | static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) |
657 | 678 | { |
658 | 679 | int ret, i; |
... | ... | @@ -683,6 +704,13 @@ |
683 | 704 | td->maxcontact_report_id = -1; |
684 | 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 | 714 | ret = hid_parse(hdev); |
687 | 715 | if (ret != 0) |
688 | 716 | goto fail; |
... | ... | @@ -691,6 +719,8 @@ |
691 | 719 | if (ret) |
692 | 720 | goto fail; |
693 | 721 | |
722 | + mt_post_parse(td); | |
723 | + | |
694 | 724 | if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) |
695 | 725 | mt_post_parse_default_settings(td); |
696 | 726 | |
697 | 727 | |
... | ... | @@ -708,9 +738,13 @@ |
708 | 738 | mt_set_maxcontacts(hdev); |
709 | 739 | mt_set_input_mode(hdev); |
710 | 740 | |
741 | + kfree(td->fields); | |
742 | + td->fields = NULL; | |
743 | + | |
711 | 744 | return 0; |
712 | 745 | |
713 | 746 | fail: |
747 | + kfree(td->fields); | |
714 | 748 | kfree(td); |
715 | 749 | return ret; |
716 | 750 | } |