diff options
Diffstat (limited to 'drivers/hid/hid-multitouch.c')
-rw-r--r-- | drivers/hid/hid-multitouch.c | 185 |
1 files changed, 85 insertions, 100 deletions
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 59c8b5c1d2de..ee0b76b398cb 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c | |||
@@ -51,12 +51,12 @@ MODULE_LICENSE("GPL"); | |||
51 | #define MT_QUIRK_VALID_IS_INRANGE (1 << 5) | 51 | #define MT_QUIRK_VALID_IS_INRANGE (1 << 5) |
52 | #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6) | 52 | #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 6) |
53 | #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8) | 53 | #define MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE (1 << 8) |
54 | #define MT_QUIRK_NO_AREA (1 << 9) | ||
54 | 55 | ||
55 | struct mt_slot { | 56 | struct mt_slot { |
56 | __s32 x, y, p, w, h; | 57 | __s32 x, y, p, w, h; |
57 | __s32 contactid; /* the device ContactID assigned to this slot */ | 58 | __s32 contactid; /* the device ContactID assigned to this slot */ |
58 | bool touch_state; /* is the touch valid? */ | 59 | bool touch_state; /* is the touch valid? */ |
59 | bool seen_in_this_frame;/* has this slot been updated */ | ||
60 | }; | 60 | }; |
61 | 61 | ||
62 | struct mt_class { | 62 | struct mt_class { |
@@ -92,8 +92,9 @@ struct mt_device { | |||
92 | __u8 touches_by_report; /* how many touches are present in one report: | 92 | __u8 touches_by_report; /* how many touches are present in one report: |
93 | * 1 means we should use a serial protocol | 93 | * 1 means we should use a serial protocol |
94 | * > 1 means hybrid (multitouch) protocol */ | 94 | * > 1 means hybrid (multitouch) protocol */ |
95 | bool serial_maybe; /* need to check for serial protocol */ | ||
95 | bool curvalid; /* is the current contact valid? */ | 96 | bool curvalid; /* is the current contact valid? */ |
96 | struct mt_slot *slots; | 97 | unsigned mt_flags; /* flags to pass to input-mt */ |
97 | }; | 98 | }; |
98 | 99 | ||
99 | /* classes of device behavior */ | 100 | /* classes of device behavior */ |
@@ -115,6 +116,7 @@ struct mt_device { | |||
115 | #define MT_CLS_EGALAX_SERIAL 0x0104 | 116 | #define MT_CLS_EGALAX_SERIAL 0x0104 |
116 | #define MT_CLS_TOPSEED 0x0105 | 117 | #define MT_CLS_TOPSEED 0x0105 |
117 | #define MT_CLS_PANASONIC 0x0106 | 118 | #define MT_CLS_PANASONIC 0x0106 |
119 | #define MT_CLS_FLATFROG 0x0107 | ||
118 | 120 | ||
119 | #define MT_DEFAULT_MAXCONTACT 10 | 121 | #define MT_DEFAULT_MAXCONTACT 10 |
120 | 122 | ||
@@ -134,25 +136,6 @@ static int cypress_compute_slot(struct mt_device *td) | |||
134 | return -1; | 136 | return -1; |
135 | } | 137 | } |
136 | 138 | ||
137 | static int find_slot_from_contactid(struct mt_device *td) | ||
138 | { | ||
139 | int i; | ||
140 | for (i = 0; i < td->maxcontacts; ++i) { | ||
141 | if (td->slots[i].contactid == td->curdata.contactid && | ||
142 | td->slots[i].touch_state) | ||
143 | return i; | ||
144 | } | ||
145 | for (i = 0; i < td->maxcontacts; ++i) { | ||
146 | if (!td->slots[i].seen_in_this_frame && | ||
147 | !td->slots[i].touch_state) | ||
148 | return i; | ||
149 | } | ||
150 | /* should not occurs. If this happens that means | ||
151 | * that the device sent more touches that it says | ||
152 | * in the report descriptor. It is ignored then. */ | ||
153 | return -1; | ||
154 | } | ||
155 | |||
156 | static struct mt_class mt_classes[] = { | 139 | static struct mt_class mt_classes[] = { |
157 | { .name = MT_CLS_DEFAULT, | 140 | { .name = MT_CLS_DEFAULT, |
158 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, | 141 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP }, |
@@ -190,7 +173,9 @@ static struct mt_class mt_classes[] = { | |||
190 | MT_QUIRK_SLOT_IS_CONTACTID, | 173 | MT_QUIRK_SLOT_IS_CONTACTID, |
191 | .sn_move = 2048, | 174 | .sn_move = 2048, |
192 | .sn_width = 128, | 175 | .sn_width = 128, |
193 | .sn_height = 128 }, | 176 | .sn_height = 128, |
177 | .maxcontacts = 60, | ||
178 | }, | ||
194 | { .name = MT_CLS_CYPRESS, | 179 | { .name = MT_CLS_CYPRESS, |
195 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | | 180 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | |
196 | MT_QUIRK_CYPRESS, | 181 | MT_QUIRK_CYPRESS, |
@@ -216,6 +201,12 @@ static struct mt_class mt_classes[] = { | |||
216 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, | 201 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, |
217 | .maxcontacts = 4 }, | 202 | .maxcontacts = 4 }, |
218 | 203 | ||
204 | { .name = MT_CLS_FLATFROG, | ||
205 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP | | ||
206 | MT_QUIRK_NO_AREA, | ||
207 | .sn_move = 2048, | ||
208 | .maxcontacts = 40, | ||
209 | }, | ||
219 | { } | 210 | { } |
220 | }; | 211 | }; |
221 | 212 | ||
@@ -319,24 +310,16 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
319 | * We need to ignore fields that belong to other collections | 310 | * We need to ignore fields that belong to other collections |
320 | * such as Mouse that might have the same GenericDesktop usages. */ | 311 | * such as Mouse that might have the same GenericDesktop usages. */ |
321 | if (field->application == HID_DG_TOUCHSCREEN) | 312 | if (field->application == HID_DG_TOUCHSCREEN) |
322 | set_bit(INPUT_PROP_DIRECT, hi->input->propbit); | 313 | td->mt_flags |= INPUT_MT_DIRECT; |
323 | else if (field->application != HID_DG_TOUCHPAD) | 314 | else if (field->application != HID_DG_TOUCHPAD) |
324 | return 0; | 315 | return 0; |
325 | 316 | ||
326 | /* In case of an indirect device (touchpad), we need to add | 317 | /* |
327 | * specific BTN_TOOL_* to be handled by the synaptics xorg | 318 | * Model touchscreens providing buttons as touchpads. |
328 | * driver. | ||
329 | * We also consider that touchscreens providing buttons are touchpads. | ||
330 | */ | 319 | */ |
331 | if (field->application == HID_DG_TOUCHPAD || | 320 | if (field->application == HID_DG_TOUCHPAD || |
332 | (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON || | 321 | (usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) |
333 | cls->is_indirect) { | 322 | td->mt_flags |= INPUT_MT_POINTER; |
334 | set_bit(INPUT_PROP_POINTER, hi->input->propbit); | ||
335 | set_bit(BTN_TOOL_FINGER, hi->input->keybit); | ||
336 | set_bit(BTN_TOOL_DOUBLETAP, hi->input->keybit); | ||
337 | set_bit(BTN_TOOL_TRIPLETAP, hi->input->keybit); | ||
338 | set_bit(BTN_TOOL_QUADTAP, hi->input->keybit); | ||
339 | } | ||
340 | 323 | ||
341 | /* eGalax devices provide a Digitizer.Stylus input which overrides | 324 | /* eGalax devices provide a Digitizer.Stylus input which overrides |
342 | * the correct Digitizers.Finger X/Y ranges. | 325 | * the correct Digitizers.Finger X/Y ranges. |
@@ -353,8 +336,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
353 | EV_ABS, ABS_MT_POSITION_X); | 336 | EV_ABS, ABS_MT_POSITION_X); |
354 | set_abs(hi->input, ABS_MT_POSITION_X, field, | 337 | set_abs(hi->input, ABS_MT_POSITION_X, field, |
355 | cls->sn_move); | 338 | cls->sn_move); |
356 | /* touchscreen emulation */ | ||
357 | set_abs(hi->input, ABS_X, field, cls->sn_move); | ||
358 | mt_store_field(usage, td, hi); | 339 | mt_store_field(usage, td, hi); |
359 | td->last_field_index = field->index; | 340 | td->last_field_index = field->index; |
360 | return 1; | 341 | return 1; |
@@ -363,8 +344,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
363 | EV_ABS, ABS_MT_POSITION_Y); | 344 | EV_ABS, ABS_MT_POSITION_Y); |
364 | set_abs(hi->input, ABS_MT_POSITION_Y, field, | 345 | set_abs(hi->input, ABS_MT_POSITION_Y, field, |
365 | cls->sn_move); | 346 | cls->sn_move); |
366 | /* touchscreen emulation */ | ||
367 | set_abs(hi->input, ABS_Y, field, cls->sn_move); | ||
368 | mt_store_field(usage, td, hi); | 347 | mt_store_field(usage, td, hi); |
369 | td->last_field_index = field->index; | 348 | td->last_field_index = field->index; |
370 | return 1; | 349 | return 1; |
@@ -388,9 +367,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
388 | td->last_field_index = field->index; | 367 | td->last_field_index = field->index; |
389 | return 1; | 368 | return 1; |
390 | case HID_DG_CONTACTID: | 369 | case HID_DG_CONTACTID: |
391 | if (!td->maxcontacts) | ||
392 | td->maxcontacts = MT_DEFAULT_MAXCONTACT; | ||
393 | input_mt_init_slots(hi->input, td->maxcontacts); | ||
394 | mt_store_field(usage, td, hi); | 370 | mt_store_field(usage, td, hi); |
395 | td->last_field_index = field->index; | 371 | td->last_field_index = field->index; |
396 | td->touches_by_report++; | 372 | td->touches_by_report++; |
@@ -398,18 +374,21 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
398 | case HID_DG_WIDTH: | 374 | case HID_DG_WIDTH: |
399 | hid_map_usage(hi, usage, bit, max, | 375 | hid_map_usage(hi, usage, bit, max, |
400 | EV_ABS, ABS_MT_TOUCH_MAJOR); | 376 | EV_ABS, ABS_MT_TOUCH_MAJOR); |
401 | set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, | 377 | if (!(cls->quirks & MT_QUIRK_NO_AREA)) |
402 | cls->sn_width); | 378 | set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field, |
379 | cls->sn_width); | ||
403 | mt_store_field(usage, td, hi); | 380 | mt_store_field(usage, td, hi); |
404 | td->last_field_index = field->index; | 381 | td->last_field_index = field->index; |
405 | return 1; | 382 | return 1; |
406 | case HID_DG_HEIGHT: | 383 | case HID_DG_HEIGHT: |
407 | hid_map_usage(hi, usage, bit, max, | 384 | hid_map_usage(hi, usage, bit, max, |
408 | EV_ABS, ABS_MT_TOUCH_MINOR); | 385 | EV_ABS, ABS_MT_TOUCH_MINOR); |
409 | set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, | 386 | if (!(cls->quirks & MT_QUIRK_NO_AREA)) { |
410 | cls->sn_height); | 387 | set_abs(hi->input, ABS_MT_TOUCH_MINOR, field, |
411 | input_set_abs_params(hi->input, | 388 | cls->sn_height); |
389 | input_set_abs_params(hi->input, | ||
412 | ABS_MT_ORIENTATION, 0, 1, 0, 0); | 390 | ABS_MT_ORIENTATION, 0, 1, 0, 0); |
391 | } | ||
413 | mt_store_field(usage, td, hi); | 392 | mt_store_field(usage, td, hi); |
414 | td->last_field_index = field->index; | 393 | td->last_field_index = field->index; |
415 | return 1; | 394 | return 1; |
@@ -418,9 +397,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
418 | EV_ABS, ABS_MT_PRESSURE); | 397 | EV_ABS, ABS_MT_PRESSURE); |
419 | set_abs(hi->input, ABS_MT_PRESSURE, field, | 398 | set_abs(hi->input, ABS_MT_PRESSURE, field, |
420 | cls->sn_pressure); | 399 | cls->sn_pressure); |
421 | /* touchscreen emulation */ | ||
422 | set_abs(hi->input, ABS_PRESSURE, field, | ||
423 | cls->sn_pressure); | ||
424 | mt_store_field(usage, td, hi); | 400 | mt_store_field(usage, td, hi); |
425 | td->last_field_index = field->index; | 401 | td->last_field_index = field->index; |
426 | return 1; | 402 | return 1; |
@@ -464,7 +440,7 @@ static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi, | |||
464 | return -1; | 440 | return -1; |
465 | } | 441 | } |
466 | 442 | ||
467 | static int mt_compute_slot(struct mt_device *td) | 443 | static int mt_compute_slot(struct mt_device *td, struct input_dev *input) |
468 | { | 444 | { |
469 | __s32 quirks = td->mtclass.quirks; | 445 | __s32 quirks = td->mtclass.quirks; |
470 | 446 | ||
@@ -480,42 +456,23 @@ static int mt_compute_slot(struct mt_device *td) | |||
480 | if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) | 456 | if (quirks & MT_QUIRK_SLOT_IS_CONTACTID_MINUS_ONE) |
481 | return td->curdata.contactid - 1; | 457 | return td->curdata.contactid - 1; |
482 | 458 | ||
483 | return find_slot_from_contactid(td); | 459 | return input_mt_get_slot_by_key(input, td->curdata.contactid); |
484 | } | 460 | } |
485 | 461 | ||
486 | /* | 462 | /* |
487 | * this function is called when a whole contact has been processed, | 463 | * this function is called when a whole contact has been processed, |
488 | * so that it can assign it to a slot and store the data there | 464 | * so that it can assign it to a slot and store the data there |
489 | */ | 465 | */ |
490 | static void mt_complete_slot(struct mt_device *td) | 466 | static void mt_complete_slot(struct mt_device *td, struct input_dev *input) |
491 | { | 467 | { |
492 | td->curdata.seen_in_this_frame = true; | ||
493 | if (td->curvalid) { | 468 | if (td->curvalid) { |
494 | int slotnum = mt_compute_slot(td); | 469 | int slotnum = mt_compute_slot(td, input); |
495 | 470 | struct mt_slot *s = &td->curdata; | |
496 | if (slotnum >= 0 && slotnum < td->maxcontacts) | ||
497 | td->slots[slotnum] = td->curdata; | ||
498 | } | ||
499 | td->num_received++; | ||
500 | } | ||
501 | |||
502 | 471 | ||
503 | /* | 472 | if (slotnum < 0 || slotnum >= td->maxcontacts) |
504 | * this function is called when a whole packet has been received and processed, | 473 | return; |
505 | * so that it can decide what to send to the input layer. | ||
506 | */ | ||
507 | static void mt_emit_event(struct mt_device *td, struct input_dev *input) | ||
508 | { | ||
509 | int i; | ||
510 | 474 | ||
511 | for (i = 0; i < td->maxcontacts; ++i) { | 475 | input_mt_slot(input, slotnum); |
512 | struct mt_slot *s = &(td->slots[i]); | ||
513 | if ((td->mtclass.quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) && | ||
514 | !s->seen_in_this_frame) { | ||
515 | s->touch_state = false; | ||
516 | } | ||
517 | |||
518 | input_mt_slot(input, i); | ||
519 | input_mt_report_slot_state(input, MT_TOOL_FINGER, | 476 | input_mt_report_slot_state(input, MT_TOOL_FINGER, |
520 | s->touch_state); | 477 | s->touch_state); |
521 | if (s->touch_state) { | 478 | if (s->touch_state) { |
@@ -532,24 +489,29 @@ static void mt_emit_event(struct mt_device *td, struct input_dev *input) | |||
532 | input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); | 489 | input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major); |
533 | input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); | 490 | input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor); |
534 | } | 491 | } |
535 | s->seen_in_this_frame = false; | ||
536 | |||
537 | } | 492 | } |
538 | 493 | ||
539 | input_mt_report_pointer_emulation(input, true); | 494 | td->num_received++; |
495 | } | ||
496 | |||
497 | /* | ||
498 | * this function is called when a whole packet has been received and processed, | ||
499 | * so that it can decide what to send to the input layer. | ||
500 | */ | ||
501 | static void mt_sync_frame(struct mt_device *td, struct input_dev *input) | ||
502 | { | ||
503 | input_mt_sync_frame(input); | ||
540 | input_sync(input); | 504 | input_sync(input); |
541 | td->num_received = 0; | 505 | td->num_received = 0; |
542 | } | 506 | } |
543 | 507 | ||
544 | |||
545 | |||
546 | static int mt_event(struct hid_device *hid, struct hid_field *field, | 508 | static int mt_event(struct hid_device *hid, struct hid_field *field, |
547 | struct hid_usage *usage, __s32 value) | 509 | struct hid_usage *usage, __s32 value) |
548 | { | 510 | { |
549 | struct mt_device *td = hid_get_drvdata(hid); | 511 | struct mt_device *td = hid_get_drvdata(hid); |
550 | __s32 quirks = td->mtclass.quirks; | 512 | __s32 quirks = td->mtclass.quirks; |
551 | 513 | ||
552 | if (hid->claimed & HID_CLAIMED_INPUT && td->slots) { | 514 | if (hid->claimed & HID_CLAIMED_INPUT) { |
553 | switch (usage->hid) { | 515 | switch (usage->hid) { |
554 | case HID_DG_INRANGE: | 516 | case HID_DG_INRANGE: |
555 | if (quirks & MT_QUIRK_ALWAYS_VALID) | 517 | if (quirks & MT_QUIRK_ALWAYS_VALID) |
@@ -602,11 +564,11 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, | |||
602 | } | 564 | } |
603 | 565 | ||
604 | if (usage->hid == td->last_slot_field) | 566 | if (usage->hid == td->last_slot_field) |
605 | mt_complete_slot(td); | 567 | mt_complete_slot(td, field->hidinput->input); |
606 | 568 | ||
607 | if (field->index == td->last_field_index | 569 | if (field->index == td->last_field_index |
608 | && td->num_received >= td->num_expected) | 570 | && td->num_received >= td->num_expected) |
609 | mt_emit_event(td, field->hidinput->input); | 571 | mt_sync_frame(td, field->hidinput->input); |
610 | 572 | ||
611 | } | 573 | } |
612 | 574 | ||
@@ -685,6 +647,35 @@ static void mt_post_parse(struct mt_device *td) | |||
685 | } | 647 | } |
686 | } | 648 | } |
687 | 649 | ||
650 | static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi) | ||
651 | |||
652 | { | ||
653 | struct mt_device *td = hid_get_drvdata(hdev); | ||
654 | struct mt_class *cls = &td->mtclass; | ||
655 | struct input_dev *input = hi->input; | ||
656 | |||
657 | /* Only initialize slots for MT input devices */ | ||
658 | if (!test_bit(ABS_MT_POSITION_X, input->absbit)) | ||
659 | return; | ||
660 | |||
661 | if (!td->maxcontacts) | ||
662 | td->maxcontacts = MT_DEFAULT_MAXCONTACT; | ||
663 | |||
664 | mt_post_parse(td); | ||
665 | if (td->serial_maybe) | ||
666 | mt_post_parse_default_settings(td); | ||
667 | |||
668 | if (cls->is_indirect) | ||
669 | td->mt_flags |= INPUT_MT_POINTER; | ||
670 | |||
671 | if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) | ||
672 | td->mt_flags |= INPUT_MT_DROP_UNUSED; | ||
673 | |||
674 | input_mt_init_slots(input, td->maxcontacts, td->mt_flags); | ||
675 | |||
676 | td->mt_flags = 0; | ||
677 | } | ||
678 | |||
688 | static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | 679 | static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) |
689 | { | 680 | { |
690 | int ret, i; | 681 | int ret, i; |
@@ -722,6 +713,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
722 | goto fail; | 713 | goto fail; |
723 | } | 714 | } |
724 | 715 | ||
716 | if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) | ||
717 | td->serial_maybe = true; | ||
718 | |||
725 | ret = hid_parse(hdev); | 719 | ret = hid_parse(hdev); |
726 | if (ret != 0) | 720 | if (ret != 0) |
727 | goto fail; | 721 | goto fail; |
@@ -730,20 +724,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
730 | if (ret) | 724 | if (ret) |
731 | goto fail; | 725 | goto fail; |
732 | 726 | ||
733 | mt_post_parse(td); | ||
734 | |||
735 | if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) | ||
736 | mt_post_parse_default_settings(td); | ||
737 | |||
738 | td->slots = kzalloc(td->maxcontacts * sizeof(struct mt_slot), | ||
739 | GFP_KERNEL); | ||
740 | if (!td->slots) { | ||
741 | dev_err(&hdev->dev, "cannot allocate multitouch slots\n"); | ||
742 | hid_hw_stop(hdev); | ||
743 | ret = -ENOMEM; | ||
744 | goto fail; | ||
745 | } | ||
746 | |||
747 | ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); | 727 | ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group); |
748 | 728 | ||
749 | mt_set_maxcontacts(hdev); | 729 | mt_set_maxcontacts(hdev); |
@@ -774,7 +754,6 @@ static void mt_remove(struct hid_device *hdev) | |||
774 | struct mt_device *td = hid_get_drvdata(hdev); | 754 | struct mt_device *td = hid_get_drvdata(hdev); |
775 | sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); | 755 | sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); |
776 | hid_hw_stop(hdev); | 756 | hid_hw_stop(hdev); |
777 | kfree(td->slots); | ||
778 | kfree(td); | 757 | kfree(td); |
779 | hid_set_drvdata(hdev, NULL); | 758 | hid_set_drvdata(hdev, NULL); |
780 | } | 759 | } |
@@ -892,6 +871,11 @@ static const struct hid_device_id mt_devices[] = { | |||
892 | MT_USB_DEVICE(USB_VENDOR_ID_ELO, | 871 | MT_USB_DEVICE(USB_VENDOR_ID_ELO, |
893 | USB_DEVICE_ID_ELO_TS2515) }, | 872 | USB_DEVICE_ID_ELO_TS2515) }, |
894 | 873 | ||
874 | /* Flatfrog Panels */ | ||
875 | { .driver_data = MT_CLS_FLATFROG, | ||
876 | MT_USB_DEVICE(USB_VENDOR_ID_FLATFROG, | ||
877 | USB_DEVICE_ID_MULTITOUCH_3200) }, | ||
878 | |||
895 | /* GeneralTouch panel */ | 879 | /* GeneralTouch panel */ |
896 | { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, | 880 | { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, |
897 | MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, | 881 | MT_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, |
@@ -1087,6 +1071,7 @@ static struct hid_driver mt_driver = { | |||
1087 | .remove = mt_remove, | 1071 | .remove = mt_remove, |
1088 | .input_mapping = mt_input_mapping, | 1072 | .input_mapping = mt_input_mapping, |
1089 | .input_mapped = mt_input_mapped, | 1073 | .input_mapped = mt_input_mapped, |
1074 | .input_configured = mt_input_configured, | ||
1090 | .feature_mapping = mt_feature_mapping, | 1075 | .feature_mapping = mt_feature_mapping, |
1091 | .usage_table = mt_grabbed_usages, | 1076 | .usage_table = mt_grabbed_usages, |
1092 | .event = mt_event, | 1077 | .event = mt_event, |