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, |
