aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2019-09-23 12:18:13 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2019-09-23 12:18:13 -0700
commit1ad0bc78948652edc3067b6b49ba31b1598faa4a (patch)
tree08c6262440c87e6241e5fc3732fff5fd3193b60e /drivers/hid
parentMerge tag 'safesetid-bugfix-5.4' of git://github.com/micah-morton/linux (diff)
parentMerge branch 'for-5.4/wacom' into for-linus (diff)
downloadlinux-dev-1ad0bc78948652edc3067b6b49ba31b1598faa4a.tar.xz
linux-dev-1ad0bc78948652edc3067b6b49ba31b1598faa4a.zip
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Jiri Kosina: - syzbot memory corruption fixes for hidraw, Prodikeys, Logitech and Sony drivers from Alan Stern and Roderick Colenbrander - stuck 'fn' key fix for hid-apple from Joao Moreno - proper propagation of EPOLLOUT from hiddev and hidraw, from Fabian Henneke - fixes for handling power management for intel-ish devices with NO_D3 flag set, from Zhang Lixu - extension of supported usage range for customer page, as some Logitech devices are actually making use of it. From Olivier Gay. - hid-multitouch is no longer filtering mice node creation, from Benjamin Tissoires - MobileStudio Pro 13 support, from Ping Cheng - a few other device ID additions and assorted smaller fixes * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (27 commits) HID: core: fix dmesg flooding if report field larger than 32bit HID: core: Add printk_once variants to hid_warn() etc HID: core: reformat and reduce hid_printk macros HID: prodikeys: Fix general protection fault during probe HID: wacom: add new MobileStudio Pro 13 support HID: sony: Fix memory corruption issue on cleanup. HID: i2c-hid: modify quirks for weida's devices HID: apple: Fix stuck function keys when using FN HID: sb0540: add support for Creative SB0540 IR receivers HID: Add quirk for HP X500 PIXART OEM mouse HID: logitech-dj: Fix crash when initial logi_dj_recv_query_paired_devices fails hid-logitech-dj: add the new Lightspeed receiver HID: logitech-dj: add support of the G700(s) receiver HID: multitouch: add support for the Smart Tech panel HID: multitouch: do not filter mice nodes HID: do not call hid_set_drvdata(hdev, NULL) in drivers HID: wacom: do not call hid_set_drvdata(hdev, NULL) HID: logitech: Fix general protection fault caused by Logitech driver HID: hidraw: Fix invalid read in hidraw_ioctl HID: wacom: support named keys on older devices ...
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/Kconfig9
-rw-r--r--drivers/hid/Makefile1
-rw-r--r--drivers/hid/hid-apple.c49
-rw-r--r--drivers/hid/hid-core.c4
-rw-r--r--drivers/hid/hid-cougar.c6
-rw-r--r--drivers/hid/hid-creative-sb0540.c268
-rw-r--r--drivers/hid/hid-gfrm.c7
-rw-r--r--drivers/hid/hid-ids.h5
-rw-r--r--drivers/hid/hid-lenovo.c2
-rw-r--r--drivers/hid/hid-lg.c10
-rw-r--r--drivers/hid/hid-lg4ff.c1
-rw-r--r--drivers/hid/hid-logitech-dj.c32
-rw-r--r--drivers/hid/hid-multitouch.c37
-rw-r--r--drivers/hid/hid-picolcd_core.c7
-rw-r--r--drivers/hid/hid-prodikeys.c12
-rw-r--r--drivers/hid/hid-quirks.c1
-rw-r--r--drivers/hid/hid-sensor-hub.c1
-rw-r--r--drivers/hid/hid-sony.c2
-rw-r--r--drivers/hid/hidraw.c4
-rw-r--r--drivers/hid/i2c-hid/i2c-hid-core.c4
-rw-r--r--drivers/hid/intel-ish-hid/ipc/hw-ish.h1
-rw-r--r--drivers/hid/intel-ish-hid/ipc/ipc.c2
-rw-r--r--drivers/hid/intel-ish-hid/ipc/pci-ish.c95
-rw-r--r--drivers/hid/usbhid/hiddev.c2
-rw-r--r--drivers/hid/wacom_sys.c25
-rw-r--r--drivers/hid/wacom_wac.c76
26 files changed, 532 insertions, 131 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index a958b9625bba..1ecb5124421c 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -273,6 +273,15 @@ config HID_CP2112
and gpiochip to expose these functions of the CP2112. The
customizable USB descriptor fields are exposed as sysfs attributes.
+config HID_CREATIVE_SB0540
+ tristate "Creative SB0540 infrared receiver"
+ depends on USB_HID
+ help
+ Support for Creative infrared SB0540-compatible remote controls, such
+ as the RM-1500 and RM-1800 remotes.
+
+ Say Y here if you want support for Creative SB0540 infrared receiver.
+
config HID_CYPRESS
tristate "Cypress mouse and barcode readers"
depends on HID
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index cc5d827c9164..0c03308cfb08 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -27,6 +27,7 @@ obj-$(CONFIG_HID_ALPS) += hid-alps.o
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
+obj-$(CONFIG_HID_CREATIVE_SB0540) += hid-creative-sb0540.o
obj-$(CONFIG_HID_ASUS) += hid-asus.o
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index 81df62f48c4c..6ac8becc2372 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -54,7 +54,6 @@ MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\")
struct apple_sc {
unsigned long quirks;
unsigned int fn_on;
- DECLARE_BITMAP(pressed_fn, KEY_CNT);
DECLARE_BITMAP(pressed_numlock, KEY_CNT);
};
@@ -181,6 +180,8 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
{
struct apple_sc *asc = hid_get_drvdata(hid);
const struct apple_key_translation *trans, *table;
+ bool do_translate;
+ u16 code = 0;
if (usage->code == KEY_FN) {
asc->fn_on = !!value;
@@ -189,8 +190,6 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
}
if (fnmode) {
- int do_translate;
-
if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
table = macbookair_fn_keys;
@@ -202,25 +201,33 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
trans = apple_find_translation (table, usage->code);
if (trans) {
- if (test_bit(usage->code, asc->pressed_fn))
- do_translate = 1;
- else if (trans->flags & APPLE_FLAG_FKEY)
- do_translate = (fnmode == 2 && asc->fn_on) ||
- (fnmode == 1 && !asc->fn_on);
- else
- do_translate = asc->fn_on;
-
- if (do_translate) {
- if (value)
- set_bit(usage->code, asc->pressed_fn);
- else
- clear_bit(usage->code, asc->pressed_fn);
-
- input_event(input, usage->type, trans->to,
- value);
-
- return 1;
+ if (test_bit(trans->from, input->key))
+ code = trans->from;
+ else if (test_bit(trans->to, input->key))
+ code = trans->to;
+
+ if (!code) {
+ if (trans->flags & APPLE_FLAG_FKEY) {
+ switch (fnmode) {
+ case 1:
+ do_translate = !asc->fn_on;
+ break;
+ case 2:
+ do_translate = asc->fn_on;
+ break;
+ default:
+ /* should never happen */
+ do_translate = false;
+ }
+ } else {
+ do_translate = asc->fn_on;
+ }
+
+ code = do_translate ? trans->to : trans->from;
}
+
+ input_event(input, usage->type, code, value);
+ return 1;
}
if (asc->quirks & APPLE_NUMLOCK_EMULATION &&
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 210b81a56e1a..3eaee2c37931 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -1311,8 +1311,8 @@ u32 hid_field_extract(const struct hid_device *hid, u8 *report,
unsigned offset, unsigned n)
{
if (n > 32) {
- hid_warn(hid, "hid_field_extract() called with n (%d) > 32! (%s)\n",
- n, current->comm);
+ hid_warn_once(hid, "%s() called with n (%d) > 32! (%s)\n",
+ __func__, n, current->comm);
n = 32;
}
diff --git a/drivers/hid/hid-cougar.c b/drivers/hid/hid-cougar.c
index e0bb7b34f3a4..4ff3bc1d25e2 100644
--- a/drivers/hid/hid-cougar.c
+++ b/drivers/hid/hid-cougar.c
@@ -207,7 +207,7 @@ static int cougar_probe(struct hid_device *hdev,
error = hid_parse(hdev);
if (error) {
hid_err(hdev, "parse failed\n");
- goto fail;
+ return error;
}
if (hdev->collection->usage == COUGAR_VENDOR_USAGE) {
@@ -219,7 +219,7 @@ static int cougar_probe(struct hid_device *hdev,
error = hid_hw_start(hdev, connect_mask);
if (error) {
hid_err(hdev, "hw start failed\n");
- goto fail;
+ return error;
}
error = cougar_bind_shared_data(hdev, cougar);
@@ -249,8 +249,6 @@ static int cougar_probe(struct hid_device *hdev,
fail_stop_and_cleanup:
hid_hw_stop(hdev);
-fail:
- hid_set_drvdata(hdev, NULL);
return error;
}
diff --git a/drivers/hid/hid-creative-sb0540.c b/drivers/hid/hid-creative-sb0540.c
new file mode 100644
index 000000000000..b4c8e7a5d3e0
--- /dev/null
+++ b/drivers/hid/hid-creative-sb0540.c
@@ -0,0 +1,268 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * HID driver for the Creative SB0540 receiver
+ *
+ * Copyright (C) 2019 Red Hat Inc. All Rights Reserved
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include "hid-ids.h"
+
+MODULE_AUTHOR("Bastien Nocera <hadess@hadess.net>");
+MODULE_DESCRIPTION("HID Creative SB0540 receiver");
+MODULE_LICENSE("GPL");
+
+static const unsigned short creative_sb0540_key_table[] = {
+ KEY_POWER,
+ KEY_RESERVED, /* text: 24bit */
+ KEY_RESERVED, /* 24bit wheel up */
+ KEY_RESERVED, /* 24bit wheel down */
+ KEY_RESERVED, /* text: CMSS */
+ KEY_RESERVED, /* CMSS wheel Up */
+ KEY_RESERVED, /* CMSS wheel Down */
+ KEY_RESERVED, /* text: EAX */
+ KEY_RESERVED, /* EAX wheel up */
+ KEY_RESERVED, /* EAX wheel down */
+ KEY_RESERVED, /* text: 3D Midi */
+ KEY_RESERVED, /* 3D Midi wheel up */
+ KEY_RESERVED, /* 3D Midi wheel down */
+ KEY_MUTE,
+ KEY_VOLUMEUP,
+ KEY_VOLUMEDOWN,
+ KEY_UP,
+ KEY_LEFT,
+ KEY_RIGHT,
+ KEY_REWIND,
+ KEY_OK,
+ KEY_FASTFORWARD,
+ KEY_DOWN,
+ KEY_AGAIN, /* text: Return, symbol: Jump to */
+ KEY_PLAY, /* text: Start */
+ KEY_ESC, /* text: Cancel */
+ KEY_RECORD,
+ KEY_OPTION,
+ KEY_MENU, /* text: Display */
+ KEY_PREVIOUS,
+ KEY_PLAYPAUSE,
+ KEY_NEXT,
+ KEY_SLOW,
+ KEY_STOP,
+ KEY_NUMERIC_1,
+ KEY_NUMERIC_2,
+ KEY_NUMERIC_3,
+ KEY_NUMERIC_4,
+ KEY_NUMERIC_5,
+ KEY_NUMERIC_6,
+ KEY_NUMERIC_7,
+ KEY_NUMERIC_8,
+ KEY_NUMERIC_9,
+ KEY_NUMERIC_0
+};
+
+/*
+ * Codes and keys from lirc's
+ * remotes/creative/lircd.conf.alsa_usb
+ * order and size must match creative_sb0540_key_table[] above
+ */
+static const unsigned short creative_sb0540_codes[] = {
+ 0x619E,
+ 0x916E,
+ 0x926D,
+ 0x936C,
+ 0x718E,
+ 0x946B,
+ 0x956A,
+ 0x8C73,
+ 0x9669,
+ 0x9768,
+ 0x9867,
+ 0x9966,
+ 0x9A65,
+ 0x6E91,
+ 0x629D,
+ 0x639C,
+ 0x7B84,
+ 0x6B94,
+ 0x728D,
+ 0x8778,
+ 0x817E,
+ 0x758A,
+ 0x8D72,
+ 0x8E71,
+ 0x8877,
+ 0x7C83,
+ 0x738C,
+ 0x827D,
+ 0x7689,
+ 0x7F80,
+ 0x7986,
+ 0x7A85,
+ 0x7D82,
+ 0x857A,
+ 0x8B74,
+ 0x8F70,
+ 0x906F,
+ 0x8A75,
+ 0x847B,
+ 0x7887,
+ 0x8976,
+ 0x837C,
+ 0x7788,
+ 0x807F
+};
+
+struct creative_sb0540 {
+ struct input_dev *input_dev;
+ struct hid_device *hid;
+ unsigned short keymap[ARRAY_SIZE(creative_sb0540_key_table)];
+};
+
+static inline u64 reverse(u64 data, int bits)
+{
+ int i;
+ u64 c;
+
+ c = 0;
+ for (i = 0; i < bits; i++) {
+ c |= (u64) (((data & (((u64) 1) << i)) ? 1 : 0))
+ << (bits - 1 - i);
+ }
+ return (c);
+}
+
+static int get_key(struct creative_sb0540 *creative_sb0540, u64 keycode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(creative_sb0540_codes); i++) {
+ if (creative_sb0540_codes[i] == keycode)
+ return creative_sb0540->keymap[i];
+ }
+
+ return 0;
+
+}
+
+static int creative_sb0540_raw_event(struct hid_device *hid,
+ struct hid_report *report, u8 *data, int len)
+{
+ struct creative_sb0540 *creative_sb0540 = hid_get_drvdata(hid);
+ u64 code, main_code;
+ int key;
+
+ if (len != 6)
+ return 0;
+
+ /* From daemons/hw_hiddev.c sb0540_rec() in lirc */
+ code = reverse(data[5], 8);
+ main_code = (code << 8) + ((~code) & 0xff);
+
+ /*
+ * Flip to get values in the same format as
+ * remotes/creative/lircd.conf.alsa_usb in lirc
+ */
+ main_code = ((main_code & 0xff) << 8) +
+ ((main_code & 0xff00) >> 8);
+
+ key = get_key(creative_sb0540, main_code);
+ if (key == 0 || key == KEY_RESERVED) {
+ hid_err(hid, "Could not get a key for main_code %llX\n",
+ main_code);
+ return 0;
+ }
+
+ input_report_key(creative_sb0540->input_dev, key, 1);
+ input_report_key(creative_sb0540->input_dev, key, 0);
+ input_sync(creative_sb0540->input_dev);
+
+ /* let hidraw and hiddev handle the report */
+ return 0;
+}
+
+static int creative_sb0540_input_configured(struct hid_device *hid,
+ struct hid_input *hidinput)
+{
+ struct input_dev *input_dev = hidinput->input;
+ struct creative_sb0540 *creative_sb0540 = hid_get_drvdata(hid);
+ int i;
+
+ creative_sb0540->input_dev = input_dev;
+
+ input_dev->keycode = creative_sb0540->keymap;
+ input_dev->keycodesize = sizeof(unsigned short);
+ input_dev->keycodemax = ARRAY_SIZE(creative_sb0540->keymap);
+
+ input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
+
+ memcpy(creative_sb0540->keymap, creative_sb0540_key_table,
+ sizeof(creative_sb0540->keymap));
+ for (i = 0; i < ARRAY_SIZE(creative_sb0540_key_table); i++)
+ set_bit(creative_sb0540->keymap[i], input_dev->keybit);
+ clear_bit(KEY_RESERVED, input_dev->keybit);
+
+ return 0;
+}
+
+static int creative_sb0540_input_mapping(struct hid_device *hid,
+ struct hid_input *hi, struct hid_field *field,
+ struct hid_usage *usage, unsigned long **bit, int *max)
+{
+ /*
+ * We are remapping the keys ourselves, so ignore the hid-input
+ * keymap processing.
+ */
+ return -1;
+}
+
+static int creative_sb0540_probe(struct hid_device *hid,
+ const struct hid_device_id *id)
+{
+ int ret;
+ struct creative_sb0540 *creative_sb0540;
+
+ creative_sb0540 = devm_kzalloc(&hid->dev,
+ sizeof(struct creative_sb0540), GFP_KERNEL);
+
+ if (!creative_sb0540)
+ return -ENOMEM;
+
+ creative_sb0540->hid = hid;
+
+ /* force input as some remotes bypass the input registration */
+ hid->quirks |= HID_QUIRK_HIDINPUT_FORCE;
+
+ hid_set_drvdata(hid, creative_sb0540);
+
+ ret = hid_parse(hid);
+ if (ret) {
+ hid_err(hid, "parse failed\n");
+ return ret;
+ }
+
+ ret = hid_hw_start(hid, HID_CONNECT_DEFAULT);
+ if (ret) {
+ hid_err(hid, "hw start failed\n");
+ return ret;
+ }
+
+ return ret;
+}
+
+static const struct hid_device_id creative_sb0540_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_CREATIVE_SB0540) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, creative_sb0540_devices);
+
+static struct hid_driver creative_sb0540_driver = {
+ .name = "creative-sb0540",
+ .id_table = creative_sb0540_devices,
+ .raw_event = creative_sb0540_raw_event,
+ .input_configured = creative_sb0540_input_configured,
+ .probe = creative_sb0540_probe,
+ .input_mapping = creative_sb0540_input_mapping,
+};
+module_hid_driver(creative_sb0540_driver);
diff --git a/drivers/hid/hid-gfrm.c b/drivers/hid/hid-gfrm.c
index 86c317320bf2..699186ff2349 100644
--- a/drivers/hid/hid-gfrm.c
+++ b/drivers/hid/hid-gfrm.c
@@ -123,12 +123,6 @@ done:
return ret;
}
-static void gfrm_remove(struct hid_device *hdev)
-{
- hid_hw_stop(hdev);
- hid_set_drvdata(hdev, NULL);
-}
-
static const struct hid_device_id gfrm_devices[] = {
{ HID_BLUETOOTH_DEVICE(0x58, 0x2000),
.driver_data = GFRM100 },
@@ -142,7 +136,6 @@ static struct hid_driver gfrm_driver = {
.name = "gfrm",
.id_table = gfrm_devices,
.probe = gfrm_probe,
- .remove = gfrm_remove,
.input_mapping = gfrm_input_mapping,
.raw_event = gfrm_raw_event,
.input_configured = gfrm_input_configured,
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 0a00be19f7a0..76969a22b0f2 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -314,6 +314,7 @@
#define USB_VENDOR_ID_CREATIVELABS 0x041e
#define USB_DEVICE_ID_CREATIVE_SB_OMNI_SURROUND_51 0x322c
#define USB_DEVICE_ID_PRODIKEYS_PCMIDI 0x2801
+#define USB_DEVICE_ID_CREATIVE_SB0540 0x3100
#define USB_VENDOR_ID_CVTOUCH 0x1ff7
#define USB_DEVICE_ID_CVTOUCH_SCREEN 0x0013
@@ -568,6 +569,7 @@
#define USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A 0x0b4a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE 0x134a
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A 0x094a
+#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941 0x0941
#define USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641 0x0641
#define USB_VENDOR_ID_HUION 0x256c
@@ -769,7 +771,8 @@
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER 0xc52f
#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2 0xc532
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2 0xc534
-#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED 0xc539
+#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1 0xc539
+#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1 0xc53f
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_POWERPLAY 0xc53a
#define USB_DEVICE_ID_SPACETRAVELLER 0xc623
#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
diff --git a/drivers/hid/hid-lenovo.c b/drivers/hid/hid-lenovo.c
index 364bc7f11d9d..96fa2a2c2cd3 100644
--- a/drivers/hid/hid-lenovo.c
+++ b/drivers/hid/hid-lenovo.c
@@ -866,8 +866,6 @@ static void lenovo_remove_tpkbd(struct hid_device *hdev)
led_classdev_unregister(&data_pointer->led_micmute);
led_classdev_unregister(&data_pointer->led_mute);
-
- hid_set_drvdata(hdev, NULL);
}
static void lenovo_remove_cptkbd(struct hid_device *hdev)
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index 5008a3dc28f4..0dc7cdfc56f7 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -818,7 +818,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (!buf) {
ret = -ENOMEM;
- goto err_free;
+ goto err_stop;
}
ret = hid_hw_raw_request(hdev, buf[0], buf, sizeof(cbuf),
@@ -850,9 +850,12 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = lg4ff_init(hdev);
if (ret)
- goto err_free;
+ goto err_stop;
return 0;
+
+err_stop:
+ hid_hw_stop(hdev);
err_free:
kfree(drv_data);
return ret;
@@ -863,8 +866,7 @@ static void lg_remove(struct hid_device *hdev)
struct lg_drv_data *drv_data = hid_get_drvdata(hdev);
if (drv_data->quirks & LG_FF4)
lg4ff_deinit(hdev);
- else
- hid_hw_stop(hdev);
+ hid_hw_stop(hdev);
kfree(drv_data);
}
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index cefba038520c..03f0220062ca 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -1477,7 +1477,6 @@ int lg4ff_deinit(struct hid_device *hid)
}
}
#endif
- hid_hw_stop(hid);
drv_data->device_props = NULL;
kfree(entry);
diff --git a/drivers/hid/hid-logitech-dj.c b/drivers/hid/hid-logitech-dj.c
index cc47f948c1d0..bb50d6e7745b 100644
--- a/drivers/hid/hid-logitech-dj.c
+++ b/drivers/hid/hid-logitech-dj.c
@@ -380,9 +380,9 @@ static const char consumer_descriptor[] = {
0x75, 0x10, /* REPORT_SIZE (16) */
0x95, 0x02, /* REPORT_COUNT (2) */
0x15, 0x01, /* LOGICAL_MIN (1) */
- 0x26, 0x8C, 0x02, /* LOGICAL_MAX (652) */
+ 0x26, 0xFF, 0x02, /* LOGICAL_MAX (767) */
0x19, 0x01, /* USAGE_MIN (1) */
- 0x2A, 0x8C, 0x02, /* USAGE_MAX (652) */
+ 0x2A, 0xFF, 0x02, /* USAGE_MAX (767) */
0x81, 0x00, /* INPUT (Data Ary Abs) */
0xC0, /* END_COLLECTION */
}; /* */
@@ -959,6 +959,7 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
break;
case 0x07:
device_type = "eQUAD step 4 Gaming";
+ logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
break;
case 0x08:
device_type = "eQUAD step 4 for gamepads";
@@ -968,7 +969,12 @@ static void logi_hidpp_recv_queue_notif(struct hid_device *hdev,
logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
break;
case 0x0c:
- device_type = "eQUAD Lightspeed";
+ device_type = "eQUAD Lightspeed 1";
+ logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
+ workitem.reports_supported |= STD_KEYBOARD;
+ break;
+ case 0x0d:
+ device_type = "eQUAD Lightspeed 1_1";
logi_hidpp_dev_conn_notif_equad(hdev, hidpp_report, &workitem);
workitem.reports_supported |= STD_KEYBOARD;
break;
@@ -1734,14 +1740,14 @@ static int logi_dj_probe(struct hid_device *hdev,
if (retval < 0) {
hid_err(hdev, "%s: logi_dj_recv_query_paired_devices error:%d\n",
__func__, retval);
- goto logi_dj_recv_query_paired_devices_failed;
+ /*
+ * This can happen with a KVM, let the probe succeed,
+ * logi_dj_recv_queue_unknown_work will retry later.
+ */
}
}
- return retval;
-
-logi_dj_recv_query_paired_devices_failed:
- hid_hw_close(hdev);
+ return 0;
llopen_failed:
switch_to_dj_mode_fail:
@@ -1832,9 +1838,17 @@ static const struct hid_device_id logi_dj_receivers[] = {
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2),
.driver_data = recvr_type_hidpp},
+ { /* Logitech G700(s) receiver (0xc531) */
+ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
+ 0xc531),
+ .driver_data = recvr_type_gaming_hidpp},
{ /* Logitech lightspeed receiver (0xc539) */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
- USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED),
+ USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1),
+ .driver_data = recvr_type_gaming_hidpp},
+ { /* Logitech lightspeed receiver (0xc53f) */
+ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH,
+ USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_LIGHTSPEED_1_1),
.driver_data = recvr_type_gaming_hidpp},
{ /* Logitech 27 MHz HID++ 1.0 receiver (0xc513) */
HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER),
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
index b603c14d043b..3cfeb1629f79 100644
--- a/drivers/hid/hid-multitouch.c
+++ b/drivers/hid/hid-multitouch.c
@@ -68,6 +68,7 @@ MODULE_LICENSE("GPL");
#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_QUIRK_SEPARATE_APP_REPORT BIT(19)
#define MT_INPUTMODE_TOUCHSCREEN 0x02
#define MT_INPUTMODE_TOUCHPAD 0x03
@@ -103,6 +104,7 @@ struct mt_usages {
struct mt_application {
struct list_head list;
unsigned int application;
+ unsigned int report_id;
struct list_head mt_usages; /* mt usages list */
__s32 quirks;
@@ -203,6 +205,7 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app);
#define MT_CLS_VTL 0x0110
#define MT_CLS_GOOGLE 0x0111
#define MT_CLS_RAZER_BLADE_STEALTH 0x0112
+#define MT_CLS_SMART_TECH 0x0113
#define MT_DEFAULT_MAXCONTACT 10
#define MT_MAX_MAXCONTACT 250
@@ -263,7 +266,8 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_HOVERING |
MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_STICKY_FINGERS |
- MT_QUIRK_WIN8_PTP_BUTTONS },
+ MT_QUIRK_WIN8_PTP_BUTTONS,
+ .export_all_inputs = true },
{ .name = MT_CLS_EXPORT_ALL_INPUTS,
.quirks = MT_QUIRK_ALWAYS_VALID |
MT_QUIRK_CONTACT_CNT_ACCURATE,
@@ -353,6 +357,12 @@ static const struct mt_class mt_classes[] = {
MT_QUIRK_CONTACT_CNT_ACCURATE |
MT_QUIRK_WIN8_PTP_BUTTONS,
},
+ { .name = MT_CLS_SMART_TECH,
+ .quirks = MT_QUIRK_ALWAYS_VALID |
+ MT_QUIRK_IGNORE_DUPLICATES |
+ MT_QUIRK_CONTACT_CNT_ACCURATE |
+ MT_QUIRK_SEPARATE_APP_REPORT,
+ },
{ }
};
@@ -509,8 +519,9 @@ static struct mt_usages *mt_allocate_usage(struct hid_device *hdev,
}
static struct mt_application *mt_allocate_application(struct mt_device *td,
- unsigned int application)
+ struct hid_report *report)
{
+ unsigned int application = report->application;
struct mt_application *mt_application;
mt_application = devm_kzalloc(&td->hdev->dev, sizeof(*mt_application),
@@ -535,6 +546,7 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
mt_application->scantime = DEFAULT_ZERO;
mt_application->raw_cc = DEFAULT_ZERO;
mt_application->quirks = td->mtclass.quirks;
+ mt_application->report_id = report->id;
list_add_tail(&mt_application->list, &td->applications);
@@ -542,19 +554,23 @@ static struct mt_application *mt_allocate_application(struct mt_device *td,
}
static struct mt_application *mt_find_application(struct mt_device *td,
- unsigned int application)
+ struct hid_report *report)
{
+ unsigned int application = report->application;
struct mt_application *tmp, *mt_application = NULL;
list_for_each_entry(tmp, &td->applications, list) {
if (application == tmp->application) {
- mt_application = tmp;
- break;
+ if (!(td->mtclass.quirks & MT_QUIRK_SEPARATE_APP_REPORT) ||
+ tmp->report_id == report->id) {
+ mt_application = tmp;
+ break;
+ }
}
}
if (!mt_application)
- mt_application = mt_allocate_application(td, application);
+ mt_application = mt_allocate_application(td, report);
return mt_application;
}
@@ -571,7 +587,7 @@ static struct mt_report_data *mt_allocate_report_data(struct mt_device *td,
return NULL;
rdata->report = report;
- rdata->application = mt_find_application(td, report->application);
+ rdata->application = mt_find_application(td, report);
if (!rdata->application) {
devm_kfree(&td->hdev->dev, rdata);
@@ -1561,6 +1577,9 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
case HID_VD_ASUS_CUSTOM_MEDIA_KEYS:
suffix = "Custom Media Keys";
break;
+ case HID_DG_PEN:
+ suffix = "Stylus";
+ break;
default:
suffix = "UNKNOWN";
break;
@@ -2022,6 +2041,10 @@ static const struct hid_device_id mt_devices[] = {
HID_DEVICE(BUS_I2C, HID_GROUP_MULTITOUCH_WIN_8,
USB_VENDOR_ID_SYNAPTICS, 0x8323) },
+ /* Smart Tech panels */
+ { .driver_data = MT_CLS_SMART_TECH,
+ MT_USB_DEVICE(0x0b8c, 0x0092)},
+
/* Stantum panels */
{ .driver_data = MT_CLS_CONFIDENCE,
MT_USB_DEVICE(USB_VENDOR_ID_STANTUM_STM,
diff --git a/drivers/hid/hid-picolcd_core.c b/drivers/hid/hid-picolcd_core.c
index 5f7a39a5d4af..1b5c63241af0 100644
--- a/drivers/hid/hid-picolcd_core.c
+++ b/drivers/hid/hid-picolcd_core.c
@@ -534,8 +534,7 @@ static int picolcd_probe(struct hid_device *hdev,
data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
if (data == NULL) {
hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
- error = -ENOMEM;
- goto err_no_cleanup;
+ return -ENOMEM;
}
spin_lock_init(&data->lock);
@@ -597,9 +596,6 @@ err_cleanup_hid_hw:
hid_hw_stop(hdev);
err_cleanup_data:
kfree(data);
-err_no_cleanup:
- hid_set_drvdata(hdev, NULL);
-
return error;
}
@@ -635,7 +631,6 @@ static void picolcd_remove(struct hid_device *hdev)
picolcd_exit_cir(data);
picolcd_exit_keys(data);
- hid_set_drvdata(hdev, NULL);
mutex_destroy(&data->mutex);
/* Finally, clean up the picolcd data itself */
kfree(data);
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index 21544ebff855..5a3b3d974d84 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -551,10 +551,14 @@ static void pcmidi_setup_extra_keys(
static int pcmidi_set_operational(struct pcmidi_snd *pm)
{
+ int rc;
+
if (pm->ifnum != 1)
return 0; /* only set up ONCE for interace 1 */
- pcmidi_get_output_report(pm);
+ rc = pcmidi_get_output_report(pm);
+ if (rc < 0)
+ return rc;
pcmidi_submit_output_report(pm, 0xc1);
return 0;
}
@@ -683,7 +687,11 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
spin_lock_init(&pm->rawmidi_in_lock);
init_sustain_timers(pm);
- pcmidi_set_operational(pm);
+ err = pcmidi_set_operational(pm);
+ if (err < 0) {
+ pk_error("failed to find output report\n");
+ goto fail_register;
+ }
/* register it */
err = snd_card_register(card);
diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c
index 166f41f3173b..c50bcd967d99 100644
--- a/drivers/hid/hid-quirks.c
+++ b/drivers/hid/hid-quirks.c
@@ -92,6 +92,7 @@ static const struct hid_device_id hid_quirks[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_LOGITECH_OEM_USB_OPTICAL_MOUSE_0B4A), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_094A), HID_QUIRK_ALWAYS_POLL },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0941), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_HP, USB_PRODUCT_ID_HP_PIXART_OEM_USB_OPTICAL_MOUSE_0641), HID_QUIRK_ALWAYS_POLL },
{ HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6680), HID_QUIRK_MULTI_INPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_INNOMEDIA, USB_DEVICE_ID_INNEX_GENESIS_ATARI), HID_QUIRK_MULTI_INPUT },
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index be92a6f79687..94c7398b5c27 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -742,7 +742,6 @@ static void sensor_hub_remove(struct hid_device *hdev)
}
spin_unlock_irqrestore(&data->lock, flags);
mfd_remove_devices(&hdev->dev);
- hid_set_drvdata(hdev, NULL);
mutex_destroy(&data->mutex);
}
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 49dd2d905c7f..73c0f7a95e2d 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -2811,7 +2811,6 @@ err_stop:
sony_cancel_work_sync(sc);
sony_remove_dev_list(sc);
sony_release_device_id(sc);
- hid_hw_stop(hdev);
return ret;
}
@@ -2876,6 +2875,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
*/
if (!(hdev->claimed & HID_CLAIMED_INPUT)) {
hid_err(hdev, "failed to claim input\n");
+ hid_hw_stop(hdev);
return -ENODEV;
}
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index 006bd6f4f653..bbc6ec1aa5cb 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -252,7 +252,7 @@ static __poll_t hidraw_poll(struct file *file, poll_table *wait)
poll_wait(file, &list->hidraw->wait, wait);
if (list->head != list->tail)
- return EPOLLIN | EPOLLRDNORM;
+ return EPOLLIN | EPOLLRDNORM | EPOLLOUT;
if (!list->hidraw->exist)
return EPOLLERR | EPOLLHUP;
return 0;
@@ -370,7 +370,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
mutex_lock(&minors_lock);
dev = hidraw_table[minor];
- if (!dev) {
+ if (!dev || !dev->exist) {
ret = -ENODEV;
goto out;
}
diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c
index 90164fed08d3..2a7c6e33bb1c 100644
--- a/drivers/hid/i2c-hid/i2c-hid-core.c
+++ b/drivers/hid/i2c-hid/i2c-hid-core.c
@@ -169,9 +169,7 @@ static const struct i2c_hid_quirks {
__u16 idProduct;
__u32 quirks;
} i2c_hid_quirks[] = {
- { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8752,
- I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
- { USB_VENDOR_ID_WEIDA, USB_DEVICE_ID_WEIDA_8755,
+ { USB_VENDOR_ID_WEIDA, HID_ANY_ID,
I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV },
{ I2C_VENDOR_ID_HANTICK, I2C_PRODUCT_ID_HANTICK_5288,
I2C_HID_QUIRK_NO_IRQ_AFTER_RESET |
diff --git a/drivers/hid/intel-ish-hid/ipc/hw-ish.h b/drivers/hid/intel-ish-hid/ipc/hw-ish.h
index 5792a104000a..6c1e6110867f 100644
--- a/drivers/hid/intel-ish-hid/ipc/hw-ish.h
+++ b/drivers/hid/intel-ish-hid/ipc/hw-ish.h
@@ -78,5 +78,6 @@ irqreturn_t ish_irq_handler(int irq, void *dev_id);
struct ishtp_device *ish_dev_init(struct pci_dev *pdev);
int ish_hw_start(struct ishtp_device *dev);
void ish_device_disable(struct ishtp_device *dev);
+int ish_disable_dma(struct ishtp_device *dev);
#endif /* _ISHTP_HW_ISH_H_ */
diff --git a/drivers/hid/intel-ish-hid/ipc/ipc.c b/drivers/hid/intel-ish-hid/ipc/ipc.c
index 18fe8af89aad..8f8dfdf64833 100644
--- a/drivers/hid/intel-ish-hid/ipc/ipc.c
+++ b/drivers/hid/intel-ish-hid/ipc/ipc.c
@@ -672,7 +672,7 @@ eoi:
*
* Return: 0 for success else error code.
*/
-static int ish_disable_dma(struct ishtp_device *dev)
+int ish_disable_dma(struct ishtp_device *dev)
{
unsigned int dma_delay;
diff --git a/drivers/hid/intel-ish-hid/ipc/pci-ish.c b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
index 279567baca3d..784dcc8c7022 100644
--- a/drivers/hid/intel-ish-hid/ipc/pci-ish.c
+++ b/drivers/hid/intel-ish-hid/ipc/pci-ish.c
@@ -14,6 +14,7 @@
#include <linux/types.h>
#include <linux/pci.h>
#include <linux/sched.h>
+#include <linux/suspend.h>
#include <linux/interrupt.h>
#include <linux/workqueue.h>
#define CREATE_TRACE_POINTS
@@ -98,6 +99,11 @@ static const struct pci_device_id ish_invalid_pci_ids[] = {
{}
};
+static inline bool ish_should_enter_d0i3(struct pci_dev *pdev)
+{
+ return !pm_suspend_via_firmware() || pdev->device == CHV_DEVICE_ID;
+}
+
/**
* ish_probe() - PCI driver probe callback
* @pdev: pci device
@@ -148,7 +154,6 @@ static int ish_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* mapping IO device memory */
hw->mem_addr = pcim_iomap_table(pdev)[0];
ishtp->pdev = pdev;
- pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
/* request and enable interrupt */
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
@@ -185,7 +190,6 @@ static void ish_remove(struct pci_dev *pdev)
struct ishtp_device *ishtp_dev = pci_get_drvdata(pdev);
ishtp_bus_remove_all_clients(ishtp_dev, false);
- pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3;
ish_device_disable(ishtp_dev);
}
@@ -207,17 +211,13 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
{
struct pci_dev *pdev = to_pci_dev(ish_resume_device);
struct ishtp_device *dev = pci_get_drvdata(pdev);
- uint32_t fwsts;
int ret;
- /* Get ISH FW status */
- fwsts = IPC_GET_ISH_FWSTS(dev->ops->get_fw_status(dev));
+ /* Check the NO_D3 flag to distinguish the resume paths */
+ if (pdev->dev_flags & PCI_DEV_FLAGS_NO_D3) {
+ pdev->dev_flags &= ~PCI_DEV_FLAGS_NO_D3;
+ disable_irq_wake(pdev->irq);
- /*
- * If currently, in ISH FW, sensor app is loaded or beyond that,
- * it means ISH isn't powered off, in this case, send a resume message.
- */
- if (fwsts >= FWSTS_SENSOR_APP_LOADED) {
ishtp_send_resume(dev);
/* Waiting to get resume response */
@@ -225,16 +225,20 @@ static void __maybe_unused ish_resume_handler(struct work_struct *work)
ret = wait_event_interruptible_timeout(dev->resume_wait,
!dev->resume_flag,
msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS));
- }
- /*
- * If in ISH FW, sensor app isn't loaded yet, or no resume response.
- * That means this platform is not S0ix compatible, or something is
- * wrong with ISH FW. So on resume, full reboot of ISH processor will
- * happen, so need to go through init sequence again.
- */
- if (dev->resume_flag)
+ /*
+ * If the flag is not cleared, something is wrong with ISH FW.
+ * So on resume, need to go through init sequence again.
+ */
+ if (dev->resume_flag)
+ ish_init(dev);
+ } else {
+ /*
+ * Resume from the D3, full reboot of ISH processor will happen,
+ * so need to go through init sequence again.
+ */
ish_init(dev);
+ }
}
/**
@@ -250,23 +254,43 @@ static int __maybe_unused ish_suspend(struct device *device)
struct pci_dev *pdev = to_pci_dev(device);
struct ishtp_device *dev = pci_get_drvdata(pdev);
- enable_irq_wake(pdev->irq);
- /*
- * If previous suspend hasn't been asnwered then ISH is likely dead,
- * don't attempt nested notification
- */
- if (dev->suspend_flag)
- return 0;
-
- dev->resume_flag = 0;
- dev->suspend_flag = 1;
- ishtp_send_suspend(dev);
-
- /* 25 ms should be enough for live ISH to flush all IPC buf */
- if (dev->suspend_flag)
- wait_event_interruptible_timeout(dev->suspend_wait,
- !dev->suspend_flag,
- msecs_to_jiffies(25));
+ if (ish_should_enter_d0i3(pdev)) {
+ /*
+ * If previous suspend hasn't been asnwered then ISH is likely
+ * dead, don't attempt nested notification
+ */
+ if (dev->suspend_flag)
+ return 0;
+
+ dev->resume_flag = 0;
+ dev->suspend_flag = 1;
+ ishtp_send_suspend(dev);
+
+ /* 25 ms should be enough for live ISH to flush all IPC buf */
+ if (dev->suspend_flag)
+ wait_event_interruptible_timeout(dev->suspend_wait,
+ !dev->suspend_flag,
+ msecs_to_jiffies(25));
+
+ if (dev->suspend_flag) {
+ /*
+ * It looks like FW halt, clear the DMA bit, and put
+ * ISH into D3, and FW would reset on resume.
+ */
+ ish_disable_dma(dev);
+ } else {
+ /* Set the NO_D3 flag, the ISH would enter D0i3 */
+ pdev->dev_flags |= PCI_DEV_FLAGS_NO_D3;
+
+ enable_irq_wake(pdev->irq);
+ }
+ } else {
+ /*
+ * Clear the DMA bit before putting ISH into D3,
+ * or ISH FW would reset automatically.
+ */
+ ish_disable_dma(dev);
+ }
return 0;
}
@@ -288,7 +312,6 @@ static int __maybe_unused ish_resume(struct device *device)
ish_resume_device = device;
dev->resume_flag = 1;
- disable_irq_wake(pdev->irq);
schedule_work(&resume_work);
return 0;
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 4e11cc6fc34b..1f9bc4483465 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -428,7 +428,7 @@ static __poll_t hiddev_poll(struct file *file, poll_table *wait)
poll_wait(file, &list->hiddev->wait, wait);
if (list->head != list->tail)
- return EPOLLIN | EPOLLRDNORM;
+ return EPOLLIN | EPOLLRDNORM | EPOLLOUT;
if (!list->hiddev->exist)
return EPOLLERR | EPOLLHUP;
return 0;
diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c
index 53bddb50aeba..5ded94b7bf68 100644
--- a/drivers/hid/wacom_sys.c
+++ b/drivers/hid/wacom_sys.c
@@ -88,7 +88,7 @@ static void wacom_wac_queue_flush(struct hid_device *hdev,
}
static int wacom_wac_pen_serial_enforce(struct hid_device *hdev,
- struct hid_report *report, u8 *raw_data, int size)
+ struct hid_report *report, u8 *raw_data, int report_size)
{
struct wacom *wacom = hid_get_drvdata(hdev);
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
@@ -149,7 +149,8 @@ static int wacom_wac_pen_serial_enforce(struct hid_device *hdev,
if (flush)
wacom_wac_queue_flush(hdev, &wacom_wac->pen_fifo);
else if (insert)
- wacom_wac_queue_insert(hdev, &wacom_wac->pen_fifo, raw_data, size);
+ wacom_wac_queue_insert(hdev, &wacom_wac->pen_fifo,
+ raw_data, report_size);
return insert && !flush;
}
@@ -2176,7 +2177,7 @@ static void wacom_update_name(struct wacom *wacom, const char *suffix)
{
struct wacom_wac *wacom_wac = &wacom->wacom_wac;
struct wacom_features *features = &wacom_wac->features;
- char name[WACOM_NAME_MAX];
+ char name[WACOM_NAME_MAX - 20]; /* Leave some room for suffixes */
/* Generic devices name unspecified */
if ((features->type == HID_GENERIC) && !strcmp("Wacom HID", features->name)) {
@@ -2718,14 +2719,12 @@ static int wacom_probe(struct hid_device *hdev,
wacom_wac->features = *((struct wacom_features *)id->driver_data);
features = &wacom_wac->features;
- if (features->check_for_hid_type && features->hid_type != hdev->type) {
- error = -ENODEV;
- goto fail;
- }
+ if (features->check_for_hid_type && features->hid_type != hdev->type)
+ return -ENODEV;
error = kfifo_alloc(&wacom_wac->pen_fifo, WACOM_PKGLEN_MAX, GFP_KERNEL);
if (error)
- goto fail;
+ return error;
wacom_wac->hid_data.inputmode = -1;
wacom_wac->mode_report = -1;
@@ -2743,12 +2742,12 @@ static int wacom_probe(struct hid_device *hdev,
error = hid_parse(hdev);
if (error) {
hid_err(hdev, "parse failed\n");
- goto fail;
+ return error;
}
error = wacom_parse_and_register(wacom, false);
if (error)
- goto fail;
+ return error;
if (hdev->bus == BUS_BLUETOOTH) {
error = device_create_file(&hdev->dev, &dev_attr_speed);
@@ -2759,10 +2758,6 @@ static int wacom_probe(struct hid_device *hdev,
}
return 0;
-
-fail:
- hid_set_drvdata(hdev, NULL);
- return error;
}
static void wacom_remove(struct hid_device *hdev)
@@ -2791,8 +2786,6 @@ static void wacom_remove(struct hid_device *hdev)
wacom_release_resources(wacom);
kfifo_free(&wacom_wac->pen_fifo);
-
- hid_set_drvdata(hdev, NULL);
}
#ifdef CONFIG_PM
diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c
index 1713235d28cb..2b0a5b8ca6e6 100644
--- a/drivers/hid/wacom_wac.c
+++ b/drivers/hid/wacom_wac.c
@@ -251,7 +251,7 @@ static int wacom_dtu_irq(struct wacom_wac *wacom)
static int wacom_dtus_irq(struct wacom_wac *wacom)
{
- char *data = wacom->data;
+ unsigned char *data = wacom->data;
struct input_dev *input = wacom->pen_input;
unsigned short prox, pressure = 0;
@@ -483,6 +483,8 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
int ring1 = 0, ring2 = 0;
int strip1 = 0, strip2 = 0;
bool prox = false;
+ bool wrench = false, keyboard = false, mute_touch = false, menu = false,
+ info = false;
/* pad packets. Works as a second tool and is always in prox */
if (!(data[0] == WACOM_REPORT_INTUOSPAD || data[0] == WACOM_REPORT_INTUOS5PAD ||
@@ -512,10 +514,32 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
keys = ((data[3] & 0x1C) ? 1<<2 : 0) |
((data[4] & 0xE0) ? 1<<1 : 0) |
((data[4] & 0x07) ? 1<<0 : 0);
+ keyboard = !!(data[4] & 0xE0);
+ info = !!(data[3] & 0x1C);
+
+ if (features->oPid) {
+ mute_touch = !!(data[4] & 0x07);
+ if (mute_touch)
+ wacom->shared->is_touch_on =
+ !wacom->shared->is_touch_on;
+ } else {
+ wrench = !!(data[4] & 0x07);
+ }
} else if (features->type == WACOM_27QHD) {
nkeys = 3;
keys = data[2] & 0x07;
+ wrench = !!(data[2] & 0x01);
+ keyboard = !!(data[2] & 0x02);
+
+ if (features->oPid) {
+ mute_touch = !!(data[2] & 0x04);
+ if (mute_touch)
+ wacom->shared->is_touch_on =
+ !wacom->shared->is_touch_on;
+ } else {
+ menu = !!(data[2] & 0x04);
+ }
input_report_abs(input, ABS_X, be16_to_cpup((__be16 *)&data[4]));
input_report_abs(input, ABS_Y, be16_to_cpup((__be16 *)&data[6]));
input_report_abs(input, ABS_Z, be16_to_cpup((__be16 *)&data[8]));
@@ -561,6 +585,9 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
if (features->type == WACOM_22HD) {
nkeys = 3;
keys = data[9] & 0x07;
+
+ info = !!(data[9] & 0x01);
+ wrench = !!(data[9] & 0x02);
}
} else {
buttons = ((data[6] & 0x10) << 5) |
@@ -572,7 +599,7 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
strip2 = ((data[3] & 0x1f) << 8) | data[4];
}
- prox = (buttons & ~(~0 << nbuttons)) | (keys & ~(~0 << nkeys)) |
+ prox = (buttons & ~(~0U << nbuttons)) | (keys & ~(~0U << nkeys)) |
(ring1 & 0x80) | (ring2 & 0x80) | strip1 | strip2;
wacom_report_numbered_buttons(input, nbuttons, buttons);
@@ -580,6 +607,18 @@ static int wacom_intuos_pad(struct wacom_wac *wacom)
for (i = 0; i < nkeys; i++)
input_report_key(input, KEY_PROG1 + i, keys & (1 << i));
+ input_report_key(input, KEY_BUTTONCONFIG, wrench);
+ input_report_key(input, KEY_ONSCREEN_KEYBOARD, keyboard);
+ input_report_key(input, KEY_CONTROLPANEL, menu);
+ input_report_key(input, KEY_INFO, info);
+
+ if (wacom->shared && wacom->shared->touch_input) {
+ input_report_switch(wacom->shared->touch_input,
+ SW_MUTE_DEVICE,
+ !wacom->shared->is_touch_on);
+ input_sync(wacom->shared->touch_input);
+ }
+
input_report_abs(input, ABS_RX, strip1);
input_report_abs(input, ABS_RY, strip2);
@@ -1483,6 +1522,12 @@ static int wacom_24hdt_irq(struct wacom_wac *wacom)
int byte_per_packet = WACOM_BYTES_PER_24HDT_PACKET;
int y_offset = 2;
+ if (wacom->shared->has_mute_touch_switch &&
+ !wacom->shared->is_touch_on) {
+ if (!wacom->shared->touch_down)
+ return 0;
+ }
+
if (wacom->features.type == WACOM_27QHDT) {
current_num_contacts = data[63];
num_contacts_left = 10;
@@ -2051,14 +2096,14 @@ static void wacom_wac_pad_event(struct hid_device *hdev, struct hid_field *field
(hdev->product == 0x34d || hdev->product == 0x34e || /* MobileStudio Pro */
hdev->product == 0x357 || hdev->product == 0x358 || /* Intuos Pro 2 */
hdev->product == 0x392 || /* Intuos Pro 2 */
- hdev->product == 0x399)) { /* MobileStudio Pro */
+ hdev->product == 0x398 || hdev->product == 0x399)) { /* MobileStudio Pro */
value = (field->logical_maximum - value);
if (hdev->product == 0x357 || hdev->product == 0x358 ||
hdev->product == 0x392)
value = wacom_offset_rotation(input, usage, value, 3, 16);
else if (hdev->product == 0x34d || hdev->product == 0x34e ||
- hdev->product == 0x399)
+ hdev->product == 0x398 || hdev->product == 0x399)
value = wacom_offset_rotation(input, usage, value, 1, 2);
}
else {
@@ -3815,6 +3860,14 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev,
/* fall through */
case WACOM_27QHDT:
+ if (wacom_wac->shared->touch->product == 0x32C ||
+ wacom_wac->shared->touch->product == 0xF6) {
+ input_dev->evbit[0] |= BIT_MASK(EV_SW);
+ __set_bit(SW_MUTE_DEVICE, input_dev->swbit);
+ wacom_wac->shared->has_mute_touch_switch = true;
+ }
+ /* fall through */
+
case MTSCREEN:
case MTTPC:
case MTTPC_B:
@@ -4050,6 +4103,12 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
__set_bit(KEY_PROG2, input_dev->keybit);
__set_bit(KEY_PROG3, input_dev->keybit);
+ __set_bit(KEY_ONSCREEN_KEYBOARD, input_dev->keybit);
+ __set_bit(KEY_INFO, input_dev->keybit);
+
+ if (!features->oPid)
+ __set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
+
input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0);
input_set_abs_params(input_dev, ABS_THROTTLE, 0, 71, 0, 0);
break;
@@ -4058,6 +4117,12 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
__set_bit(KEY_PROG1, input_dev->keybit);
__set_bit(KEY_PROG2, input_dev->keybit);
__set_bit(KEY_PROG3, input_dev->keybit);
+
+ __set_bit(KEY_ONSCREEN_KEYBOARD, input_dev->keybit);
+ __set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
+
+ if (!features->oPid)
+ __set_bit(KEY_CONTROLPANEL, input_dev->keybit);
input_set_abs_params(input_dev, ABS_X, -2048, 2048, 0, 0);
input_abs_set_res(input_dev, ABS_X, 1024); /* points/g */
input_set_abs_params(input_dev, ABS_Y, -2048, 2048, 0, 0);
@@ -4071,6 +4136,9 @@ int wacom_setup_pad_input_capabilities(struct input_dev *input_dev,
__set_bit(KEY_PROG1, input_dev->keybit);
__set_bit(KEY_PROG2, input_dev->keybit);
__set_bit(KEY_PROG3, input_dev->keybit);
+
+ __set_bit(KEY_BUTTONCONFIG, input_dev->keybit);
+ __set_bit(KEY_INFO, input_dev->keybit);
/* fall through */
case WACOM_21UX2: