Commit 3ac36d15557d1bedfb1151d9911b9587b2d40759

Authored by Benjamin Tissoires
Committed by Jiri Kosina
1 parent 16b79bb8ec

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 }