aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-multitouch.c
diff options
context:
space:
mode:
authorBenjamin Tissoires <benjamin.tissoires@enac.fr>2012-05-04 08:53:46 -0400
committerJiri Kosina <jkosina@suse.cz>2012-05-10 05:35:43 -0400
commit3ac36d15557d1bedfb1151d9911b9587b2d40759 (patch)
treee69d4cfdd77ddeff31e9296a081d5bd502473184 /drivers/hid/hid-multitouch.c
parent16b79bb8ec4f20527525f8c063ae3e4d77388e97 (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.c58
1 files changed, 46 insertions, 12 deletions
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index 25b94253e68..6e3332a9997 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
73struct mt_fields {
74 unsigned usages[HID_MAX_FIELDS];
75 unsigned int length;
76};
77
73struct mt_device { 78struct 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
281static void set_last_slot_field(struct hid_usage *usage, struct mt_device *td, 288static 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
288static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, 299static 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
667static 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
656static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) 677static 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
713fail: 746fail:
747 kfree(td->fields);
714 kfree(td); 748 kfree(td);
715 return ret; 749 return ret;
716} 750}