diff options
Diffstat (limited to 'drivers/hid/hid-multitouch.c')
-rw-r--r-- | drivers/hid/hid-multitouch.c | 76 |
1 files changed, 64 insertions, 12 deletions
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 07d3183fdde5..ee01e65e22d6 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c | |||
@@ -5,6 +5,12 @@ | |||
5 | * Copyright (c) 2010-2011 Benjamin Tissoires <benjamin.tissoires@gmail.com> | 5 | * Copyright (c) 2010-2011 Benjamin Tissoires <benjamin.tissoires@gmail.com> |
6 | * Copyright (c) 2010-2011 Ecole Nationale de l'Aviation Civile, France | 6 | * Copyright (c) 2010-2011 Ecole Nationale de l'Aviation Civile, France |
7 | * | 7 | * |
8 | * This code is partly based on hid-egalax.c: | ||
9 | * | ||
10 | * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr> | ||
11 | * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se> | ||
12 | * Copyright (c) 2010 Canonical, Ltd. | ||
13 | * | ||
8 | */ | 14 | */ |
9 | 15 | ||
10 | /* | 16 | /* |
@@ -24,6 +30,7 @@ | |||
24 | 30 | ||
25 | 31 | ||
26 | MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); | 32 | MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>"); |
33 | MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>"); | ||
27 | MODULE_DESCRIPTION("HID multitouch panels"); | 34 | MODULE_DESCRIPTION("HID multitouch panels"); |
28 | MODULE_LICENSE("GPL"); | 35 | MODULE_LICENSE("GPL"); |
29 | 36 | ||
@@ -36,6 +43,7 @@ MODULE_LICENSE("GPL"); | |||
36 | #define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3) | 43 | #define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3) |
37 | #define MT_QUIRK_VALID_IS_INRANGE (1 << 4) | 44 | #define MT_QUIRK_VALID_IS_INRANGE (1 << 4) |
38 | #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5) | 45 | #define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5) |
46 | #define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 6) | ||
39 | 47 | ||
40 | struct mt_slot { | 48 | struct mt_slot { |
41 | __s32 x, y, p, w, h; | 49 | __s32 x, y, p, w, h; |
@@ -65,10 +73,11 @@ struct mt_class { | |||
65 | }; | 73 | }; |
66 | 74 | ||
67 | /* classes of device behavior */ | 75 | /* classes of device behavior */ |
68 | #define MT_CLS_DEFAULT 1 | 76 | #define MT_CLS_DEFAULT 1 |
69 | #define MT_CLS_DUAL1 2 | 77 | #define MT_CLS_DUAL_INRANGE_CONTACTID 2 |
70 | #define MT_CLS_DUAL2 3 | 78 | #define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 3 |
71 | #define MT_CLS_CYPRESS 4 | 79 | #define MT_CLS_CYPRESS 4 |
80 | #define MT_CLS_EGALAX 5 | ||
72 | 81 | ||
73 | /* | 82 | /* |
74 | * these device-dependent functions determine what slot corresponds | 83 | * these device-dependent functions determine what slot corresponds |
@@ -104,13 +113,13 @@ static int find_slot_from_contactid(struct mt_device *td) | |||
104 | 113 | ||
105 | struct mt_class mt_classes[] = { | 114 | struct mt_class mt_classes[] = { |
106 | { .name = MT_CLS_DEFAULT, | 115 | { .name = MT_CLS_DEFAULT, |
107 | .quirks = MT_QUIRK_VALID_IS_INRANGE, | 116 | .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP, |
108 | .maxcontacts = 10 }, | 117 | .maxcontacts = 10 }, |
109 | { .name = MT_CLS_DUAL1, | 118 | { .name = MT_CLS_DUAL_INRANGE_CONTACTID, |
110 | .quirks = MT_QUIRK_VALID_IS_INRANGE | | 119 | .quirks = MT_QUIRK_VALID_IS_INRANGE | |
111 | MT_QUIRK_SLOT_IS_CONTACTID, | 120 | MT_QUIRK_SLOT_IS_CONTACTID, |
112 | .maxcontacts = 2 }, | 121 | .maxcontacts = 2 }, |
113 | { .name = MT_CLS_DUAL2, | 122 | { .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, |
114 | .quirks = MT_QUIRK_VALID_IS_INRANGE | | 123 | .quirks = MT_QUIRK_VALID_IS_INRANGE | |
115 | MT_QUIRK_SLOT_IS_CONTACTNUMBER, | 124 | MT_QUIRK_SLOT_IS_CONTACTNUMBER, |
116 | .maxcontacts = 2 }, | 125 | .maxcontacts = 2 }, |
@@ -119,10 +128,18 @@ struct mt_class mt_classes[] = { | |||
119 | MT_QUIRK_CYPRESS, | 128 | MT_QUIRK_CYPRESS, |
120 | .maxcontacts = 10 }, | 129 | .maxcontacts = 10 }, |
121 | 130 | ||
131 | { .name = MT_CLS_EGALAX, | ||
132 | .quirks = MT_QUIRK_SLOT_IS_CONTACTID | | ||
133 | MT_QUIRK_VALID_IS_INRANGE | | ||
134 | MT_QUIRK_EGALAX_XYZ_FIXUP, | ||
135 | .maxcontacts = 2, | ||
136 | .sn_move = 4096, | ||
137 | .sn_pressure = 32, | ||
138 | }, | ||
122 | { } | 139 | { } |
123 | }; | 140 | }; |
124 | 141 | ||
125 | static void mt_feature_mapping(struct hid_device *hdev, struct hid_input *hi, | 142 | static void mt_feature_mapping(struct hid_device *hdev, |
126 | struct hid_field *field, struct hid_usage *usage) | 143 | struct hid_field *field, struct hid_usage *usage) |
127 | { | 144 | { |
128 | if (usage->hid == HID_DG_INPUTMODE) { | 145 | if (usage->hid == HID_DG_INPUTMODE) { |
@@ -146,11 +163,15 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
146 | { | 163 | { |
147 | struct mt_device *td = hid_get_drvdata(hdev); | 164 | struct mt_device *td = hid_get_drvdata(hdev); |
148 | struct mt_class *cls = td->mtclass; | 165 | struct mt_class *cls = td->mtclass; |
166 | __s32 quirks = cls->quirks; | ||
167 | |||
149 | switch (usage->hid & HID_USAGE_PAGE) { | 168 | switch (usage->hid & HID_USAGE_PAGE) { |
150 | 169 | ||
151 | case HID_UP_GENDESK: | 170 | case HID_UP_GENDESK: |
152 | switch (usage->hid) { | 171 | switch (usage->hid) { |
153 | case HID_GD_X: | 172 | case HID_GD_X: |
173 | if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP) | ||
174 | field->logical_maximum = 32760; | ||
154 | hid_map_usage(hi, usage, bit, max, | 175 | hid_map_usage(hi, usage, bit, max, |
155 | EV_ABS, ABS_MT_POSITION_X); | 176 | EV_ABS, ABS_MT_POSITION_X); |
156 | set_abs(hi->input, ABS_MT_POSITION_X, field, | 177 | set_abs(hi->input, ABS_MT_POSITION_X, field, |
@@ -160,6 +181,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
160 | td->last_slot_field = usage->hid; | 181 | td->last_slot_field = usage->hid; |
161 | return 1; | 182 | return 1; |
162 | case HID_GD_Y: | 183 | case HID_GD_Y: |
184 | if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP) | ||
185 | field->logical_maximum = 32760; | ||
163 | hid_map_usage(hi, usage, bit, max, | 186 | hid_map_usage(hi, usage, bit, max, |
164 | EV_ABS, ABS_MT_POSITION_Y); | 187 | EV_ABS, ABS_MT_POSITION_Y); |
165 | set_abs(hi->input, ABS_MT_POSITION_Y, field, | 188 | set_abs(hi->input, ABS_MT_POSITION_Y, field, |
@@ -203,6 +226,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi, | |||
203 | td->last_slot_field = usage->hid; | 226 | td->last_slot_field = usage->hid; |
204 | return 1; | 227 | return 1; |
205 | case HID_DG_TIPPRESSURE: | 228 | case HID_DG_TIPPRESSURE: |
229 | if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP) | ||
230 | field->logical_minimum = 0; | ||
206 | hid_map_usage(hi, usage, bit, max, | 231 | hid_map_usage(hi, usage, bit, max, |
207 | EV_ABS, ABS_MT_PRESSURE); | 232 | EV_ABS, ABS_MT_PRESSURE); |
208 | set_abs(hi->input, ABS_MT_PRESSURE, field, | 233 | set_abs(hi->input, ABS_MT_PRESSURE, field, |
@@ -363,8 +388,11 @@ static int mt_event(struct hid_device *hid, struct hid_field *field, | |||
363 | return 0; | 388 | return 0; |
364 | } | 389 | } |
365 | 390 | ||
366 | if (usage->hid == td->last_slot_field) | 391 | if (usage->hid == td->last_slot_field) { |
367 | mt_complete_slot(td); | 392 | mt_complete_slot(td); |
393 | if (!td->last_field_index) | ||
394 | mt_emit_event(td, field->hidinput->input); | ||
395 | } | ||
368 | 396 | ||
369 | if (field->index == td->last_field_index | 397 | if (field->index == td->last_field_index |
370 | && td->num_received >= td->num_expected) | 398 | && td->num_received >= td->num_expected) |
@@ -466,18 +494,42 @@ static const struct hid_device_id mt_devices[] = { | |||
466 | USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, | 494 | USB_DEVICE_ID_CYPRESS_TRUETOUCH) }, |
467 | 495 | ||
468 | /* GeneralTouch panel */ | 496 | /* GeneralTouch panel */ |
469 | { .driver_data = MT_CLS_DUAL2, | 497 | { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER, |
470 | HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, | 498 | HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, |
471 | USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, | 499 | USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) }, |
472 | 500 | ||
501 | /* IRTOUCH panels */ | ||
502 | { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, | ||
503 | HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, | ||
504 | USB_DEVICE_ID_IRTOUCH_INFRARED_USB) }, | ||
505 | |||
473 | /* PixCir-based panels */ | 506 | /* PixCir-based panels */ |
474 | { .driver_data = MT_CLS_DUAL1, | 507 | { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, |
475 | HID_USB_DEVICE(USB_VENDOR_ID_HANVON, | 508 | HID_USB_DEVICE(USB_VENDOR_ID_HANVON, |
476 | USB_DEVICE_ID_HANVON_MULTITOUCH) }, | 509 | USB_DEVICE_ID_HANVON_MULTITOUCH) }, |
477 | { .driver_data = MT_CLS_DUAL1, | 510 | { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID, |
478 | HID_USB_DEVICE(USB_VENDOR_ID_CANDO, | 511 | HID_USB_DEVICE(USB_VENDOR_ID_CANDO, |
479 | USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, | 512 | USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) }, |
480 | 513 | ||
514 | /* Resistive eGalax devices */ | ||
515 | { .driver_data = MT_CLS_EGALAX, | ||
516 | HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
517 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, | ||
518 | { .driver_data = MT_CLS_EGALAX, | ||
519 | HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
520 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) }, | ||
521 | |||
522 | /* Capacitive eGalax devices */ | ||
523 | { .driver_data = MT_CLS_EGALAX, | ||
524 | HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
525 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) }, | ||
526 | { .driver_data = MT_CLS_EGALAX, | ||
527 | HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
528 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) }, | ||
529 | { .driver_data = MT_CLS_EGALAX, | ||
530 | HID_USB_DEVICE(USB_VENDOR_ID_DWAV, | ||
531 | USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) }, | ||
532 | |||
481 | { } | 533 | { } |
482 | }; | 534 | }; |
483 | MODULE_DEVICE_TABLE(hid, mt_devices); | 535 | MODULE_DEVICE_TABLE(hid, mt_devices); |