Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 23 Sep 2019 19:18:13 +0000 (12:18 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 23 Sep 2019 19:18:13 +0000 (12:18 -0700)
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
  ...

28 files changed:
MAINTAINERS
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-cougar.c
drivers/hid/hid-creative-sb0540.c [new file with mode: 0644]
drivers/hid/hid-gfrm.c
drivers/hid/hid-ids.h
drivers/hid/hid-lenovo.c
drivers/hid/hid-lg.c
drivers/hid/hid-lg4ff.c
drivers/hid/hid-logitech-dj.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-picolcd_core.c
drivers/hid/hid-prodikeys.c
drivers/hid/hid-quirks.c
drivers/hid/hid-sensor-hub.c
drivers/hid/hid-sony.c
drivers/hid/hidraw.c
drivers/hid/i2c-hid/i2c-hid-core.c
drivers/hid/intel-ish-hid/ipc/hw-ish.h
drivers/hid/intel-ish-hid/ipc/ipc.c
drivers/hid/intel-ish-hid/ipc/pci-ish.c
drivers/hid/usbhid/hiddev.c
drivers/hid/wacom_sys.c
drivers/hid/wacom_wac.c
include/linux/hid.h

index a400af0501c92a2dc362c571dd8a120ee40870eb..7ea0c11b8e8d5e203fb1d10ff4bfe9882e131ef3 100644 (file)
@@ -4338,6 +4338,12 @@ S:       Maintained
 F:     Documentation/filesystems/cramfs.txt
 F:     fs/cramfs/
 
+CREATIVE SB0540
+M:     Bastien Nocera <hadess@hadess.net>
+L:     linux-input@vger.kernel.org
+S:     Maintained
+F:     drivers/hid/hid-creative-sb0540.c
+
 CRYPTO API
 M:     Herbert Xu <herbert@gondor.apana.org.au>
 M:     "David S. Miller" <davem@davemloft.net>
index a958b9625bbaf2900b3fd5caa362f5b4138d85bb..1ecb5124421c00cd99d1caede390cc7ce1d5ff39 100644 (file)
@@ -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
index cc5d827c9164432f7a9f88884e224561d445c0dc..0c03308cfb08f2894758a4b880c8a55427d5c9e6 100644 (file)
@@ -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
index 81df62f48c4c32b8d1b89a89ea3f85b95450281c..6ac8becc2372efdd303ba29d14a246e9f5290239 100644 (file)
@@ -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 &&
index 210b81a56e1a111507737ac96cf5b510e416b3b6..3eaee2c37931bad846decfa127bb905c134770e9 100644 (file)
@@ -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;
        }
 
index e0bb7b34f3a4de8a1f4b51a9f3bc8406b21cd621..4ff3bc1d25e23fe91b4d8460e4ab13d934ea14c2 100644 (file)
@@ -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 (file)
index 0000000..b4c8e7a
--- /dev/null
@@ -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);
index 86c317320bf20d3c7a91dfc05dfed48d74be6a9e..699186ff2349e92a6ee70ef23b93e1f6af6f4e88 100644 (file)
@@ -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,
index 0a00be19f7a0de2f1d8d4ddcf5c96ece894f7fcf..76969a22b0f2f796a2b424ed252a8c0d08c3e3bd 100644 (file)
 #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
 #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
 #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
index 364bc7f11d9d9d757a9efbc3142f922798c48aff..96fa2a2c2cd3a65f91a2031be36aac59c53452c6 100644 (file)
@@ -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)
index 5008a3dc28f454a89803f361c35673b97f0f9119..0dc7cdfc56f77470b8a8c853ebd0077b4955853c 100644 (file)
@@ -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);
 }
 
index cefba038520ceb4d7901b640c09277708192488f..03f0220062cab641a725eddc2e4d51c1bedca141 100644 (file)
@@ -1477,7 +1477,6 @@ int lg4ff_deinit(struct hid_device *hid)
                }
        }
 #endif
-       hid_hw_stop(hid);
        drv_data->device_props = NULL;
 
        kfree(entry);
index cc47f948c1d0c54632e683a0d094cc1ae4902b32..bb50d6e7745bcc35c174ab6c0b64536748849e58 100644 (file)
@@ -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),
index b603c14d043b89c146fc55ff71da16147b157c80..3cfeb1629f79fec23e0ceadc32be2081c29b1f87 100644 (file)
@@ -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,
index 5f7a39a5d4afab5906497aa99640ffb1e9757249..1b5c63241af0585d21fac6d24512c5742aae0b97 100644 (file)
@@ -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);
index 21544ebff85545b5349e88b512d9e82f69484e9b..5a3b3d974d849c28503f6f6390312384d6e1868f 100644 (file)
@@ -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);
index 166f41f3173b8baa52bb033141f89db9ca9b967b..c50bcd967d9941a04a7b242af060ef7db48fa2e8 100644 (file)
@@ -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 },
index be92a6f79687094d917d4ba1cfdaa1494d88f481..94c7398b5c279f21775f5b1b5e550e0d848818c6 100644 (file)
@@ -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);
 }
 
index 49dd2d905c7f6b7f799e9de24c484a901808eddb..73c0f7a95e2dcea13d10b37176c9d7678074af1c 100644 (file)
@@ -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;
        }
 
index 006bd6f4f653f00a013efdb8cba2abbd34c01457..bbc6ec1aa5cb13eb4a856972a2d22739b78cc846 100644 (file)
@@ -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;
        }
index 90164fed08d35eca2c34250c8b7cb3814ea99f53..2a7c6e33bb1c4322b6851e42988f593e69ae527f 100644 (file)
@@ -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 |
index 5792a104000a915c55a2eae60354b47309433237..6c1e6110867f0d71ad279d41bc61c3d81f384dcc 100644 (file)
@@ -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_ */
index 18fe8af89aadde393c1ad80aa9b9d2d89441672d..8f8dfdf64833e2d56a7fd41d0d0a82f58e1b065d 100644 (file)
@@ -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;
 
index 279567baca3d95bd127256e84805a84f94f54a67..784dcc8c702280800704abb903fc3ec3a79e6687 100644 (file)
@@ -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;
index 4e11cc6fc34bc68afc856a20315e0092ed8f97c7..1f9bc4483465e1d1beae590192d6736a10546739 100644 (file)
@@ -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;
index 53bddb50aebaf500f0f5059a9fd2cba56e7b4182..5ded94b7bf684b87359549444c6f1cdddc17bbf2 100644 (file)
@@ -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
index 1713235d28cb01c1038b6fd1590849f684018510..2b0a5b8ca6e692850aa71ab21c3663fc5b56041b 100644 (file)
@@ -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:
index d770ab1a0479f9d5e650eb566ac69dd7cfc76f33..cd41f209043f6dabe779040724883e14b75129c6 100644 (file)
@@ -1154,29 +1154,32 @@ int hid_pidff_init(struct hid_device *hid);
 #define hid_pidff_init NULL
 #endif
 
-#define dbg_hid(format, arg...)                                                \
+#define dbg_hid(fmt, ...)                                              \
 do {                                                                   \
        if (hid_debug)                                                  \
-               printk(KERN_DEBUG "%s: " format, __FILE__, ##arg);      \
+               printk(KERN_DEBUG "%s: " fmt, __FILE__, ##__VA_ARGS__); \
 } while (0)
 
-#define hid_printk(level, hid, fmt, arg...)            \
-       dev_printk(level, &(hid)->dev, fmt, ##arg)
-#define hid_emerg(hid, fmt, arg...)                    \
-       dev_emerg(&(hid)->dev, fmt, ##arg)
-#define hid_crit(hid, fmt, arg...)                     \
-       dev_crit(&(hid)->dev, fmt, ##arg)
-#define hid_alert(hid, fmt, arg...)                    \
-       dev_alert(&(hid)->dev, fmt, ##arg)
-#define hid_err(hid, fmt, arg...)                      \
-       dev_err(&(hid)->dev, fmt, ##arg)
-#define hid_notice(hid, fmt, arg...)                   \
-       dev_notice(&(hid)->dev, fmt, ##arg)
-#define hid_warn(hid, fmt, arg...)                     \
-       dev_warn(&(hid)->dev, fmt, ##arg)
-#define hid_info(hid, fmt, arg...)                     \
-       dev_info(&(hid)->dev, fmt, ##arg)
-#define hid_dbg(hid, fmt, arg...)                      \
-       dev_dbg(&(hid)->dev, fmt, ##arg)
+#define hid_err(hid, fmt, ...)                         \
+       dev_err(&(hid)->dev, fmt, ##__VA_ARGS__)
+#define hid_notice(hid, fmt, ...)                      \
+       dev_notice(&(hid)->dev, fmt, ##__VA_ARGS__)
+#define hid_warn(hid, fmt, ...)                                \
+       dev_warn(&(hid)->dev, fmt, ##__VA_ARGS__)
+#define hid_info(hid, fmt, ...)                                \
+       dev_info(&(hid)->dev, fmt, ##__VA_ARGS__)
+#define hid_dbg(hid, fmt, ...)                         \
+       dev_dbg(&(hid)->dev, fmt, ##__VA_ARGS__)
+
+#define hid_err_once(hid, fmt, ...)                    \
+       dev_err_once(&(hid)->dev, fmt, ##__VA_ARGS__)
+#define hid_notice_once(hid, fmt, ...)                 \
+       dev_notice_once(&(hid)->dev, fmt, ##__VA_ARGS__)
+#define hid_warn_once(hid, fmt, ...)                   \
+       dev_warn_once(&(hid)->dev, fmt, ##__VA_ARGS__)
+#define hid_info_once(hid, fmt, ...)                   \
+       dev_info_once(&(hid)->dev, fmt, ##__VA_ARGS__)
+#define hid_dbg_once(hid, fmt, ...)                    \
+       dev_dbg_once(&(hid)->dev, fmt, ##__VA_ARGS__)
 
 #endif