From ad8378ede6f933cd6fe0c4c12ec65a3db469b2ca Mon Sep 17 00:00:00 2001 From: Bhumika Goyal Date: Mon, 21 Aug 2017 17:13:09 +0530 Subject: [PATCH 01/33] HID: make device_attribute const Make this const as it is only passed as an argument to the function device_create_file and device_remove_file and the corresponding arguments are of type const. Done using Coccinelle Signed-off-by: Bhumika Goyal Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 9bc91160819b..24e929cbf0e8 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1662,7 +1662,7 @@ static struct bin_attribute dev_bin_attr_report_desc = { .size = HID_MAX_DESCRIPTOR_SIZE, }; -static struct device_attribute dev_attr_country = { +static const struct device_attribute dev_attr_country = { .attr = { .name = "country", .mode = 0444 }, .show = show_country, }; From 47af1cdb309c65b36230b44e77383ed53b503d0e Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 25 Aug 2017 18:12:50 +0100 Subject: [PATCH 02/33] HID: hid-lg: make array cbuf static const to shink object code size Don't populate array cbuf on the stack, instead make it static. Makes the object code smaller by over 110 bytes: Before: text data bss dec hex filename 15096 3504 128 18728 4928 drivers/hid/hid-lg.o After: text data bss dec hex filename 14884 3600 128 18612 48b4 drivers/hid/hid-lg.o Signed-off-by: Colin Ian King Signed-off-by: Jiri Kosina --- drivers/hid/hid-lg.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c index 52026dc94d5c..596227ddb6e0 100644 --- a/drivers/hid/hid-lg.c +++ b/drivers/hid/hid-lg.c @@ -756,7 +756,9 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id) /* Setup wireless link with Logitech Wii wheel */ if (hdev->product == USB_DEVICE_ID_LOGITECH_WII_WHEEL) { - const unsigned char cbuf[] = { 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + static const unsigned char cbuf[] = { + 0x00, 0xAF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 + }; u8 *buf = kmemdup(cbuf, sizeof(cbuf), GFP_KERNEL); if (!buf) { From 7690dd18ddeda98521f4966e60e1a70b97316d11 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Thu, 7 Sep 2017 17:48:55 -0700 Subject: [PATCH 03/33] HID: wacom: generic: Use generic codepath terminology in wacom_wac_pen_report The terminology used to describe the various degrees of pen proximity within the wacom_wac_pen_report function does not match that used elsewhere in the generic codepath. Specifically, the names of the variables "prox" and "range" were inspired by the non-generic codepaths. To make the generic codepath internally consistent, replace these terms with "range" and "sense" respectively. Signed-off-by: Jason Gerecke Signed-off-by: Ping Cheng Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index aa692e28b2cd..cdf95e1999d1 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2217,7 +2217,7 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field if (!usage->type || delay_pen_events(wacom_wac)) return; - /* send pen events only when the pen is in/entering/leaving proximity */ + /* send pen events only when the pen is in/entering/leaving range */ if (!wacom_wac->hid_data.inrange_state && !wacom_wac->tool[0]) return; @@ -2236,11 +2236,11 @@ static void wacom_wac_pen_report(struct hid_device *hdev, struct wacom *wacom = hid_get_drvdata(hdev); struct wacom_wac *wacom_wac = &wacom->wacom_wac; struct input_dev *input = wacom_wac->pen_input; - bool prox = wacom_wac->hid_data.inrange_state; - bool range = wacom_wac->hid_data.sense_state; + bool range = wacom_wac->hid_data.inrange_state; + bool sense = wacom_wac->hid_data.sense_state; - if (!wacom_wac->tool[0] && prox) { /* first in prox */ - /* Going into proximity select tool */ + if (!wacom_wac->tool[0] && range) { /* first in range */ + /* Going into range select tool */ if (wacom_wac->hid_data.invert_state) wacom_wac->tool[0] = BTN_TOOL_RUBBER; else if (wacom_wac->id[0]) @@ -2250,7 +2250,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev, } /* keep pen state for touch events */ - wacom_wac->shared->stylus_in_proximity = range; + wacom_wac->shared->stylus_in_proximity = sense; if (!delay_pen_events(wacom_wac) && wacom_wac->tool[0]) { int id = wacom_wac->id[0]; @@ -2269,10 +2269,10 @@ static void wacom_wac_pen_report(struct hid_device *hdev, */ input_report_key(input, BTN_TOUCH, wacom_wac->hid_data.tipswitch); - input_report_key(input, wacom_wac->tool[0], prox); + input_report_key(input, wacom_wac->tool[0], range); if (wacom_wac->serial[0]) { input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]); - input_report_abs(input, ABS_MISC, prox ? id : 0); + input_report_abs(input, ABS_MISC, range ? id : 0); } wacom_wac->hid_data.tipswitch = false; @@ -2280,7 +2280,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev, input_sync(input); } - if (!prox) { + if (!range) { wacom_wac->tool[0] = 0; wacom_wac->id[0] = 0; wacom_wac->serial[0] = 0; From 4affc2331a70fff3d0d0e8f28ead80aa2b8b589a Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Thu, 7 Sep 2017 17:49:50 -0700 Subject: [PATCH 04/33] HID: wacom: generic: Leave tool in prox until it completely leaves sense The legacy Intuos codepath and tablet behavior (e.g. the 1st-gen Intuos Pro, Cintiq 27, etc.) would result in a BTN_TOOL_* event not being cleared to zero until the tool had completely left the sensing range of the tablet. Before the final "out of prox" packet would be sent, zero or more "in range" packets could be sent to indicate that a pen was still detectable but not within a useful distance. These "in range" packets were used by the driver to keep touch input disabled at greater pen distances. In addition to keeping the `stylus_in_proximity` flag set, the driver would leave the current BTN_TOOL_* marked as being in proximity as well. The new HID codepath also sets `stylus_in_proximity` based on the "sense" flag, but does not leave the current BTN_TOOL_* marked as being in prox. This information is potentially useful to for a future userspace-based palm rejection, so this patch modifies the driver to continue sending it. Signed-off-by: Jason Gerecke Reviewed-by: Ping Cheng Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index cdf95e1999d1..9b3a247ee552 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2217,8 +2217,8 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field if (!usage->type || delay_pen_events(wacom_wac)) return; - /* send pen events only when the pen is in/entering/leaving range */ - if (!wacom_wac->hid_data.inrange_state && !wacom_wac->tool[0]) + /* send pen events only when the pen is in range */ + if (!wacom_wac->hid_data.inrange_state) return; input_event(input, usage->type, usage->code, value); @@ -2269,10 +2269,10 @@ static void wacom_wac_pen_report(struct hid_device *hdev, */ input_report_key(input, BTN_TOUCH, wacom_wac->hid_data.tipswitch); - input_report_key(input, wacom_wac->tool[0], range); + input_report_key(input, wacom_wac->tool[0], sense); if (wacom_wac->serial[0]) { input_event(input, EV_MSC, MSC_SERIAL, wacom_wac->serial[0]); - input_report_abs(input, ABS_MISC, range ? id : 0); + input_report_abs(input, ABS_MISC, sense ? id : 0); } wacom_wac->hid_data.tipswitch = false; @@ -2280,7 +2280,7 @@ static void wacom_wac_pen_report(struct hid_device *hdev, input_sync(input); } - if (!range) { + if (!sense) { wacom_wac->tool[0] = 0; wacom_wac->id[0] = 0; wacom_wac->serial[0] = 0; From 3e70969e44ee52d72053145dab2cbad74109c685 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Thu, 7 Sep 2017 17:51:06 -0700 Subject: [PATCH 05/33] HID: wacom: generic: Send BTN_TOOL_PEN in prox once the pen enters range When a pen is first able to to be sensed by the tablet, we would like to inform userspace that a tool is nearby so that it can attempt to perform palm rejection. Unfortunately, we don't know any information about the tool that is nearby, so the best we can do is send a prox event for a generic BTN_TOOL_PEN. If the pen later comes closer and enters proximity, we can determine the actual tool type and send BTN_TOOL_PEN out of prox if necessary. Signed-off-by: Ping Cheng Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 9b3a247ee552..929a1ceabc21 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2247,6 +2247,17 @@ static void wacom_wac_pen_report(struct hid_device *hdev, wacom_wac->tool[0] = wacom_intuos_get_tool_type(wacom_wac->id[0]); else wacom_wac->tool[0] = BTN_TOOL_PEN; + + if (wacom_wac->shared->stylus_in_proximity && + wacom_wac->tool[0] != BTN_TOOL_PEN) { + input_report_key(input, BTN_TOOL_PEN, 0); + input_sync(input); + } + } + else if (!wacom_wac->tool[0] && !range) { /* entering in sense */ + input_report_key(input, BTN_TOOL_PEN, sense); + input_report_key(input, BTN_TOUCH, 0); + input_sync(input); } /* keep pen state for touch events */ From 5b40104edfb003b1e8bae3e546771e6edb59c6b7 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Thu, 7 Sep 2017 17:52:15 -0700 Subject: [PATCH 06/33] HID: wacom: generic: Reset events back to zero when pen leaves As a pen leaves, we need to be sure to reset all events back to zero so that userspace is able to get the complete pen state when it enters proximity again. Signed-off-by: Jason Gerecke Reviewed-by: Ping Cheng Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 929a1ceabc21..2926e36cb684 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2218,10 +2218,10 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field return; /* send pen events only when the pen is in range */ - if (!wacom_wac->hid_data.inrange_state) - return; - - input_event(input, usage->type, usage->code, value); + if (wacom_wac->hid_data.inrange_state) + input_event(input, usage->type, usage->code, value); + else if (wacom_wac->shared->stylus_in_proximity && !wacom_wac->hid_data.sense_state) + input_event(input, usage->type, usage->code, 0); } static void wacom_wac_pen_pre_report(struct hid_device *hdev, From 832e1eeeba916b389c3ba090d8335aff3089428e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20Belleng=C3=A9?= Date: Thu, 7 Sep 2017 21:17:28 +0200 Subject: [PATCH 07/33] HID: asus: Add support for Fn keys on Asus ROG G752 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch adds support for Fn keys on Asus ROG G752 laptop. The report descriptor is broken so I fixed it. Tested on an Asus G752VT. Resent fix white space fixes Signed-off-by: Maxime Bellengé Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 29 +++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 2 +- drivers/hid/hid-ids.h | 1 + 3 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 50c294be8324..27651f50738e 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -67,6 +67,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define QUIRK_USE_KBD_BACKLIGHT BIT(5) #define QUIRK_T100_KEYBOARD BIT(6) #define QUIRK_T100CHI BIT(7) +#define QUIRK_G752_KEYBOARD BIT(8) #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ QUIRK_NO_INIT_REPORTS | \ @@ -670,6 +671,11 @@ static void asus_remove(struct hid_device *hdev) hid_hw_stop(hdev); } +static const __u8 asus_g752_fixed_rdesc[] = { + 0x19, 0x00, /* Usage Minimum (0x00) */ + 0x2A, 0xFF, 0x00, /* Usage Maximum (0xFF) */ +}; + static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize) { @@ -708,6 +714,27 @@ static __u8 *asus_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[391] = 0xff; rdesc[402] = 0x00; } + if (drvdata->quirks & QUIRK_G752_KEYBOARD && + *rsize == 75 && rdesc[61] == 0x15 && rdesc[62] == 0x00) { + /* report is missing usage mninum and maximum */ + __u8 *new_rdesc; + size_t new_size = *rsize + sizeof(asus_g752_fixed_rdesc); + + new_rdesc = devm_kzalloc(&hdev->dev, new_size, GFP_KERNEL); + if (new_rdesc == NULL) + return rdesc; + + hid_info(hdev, "Fixing up Asus G752 keyb report descriptor\n"); + /* copy the valid part */ + memcpy(new_rdesc, rdesc, 61); + /* insert missing part */ + memcpy(new_rdesc + 61, asus_g752_fixed_rdesc, sizeof(asus_g752_fixed_rdesc)); + /* copy remaining data */ + memcpy(new_rdesc + 61 + sizeof(asus_g752_fixed_rdesc), rdesc + 61, *rsize - 61); + + *rsize = new_size; + rdesc = new_rdesc; + } return rdesc; } @@ -721,6 +748,8 @@ static const struct hid_device_id asus_devices[] = { USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2), QUIRK_USE_KBD_BACKLIGHT }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, + USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3), QUIRK_G752_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD), QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 9bc91160819b..4c1a499c6a62 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1979,6 +1979,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3) }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_ASUS_MD_5112) }, { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_ASUS_MD_5110) }, @@ -3119,4 +3120,3 @@ MODULE_AUTHOR("Andreas Gal"); MODULE_AUTHOR("Vojtech Pavlik"); MODULE_AUTHOR("Jiri Kosina"); MODULE_LICENSE("GPL"); - diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b397a14ab970..1b1fca0560f2 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -182,6 +182,7 @@ #define USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD 0x0101 #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854 #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837 +#define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822 #define USB_VENDOR_ID_ATEN 0x0557 #define USB_DEVICE_ID_ATEN_UC100KM 0x2004 From 4f210c2938053e894ee00500dd0661f7a27a6ff4 Mon Sep 17 00:00:00 2001 From: Jaejoong Kim Date: Wed, 20 Sep 2017 18:40:36 +0900 Subject: [PATCH 08/33] HID: add comment for power callback in struct hid_ll_driver There is a missing comment in struct hid_ll_driver. So, add it. Signed-off-by: Jaejoong Kim Signed-off-by: Jiri Kosina --- include/linux/hid.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/linux/hid.h b/include/linux/hid.h index ab05a86269dc..7c3d4a17bbde 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -753,6 +753,7 @@ struct hid_driver { * @stop: called on remove * @open: called by input layer on open * @close: called by input layer on close + * @power: request underlying hardware to enter requested power mode * @parse: this method is called only once to parse the device data, * shouldn't allocate anything to not leak memory * @request: send report request to device (e.g. feature report) From fc5431dc06d442828c8f92fb913257f7df3079aa Mon Sep 17 00:00:00 2001 From: Randy Dunlap Date: Sat, 23 Sep 2017 17:33:21 -0700 Subject: [PATCH 09/33] HID: retrode: tell what a Retrode is and drop a blank line Add descriptive info to prompt string so that someone can know what a Retrode is. Drop an unneeded blank line. Signed-off-by: Randy Dunlap Cc: Bastien Nocera Cc: Jiri Kosina Cc: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 0a3117cc29e7..d95c1abbd4cc 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -749,11 +749,10 @@ config HID_PRIMAX HID standard. config HID_RETRODE - tristate "Retrode" + tristate "Retrode 2 USB adapter for vintage video games" depends on USB_HID ---help--- Support for - * Retrode 2 cartridge and controller adapter config HID_ROCCAT From 29cc309d8bf19a36c5196bf626662319af6e3c0b Mon Sep 17 00:00:00 2001 From: Nicolas Boichat Date: Tue, 22 Aug 2017 09:10:11 +0800 Subject: [PATCH 10/33] HID: hid-multitouch: forward MSC_TIMESTAMP Computes and forwards the device timestamp according to the specification. Many devices use a 16-bit timestamp field, with a resolution of 100us, therefore rolling around very frequently (every 6.5 seconds). To make sure there is no ambiguity, the timestamp reported to the input stack reset to 0 whenever the time between 2 received events is greater than MAX_TIMESTAMP_INTERVAL (1 second). Signed-off-by: Nicolas Boichat Acked-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 42 ++++++++++++++++++++++++++++++++++++ include/linux/hid.h | 1 + 2 files changed, 43 insertions(+) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 440b999304a5..996bdc9bf0e5 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -43,6 +43,7 @@ #include #include #include +#include #include #include @@ -136,6 +137,9 @@ struct mt_device { bool serial_maybe; /* need to check for serial protocol */ bool curvalid; /* is the current contact valid? */ unsigned mt_flags; /* flags to pass to input-mt */ + __s32 dev_time; /* the scan time provided by the device */ + unsigned long jiffies; /* the frame's jiffies */ + int timestamp; /* the timestamp to be sent */ }; static void mt_post_parse_default_settings(struct mt_device *td); @@ -177,6 +181,12 @@ static void mt_post_parse(struct mt_device *td); #define MT_DEFAULT_MAXCONTACT 10 #define MT_MAX_MAXCONTACT 250 +/* + * Resync device and local timestamps after that many microseconds without + * receiving data. + */ +#define MAX_TIMESTAMP_INTERVAL 1000000 + #define MT_USB_DEVICE(v, p) HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH, v, p) #define MT_BT_DEVICE(v, p) HID_DEVICE(BUS_BLUETOOTH, HID_GROUP_MULTITOUCH, v, p) @@ -583,6 +593,12 @@ static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi, cls->sn_pressure); mt_store_field(usage, td, hi); return 1; + case HID_DG_SCANTIME: + hid_map_usage(hi, usage, bit, max, + EV_MSC, MSC_TIMESTAMP); + input_set_capability(hi->input, EV_MSC, MSC_TIMESTAMP); + mt_store_field(usage, td, hi); + return 1; case HID_DG_CONTACTCOUNT: /* Ignore if indexes are out of bounds. */ if (field->index >= field->report->maxfield || @@ -718,6 +734,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) { input_mt_sync_frame(input); + input_event(input, EV_MSC, MSC_TIMESTAMP, td->timestamp); input_sync(input); td->num_received = 0; if (test_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags)) @@ -727,6 +744,28 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input) clear_bit(MT_IO_FLAGS_ACTIVE_SLOTS, &td->mt_io_flags); } +static int mt_compute_timestamp(struct mt_device *td, struct hid_field *field, + __s32 value) +{ + long delta = value - td->dev_time; + unsigned long jdelta = jiffies_to_usecs(jiffies - td->jiffies); + + td->jiffies = jiffies; + td->dev_time = value; + + if (delta < 0) + delta += field->logical_maximum; + + /* HID_DG_SCANTIME is expressed in 100us, we want it in us. */ + delta *= 100; + + if (jdelta > MAX_TIMESTAMP_INTERVAL) + /* No data received for a while, resync the timestamp. */ + return 0; + else + return td->timestamp + delta; +} + static int mt_touch_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value) { @@ -787,6 +826,9 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field, case HID_DG_HEIGHT: td->curdata.h = value; break; + case HID_DG_SCANTIME: + td->timestamp = mt_compute_timestamp(td, field, value); + break; case HID_DG_CONTACTCOUNT: break; case HID_DG_TOUCH: diff --git a/include/linux/hid.h b/include/linux/hid.h index ab05a86269dc..47dd962d9a7a 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -289,6 +289,7 @@ struct hid_item { #define HID_DG_DEVICEINDEX 0x000d0053 #define HID_DG_CONTACTCOUNT 0x000d0054 #define HID_DG_CONTACTMAX 0x000d0055 +#define HID_DG_SCANTIME 0x000d0056 #define HID_DG_BUTTONTYPE 0x000d0059 #define HID_DG_BARRELSWITCH2 0x000d005a #define HID_DG_TOOLSERIALNUMBER 0x000d005b From 654c192a72ffa7e415a9f58a4f4c5f4368b754e7 Mon Sep 17 00:00:00 2001 From: Ping Cheng Date: Tue, 3 Oct 2017 15:05:41 -0700 Subject: [PATCH 11/33] HID: hid-input: Add eraser usage to hidinput_configure_usage Some tablets report eraser usage to indicate the eraser tool tip is touching the surface. But, hidinput_configure_usage didn't support the usage, which led it falls into default as ABS_MISC. Signed-off-by: Ping Cheng Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 199f6a01fc62..04d01b57d94c 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -797,6 +797,15 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel map_key_clear(BTN_STYLUS); break; + case 0x45: /* ERASER */ + /* + * This event is reported when eraser tip touches the surface. + * Actual eraser (BTN_TOOL_RUBBER) is set by Invert usage when + * tool gets in proximity. + */ + map_key_clear(BTN_TOUCH); + break; + case 0x46: /* TabletPick */ case 0x5a: /* SecondaryBarrelSwitch */ map_key_clear(BTN_STYLUS2); From af42377978852234974c26efcca3d70eb86bd349 Mon Sep 17 00:00:00 2001 From: Arvind Yadav Date: Mon, 25 Sep 2017 17:34:27 +0530 Subject: [PATCH 12/33] HID: hyperv: pr_err() strings should end with newlines pr_err() messages should terminated with a new-line to avoid other messages being concatenated onto the end. Signed-off-by: Arvind Yadav Signed-off-by: Jiri Kosina --- drivers/hid/hid-hyperv.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-hyperv.c b/drivers/hid/hid-hyperv.c index 6039f071fab1..3aa2bb9f0f81 100644 --- a/drivers/hid/hid-hyperv.c +++ b/drivers/hid/hid-hyperv.c @@ -313,7 +313,7 @@ static void mousevsc_on_receive(struct hv_device *device, break; default: - pr_err("unsupported hid msg type - type %d len %d", + pr_err("unsupported hid msg type - type %d len %d\n", hid_msg->header.type, hid_msg->header.size); break; } From 2f84723de7cdd031f293b900fecd68ddbec3feaa Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Thu, 5 Oct 2017 11:14:02 -0700 Subject: [PATCH 13/33] Revert "HID: wacom: generic: Send BTN_TOOL_PEN in prox once the pen enters range" This reverts commit 3e70969e44ee52d72053145dab2cbad74109c685. This commit causes a few problems for userspace. The most noteworthy are problems related to the distinguishing of different pens and pointer jumps when entering proximity. Userspace is written with the expectation that a pen will provide its tool ID and serial number (if available) in the very first in-prox report. By sending BTN_TOOL_PEN when the tablet starts communicating rather than waiting until a tool ID/serial number is available, userspace ends up treating all pens as being the same and lacking a serial number. Similarly, userspace assumes that the first report will contain X/Y data, but by marking the pen as being in-prox without an X/Y coordinate, userspace ends up warping the pen to the last- known X/Y location. As of commit 5b40104edfb0 ("HID: wacom: generic: Reset events back to zero when pen leaves") this means warping to (0,0). Signed-off-by: Jason Gerecke Acked-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 2926e36cb684..e3223b0c4f90 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2247,17 +2247,6 @@ static void wacom_wac_pen_report(struct hid_device *hdev, wacom_wac->tool[0] = wacom_intuos_get_tool_type(wacom_wac->id[0]); else wacom_wac->tool[0] = BTN_TOOL_PEN; - - if (wacom_wac->shared->stylus_in_proximity && - wacom_wac->tool[0] != BTN_TOOL_PEN) { - input_report_key(input, BTN_TOOL_PEN, 0); - input_sync(input); - } - } - else if (!wacom_wac->tool[0] && !range) { /* entering in sense */ - input_report_key(input, BTN_TOOL_PEN, sense); - input_report_key(input, BTN_TOUCH, 0); - input_sync(input); } /* keep pen state for touch events */ From 0ee32774aed648854a06bc3fae636f20f5f75a68 Mon Sep 17 00:00:00 2001 From: Kees Cook Date: Wed, 4 Oct 2017 17:53:24 -0700 Subject: [PATCH 14/33] HID: usbhid: Convert timers to use timer_setup() In preparation for unconditionally passing the struct timer_list pointer to all timer callbacks, switch to using the new timer_setup() and from_timer() (introduced by 686fef928bba ("timer: Prepare to change timer callback argument type")) to pass the timer pointer explicitly. Adds pointer back to hid_device for multitouch. [jkosina@suse.cz: extend changelog a little bit as asked for by Benjamin] Cc: Jiri Kosina Cc: Benjamin Tissoires Cc: linux-input@vger.kernel.org Cc: linux-usb@vger.kernel.org Cc: Thomas Gleixner Signed-off-by: Kees Cook Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-multitouch.c | 10 ++++++---- drivers/hid/usbhid/hid-core.c | 8 ++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c index 9e8c4d2ba11d..8ba95c3af056 100644 --- a/drivers/hid/hid-multitouch.c +++ b/drivers/hid/hid-multitouch.c @@ -112,6 +112,7 @@ struct mt_device { struct mt_slot curdata; /* placeholder of incoming data */ struct mt_class mtclass; /* our mt device class */ struct timer_list release_timer; /* to release sticky fingers */ + struct hid_device *hdev; /* hid_device we're attached to */ struct mt_fields *fields; /* temporary placeholder for storing the multitouch fields */ unsigned long mt_io_flags; /* mt flags (MT_IO_FLAGS_*) */ @@ -1246,10 +1247,10 @@ static void mt_release_contacts(struct hid_device *hid) td->num_received = 0; } -static void mt_expired_timeout(unsigned long arg) +static void mt_expired_timeout(struct timer_list *t) { - struct hid_device *hdev = (void *)arg; - struct mt_device *td = hid_get_drvdata(hdev); + struct mt_device *td = from_timer(td, t, release_timer); + struct hid_device *hdev = td->hdev; /* * An input report came in just before we release the sticky fingers, @@ -1280,6 +1281,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) dev_err(&hdev->dev, "cannot allocate multitouch data\n"); return -ENOMEM; } + td->hdev = hdev; td->mtclass = *mtclass; td->inputmode = -1; td->maxcontact_report_id = -1; @@ -1331,7 +1333,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id) */ hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; - setup_timer(&td->release_timer, mt_expired_timeout, (long)hdev); + timer_setup(&td->release_timer, mt_expired_timeout, 0); ret = hid_parse(hdev); if (ret != 0) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 089bad8a9a21..9f9fe0e58f5b 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -101,10 +101,10 @@ static int hid_start_in(struct hid_device *hid) } /* I/O retry timer routine */ -static void hid_retry_timeout(unsigned long _hid) +static void hid_retry_timeout(struct timer_list *t) { - struct hid_device *hid = (struct hid_device *) _hid; - struct usbhid_device *usbhid = hid->driver_data; + struct usbhid_device *usbhid = from_timer(usbhid, t, io_retry); + struct hid_device *hid = usbhid->hid; dev_dbg(&usbhid->intf->dev, "retrying intr urb\n"); if (hid_start_in(hid)) @@ -1363,7 +1363,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id * init_waitqueue_head(&usbhid->wait); INIT_WORK(&usbhid->reset_work, hid_reset); - setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid); + timer_setup(&usbhid->io_retry, hid_retry_timeout, 0); spin_lock_init(&usbhid->lock); ret = hid_add_device(hid); From ce6abcf83bf451159f421fe4f928147a882ec9da Mon Sep 17 00:00:00 2001 From: Masaki Ota Date: Fri, 6 Oct 2017 11:53:13 +0900 Subject: [PATCH 15/33] HID: alps: delete unnecessary struct u1_dev devInfo Delete "struct u1_dev devInfo" structure, because u1_dev structure is already declared as "struct u1_dev *data". [jkosina@suse.cz: rewrite changelog] Signed-off-by: Masaki Ota Signed-off-by: Jiri Kosina --- drivers/hid/hid-alps.c | 69 +++++++++++++++++++++--------------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c index ed9c0ea5b026..519bfcf9eaf0 100644 --- a/drivers/hid/hid-alps.c +++ b/drivers/hid/hid-alps.c @@ -259,7 +259,6 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct u1_dev *data = hid_get_drvdata(hdev); struct input_dev *input = hi->input, *input2; - struct u1_dev devInfo; int ret; int res_x, res_y, i; @@ -275,58 +274,58 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) /* Device initialization */ ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, - &devInfo.dev_ctrl, 0, true); + &data->dev_ctrl, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_DEV_CTRL_1 (%d)\n", ret); goto exit; } - devInfo.dev_ctrl &= ~U1_DISABLE_DEV; - devInfo.dev_ctrl |= U1_TP_ABS_MODE; + data->dev_ctrl &= ~U1_DISABLE_DEV; + data->dev_ctrl |= U1_TP_ABS_MODE; ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, - NULL, devInfo.dev_ctrl, false); + NULL, data->dev_ctrl, false); if (ret < 0) { dev_err(&hdev->dev, "failed to change TP mode (%d)\n", ret); goto exit; } ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_X, - &devInfo.sen_line_num_x, 0, true); + &data->sen_line_num_x, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_NUM_SENS_X (%d)\n", ret); goto exit; } ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_Y, - &devInfo.sen_line_num_y, 0, true); + &data->sen_line_num_y, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_NUM_SENS_Y (%d)\n", ret); goto exit; } ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_X, - &devInfo.pitch_x, 0, true); + &data->pitch_x, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_PITCH_SENS_X (%d)\n", ret); goto exit; } ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_Y, - &devInfo.pitch_y, 0, true); + &data->pitch_y, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_PITCH_SENS_Y (%d)\n", ret); goto exit; } ret = u1_read_write_register(hdev, ADDRESS_U1_RESO_DWN_ABS, - &devInfo.resolution, 0, true); + &data->resolution, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_RESO_DWN_ABS (%d)\n", ret); goto exit; } ret = u1_read_write_register(hdev, ADDRESS_U1_PAD_BTN, - &devInfo.btn_info, 0, true); + &data->btn_info, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_PAD_BTN (%d)\n", ret); goto exit; @@ -334,29 +333,29 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) /* Check StickPointer device */ ret = u1_read_write_register(hdev, ADDRESS_U1_DEVICE_TYP, - &devInfo.dev_type, 0, true); + &data->dev_type, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_DEVICE_TYP (%d)\n", ret); goto exit; } - devInfo.x_active_len_mm = - (devInfo.pitch_x * (devInfo.sen_line_num_x - 1)) / 10; - devInfo.y_active_len_mm = - (devInfo.pitch_y * (devInfo.sen_line_num_y - 1)) / 10; + data->x_active_len_mm = + (data->pitch_x * (data->sen_line_num_x - 1)) / 10; + data->y_active_len_mm = + (data->pitch_y * (data->sen_line_num_y - 1)) / 10; - devInfo.x_max = - (devInfo.resolution << 2) * (devInfo.sen_line_num_x - 1); - devInfo.y_max = - (devInfo.resolution << 2) * (devInfo.sen_line_num_y - 1); + data->x_max = + (data->resolution << 2) * (data->sen_line_num_x - 1); + data->y_max = + (data->resolution << 2) * (data->sen_line_num_y - 1); __set_bit(EV_ABS, input->evbit); - input_set_abs_params(input, ABS_MT_POSITION_X, 1, devInfo.x_max, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 1, devInfo.y_max, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_X, 1, data->x_max, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, 1, data->y_max, 0, 0); - if (devInfo.x_active_len_mm && devInfo.y_active_len_mm) { - res_x = (devInfo.x_max - 1) / devInfo.x_active_len_mm; - res_y = (devInfo.y_max - 1) / devInfo.y_active_len_mm; + if (data->x_active_len_mm && data->y_active_len_mm) { + res_x = (data->x_max - 1) / data->x_active_len_mm; + res_y = (data->y_max - 1) / data->y_active_len_mm; input_abs_set_res(input, ABS_MT_POSITION_X, res_x); input_abs_set_res(input, ABS_MT_POSITION_Y, res_y); @@ -367,20 +366,20 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) input_mt_init_slots(input, MAX_TOUCHES, INPUT_MT_POINTER); __set_bit(EV_KEY, input->evbit); - if ((devInfo.btn_info & 0x0F) == (devInfo.btn_info & 0xF0) >> 4) { - devInfo.btn_cnt = (devInfo.btn_info & 0x0F); + if ((data->btn_info & 0x0F) == (data->btn_info & 0xF0) >> 4) { + data->btn_cnt = (data->btn_info & 0x0F); } else { /* Button pad */ - devInfo.btn_cnt = 1; + data->btn_cnt = 1; __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); } - for (i = 0; i < devInfo.btn_cnt; i++) + for (i = 0; i < data->btn_cnt; i++) __set_bit(BTN_LEFT + i, input->keybit); /* Stick device initialization */ - if (devInfo.dev_type & U1_DEVTYPE_SP_SUPPORT) { + if (data->dev_type & U1_DEVTYPE_SP_SUPPORT) { input2 = input_allocate_device(); if (!input2) { @@ -390,9 +389,9 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) data->input2 = input2; - devInfo.dev_ctrl |= U1_SP_ABS_MODE; + data->dev_ctrl |= U1_SP_ABS_MODE; ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, - NULL, devInfo.dev_ctrl, false); + NULL, data->dev_ctrl, false); if (ret < 0) { dev_err(&hdev->dev, "failed SP mode (%d)\n", ret); input_free_device(input2); @@ -400,7 +399,7 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) } ret = u1_read_write_register(hdev, ADDRESS_U1_SP_BTN, - &devInfo.sp_btn_info, 0, true); + &data->sp_btn_info, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_SP_BTN (%d)\n", ret); input_free_device(input2); @@ -416,8 +415,8 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) input2->dev.parent = input->dev.parent; __set_bit(EV_KEY, input2->evbit); - devInfo.sp_btn_cnt = (devInfo.sp_btn_info & 0x0F); - for (i = 0; i < devInfo.sp_btn_cnt; i++) + data->sp_btn_cnt = (data->sp_btn_info & 0x0F); + for (i = 0; i < data->sp_btn_cnt; i++) __set_bit(BTN_LEFT + i, input2->keybit); __set_bit(EV_REL, input2->evbit); From 5d8c720d3b74413cc62d5015f23f57a51dc06112 Mon Sep 17 00:00:00 2001 From: Masaki Ota Date: Fri, 6 Oct 2017 11:53:14 +0900 Subject: [PATCH 16/33] HID: alps: Separate U1 device code Create 'static int u1_init()' and factor out U1 device initialization code from main initialization and introduce per-device 'has_sp' flag. [jkosina@suse.cz: rewrite changelog] Signed-off-by: Masaki Ota Signed-off-by: Jiri Kosina --- drivers/hid/hid-alps.c | 204 ++++++++++++++++++++++------------------- 1 file changed, 109 insertions(+), 95 deletions(-) diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c index 519bfcf9eaf0..c4ea5c6c9be9 100644 --- a/drivers/hid/hid-alps.c +++ b/drivers/hid/hid-alps.c @@ -75,6 +75,7 @@ * @y_max: maximum y coordinate value * @btn_cnt: number of buttons * @sp_btn_cnt: number of stick buttons + * @has_sp: boolean of sp existense */ struct u1_dev { struct input_dev *input; @@ -96,6 +97,7 @@ struct u1_dev { u32 y_max; u32 btn_cnt; u32 sp_btn_cnt; + u8 has_sp; }; static int u1_read_write_register(struct hid_device *hdev, u32 address, @@ -255,6 +257,109 @@ static int alps_post_resume(struct hid_device *hdev) } #endif /* CONFIG_PM */ +static int u1_init(struct hid_device *hdev, struct u1_dev *pri_data) +{ + int ret; + + /* Device initialization */ + ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, + &pri_data->dev_ctrl, 0, true); + if (ret < 0) { + dev_err(&hdev->dev, "failed U1_DEV_CTRL_1 (%d)\n", ret); + goto exit; + } + + pri_data->dev_ctrl &= ~U1_DISABLE_DEV; + pri_data->dev_ctrl |= U1_TP_ABS_MODE; + ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, + NULL, pri_data->dev_ctrl, false); + if (ret < 0) { + dev_err(&hdev->dev, "failed to change TP mode (%d)\n", ret); + goto exit; + } + + ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_X, + &pri_data->sen_line_num_x, 0, true); + if (ret < 0) { + dev_err(&hdev->dev, "failed U1_NUM_SENS_X (%d)\n", ret); + goto exit; + } + + ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_Y, + &pri_data->sen_line_num_y, 0, true); + if (ret < 0) { + dev_err(&hdev->dev, "failed U1_NUM_SENS_Y (%d)\n", ret); + goto exit; + } + + ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_X, + &pri_data->pitch_x, 0, true); + if (ret < 0) { + dev_err(&hdev->dev, "failed U1_PITCH_SENS_X (%d)\n", ret); + goto exit; + } + + ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_Y, + &pri_data->pitch_y, 0, true); + if (ret < 0) { + dev_err(&hdev->dev, "failed U1_PITCH_SENS_Y (%d)\n", ret); + goto exit; + } + + ret = u1_read_write_register(hdev, ADDRESS_U1_RESO_DWN_ABS, + &pri_data->resolution, 0, true); + if (ret < 0) { + dev_err(&hdev->dev, "failed U1_RESO_DWN_ABS (%d)\n", ret); + goto exit; + } + pri_data->x_active_len_mm = + (pri_data->pitch_x * (pri_data->sen_line_num_x - 1)) / 10; + pri_data->y_active_len_mm = + (pri_data->pitch_y * (pri_data->sen_line_num_y - 1)) / 10; + + pri_data->x_max = + (pri_data->resolution << 2) * (pri_data->sen_line_num_x - 1); + pri_data->y_max = + (pri_data->resolution << 2) * (pri_data->sen_line_num_y - 1); + + ret = u1_read_write_register(hdev, ADDRESS_U1_PAD_BTN, + &pri_data->btn_info, 0, true); + if (ret < 0) { + dev_err(&hdev->dev, "failed U1_PAD_BTN (%d)\n", ret); + goto exit; + } + + pri_data->has_sp = 0; + /* Check StickPointer device */ + ret = u1_read_write_register(hdev, ADDRESS_U1_DEVICE_TYP, + &pri_data->dev_type, 0, true); + if (ret < 0) { + dev_err(&hdev->dev, "failed U1_DEVICE_TYP (%d)\n", ret); + goto exit; + } + + if (pri_data->dev_type & U1_DEVTYPE_SP_SUPPORT) { + pri_data->dev_ctrl |= U1_SP_ABS_MODE; + ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, + NULL, pri_data->dev_ctrl, false); + if (ret < 0) { + dev_err(&hdev->dev, "failed SP mode (%d)\n", ret); + goto exit; + } + + ret = u1_read_write_register(hdev, ADDRESS_U1_SP_BTN, + &pri_data->sp_btn_info, 0, true); + if (ret < 0) { + dev_err(&hdev->dev, "failed U1_SP_BTN (%d)\n", ret); + goto exit; + } + pri_data->has_sp = 1; + } + +exit: + return ret; +} + static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) { struct u1_dev *data = hid_get_drvdata(hdev); @@ -272,82 +377,10 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) /* Allow incoming hid reports */ hid_device_io_start(hdev); - /* Device initialization */ - ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, - &data->dev_ctrl, 0, true); - if (ret < 0) { - dev_err(&hdev->dev, "failed U1_DEV_CTRL_1 (%d)\n", ret); + ret = u1_init(hdev, data); + + if (ret) goto exit; - } - - data->dev_ctrl &= ~U1_DISABLE_DEV; - data->dev_ctrl |= U1_TP_ABS_MODE; - ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, - NULL, data->dev_ctrl, false); - if (ret < 0) { - dev_err(&hdev->dev, "failed to change TP mode (%d)\n", ret); - goto exit; - } - - ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_X, - &data->sen_line_num_x, 0, true); - if (ret < 0) { - dev_err(&hdev->dev, "failed U1_NUM_SENS_X (%d)\n", ret); - goto exit; - } - - ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_Y, - &data->sen_line_num_y, 0, true); - if (ret < 0) { - dev_err(&hdev->dev, "failed U1_NUM_SENS_Y (%d)\n", ret); - goto exit; - } - - ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_X, - &data->pitch_x, 0, true); - if (ret < 0) { - dev_err(&hdev->dev, "failed U1_PITCH_SENS_X (%d)\n", ret); - goto exit; - } - - ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_Y, - &data->pitch_y, 0, true); - if (ret < 0) { - dev_err(&hdev->dev, "failed U1_PITCH_SENS_Y (%d)\n", ret); - goto exit; - } - - ret = u1_read_write_register(hdev, ADDRESS_U1_RESO_DWN_ABS, - &data->resolution, 0, true); - if (ret < 0) { - dev_err(&hdev->dev, "failed U1_RESO_DWN_ABS (%d)\n", ret); - goto exit; - } - - ret = u1_read_write_register(hdev, ADDRESS_U1_PAD_BTN, - &data->btn_info, 0, true); - if (ret < 0) { - dev_err(&hdev->dev, "failed U1_PAD_BTN (%d)\n", ret); - goto exit; - } - - /* Check StickPointer device */ - ret = u1_read_write_register(hdev, ADDRESS_U1_DEVICE_TYP, - &data->dev_type, 0, true); - if (ret < 0) { - dev_err(&hdev->dev, "failed U1_DEVICE_TYP (%d)\n", ret); - goto exit; - } - - data->x_active_len_mm = - (data->pitch_x * (data->sen_line_num_x - 1)) / 10; - data->y_active_len_mm = - (data->pitch_y * (data->sen_line_num_y - 1)) / 10; - - data->x_max = - (data->resolution << 2) * (data->sen_line_num_x - 1); - data->y_max = - (data->resolution << 2) * (data->sen_line_num_y - 1); __set_bit(EV_ABS, input->evbit); input_set_abs_params(input, ABS_MT_POSITION_X, 1, data->x_max, 0, 0); @@ -379,8 +412,7 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) /* Stick device initialization */ - if (data->dev_type & U1_DEVTYPE_SP_SUPPORT) { - + if (data->has_sp) { input2 = input_allocate_device(); if (!input2) { ret = -ENOMEM; @@ -388,24 +420,6 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) } data->input2 = input2; - - data->dev_ctrl |= U1_SP_ABS_MODE; - ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, - NULL, data->dev_ctrl, false); - if (ret < 0) { - dev_err(&hdev->dev, "failed SP mode (%d)\n", ret); - input_free_device(input2); - goto exit; - } - - ret = u1_read_write_register(hdev, ADDRESS_U1_SP_BTN, - &data->sp_btn_info, 0, true); - if (ret < 0) { - dev_err(&hdev->dev, "failed U1_SP_BTN (%d)\n", ret); - input_free_device(input2); - goto exit; - } - input2->phys = input->phys; input2->name = "DualPoint Stick"; input2->id.bustype = BUS_I2C; From c7083d3f53482e8a2a6ee1238fbedfa7dbea7b3c Mon Sep 17 00:00:00 2001 From: Masaki Ota Date: Fri, 6 Oct 2017 11:53:15 +0900 Subject: [PATCH 17/33] HID: alps: properly handle max_fingers and minimum on X and Y axis Create x_min, y_min and max_fingers variables for set correct XY minimum value and the number of max finger on each devices. [jkosina@suse.cz: update shortlog] Signed-off-by: Masaki Ota Signed-off-by: Jiri Kosina --- drivers/hid/hid-alps.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c index c4ea5c6c9be9..201fe175cba3 100644 --- a/drivers/hid/hid-alps.c +++ b/drivers/hid/hid-alps.c @@ -73,9 +73,12 @@ * @y_active_len_mm: active area length of Y (mm) * @x_max: maximum x coordinate value * @y_max: maximum y coordinate value + * @x_min: minimum x coordinate value + * @y_min: minimum y coordinate value * @btn_cnt: number of buttons * @sp_btn_cnt: number of stick buttons * @has_sp: boolean of sp existense + * @max_fingers: total number of fingers */ struct u1_dev { struct input_dev *input; @@ -95,9 +98,12 @@ struct u1_dev { u32 y_active_len_mm; u32 x_max; u32 y_max; + u32 x_min; + u32 y_min; u32 btn_cnt; u32 sp_btn_cnt; u8 has_sp; + u8 max_fingers; }; static int u1_read_write_register(struct hid_device *hdev, u32 address, @@ -319,8 +325,10 @@ static int u1_init(struct hid_device *hdev, struct u1_dev *pri_data) pri_data->x_max = (pri_data->resolution << 2) * (pri_data->sen_line_num_x - 1); + pri_data->x_min = 1; pri_data->y_max = (pri_data->resolution << 2) * (pri_data->sen_line_num_y - 1); + pri_data->y_min = 1; ret = u1_read_write_register(hdev, ADDRESS_U1_PAD_BTN, &pri_data->btn_info, 0, true); @@ -328,6 +336,12 @@ static int u1_init(struct hid_device *hdev, struct u1_dev *pri_data) dev_err(&hdev->dev, "failed U1_PAD_BTN (%d)\n", ret); goto exit; } + if ((pri_data->btn_info & 0x0F) == (pri_data->btn_info & 0xF0) >> 4) { + pri_data->btn_cnt = (pri_data->btn_info & 0x0F); + } else { + /* Button pad */ + pri_data->btn_cnt = 1; + } pri_data->has_sp = 0; /* Check StickPointer device */ @@ -355,7 +369,7 @@ static int u1_init(struct hid_device *hdev, struct u1_dev *pri_data) } pri_data->has_sp = 1; } - + pri_data->max_fingers = 5; exit: return ret; } @@ -383,8 +397,10 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) goto exit; __set_bit(EV_ABS, input->evbit); - input_set_abs_params(input, ABS_MT_POSITION_X, 1, data->x_max, 0, 0); - input_set_abs_params(input, ABS_MT_POSITION_Y, 1, data->y_max, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_X, + data->x_min, data->x_max, 0, 0); + input_set_abs_params(input, ABS_MT_POSITION_Y, + data->y_min, data->y_max, 0, 0); if (data->x_active_len_mm && data->y_active_len_mm) { res_x = (data->x_max - 1) / data->x_active_len_mm; @@ -396,26 +412,21 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) input_set_abs_params(input, ABS_MT_PRESSURE, 0, 64, 0, 0); - input_mt_init_slots(input, MAX_TOUCHES, INPUT_MT_POINTER); + input_mt_init_slots(input, data->max_fingers, INPUT_MT_POINTER); __set_bit(EV_KEY, input->evbit); - if ((data->btn_info & 0x0F) == (data->btn_info & 0xF0) >> 4) { - data->btn_cnt = (data->btn_info & 0x0F); - } else { - /* Button pad */ - data->btn_cnt = 1; + + if (data->btn_cnt == 1) __set_bit(INPUT_PROP_BUTTONPAD, input->propbit); - } for (i = 0; i < data->btn_cnt; i++) __set_bit(BTN_LEFT + i, input->keybit); - /* Stick device initialization */ if (data->has_sp) { input2 = input_allocate_device(); if (!input2) { - ret = -ENOMEM; + input_free_device(input2); goto exit; } @@ -439,8 +450,7 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) __set_bit(INPUT_PROP_POINTER, input2->propbit); __set_bit(INPUT_PROP_POINTING_STICK, input2->propbit); - ret = input_register_device(data->input2); - if (ret) { + if (input_register_device(data->input2)) { input_free_device(input2); goto exit; } From 5992262d59ccbfaa86ea8b10122653429685b3f9 Mon Sep 17 00:00:00 2001 From: Masaki Ota Date: Fri, 6 Oct 2017 11:53:16 +0900 Subject: [PATCH 18/33] HID: alps: remove variables local to u1_init() from the device struct Move dev_ctrl, dev_type, sen_line_num_x, sen_line_num_y, pitch_x, pitch_y, resolution, btn_info from u1_dev structure to "u1_init()", because these variables are only used in there. [jkosina@suse.cz: rewrite changelog] Signed-off-by: Masaki Ota Signed-off-by: Jiri Kosina --- drivers/hid/hid-alps.c | 67 +++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 40 deletions(-) diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c index 201fe175cba3..4c323b58e009 100644 --- a/drivers/hid/hid-alps.c +++ b/drivers/hid/hid-alps.c @@ -61,14 +61,10 @@ * @input2: pointer to the kernel input2 device * @hdev: pointer to the struct hid_device * - * @dev_ctrl: device control parameter * @dev_type: device type - * @sen_line_num_x: number of sensor line of X - * @sen_line_num_y: number of sensor line of Y - * @pitch_x: sensor pitch of X - * @pitch_y: sensor pitch of Y - * @resolution: resolution - * @btn_info: button information + * @max_fingers: total number of fingers + * @has_sp: boolean of sp existense + * @sp_btn_info: button information * @x_active_len_mm: active area length of X (mm) * @y_active_len_mm: active area length of Y (mm) * @x_max: maximum x coordinate value @@ -77,22 +73,14 @@ * @y_min: minimum y coordinate value * @btn_cnt: number of buttons * @sp_btn_cnt: number of stick buttons - * @has_sp: boolean of sp existense - * @max_fingers: total number of fingers */ struct u1_dev { struct input_dev *input; struct input_dev *input2; struct hid_device *hdev; - u8 dev_ctrl; - u8 dev_type; - u8 sen_line_num_x; - u8 sen_line_num_y; - u8 pitch_x; - u8 pitch_y; - u8 resolution; - u8 btn_info; + u8 max_fingers; + u8 has_sp; u8 sp_btn_info; u32 x_active_len_mm; u32 y_active_len_mm; @@ -102,8 +90,6 @@ struct u1_dev { u32 y_min; u32 btn_cnt; u32 sp_btn_cnt; - u8 has_sp; - u8 max_fingers; }; static int u1_read_write_register(struct hid_device *hdev, u32 address, @@ -266,78 +252,80 @@ static int alps_post_resume(struct hid_device *hdev) static int u1_init(struct hid_device *hdev, struct u1_dev *pri_data) { int ret; + u8 tmp, dev_ctrl, sen_line_num_x, sen_line_num_y; + u8 pitch_x, pitch_y, resolution; /* Device initialization */ ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, - &pri_data->dev_ctrl, 0, true); + &dev_ctrl, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_DEV_CTRL_1 (%d)\n", ret); goto exit; } - pri_data->dev_ctrl &= ~U1_DISABLE_DEV; - pri_data->dev_ctrl |= U1_TP_ABS_MODE; + dev_ctrl &= ~U1_DISABLE_DEV; + dev_ctrl |= U1_TP_ABS_MODE; ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, - NULL, pri_data->dev_ctrl, false); + NULL, dev_ctrl, false); if (ret < 0) { dev_err(&hdev->dev, "failed to change TP mode (%d)\n", ret); goto exit; } ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_X, - &pri_data->sen_line_num_x, 0, true); + &sen_line_num_x, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_NUM_SENS_X (%d)\n", ret); goto exit; } ret = u1_read_write_register(hdev, ADDRESS_U1_NUM_SENS_Y, - &pri_data->sen_line_num_y, 0, true); + &sen_line_num_y, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_NUM_SENS_Y (%d)\n", ret); goto exit; } ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_X, - &pri_data->pitch_x, 0, true); + &pitch_x, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_PITCH_SENS_X (%d)\n", ret); goto exit; } ret = u1_read_write_register(hdev, ADDRESS_U1_PITCH_SENS_Y, - &pri_data->pitch_y, 0, true); + &pitch_y, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_PITCH_SENS_Y (%d)\n", ret); goto exit; } ret = u1_read_write_register(hdev, ADDRESS_U1_RESO_DWN_ABS, - &pri_data->resolution, 0, true); + &resolution, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_RESO_DWN_ABS (%d)\n", ret); goto exit; } pri_data->x_active_len_mm = - (pri_data->pitch_x * (pri_data->sen_line_num_x - 1)) / 10; + (pitch_x * (sen_line_num_x - 1)) / 10; pri_data->y_active_len_mm = - (pri_data->pitch_y * (pri_data->sen_line_num_y - 1)) / 10; + (pitch_y * (sen_line_num_y - 1)) / 10; pri_data->x_max = - (pri_data->resolution << 2) * (pri_data->sen_line_num_x - 1); + (resolution << 2) * (sen_line_num_x - 1); pri_data->x_min = 1; pri_data->y_max = - (pri_data->resolution << 2) * (pri_data->sen_line_num_y - 1); + (resolution << 2) * (sen_line_num_y - 1); pri_data->y_min = 1; ret = u1_read_write_register(hdev, ADDRESS_U1_PAD_BTN, - &pri_data->btn_info, 0, true); + &tmp, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_PAD_BTN (%d)\n", ret); goto exit; } - if ((pri_data->btn_info & 0x0F) == (pri_data->btn_info & 0xF0) >> 4) { - pri_data->btn_cnt = (pri_data->btn_info & 0x0F); + if ((tmp & 0x0F) == (tmp & 0xF0) >> 4) { + pri_data->btn_cnt = (tmp & 0x0F); } else { /* Button pad */ pri_data->btn_cnt = 1; @@ -346,16 +334,15 @@ static int u1_init(struct hid_device *hdev, struct u1_dev *pri_data) pri_data->has_sp = 0; /* Check StickPointer device */ ret = u1_read_write_register(hdev, ADDRESS_U1_DEVICE_TYP, - &pri_data->dev_type, 0, true); + &tmp, 0, true); if (ret < 0) { dev_err(&hdev->dev, "failed U1_DEVICE_TYP (%d)\n", ret); goto exit; } - - if (pri_data->dev_type & U1_DEVTYPE_SP_SUPPORT) { - pri_data->dev_ctrl |= U1_SP_ABS_MODE; + if (tmp & U1_DEVTYPE_SP_SUPPORT) { + dev_ctrl |= U1_SP_ABS_MODE; ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, - NULL, pri_data->dev_ctrl, false); + NULL, dev_ctrl, false); if (ret < 0) { dev_err(&hdev->dev, "failed SP mode (%d)\n", ret); goto exit; From 73196ebe134d11a68a2e27814c489d685cfc8b03 Mon Sep 17 00:00:00 2001 From: Masaki Ota Date: Fri, 6 Oct 2017 11:53:17 +0900 Subject: [PATCH 19/33] HID: alps: add support for Alps T4 Touchpad device - Define T4 device specification value for support T4 device. - Creeate "t4_contact_data" and "t4_input_report" structure for decoding and storing T4-specific data - Create "t4_calc_check_sum()" function for calculating checksum value to send to the device. T4 needs to send this value when reading or writing device address value. - Create "t4_read_write_register()" function for reading and writing device address value. - Create "t4_raw_event()" function for decodin XYZ, palm and button data. - Replace "MAX_TOUCHES" fixed variable to "max_fingers" variable. - Add T4 devuce product ID. (0x120C) T4 device is used on HP EliteBook 1000 series and Zbook Stduio [jkosina@suse.cz: rewrite changelog] Signed-off-by: Masaki Ota Signed-off-by: Jiri Kosina --- drivers/hid/hid-alps.c | 341 ++++++++++++++++++++++++++++++++++++++--- drivers/hid/hid-core.c | 2 + drivers/hid/hid-ids.h | 2 + 3 files changed, 324 insertions(+), 21 deletions(-) diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c index 4c323b58e009..5ae2cba8fe76 100644 --- a/drivers/hid/hid-alps.c +++ b/drivers/hid/hid-alps.c @@ -52,8 +52,30 @@ #define ADDRESS_U1_PAD_BTN 0x00800052 #define ADDRESS_U1_SP_BTN 0x0080009F +#define T4_INPUT_REPORT_LEN sizeof(struct t4_input_report) +#define T4_FEATURE_REPORT_LEN T4_INPUT_REPORT_LEN +#define T4_FEATURE_REPORT_ID 7 +#define T4_CMD_REGISTER_READ 0x08 +#define T4_CMD_REGISTER_WRITE 0x07 + +#define T4_ADDRESS_BASE 0xC2C0 +#define PRM_SYS_CONFIG_1 (T4_ADDRESS_BASE + 0x0002) +#define T4_PRM_FEED_CONFIG_1 (T4_ADDRESS_BASE + 0x0004) +#define T4_PRM_FEED_CONFIG_4 (T4_ADDRESS_BASE + 0x001A) +#define T4_PRM_ID_CONFIG_3 (T4_ADDRESS_BASE + 0x00B0) + + +#define T4_FEEDCFG4_ADVANCED_ABS_ENABLE 0x01 +#define T4_I2C_ABS 0x78 + +#define T4_COUNT_PER_ELECTRODE 256 #define MAX_TOUCHES 5 +enum dev_num { + U1, + T4, + UNKNOWN, +}; /** * struct u1_data * @@ -74,11 +96,12 @@ * @btn_cnt: number of buttons * @sp_btn_cnt: number of stick buttons */ -struct u1_dev { +struct alps_dev { struct input_dev *input; struct input_dev *input2; struct hid_device *hdev; + enum dev_num dev_type; u8 max_fingers; u8 has_sp; u8 sp_btn_info; @@ -92,6 +115,141 @@ struct u1_dev { u32 sp_btn_cnt; }; +struct t4_contact_data { + u8 palm; + u8 x_lo; + u8 x_hi; + u8 y_lo; + u8 y_hi; +}; + +struct t4_input_report { + u8 reportID; + u8 numContacts; + struct t4_contact_data contact[5]; + u8 button; + u8 track[5]; + u8 zx[5], zy[5]; + u8 palmTime[5]; + u8 kilroy; + u16 timeStamp; +}; + +static u16 t4_calc_check_sum(u8 *buffer, + unsigned long offset, unsigned long length) +{ + u16 sum1 = 0xFF, sum2 = 0xFF; + unsigned long i = 0; + + if (offset + length >= 50) + return 0; + + while (length > 0) { + u32 tlen = length > 20 ? 20 : length; + + length -= tlen; + + do { + sum1 += buffer[offset + i]; + sum2 += sum1; + i++; + } while (--tlen > 0); + + sum1 = (sum1 & 0xFF) + (sum1 >> 8); + sum2 = (sum2 & 0xFF) + (sum2 >> 8); + } + + sum1 = (sum1 & 0xFF) + (sum1 >> 8); + sum2 = (sum2 & 0xFF) + (sum2 >> 8); + + return(sum2 << 8 | sum1); +} + +static int t4_read_write_register(struct hid_device *hdev, u32 address, + u8 *read_val, u8 write_val, bool read_flag) +{ + int ret; + u16 check_sum; + u8 *input; + u8 *readbuf; + + input = kzalloc(T4_FEATURE_REPORT_LEN, GFP_KERNEL); + if (!input) + return -ENOMEM; + + input[0] = T4_FEATURE_REPORT_ID; + if (read_flag) { + input[1] = T4_CMD_REGISTER_READ; + input[8] = 0x00; + } else { + input[1] = T4_CMD_REGISTER_WRITE; + input[8] = write_val; + } + put_unaligned_le32(address, input + 2); + input[6] = 1; + input[7] = 0; + + /* Calculate the checksum */ + check_sum = t4_calc_check_sum(input, 1, 8); + input[9] = (u8)check_sum; + input[10] = (u8)(check_sum >> 8); + input[11] = 0; + + ret = hid_hw_raw_request(hdev, T4_FEATURE_REPORT_ID, input, + T4_FEATURE_REPORT_LEN, + HID_FEATURE_REPORT, HID_REQ_SET_REPORT); + + if (ret < 0) { + dev_err(&hdev->dev, "failed to read command (%d)\n", ret); + goto exit; + } + + readbuf = kzalloc(T4_FEATURE_REPORT_LEN, GFP_KERNEL); + if (read_flag) { + if (!readbuf) { + ret = -ENOMEM; + goto exit; + } + + ret = hid_hw_raw_request(hdev, T4_FEATURE_REPORT_ID, readbuf, + T4_FEATURE_REPORT_LEN, + HID_FEATURE_REPORT, HID_REQ_GET_REPORT); + if (ret < 0) { + dev_err(&hdev->dev, "failed read register (%d)\n", ret); + goto exit_readbuf; + } + + if (*(u32 *)&readbuf[6] != address) { + dev_err(&hdev->dev, "read register address error (%x,%x)\n", + *(u32 *)&readbuf[6], address); + goto exit_readbuf; + } + + if (*(u16 *)&readbuf[10] != 1) { + dev_err(&hdev->dev, "read register size error (%x)\n", + *(u16 *)&readbuf[10]); + goto exit_readbuf; + } + + check_sum = t4_calc_check_sum(readbuf, 6, 7); + if (*(u16 *)&readbuf[13] != check_sum) { + dev_err(&hdev->dev, "read register checksum error (%x,%x)\n", + *(u16 *)&readbuf[13], check_sum); + goto exit_readbuf; + } + + *read_val = readbuf[12]; + } + + ret = 0; + +exit_readbuf: + kfree(readbuf); +exit: + kfree(input); + return ret; +} + static int u1_read_write_register(struct hid_device *hdev, u32 address, u8 *read_val, u8 write_val, bool read_flag) { @@ -159,21 +317,60 @@ static int u1_read_write_register(struct hid_device *hdev, u32 address, return ret; } -static int alps_raw_event(struct hid_device *hdev, - struct hid_report *report, u8 *data, int size) +static int t4_raw_event(struct alps_dev *hdata, u8 *data, int size) +{ + unsigned int x, y, z; + int i; + struct t4_input_report *p_report = (struct t4_input_report *)data; + + if (!data) + return 0; + for (i = 0; i < hdata->max_fingers; i++) { + x = p_report->contact[i].x_hi << 8 | p_report->contact[i].x_lo; + y = p_report->contact[i].y_hi << 8 | p_report->contact[i].y_lo; + y = hdata->y_max - y + hdata->y_min; + z = (p_report->contact[i].palm < 0x80 && + p_report->contact[i].palm > 0) * 62; + if (x == 0xffff) { + x = 0; + y = 0; + z = 0; + } + input_mt_slot(hdata->input, i); + + input_mt_report_slot_state(hdata->input, + MT_TOOL_FINGER, z != 0); + + if (!z) + continue; + + input_report_abs(hdata->input, ABS_MT_POSITION_X, x); + input_report_abs(hdata->input, ABS_MT_POSITION_Y, y); + input_report_abs(hdata->input, ABS_MT_PRESSURE, z); + } + input_mt_sync_frame(hdata->input); + + input_report_key(hdata->input, BTN_LEFT, p_report->button); + + input_sync(hdata->input); + return 1; +} + +static int u1_raw_event(struct alps_dev *hdata, u8 *data, int size) { unsigned int x, y, z; int i; short sp_x, sp_y; - struct u1_dev *hdata = hid_get_drvdata(hdev); + if (!data) + return 0; switch (data[0]) { case U1_MOUSE_REPORT_ID: break; case U1_FEATURE_REPORT_ID: break; case U1_ABSOLUTE_REPORT_ID: - for (i = 0; i < MAX_TOUCHES; i++) { + for (i = 0; i < hdata->max_fingers; i++) { u8 *contact = &data[i * 5]; x = get_unaligned_le16(contact + 3); @@ -235,21 +432,52 @@ static int alps_raw_event(struct hid_device *hdev, return 0; } -#ifdef CONFIG_PM -static int alps_post_reset(struct hid_device *hdev) +static int alps_raw_event(struct hid_device *hdev, + struct hid_report *report, u8 *data, int size) { - return u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, - NULL, U1_TP_ABS_MODE | U1_SP_ABS_MODE, false); + int ret = 0; + struct alps_dev *hdata = hid_get_drvdata(hdev); + + switch (hdev->product) { + case HID_PRODUCT_ID_T4_BTNLESS: + ret = t4_raw_event(hdata, data, size); + break; + default: + ret = u1_raw_event(hdata, data, size); + break; + } + return ret; } -static int alps_post_resume(struct hid_device *hdev) +static int __maybe_unused alps_post_reset(struct hid_device *hdev) { - return u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, - NULL, U1_TP_ABS_MODE | U1_SP_ABS_MODE, false); -} -#endif /* CONFIG_PM */ + int ret = -1; + struct alps_dev *data = hid_get_drvdata(hdev); -static int u1_init(struct hid_device *hdev, struct u1_dev *pri_data) + switch (data->dev_type) { + case T4: + ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_1, + NULL, T4_I2C_ABS, false); + ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_4, + NULL, T4_FEEDCFG4_ADVANCED_ABS_ENABLE, false); + break; + case U1: + ret = u1_read_write_register(hdev, + ADDRESS_U1_DEV_CTRL_1, NULL, + U1_TP_ABS_MODE | U1_SP_ABS_MODE, false); + break; + default: + break; + } + return ret; +} + +static int __maybe_unused alps_post_resume(struct hid_device *hdev) +{ + return alps_post_reset(hdev); +} + +static int u1_init(struct hid_device *hdev, struct alps_dev *pri_data) { int ret; u8 tmp, dev_ctrl, sen_line_num_x, sen_line_num_y; @@ -361,9 +589,60 @@ static int u1_init(struct hid_device *hdev, struct u1_dev *pri_data) return ret; } +static int T4_init(struct hid_device *hdev, struct alps_dev *pri_data) +{ + int ret; + u8 tmp, sen_line_num_x, sen_line_num_y; + + ret = t4_read_write_register(hdev, T4_PRM_ID_CONFIG_3, &tmp, 0, true); + if (ret < 0) { + dev_err(&hdev->dev, "failed T4_PRM_ID_CONFIG_3 (%d)\n", ret); + goto exit; + } + sen_line_num_x = 16 + ((tmp & 0x0F) | (tmp & 0x08 ? 0xF0 : 0)); + sen_line_num_y = 12 + (((tmp & 0xF0) >> 4) | (tmp & 0x80 ? 0xF0 : 0)); + + pri_data->x_max = sen_line_num_x * T4_COUNT_PER_ELECTRODE; + pri_data->x_min = T4_COUNT_PER_ELECTRODE; + pri_data->y_max = sen_line_num_y * T4_COUNT_PER_ELECTRODE; + pri_data->y_min = T4_COUNT_PER_ELECTRODE; + pri_data->x_active_len_mm = pri_data->y_active_len_mm = 0; + pri_data->btn_cnt = 1; + + ret = t4_read_write_register(hdev, PRM_SYS_CONFIG_1, &tmp, 0, true); + if (ret < 0) { + dev_err(&hdev->dev, "failed PRM_SYS_CONFIG_1 (%d)\n", ret); + goto exit; + } + tmp |= 0x02; + ret = t4_read_write_register(hdev, PRM_SYS_CONFIG_1, NULL, tmp, false); + if (ret < 0) { + dev_err(&hdev->dev, "failed PRM_SYS_CONFIG_1 (%d)\n", ret); + goto exit; + } + + ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_1, + NULL, T4_I2C_ABS, false); + if (ret < 0) { + dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_1 (%d)\n", ret); + goto exit; + } + + ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_4, NULL, + T4_FEEDCFG4_ADVANCED_ABS_ENABLE, false); + if (ret < 0) { + dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_4 (%d)\n", ret); + goto exit; + } + pri_data->max_fingers = 5; + pri_data->has_sp = 0; +exit: + return ret; +} + static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) { - struct u1_dev *data = hid_get_drvdata(hdev); + struct alps_dev *data = hid_get_drvdata(hdev); struct input_dev *input = hi->input, *input2; int ret; int res_x, res_y, i; @@ -377,8 +656,16 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) /* Allow incoming hid reports */ hid_device_io_start(hdev); - - ret = u1_init(hdev, data); + switch (data->dev_type) { + case T4: + ret = T4_init(hdev, data); + break; + case U1: + ret = u1_init(hdev, data); + break; + default: + break; + } if (ret) goto exit; @@ -458,10 +745,9 @@ static int alps_input_mapping(struct hid_device *hdev, static int alps_probe(struct hid_device *hdev, const struct hid_device_id *id) { - struct u1_dev *data = NULL; + struct alps_dev *data = NULL; int ret; - - data = devm_kzalloc(&hdev->dev, sizeof(struct u1_dev), GFP_KERNEL); + data = devm_kzalloc(&hdev->dev, sizeof(struct alps_dev), GFP_KERNEL); if (!data) return -ENOMEM; @@ -476,6 +762,17 @@ static int alps_probe(struct hid_device *hdev, const struct hid_device_id *id) return ret; } + switch (hdev->product) { + case HID_DEVICE_ID_ALPS_T4_BTNLESS: + data->dev_type = T4; + break; + case HID_DEVICE_ID_ALPS_U1_DUAL: + data->dev_type = U1; + break; + default: + data->dev_type = UNKNOWN; + } + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (ret) { hid_err(hdev, "hw start failed\n"); @@ -493,6 +790,8 @@ static void alps_remove(struct hid_device *hdev) static const struct hid_device_id alps_id[] = { { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) }, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, + USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_T4_BTNLESS) }, { } }; MODULE_DEVICE_TABLE(hid, alps_id); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 330ca983828b..7410a7bf4461 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1889,6 +1889,8 @@ static const struct hid_device_id hid_have_special_driver[] = { #endif #if IS_ENABLED(CONFIG_HID_ALPS) { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_T4_BTNLESS) }, #endif #if IS_ENABLED(CONFIG_HID_APPLE) { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index be2e005c3c51..edc9f2ae2810 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -77,6 +77,8 @@ #define HID_DEVICE_ID_ALPS_U1_DUAL 0x120B #define HID_DEVICE_ID_ALPS_U1_DUAL_PTP 0x121F #define HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP 0x1220 +#define HID_DEVICE_ID_ALPS_T4_BTNLESS 0x120C + #define USB_VENDOR_ID_AMI 0x046b #define USB_DEVICE_ID_AMI_VIRT_KEYBOARD_AND_MOUSE 0xff10 From 287b8e11972f934052f4ed0751df465a5e84b69c Mon Sep 17 00:00:00 2001 From: Masaki Ota Date: Fri, 6 Oct 2017 11:53:18 +0900 Subject: [PATCH 20/33] HID: alps: add new U1 device ID Add new U1 device Product ID This device is used on HP Elite book x360 series. [jkosina@suse.cz: update changelog] Signed-off-by: Masaki Ota Signed-off-by: Jiri Kosina --- drivers/hid/hid-alps.c | 3 +++ drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 1 + 3 files changed, 5 insertions(+) diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c index 5ae2cba8fe76..b1eeb4839bfc 100644 --- a/drivers/hid/hid-alps.c +++ b/drivers/hid/hid-alps.c @@ -767,6 +767,7 @@ static int alps_probe(struct hid_device *hdev, const struct hid_device_id *id) data->dev_type = T4; break; case HID_DEVICE_ID_ALPS_U1_DUAL: + case HID_DEVICE_ID_ALPS_U1: data->dev_type = U1; break; default: @@ -790,6 +791,8 @@ static void alps_remove(struct hid_device *hdev) static const struct hid_device_id alps_id[] = { { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) }, + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, + USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1) }, { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_T4_BTNLESS) }, { } diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 7410a7bf4461..f1435374006e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1890,6 +1890,7 @@ static const struct hid_device_id hid_have_special_driver[] = { #if IS_ENABLED(CONFIG_HID_ALPS) { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) }, { HID_I2C_DEVICE(USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) }, + { HID_I2C_DEVICE(USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1) }, { HID_I2C_DEVICE(USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_T4_BTNLESS) }, #endif #if IS_ENABLED(CONFIG_HID_APPLE) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index edc9f2ae2810..f265c3362f67 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -77,6 +77,7 @@ #define HID_DEVICE_ID_ALPS_U1_DUAL 0x120B #define HID_DEVICE_ID_ALPS_U1_DUAL_PTP 0x121F #define HID_DEVICE_ID_ALPS_U1_DUAL_3BTN_PTP 0x1220 +#define HID_DEVICE_ID_ALPS_U1 0x1215 #define HID_DEVICE_ID_ALPS_T4_BTNLESS 0x120C From 1fc26792b6e3bb270313063a33b6e5ffd315440b Mon Sep 17 00:00:00 2001 From: Florian Mueller Date: Mon, 16 Oct 2017 09:29:11 +0200 Subject: [PATCH 21/33] HID: add multi-input quirk for GamepadBlock The GamepadBlock game controller adapter needs HID_QUIRK_MULTI_INPUT to split it up into two input devices. Without this quirk the adapter is falsely recognized as only one device and mixes up the inputs of the two connected controllers. Signed-off-by: Florian Mueller Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/usbhid/hid-quirks.c | 1 + 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index be2e005c3c51..c24ebc413223 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -729,6 +729,9 @@ #define USB_DEVICE_ID_MCC_PMD1024LS 0x0076 #define USB_DEVICE_ID_MCC_PMD1208LS 0x007a +#define USB_VENDOR_ID_MCS 0x16d0 +#define USB_DEVICE_ID_MCS_GAMEPADBLOCK 0x0bcc + #define USB_VENDOR_ID_MGE 0x0463 #define USB_DEVICE_ID_MGE_UPS 0xffff #define USB_DEVICE_ID_MGE_UPS1 0x0001 diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index f489a5cfcb48..331f7f34ec14 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -170,6 +170,7 @@ static const struct hid_blacklist { { USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_2NES2SNES, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_DRACAL_RAPHNET, USB_DEVICE_ID_RAPHNET_4NES4SNES, HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI, HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_MCS, USB_DEVICE_ID_MCS_GAMEPADBLOCK, HID_QUIRK_MULTI_INPUT }, { 0, 0 } }; From ef14a4bf0910d06c7e202552914028d4956809cb Mon Sep 17 00:00:00 2001 From: Andrew Duggan Date: Tue, 17 Oct 2017 18:37:36 -0700 Subject: [PATCH 22/33] HID: rmi: Check that a device is a RMI device before calling RMI functions The hid-rmi driver may handle non rmi devices on composite USB devices. Callbacks need to make sure that the current device is a RMI device before calling RMI specific functions. Most callbacks already have this check, but this patch adds checks to the remaining callbacks. Reported-by: Hendrik Langer Tested-by: Hendrik Langer Reviewed-by: Benjamin Tissoires Signed-off-by: Andrew Duggan Signed-off-by: Jiri Kosina --- drivers/hid/hid-rmi.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-rmi.c b/drivers/hid/hid-rmi.c index ef241d66562e..0f43c4292685 100644 --- a/drivers/hid/hid-rmi.c +++ b/drivers/hid/hid-rmi.c @@ -368,6 +368,11 @@ static int rmi_check_sanity(struct hid_device *hdev, u8 *data, int size) static int rmi_raw_event(struct hid_device *hdev, struct hid_report *report, u8 *data, int size) { + struct rmi_data *hdata = hid_get_drvdata(hdev); + + if (!(hdata->device_flags & RMI_DEVICE)) + return 0; + size = rmi_check_sanity(hdev, data, size); if (size < 2) return 0; @@ -713,9 +718,11 @@ static void rmi_remove(struct hid_device *hdev) { struct rmi_data *hdata = hid_get_drvdata(hdev); - clear_bit(RMI_STARTED, &hdata->flags); - cancel_work_sync(&hdata->reset_work); - rmi_unregister_transport_device(&hdata->xport); + if (hdata->device_flags & RMI_DEVICE) { + clear_bit(RMI_STARTED, &hdata->flags); + cancel_work_sync(&hdata->reset_work); + rmi_unregister_transport_device(&hdata->xport); + } hid_hw_stop(hdev); } From 885e89f601a52cc6fb025b009df58ba83d142734 Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Wed, 18 Oct 2017 08:27:13 -0700 Subject: [PATCH 23/33] HID: wacom: generic: Recognize WACOM_HID_WD_PEN as a type of pen collection The WACOM_PEN_FIELD macro is used to determine if a given HID field should be associated with pen input. This field includes several known collection types that Wacom pen data is contained in, but the WACOM_HID_WD_PEN application collection type is notably missing. This can result in fields within this kind of collection being completely ignored by the `wacom_usage_mapping` function, preventing the later '*_event' functions from being notified about changes to their value. Fixes: c9c095874a ("HID: wacom: generic: Support and use 'Custom HID' mode and usages") Fixes: ac2423c975 ("HID: wacom: generic: add vendor defined touch") Cc: stable@vger.kernel.org Reviewed-by: Ping Cheng Reviewed-by: Benjamin Tissoires Signed-off-by: Jason Gerecke Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.h | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 8a03654048bf..feb62fd4dfc3 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -166,6 +166,7 @@ ((f)->physical == HID_DG_PEN) || \ ((f)->application == HID_DG_PEN) || \ ((f)->application == HID_DG_DIGITIZER) || \ + ((f)->application == WACOM_HID_WD_PEN) || \ ((f)->application == WACOM_HID_WD_DIGITIZER) || \ ((f)->application == WACOM_HID_G9_PEN) || \ ((f)->application == WACOM_HID_G11_PEN)) From 6cb6d98abdb06de867e34fde92912fdb89477897 Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Tue, 17 Oct 2017 15:31:51 +0100 Subject: [PATCH 24/33] HID: hid-logitech: remove redundant assignment to pointer value The pointer value is being assigned a value and this is never read, and later on it is being assigned a new value. This the first assignment is redundant and can be removed and hence also the variables report and report_list. Cleans up the clang warning: Value stored to 'value' during its initialization is never read Signed-off-by: Colin Ian King Signed-off-by: Jiri Kosina --- drivers/hid/hid-lg4ff.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c index 1fc12e357035..512d67e1aae3 100644 --- a/drivers/hid/hid-lg4ff.c +++ b/drivers/hid/hid-lg4ff.c @@ -474,9 +474,7 @@ static int lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *effec static void lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitude) { struct hid_device *hid = input_get_drvdata(dev); - struct list_head *report_list = &hid->report_enum[HID_OUTPUT_REPORT].report_list; - struct hid_report *report = list_entry(report_list->next, struct hid_report, list); - s32 *value = report->field[0]->value; + s32 *value; u32 expand_a, expand_b; struct lg4ff_device_entry *entry; struct lg_drv_data *drv_data; From 1477edb4853bd730e3ab37fa9165651c03c2cc05 Mon Sep 17 00:00:00 2001 From: Viktor Chapliev Date: Tue, 7 Nov 2017 11:13:16 +0300 Subject: [PATCH 25/33] HID: Add ID 044f:b605 ThrustMaster, Inc. force feedback Racing Wheel Add ID 044f:b605 ThrustMaster, Inc. force feedback Racing Wheel Signed-off-by: Viktor Chapliev Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 + drivers/hid/hid-tmff.c | 2 ++ 2 files changed, 3 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 330ca983828b..e7a45887afc4 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -2329,6 +2329,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb323) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324) }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb605) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) }, diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c index b83376077d72..bea8def64f43 100644 --- a/drivers/hid/hid-tmff.c +++ b/drivers/hid/hid-tmff.c @@ -242,6 +242,8 @@ static const struct hid_device_id tm_devices[] = { .driver_data = (unsigned long)ff_rumble }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb324), /* Dual Trigger 3-in-1 (PS3 Mode) */ .driver_data = (unsigned long)ff_rumble }, + { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb605), /* NASCAR PRO FF2 Wheel */ + .driver_data = (unsigned long)ff_joystick }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651), /* FGT Rumble Force Wheel */ .driver_data = (unsigned long)ff_rumble }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653), /* RGT Force Feedback CLUTCH Raging Wheel */ From cde3076bdc38bf436e517a379759a9092c6ffd4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Szymanski?= Date: Thu, 2 Nov 2017 12:12:43 +0100 Subject: [PATCH 26/33] HID: cp2112: add HIDRAW dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Otherwise, with HIDRAW=n, the probe function crashes because of null dereference of hdev->hidraw. Cc: stable@vger.kernel.org Fixes: 42cb6b35b9e6 ("HID: cp2112: use proper hidraw name with minor number") Signed-off-by: Sébastien Szymanski Acked-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index d95c1abbd4cc..af061b54c242 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -230,7 +230,7 @@ config HID_CMEDIA config HID_CP2112 tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support" - depends on USB_HID && I2C && GPIOLIB + depends on USB_HID && HIDRAW && I2C && GPIOLIB select GPIOLIB_IRQCHIP ---help--- Support for Silicon Labs CP2112 HID USB to SMBus Master Bridge. From 339ee3fcbdab736adbc30b7a3d675005c61a2a40 Mon Sep 17 00:00:00 2001 From: Mustafa Kuscu Date: Sat, 28 Oct 2017 10:31:40 +0300 Subject: [PATCH 27/33] HID: add backlight level quirk for Asus ROG laptops On laptops such as Asus GL553VD, setting keyboard backlight levels does not work. This change enables F3/F4 keys to set backlight levels (from 0 to 3, total 4 levels) on such laptops. It is intended only to the following device: 0x0b05 1854: P: Vendor=0b05 ProdID=1854 Rev=03.02 S: Manufacturer=ITE Tech. Inc. S: Product=ITE Device(8910) [jkosina@suse.cz: massage changelog a little bit] Signed-off-by: Mustafa C Kuscu Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 27651f50738e..1bb7b63b3150 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -745,7 +745,7 @@ static const struct hid_device_id asus_devices[] = { { HID_I2C_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_I2C_TOUCHPAD), I2C_TOUCHPAD_QUIRKS }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, - USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1) }, + USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1), QUIRK_USE_KBD_BACKLIGHT }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2), QUIRK_USE_KBD_BACKLIGHT }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, From 402946a8ef71ebfd1cbb19829db2da62906f0519 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Tue, 7 Nov 2017 13:28:00 +0100 Subject: [PATCH 28/33] HID: i2c-hid: Add no-irq-after-reset quirk for 0911:5288 device Several cheap Apollo Lake based laptops / 2-in-1s use an i2c-hid mt touchpad which is advertised by the DSDT with an ACPI HID of "SYNA3602", this touchpad can be found on e.g. the Cube Thinker and the EZBook 3 Pro. On my "T-bao Tbook air" the i2c-hid driver fails to bind to this touchpad: "i2c_hid i2c-SYNA3602:00: failed to reset device.". After some debuging this it seems that this touchpad simply never sends an interrupt after a reset as expected by the i2c hid driver. This commit adds a quirk for this device, making i2c_hid_command sleep 100ms after a reset instead of waiting for an irq, fixing i2c-hid failing to bind to this touchpad. Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 3 +++ drivers/hid/i2c-hid/i2c-hid.c | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index b397a14ab970..bb8e54fbbc21 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -507,6 +507,9 @@ #define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003 #define USB_DEVICE_ID_GYRATION_REMOTE_3 0x0008 +#define I2C_VENDOR_ID_HANTICK 0x0911 +#define I2C_PRODUCT_ID_HANTICK_5288 0x5288 + #define USB_VENDOR_ID_HANWANG 0x0b57 #define USB_DEVICE_ID_HANWANG_TABLET_FIRST 0x5000 #define USB_DEVICE_ID_HANWANG_TABLET_LAST 0x8fff diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c index 77396145d2d0..3e0652b6f657 100644 --- a/drivers/hid/i2c-hid/i2c-hid.c +++ b/drivers/hid/i2c-hid/i2c-hid.c @@ -46,6 +46,7 @@ /* quirks to control the device */ #define I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV BIT(0) +#define I2C_HID_QUIRK_NO_IRQ_AFTER_RESET BIT(1) /* flags */ #define I2C_HID_STARTED 0 @@ -168,6 +169,8 @@ static const struct i2c_hid_quirks { I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV }, { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8755, I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV }, + { I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288, + I2C_HID_QUIRK_NO_IRQ_AFTER_RESET }, { 0, 0 } }; @@ -252,7 +255,9 @@ static int __i2c_hid_command(struct i2c_client *client, ret = 0; - if (wait) { + if (wait && (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET)) { + msleep(100); + } else if (wait) { i2c_hid_dbg(ihid, "%s: waiting...\n", __func__); if (!wait_event_timeout(ihid->wait, !test_bit(I2C_HID_RESET_PENDING, &ihid->flags), From 492ca83c3d19fba1622164f07cd7b775596a7db2 Mon Sep 17 00:00:00 2001 From: Bastien Nocera Date: Tue, 7 Nov 2017 15:24:47 +0100 Subject: [PATCH 29/33] HID: sony: Fix SHANWAN pad rumbling on USB The SHANWAN PS3 clone joypad will start its rumble motors as soon as it is plugged in via USB. As the additional USB interrupt does nothing on the original PS3 Sixaxis joypads, and makes a number of other clone joypads actually start sending data, disable that call for the SHANWAN so the rumble motors aren't started on plug. Signed-off-by: Bastien Nocera Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index d03203a82e8f..b9dc3ac4d4aa 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1439,10 +1439,16 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev) goto out; } - ret = hid_hw_output_report(hdev, buf, 1); - if (ret < 0) { - hid_info(hdev, "can't set operational mode: step 3, ignoring\n"); - ret = 0; + /* + * But the USB interrupt would cause SHANWAN controllers to + * start rumbling non-stop. + */ + if (strcmp(hdev->name, "SHANWAN PS3 GamePad")) { + ret = hid_hw_output_report(hdev, buf, 1); + if (ret < 0) { + hid_info(hdev, "can't set operational mode: step 3, ignoring\n"); + ret = 0; + } } out: From 9e429d564926d3bca49907fa03031da705ad6f2c Mon Sep 17 00:00:00 2001 From: Jason Gerecke Date: Tue, 7 Nov 2017 08:25:17 -0800 Subject: [PATCH 30/33] HID: wacom: generic: Send BTN_STYLUS3 when both barrel switches are set The Wacom Pro Pen 3D includes a third barrel switch which is intended to be particularly useful in applications where one frequency uses pan, zoom, and rotate to navigate around a scene or model. The pen is compatible with the MobileStudio Pro, 2nd-gen Intuos Pro, and Cintiq Pro. When the third button is pressed, these devices set both the HID_DG_BARRELSWITCH and HID_DG_BARRELSWITCH2 usages since their HID descriptors do not include a usage specific to the button. Rather than send both BTN_STYLUS and BTN_STYLUS2 when the third button is pressed, userspace (libinput) has requested that we detect this condition and report a newly-defined BTN_STYLUS3 event instead. We could define a quirk specific to devices compatible with the Pro Pen 3D, but the liklihood of seeing both barrel switch bits set with other pens/devices is low enough to not worry about (pens mechanically prevent accidental activation of multiple switches). Signed-off-by: Jason Gerecke Acked-by: Dmitry Torokhov Acked-by: Peter Hutterer Acked-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/wacom_wac.c | 18 ++++++++++++++++-- drivers/hid/wacom_wac.h | 2 ++ include/uapi/linux/input-event-codes.h | 1 + 3 files changed, 19 insertions(+), 2 deletions(-) diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index e3223b0c4f90..16af6886e828 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2140,6 +2140,12 @@ static void wacom_wac_pen_event(struct hid_device *hdev, struct hid_field *field case HID_DG_TIPSWITCH: wacom_wac->hid_data.tipswitch |= value; return; + case HID_DG_BARRELSWITCH: + wacom_wac->hid_data.barrelswitch = value; + return; + case HID_DG_BARRELSWITCH2: + wacom_wac->hid_data.barrelswitch2 = value; + return; case HID_DG_TOOLSERIALNUMBER: if (value) { wacom_wac->serial[0] = (wacom_wac->serial[0] & ~0xFFFFFFFFULL); @@ -2254,6 +2260,12 @@ static void wacom_wac_pen_report(struct hid_device *hdev, if (!delay_pen_events(wacom_wac) && wacom_wac->tool[0]) { int id = wacom_wac->id[0]; + int sw_state = wacom_wac->hid_data.barrelswitch | + (wacom_wac->hid_data.barrelswitch2 << 1); + + input_report_key(input, BTN_STYLUS, sw_state == 1); + input_report_key(input, BTN_STYLUS2, sw_state == 2); + input_report_key(input, BTN_STYLUS3, sw_state == 3); /* * Non-USI EMR tools should have their IDs mangled to @@ -3300,9 +3312,11 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, else __set_bit(INPUT_PROP_POINTER, input_dev->propbit); - if (features->type == HID_GENERIC) - /* setup has already been done */ + if (features->type == HID_GENERIC) { + /* setup has already been done; apply otherwise-undetectible quirks */ + input_set_capability(input_dev, EV_KEY, BTN_STYLUS3); return 0; + } __set_bit(BTN_TOUCH, input_dev->keybit); __set_bit(ABS_MISC, input_dev->absbit); diff --git a/drivers/hid/wacom_wac.h b/drivers/hid/wacom_wac.h index 8a03654048bf..69dda27e8dde 100644 --- a/drivers/hid/wacom_wac.h +++ b/drivers/hid/wacom_wac.h @@ -291,6 +291,8 @@ struct hid_data { bool inrange_state; bool invert_state; bool tipswitch; + bool barrelswitch; + bool barrelswitch2; int x; int y; int pressure; diff --git a/include/uapi/linux/input-event-codes.h b/include/uapi/linux/input-event-codes.h index 179891074b3c..9b3a522f50d1 100644 --- a/include/uapi/linux/input-event-codes.h +++ b/include/uapi/linux/input-event-codes.h @@ -406,6 +406,7 @@ #define BTN_TOOL_MOUSE 0x146 #define BTN_TOOL_LENS 0x147 #define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */ +#define BTN_STYLUS3 0x149 #define BTN_TOUCH 0x14a #define BTN_STYLUS 0x14b #define BTN_STYLUS2 0x14c From 5b01b3b8b122fde7fbe116803f7863667b4c5beb Mon Sep 17 00:00:00 2001 From: Benjamin Tissoires Date: Fri, 3 Nov 2017 18:29:47 +0100 Subject: [PATCH 31/33] HID: Wacom: switch Dell canvas into highres mode The Dell Canvas exports 2 collections for the Pen part. The only difference between the 2 is that the default one has half the resolution of the second one. The Windows driver switches the tablet into the second mode, so we should behave the same. Signed-off-by: Benjamin Tissoires Reviewed-by: Jason Gerecke --- drivers/hid/wacom_sys.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index 735bfbbcaa82..ab3178bef0b6 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -196,6 +196,13 @@ static void wacom_feature_mapping(struct hid_device *hdev, kfree(data); break; } + + if (hdev->vendor == USB_VENDOR_ID_WACOM && + hdev->product == 0x4200 /* Dell Canvas 27 */ && + field->application == HID_UP_MSVENDOR) { + wacom->wacom_wac.mode_report = field->report->id; + wacom->wacom_wac.mode_value = 2; + } } /* From ce4dd820d7bc4352e042bd3c7100d509b34ab6ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Szymanski?= Date: Thu, 2 Nov 2017 12:12:42 +0100 Subject: [PATCH 32/33] HID: cp2112: fix interface specification URL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Sébastien Szymanski Acked-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-cp2112.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index 078026f63b6f..28e3c18a4689 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -21,7 +21,7 @@ * Data Sheet: * http://www.silabs.com/Support%20Documents/TechnicalDocs/CP2112.pdf * Programming Interface Specification: - * http://www.silabs.com/Support%20Documents/TechnicalDocs/AN495.pdf + * https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf */ #include From 7da85fbf1c87d4f73621e0e7666a3387497075a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Szymanski?= Date: Fri, 10 Nov 2017 10:01:43 +0100 Subject: [PATCH 33/33] HID: cp2112: fix broken gpio_direction_input callback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When everything goes smoothly, ret is set to 0 which makes the function to return EIO error. Fixes: 8e9faa15469e ("HID: cp2112: fix gpio-callback error handling") Signed-off-by: Sébastien Szymanski Reviewed-by: Benjamin Tissoires Signed-off-by: Jiri Kosina --- drivers/hid/hid-cp2112.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index 28e3c18a4689..68cdc962265b 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -196,6 +196,8 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset) HID_REQ_GET_REPORT); if (ret != CP2112_GPIO_CONFIG_LENGTH) { hid_err(hdev, "error requesting GPIO config: %d\n", ret); + if (ret >= 0) + ret = -EIO; goto exit; } @@ -205,8 +207,10 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset) ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf, CP2112_GPIO_CONFIG_LENGTH, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); - if (ret < 0) { + if (ret != CP2112_GPIO_CONFIG_LENGTH) { hid_err(hdev, "error setting GPIO config: %d\n", ret); + if (ret >= 0) + ret = -EIO; goto exit; } @@ -214,7 +218,7 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset) exit: mutex_unlock(&dev->lock); - return ret < 0 ? ret : -EIO; + return ret; } static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)