diff options
author | Benjamin Tissoires <benjamin.tissoires@redhat.com> | 2017-01-30 04:48:06 -0500 |
---|---|---|
committer | Jiri Kosina <jkosina@suse.cz> | 2017-02-03 08:45:57 -0500 |
commit | f3287a995ac3520b1afcf03932b9c405f502657c (patch) | |
tree | b54c9641b4d2a6be1d7b8ad6bec8c9db2a245855 | |
parent | 8e9faa15469ed7c7467423db4c62aeed3ff4cae3 (diff) |
HID: multitouch: fix LG Melfas touchscreen
The LG Melfas touchscreen has a bad firmware where it declares the Contact ID
field as constant while it shouldn't. This messes up the autodetection and the
reporting of the events by hid-multitouch given that hid-input ignores constant
fields.
The autodetection is simply worked around by manually adding the device to
hid_have_special_driver[].
The processing of the events requires either a report fixup, or some specific
case handling. Given that the report fixup would require to basically rewrite
all the report descriptor, I went for the programatic way of fixing that after
the report descriptors are loaded.
Link: https://bugzilla.redhat.com/show_bug.cgi?id=1416181
Signed-off-by: Benjamin Tissoires <benjamin.tissoires@redhat.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
-rw-r--r-- | drivers/hid/hid-core.c | 1 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 1 | ||||
-rw-r--r-- | drivers/hid/hid-multitouch.c | 44 |
3 files changed, 46 insertions, 0 deletions
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index ea36b557d5ee..1f6d0c000381 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c | |||
@@ -1933,6 +1933,7 @@ static const struct hid_device_id hid_have_special_driver[] = { | |||
1933 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) }, | 1933 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_CBTKBD) }, |
1934 | { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) }, | 1934 | { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPPRODOCK) }, |
1935 | #endif | 1935 | #endif |
1936 | { HID_USB_DEVICE(USB_VENDOR_ID_LG, USB_DEVICE_ID_LG_MELFAS_MT) }, | ||
1936 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, | 1937 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, |
1937 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, | 1938 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) }, |
1938 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, | 1939 | { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) }, |
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 350accfee8e8..8943a58c626d 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h | |||
@@ -633,6 +633,7 @@ | |||
633 | 633 | ||
634 | #define USB_VENDOR_ID_LG 0x1fd2 | 634 | #define USB_VENDOR_ID_LG 0x1fd2 |
635 | #define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 | 635 | #define USB_DEVICE_ID_LG_MULTITOUCH 0x0064 |
636 | #define USB_DEVICE_ID_LG_MELFAS_MT 0x6007 | ||
636 | 637 | ||
637 | #define USB_VENDOR_ID_LOGITECH 0x046d | 638 | #define USB_VENDOR_ID_LOGITECH 0x046d |
638 | #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e | 639 | #define USB_DEVICE_ID_LOGITECH_AUDIOHUB 0x0a0e |
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 6dca66806844..692647485a53 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c | |||
@@ -68,6 +68,7 @@ MODULE_LICENSE("GPL"); | |||
68 | #define MT_QUIRK_HOVERING (1 << 11) | 68 | #define MT_QUIRK_HOVERING (1 << 11) |
69 | #define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12) | 69 | #define MT_QUIRK_CONTACT_CNT_ACCURATE (1 << 12) |
70 | #define MT_QUIRK_FORCE_GET_FEATURE (1 << 13) | 70 | #define MT_QUIRK_FORCE_GET_FEATURE (1 << 13) |
71 | #define MT_QUIRK_FIX_CONST_CONTACT_ID (1 << 14) | ||
71 | 72 | ||
72 | #define MT_INPUTMODE_TOUCHSCREEN 0x02 | 73 | #define MT_INPUTMODE_TOUCHSCREEN 0x02 |
73 | #define MT_INPUTMODE_TOUCHPAD 0x03 | 74 | #define MT_INPUTMODE_TOUCHPAD 0x03 |
@@ -157,6 +158,7 @@ static void mt_post_parse(struct mt_device *td); | |||
157 | #define MT_CLS_FLATFROG 0x0107 | 158 | #define MT_CLS_FLATFROG 0x0107 |
158 | #define MT_CLS_GENERALTOUCH_TWOFINGERS 0x0108 | 159 | #define MT_CLS_GENERALTOUCH_TWOFINGERS 0x0108 |
159 | #define MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109 | 160 | #define MT_CLS_GENERALTOUCH_PWT_TENFINGERS 0x0109 |
161 | #define MT_CLS_LG 0x010a | ||
160 | #define MT_CLS_VTL 0x0110 | 162 | #define MT_CLS_VTL 0x0110 |
161 | 163 | ||
162 | #define MT_DEFAULT_MAXCONTACT 10 | 164 | #define MT_DEFAULT_MAXCONTACT 10 |
@@ -263,6 +265,12 @@ static struct mt_class mt_classes[] = { | |||
263 | .sn_move = 2048, | 265 | .sn_move = 2048, |
264 | .maxcontacts = 40, | 266 | .maxcontacts = 40, |
265 | }, | 267 | }, |
268 | { .name = MT_CLS_LG, | ||
269 | .quirks = MT_QUIRK_ALWAYS_VALID | | ||
270 | MT_QUIRK_FIX_CONST_CONTACT_ID | | ||
271 | MT_QUIRK_IGNORE_DUPLICATES | | ||
272 | MT_QUIRK_HOVERING | | ||
273 | MT_QUIRK_CONTACT_CNT_ACCURATE }, | ||
266 | { .name = MT_CLS_VTL, | 274 | { .name = MT_CLS_VTL, |
267 | .quirks = MT_QUIRK_ALWAYS_VALID | | 275 | .quirks = MT_QUIRK_ALWAYS_VALID | |
268 | MT_QUIRK_CONTACT_CNT_ACCURATE | | 276 | MT_QUIRK_CONTACT_CNT_ACCURATE | |
@@ -1078,6 +1086,34 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi) | |||
1078 | return 0; | 1086 | return 0; |
1079 | } | 1087 | } |
1080 | 1088 | ||
1089 | static void mt_fix_const_field(struct hid_field *field, unsigned int usage) | ||
1090 | { | ||
1091 | if (field->usage[0].hid != usage || | ||
1092 | !(field->flags & HID_MAIN_ITEM_CONSTANT)) | ||
1093 | return; | ||
1094 | |||
1095 | field->flags &= ~HID_MAIN_ITEM_CONSTANT; | ||
1096 | field->flags |= HID_MAIN_ITEM_VARIABLE; | ||
1097 | } | ||
1098 | |||
1099 | static void mt_fix_const_fields(struct hid_device *hdev, unsigned int usage) | ||
1100 | { | ||
1101 | struct hid_report *report; | ||
1102 | int i; | ||
1103 | |||
1104 | list_for_each_entry(report, | ||
1105 | &hdev->report_enum[HID_INPUT_REPORT].report_list, | ||
1106 | list) { | ||
1107 | |||
1108 | if (!report->maxfield) | ||
1109 | continue; | ||
1110 | |||
1111 | for (i = 0; i < report->maxfield; i++) | ||
1112 | if (report->field[i]->maxusage >= 1) | ||
1113 | mt_fix_const_field(report->field[i], usage); | ||
1114 | } | ||
1115 | } | ||
1116 | |||
1081 | static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | 1117 | static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) |
1082 | { | 1118 | { |
1083 | int ret, i; | 1119 | int ret, i; |
@@ -1151,6 +1187,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) | |||
1151 | if (ret != 0) | 1187 | if (ret != 0) |
1152 | return ret; | 1188 | return ret; |
1153 | 1189 | ||
1190 | if (mtclass->quirks & MT_QUIRK_FIX_CONST_CONTACT_ID) | ||
1191 | mt_fix_const_fields(hdev, HID_DG_CONTACTID); | ||
1192 | |||
1154 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); | 1193 | ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); |
1155 | if (ret) | 1194 | if (ret) |
1156 | return ret; | 1195 | return ret; |
@@ -1398,6 +1437,11 @@ static const struct hid_device_id mt_devices[] = { | |||
1398 | MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, | 1437 | MT_USB_DEVICE(USB_VENDOR_ID_ILITEK, |
1399 | USB_DEVICE_ID_ILITEK_MULTITOUCH) }, | 1438 | USB_DEVICE_ID_ILITEK_MULTITOUCH) }, |
1400 | 1439 | ||
1440 | /* LG Melfas panel */ | ||
1441 | { .driver_data = MT_CLS_LG, | ||
1442 | HID_USB_DEVICE(USB_VENDOR_ID_LG, | ||
1443 | USB_DEVICE_ID_LG_MELFAS_MT) }, | ||
1444 | |||
1401 | /* MosArt panels */ | 1445 | /* MosArt panels */ |
1402 | { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, | 1446 | { .driver_data = MT_CLS_CONFIDENCE_MINUS_ONE, |
1403 | MT_USB_DEVICE(USB_VENDOR_ID_ASUS, | 1447 | MT_USB_DEVICE(USB_VENDOR_ID_ASUS, |