From d9c57a7090ba5eaef716e0ab443d6bdd06278a68 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 20 Mar 2018 12:04:45 +0100 Subject: [PATCH 1/7] HID: multitouch: export a quirk for the button handling of touchpads Instead of using the class name, we better have a specific quirk for it so other classes can make use of it. Signed-off-by: Benjamin Tissoires Acked-by: Peter Hutterer Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 3b4739bde05d..504a95e0388f 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -74,6 +74,7 @@ MODULE_LICENSE("GPL"); #define MT_QUIRK_TOUCH_SIZE_SCALING BIT(15) #define MT_QUIRK_STICKY_FINGERS BIT(16) #define MT_QUIRK_ASUS_CUSTOM_UP BIT(17) +#define MT_QUIRK_WIN8_PTP_BUTTONS BIT(18) #define MT_INPUTMODE_TOUCHSCREEN 0x02 #define MT_INPUTMODE_TOUCHPAD 0x03 @@ -241,7 +242,8 @@ static struct mt_class mt_classes[] = { MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | MT_QUIRK_CONTACT_CNT_ACCURATE | - MT_QUIRK_STICKY_FINGERS }, + MT_QUIRK_STICKY_FINGERS | + MT_QUIRK_WIN8_PTP_BUTTONS }, { .name = MT_CLS_EXPORT_ALL_INPUTS, .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_CONTACT_CNT_ACCURATE, @@ -250,7 +252,8 @@ static struct mt_class mt_classes[] = { .quirks = MT_QUIRK_ALWAYS_VALID | MT_QUIRK_IGNORE_DUPLICATES | MT_QUIRK_HOVERING | - MT_QUIRK_CONTACT_CNT_ACCURATE, + MT_QUIRK_CONTACT_CNT_ACCURATE | + MT_QUIRK_WIN8_PTP_BUTTONS, .export_all_inputs = true }, /* @@ -659,8 +662,7 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, * MS PTP spec says that external buttons left and right have * usages 2 and 3. */ - if ((cls->name == MT_CLS_WIN_8 || - cls->name == MT_CLS_WIN_8_DUAL) && + if ((cls->quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && field->application == HID_DG_TOUCHPAD && (usage->hid & HID_USAGE) > 1) code--; @@ -772,9 +774,7 @@ static void mt_complete_slot(struct mt_device *td, struct input_dev *input) */ static void mt_sync_frame(struct mt_device *td, struct input_dev *input) { - __s32 cls = td->mtclass.name; - - if (cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) + if (td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS) input_event(input, EV_KEY, BTN_LEFT, td->left_button_state); input_mt_sync_frame(input); @@ -826,7 +826,6 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, bool first_packet) { struct mt_device *td = hid_get_drvdata(hid); - __s32 cls = td->mtclass.name; __s32 quirks = td->mtclass.quirks; struct input_dev *input = field->hidinput->input; @@ -904,7 +903,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, * non finger/touch events in the first_packet of * a (possible) multi-packet frame. */ - if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) && + if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && !first_packet) return; @@ -915,7 +914,7 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, * BTN_LEFT if either is pressed, so we or all values * together and report the result in mt_sync_frame(). */ - if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) && + if ((quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && usage->type == EV_KEY && usage->code == BTN_LEFT) { td->left_button_state |= value; return; @@ -939,7 +938,6 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, static void mt_touch_report(struct hid_device *hid, struct hid_report *report) { struct mt_device *td = hid_get_drvdata(hid); - __s32 cls = td->mtclass.name; struct hid_field *field; bool first_packet; unsigned count; @@ -968,7 +966,7 @@ static void mt_touch_report(struct hid_device *hid, struct hid_report *report) * of a possible multi-packet frame be checking that the * timestamp has changed. */ - if ((cls == MT_CLS_WIN_8 || cls == MT_CLS_WIN_8_DUAL) && + if ((td->mtclass.quirks & MT_QUIRK_WIN8_PTP_BUTTONS) && td->num_received == 0 && td->prev_scantime != scantime) td->num_expected = value; /* A non 0 contact count always indicates a first packet */ From 843e475f944a531210c71943efe09fca346a9a03 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 20 Mar 2018 12:04:46 +0100 Subject: [PATCH 2/7] HID: multitouch: remove dead zones of Razer Blade Stealth The Razer Blade Stealth detects palms too aggressively and this creates a dead zone around the touchpad. Users like being able to use their entire touchpad, so we should probably not filter out the "palm" events from the device and report them as regular touches, leaving the palm detection up to the upper stack Link: https://bugs.freedesktop.org/show_bug.cgi?id=105409 Signed-off-by: Benjamin Tissoires Acked-by: Peter Hutterer Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 504a95e0388f..bc724e6b75c9 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -184,6 +184,7 @@ static void mt_post_parse(struct mt_device *td); #define MT_CLS_ASUS 0x010b #define MT_CLS_VTL 0x0110 #define MT_CLS_GOOGLE 0x0111 +#define MT_CLS_RAZER_BLADE_STEALTH 0x0112 #define MT_DEFAULT_MAXCONTACT 10 #define MT_MAX_MAXCONTACT 250 @@ -326,6 +327,13 @@ static struct mt_class mt_classes[] = { MT_QUIRK_SLOT_IS_CONTACTID | MT_QUIRK_HOVERING }, + { .name = MT_CLS_RAZER_BLADE_STEALTH, + .quirks = MT_QUIRK_ALWAYS_VALID | + MT_QUIRK_IGNORE_DUPLICATES | + MT_QUIRK_HOVERING | + MT_QUIRK_CONTACT_CNT_ACCURATE | + MT_QUIRK_WIN8_PTP_BUTTONS, + }, { } }; @@ -1791,6 +1799,11 @@ static const struct hid_device_id mt_devices[] = { MT_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001) }, + /* Razer touchpads */ + { .driver_data = MT_CLS_RAZER_BLADE_STEALTH, + HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8, + USB_VENDOR_ID_SYNAPTICS, 0x8323) }, + /* Stantum panels */ { .driver_data = MT_CLS_CONFIDENCE, MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM, From 1c6ef16d38091a1820e98df25900b5977e404bbd Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 20 Mar 2018 12:04:47 +0100 Subject: [PATCH 3/7] HID: use BIT macro instead of plain integers for flags This can lead to some hairy situation with the developer losing a day or two realizing that 4 should be after 2, not 3. Signed-off-by: Benjamin Tissoires Reviewed-by: Dmitry Torokhov Acked-by: Peter Hutterer -- include/linux/hid.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) Signed-off-by: Jiri Kosina --- include/linux/hid.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/include/linux/hid.h b/include/linux/hid.h index 091a81cf330f..d104f2ebc809 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -26,6 +26,7 @@ #define __HID_H +#include #include #include #include @@ -494,13 +495,13 @@ struct hid_output_fifo { char *raw_report; }; -#define HID_CLAIMED_INPUT 1 -#define HID_CLAIMED_HIDDEV 2 -#define HID_CLAIMED_HIDRAW 4 -#define HID_CLAIMED_DRIVER 8 +#define HID_CLAIMED_INPUT BIT(0) +#define HID_CLAIMED_HIDDEV BIT(1) +#define HID_CLAIMED_HIDRAW BIT(2) +#define HID_CLAIMED_DRIVER BIT(3) -#define HID_STAT_ADDED 1 -#define HID_STAT_PARSED 2 +#define HID_STAT_ADDED BIT(0) +#define HID_STAT_PARSED BIT(1) struct hid_input { struct list_head list; From c30e5989d6926c5c1c77c87ed1e54f506e095d74 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 20 Mar 2018 12:04:48 +0100 Subject: [PATCH 4/7] HID: use BIT() macro for quirks too This should prevent future mess ups fortunately. Signed-off-by: Benjamin Tissoires Acked-by: Peter Hutterer -- include/linux/hid.h | 52 ++++++++++++++++++++++++++-------------------------- 1 file changed, 26 insertions(+), 26 deletions(-) Signed-off-by: Jiri Kosina --- include/linux/hid.h | 52 ++++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/include/linux/hid.h b/include/linux/hid.h index d104f2ebc809..bc92005e5f08 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -311,13 +311,13 @@ struct hid_item { * HID connect requests */ -#define HID_CONNECT_HIDINPUT 0x01 -#define HID_CONNECT_HIDINPUT_FORCE 0x02 -#define HID_CONNECT_HIDRAW 0x04 -#define HID_CONNECT_HIDDEV 0x08 -#define HID_CONNECT_HIDDEV_FORCE 0x10 -#define HID_CONNECT_FF 0x20 -#define HID_CONNECT_DRIVER 0x40 +#define HID_CONNECT_HIDINPUT BIT(0) +#define HID_CONNECT_HIDINPUT_FORCE BIT(1) +#define HID_CONNECT_HIDRAW BIT(2) +#define HID_CONNECT_HIDDEV BIT(3) +#define HID_CONNECT_HIDDEV_FORCE BIT(4) +#define HID_CONNECT_FF BIT(5) +#define HID_CONNECT_DRIVER BIT(6) #define HID_CONNECT_DEFAULT (HID_CONNECT_HIDINPUT|HID_CONNECT_HIDRAW| \ HID_CONNECT_HIDDEV|HID_CONNECT_FF) @@ -330,25 +330,25 @@ struct hid_item { */ #define MAX_USBHID_BOOT_QUIRKS 4 -#define HID_QUIRK_INVERT 0x00000001 -#define HID_QUIRK_NOTOUCH 0x00000002 -#define HID_QUIRK_IGNORE 0x00000004 -#define HID_QUIRK_NOGET 0x00000008 -#define HID_QUIRK_HIDDEV_FORCE 0x00000010 -#define HID_QUIRK_BADPAD 0x00000020 -#define HID_QUIRK_MULTI_INPUT 0x00000040 -#define HID_QUIRK_HIDINPUT_FORCE 0x00000080 -#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100 -/* 0x00000200 reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */ -#define HID_QUIRK_ALWAYS_POLL 0x00000400 -#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 -#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID 0x00020000 -#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP 0x00040000 -#define HID_QUIRK_HAVE_SPECIAL_DRIVER 0x00080000 -#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 -#define HID_QUIRK_NO_INIT_REPORTS 0x20000000 -#define HID_QUIRK_NO_IGNORE 0x40000000 -#define HID_QUIRK_NO_INPUT_SYNC 0x80000000 +#define HID_QUIRK_INVERT BIT(0) +#define HID_QUIRK_NOTOUCH BIT(1) +#define HID_QUIRK_IGNORE BIT(2) +#define HID_QUIRK_NOGET BIT(3) +#define HID_QUIRK_HIDDEV_FORCE BIT(4) +#define HID_QUIRK_BADPAD BIT(5) +#define HID_QUIRK_MULTI_INPUT BIT(6) +#define HID_QUIRK_HIDINPUT_FORCE BIT(7) +#define HID_QUIRK_NO_EMPTY_INPUT BIT(8) +/* BIT(9) reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */ +#define HID_QUIRK_ALWAYS_POLL BIT(10) +#define HID_QUIRK_SKIP_OUTPUT_REPORTS BIT(16) +#define HID_QUIRK_SKIP_OUTPUT_REPORT_ID BIT(17) +#define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP BIT(18) +#define HID_QUIRK_HAVE_SPECIAL_DRIVER BIT(19) +#define HID_QUIRK_FULLSPEED_INTERVAL BIT(28) +#define HID_QUIRK_NO_INIT_REPORTS BIT(29) +#define HID_QUIRK_NO_IGNORE BIT(30) +#define HID_QUIRK_NO_INPUT_SYNC BIT(31) /* * HID device groups From 39335d1cbb8fb3260ac5f18fbcc45beb690e5ebd Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 20 Mar 2018 12:04:49 +0100 Subject: [PATCH 5/7] HID: core: remove the need for HID_QUIRK_NO_EMPTY_INPUT There is no real point of registering an empty input node. This should be default, but given some drivers need the blank input node to set it up during input_configured, we need to postpone the check for hidinput_has_been_populated(). Signed-off-by: Benjamin Tissoires Acked-by: Peter Hutterer Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 3 +-- drivers/hid/hid-input.c | 10 +++++----- drivers/hid/hid-multitouch.c | 1 - drivers/hid/hid-uclogic.c | 1 - include/linux/hid.h | 2 +- 5 files changed, 7 insertions(+), 10 deletions(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 88b9703318e4..cc738ebf93ac 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -644,8 +644,7 @@ static int asus_probe(struct hid_device *hdev, const struct hid_device_id *id) * All functionality is on a single HID interface and for * userspace the touchpad must be a separate input_dev. */ - hdev->quirks |= HID_QUIRK_MULTI_INPUT | - HID_QUIRK_NO_EMPTY_INPUT; + hdev->quirks |= HID_QUIRK_MULTI_INPUT; drvdata->tp = &asus_t100chi_tp; } diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 04d01b57d94c..b237b5590227 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -1656,16 +1656,16 @@ int hidinput_connect(struct hid_device *hid, unsigned int force) } list_for_each_entry_safe(hidinput, next, &hid->inputs, list) { - if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) && - !hidinput_has_been_populated(hidinput)) { + if (drv->input_configured && + drv->input_configured(hid, hidinput)) + goto out_unwind; + + if (!hidinput_has_been_populated(hidinput)) { /* no need to register an input device not populated */ hidinput_cleanup_hidinput(hid, hidinput); continue; } - if (drv->input_configured && - drv->input_configured(hid, hidinput)) - goto out_unwind; if (input_register_device(hidinput->input)) goto out_unwind; hidinput->registered = true; diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index bc724e6b75c9..c4d89830cd1f 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -1469,7 +1469,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) * device. */ hdev->quirks |= HID_QUIRK_MULTI_INPUT; - hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT; /* * Some multitouch screens do not like to be polled for input diff --git a/drivers/hid/hid-uclogic.c b/drivers/hid/hid-uclogic.c index e3e6e5c893cc..56b196d60041 100644 --- a/drivers/hid/hid-uclogic.c +++ b/drivers/hid/hid-uclogic.c @@ -946,7 +946,6 @@ static int uclogic_probe(struct hid_device *hdev, * than the pen, so use QUIRK_MULTI_INPUT for all tablets. */ hdev->quirks |= HID_QUIRK_MULTI_INPUT; - hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT; /* Allocate and assign driver data */ drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL); diff --git a/include/linux/hid.h b/include/linux/hid.h index bc92005e5f08..b0db16fa7093 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -338,7 +338,7 @@ struct hid_item { #define HID_QUIRK_BADPAD BIT(5) #define HID_QUIRK_MULTI_INPUT BIT(6) #define HID_QUIRK_HIDINPUT_FORCE BIT(7) -#define HID_QUIRK_NO_EMPTY_INPUT BIT(8) +/* BIT(8) reserved for backward compatibility, was HID_QUIRK_NO_EMPTY_INPUT */ /* BIT(9) reserved for backward compatibility, was NO_INIT_INPUT_REPORTS */ #define HID_QUIRK_ALWAYS_POLL BIT(10) #define HID_QUIRK_SKIP_OUTPUT_REPORTS BIT(16) From adaabbf48fdf0ef31997e4054a88aaba16ad8b76 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 20 Mar 2018 12:04:50 +0100 Subject: [PATCH 6/7] HID: multitouch: do not set HID_QUIRK_NO_INIT_REPORTS It is set by default now, so there is no point setting it in the driver Signed-off-by: Benjamin Tissoires Acked-by: Peter Hutterer Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 18 +----------------- 1 file changed, 1 insertion(+), 17 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index c4d89830cd1f..f05d372ba71e 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -380,7 +380,6 @@ static const struct attribute_group mt_attribute_group = { static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) { - struct mt_device *td = hid_get_drvdata(hdev); int ret, size = hid_report_len(report); u8 *buf; @@ -388,7 +387,7 @@ static void mt_get_feature(struct hid_device *hdev, struct hid_report *report) * Do not fetch the feature report if the device has been explicitly * marked as non-capable. */ - if (td->initial_quirks & HID_QUIRK_NO_INIT_REPORTS) + if (hdev->quirks & HID_QUIRK_NO_INIT_REPORTS) return; buf = hid_alloc_report_buf(report, GFP_KERNEL); @@ -1470,21 +1469,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) */ hdev->quirks |= HID_QUIRK_MULTI_INPUT; - /* - * Some multitouch screens do not like to be polled for input - * reports. Fortunately, the Win8 spec says that all touches - * should be sent during each report, making the initialization - * of input reports unnecessary. For Win7 devices, well, let's hope - * they will still be happy (this is only be a problem if a touch - * was already there while probing the device). - * - * In addition some touchpads do not behave well if we read - * all feature reports from them. Instead we prevent - * initial report fetching and then selectively fetch each - * report we are interested in. - */ - hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; - timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); From 2904e68ff2ceb6f18f2f130749e6862c90725ab6 Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Tue, 20 Mar 2018 12:04:51 +0100 Subject: [PATCH 7/7] HID: core: reset the quirks before calling probe again Given that now the quirk handling is done in hid-quirk.c, we can actually reset the quirks before calling .probe(), so that the drivers do not need to keep track of initial quirks. Signed-off-by: Benjamin Tissoires Acked-by: Peter Hutterer Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 ++ drivers/hid/hid-multitouch.c | 7 ------- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index c2560aae5542..fdb8b6ed6d4c 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1966,6 +1966,8 @@ static int hid_device_probe(struct device *dev) } } + /* reset the quirks that has been previously set */ + hdev->quirks = hid_lookup_quirk(hdev); hdev->driver = hdrv; if (hdrv->probe) { ret = hdrv->probe(hdev, id); diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index f05d372ba71e..6ae2d14146b3 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -127,7 +127,6 @@ struct mt_device { int left_button_state; /* left button state */ unsigned last_slot_field; /* the last field of a slot */ unsigned mt_report_id; /* the report ID of the multitouch device */ - unsigned long initial_quirks; /* initial quirks state */ __s16 inputmode; /* InputMode HID feature, -1 if non-existent */ __s16 inputmode_index; /* InputMode HID feature index in the report */ __s16 maxcontact_report_id; /* Maximum Contact Number HID feature, @@ -1452,11 +1451,6 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) if (id->vendor == HID_ANY_ID && id->product == HID_ANY_ID) td->serial_maybe = true; - /* - * Store the initial quirk state - */ - td->initial_quirks = hdev->quirks; - /* This allows the driver to correctly support devices * that emit events over several HID messages. */ @@ -1526,7 +1520,6 @@ static void mt_remove(struct hid_device *hdev) sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group); hid_hw_stop(hdev); - hdev->quirks = td->initial_quirks; } /*