]> git.proxmox.com Git - mirror_ubuntu-kernels.git/commitdiff
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
authorLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 Mar 2022 19:22:16 +0000 (12:22 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Fri, 25 Mar 2022 19:22:16 +0000 (12:22 -0700)
Pull HID updates from Jiri Kosina:

 - rework of generic input handling which ultimately makes the
   processing of tablet events more generic and reliable (Benjamin
   Tissoires)

 - fixes for handling unnumbered reports fully correctly in i2c-hid
   (Angela Czubak, Dmitry Torokhov)

 - untangling of intermingled code for sending and handling output
   reports in i2c-hid (Dmitry Torokhov)

 - Apple magic keyboard support improvements for newer models (José
   Expósito)

 - Apple T2 Macs support improvements (Aun-Ali Zaidi, Paul Pawlowski)

 - driver for Razer Blackwidow keyboards (Jelle van der Waa)

 - driver for SiGma Micro keyboards (Desmond Lim)

 - integration of first part of DIGImend patches in order to ultimately
   vastly improve Linux support of tablets (Nikolai Kondrashov, José
   Expósito)

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (55 commits)
  HID: intel-ish-hid: Use dma_alloc_coherent for firmware update
  Input: docs: add more details on the use of BTN_TOOL
  HID: input: accommodate priorities for slotted devices
  HID: input: remove the need for HID_QUIRK_INVERT
  HID: input: enforce Invert usage to be processed before InRange
  HID: core: for input reports, process the usages by priority list
  HID: compute an ordered list of input fields to process
  HID: input: move up out-of-range processing of input values
  HID: input: rework spaghetti code with switch statements
  HID: input: tag touchscreens as such if the physical is not there
  HID: core: split data fetching from processing in hid_input_field()
  HID: core: de-duplicate some code in hid_input_field()
  HID: core: statically allocate read buffers
  HID: uclogic: Support multiple frame input devices
  HID: uclogic: Define report IDs before their descriptors
  HID: uclogic: Put version first in rdesc namespace
  HID: uclogic: Use "frame" instead of "buttonpad"
  HID: uclogic: Use different constants for frame report IDs
  HID: uclogic: Specify total report size to buttonpad macro
  HID: uclogic: Switch to matching subreport bytes
  ...

20 files changed:
Documentation/input/event-codes.rst
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
drivers/hid/hid-apple.c
drivers/hid/hid-core.c
drivers/hid/hid-google-hammer.c
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-quirks.c
drivers/hid/hid-razer.c [new file with mode: 0644]
drivers/hid/hid-sigmamicro.c [new file with mode: 0644]
drivers/hid/hid-uclogic-core.c
drivers/hid/hid-uclogic-params.c
drivers/hid/hid-uclogic-params.h
drivers/hid/hid-uclogic-rdesc.c
drivers/hid/hid-uclogic-rdesc.h
drivers/hid/i2c-hid/i2c-hid-core.c
drivers/hid/intel-ish-hid/ishtp-fw-loader.c
include/linux/hid.h

index b24ae7d292cc191f8da0103c9de6fa56fcea4ce2..8741d390b1843b92070f8e2f918760fd102a4b79 100644 (file)
@@ -137,7 +137,11 @@ A few EV_KEY codes have special meanings:
     code should be set to a value of 1. When the tool is no longer interacting
     with the input device, the BTN_TOOL_<name> code should be reset to 0. All
     trackpads, tablets, and touchscreens should use at least one BTN_TOOL_<name>
-    code when events are generated.
+    code when events are generated. Likewise all trackpads, tablets, and
+    touchscreens should export only one BTN_TOOL_<name> at a time. To not break
+    existing userspace, it is recommended to not switch tool in one EV_SYN frame
+    but first emitting the old BTN_TOOL_<name> at 0, then emit one SYN_REPORT
+    and then set the new BTN_TOOL_<name> at 1.
 
 * BTN_TOUCH:
 
index f5544157576c97fdec7fd72d4dc8de0b8480ddd4..7a674873d7947fc040b6c1513b52cba0f1fea88f 100644 (file)
@@ -128,6 +128,8 @@ config HID_ACRUX_FF
 config HID_APPLE
        tristate "Apple {i,Power,Mac}Books"
        depends on HID
+       depends on LEDS_CLASS
+       depends on NEW_LEDS
        default !EXPERT
        help
        Support for some Apple devices which less or more break
@@ -929,6 +931,13 @@ config PLAYSTATION_FF
          Say Y here if you would like to enable force feedback support for
          PlayStation game controllers.
 
+config HID_RAZER
+       tristate "Razer non-fully HID-compliant devices"
+       depends on HID
+       help
+       Support for Razer devices that are not fully compliant with the
+       HID standard.
+
 config HID_PRIMAX
        tristate "Primax non-fully HID-compliant devices"
        depends on HID
@@ -984,6 +993,16 @@ config HID_SEMITEK
        - Woo-dy
        - X-Bows Nature/Knight
 
+config HID_SIGMAMICRO
+       tristate "SiGma Micro-based keyboards"
+       depends on USB_HID
+       help
+         Support for keyboards that use the SiGma Micro (a.k.a SigmaChip) IC.
+
+         Supported devices:
+         - Landslides KR-700
+         - Rapoo V500
+
 config HID_SONY
        tristate "Sony PS2/3/4 accessories"
        depends on USB_HID
index 6d3e630e81af51af5c1c853fce48a5484e4c08d3..d5ce8d747b140b1af99e9d3ab9418ab06383cd9e 100644 (file)
@@ -99,6 +99,7 @@ hid-picolcd-$(CONFIG_DEBUG_FS)                += hid-picolcd_debugfs.o
 obj-$(CONFIG_HID_PLANTRONICS)  += hid-plantronics.o
 obj-$(CONFIG_HID_PLAYSTATION)  += hid-playstation.o
 obj-$(CONFIG_HID_PRIMAX)       += hid-primax.o
+obj-$(CONFIG_HID_RAZER)        += hid-razer.o
 obj-$(CONFIG_HID_REDRAGON)     += hid-redragon.o
 obj-$(CONFIG_HID_RETRODE)      += hid-retrode.o
 obj-$(CONFIG_HID_ROCCAT)       += hid-roccat.o hid-roccat-common.o \
@@ -109,6 +110,7 @@ obj-$(CONFIG_HID_RMI)               += hid-rmi.o
 obj-$(CONFIG_HID_SAITEK)       += hid-saitek.o
 obj-$(CONFIG_HID_SAMSUNG)      += hid-samsung.o
 obj-$(CONFIG_HID_SEMITEK)      += hid-semitek.o
+obj-$(CONFIG_HID_SIGMAMICRO)   += hid-sigmamicro.o
 obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
 obj-$(CONFIG_HID_SONY)         += hid-sony.o
 obj-$(CONFIG_HID_SPEEDLINK)    += hid-speedlink.o
index 19fa734a9a793a7e86c1913b67a50a93be671f53..6b5fd90b0bd1b89a937d81b483cb1841ce65f369 100644 (file)
@@ -301,11 +301,8 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
        pci_set_master(pdev);
        rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
        if (rc) {
-               rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
-               if (rc) {
-                       dev_err(&pdev->dev, "failed to set DMA mask\n");
-                       return rc;
-               }
+               dev_err(&pdev->dev, "failed to set DMA mask\n");
+               return rc;
        }
 
        privdata->cl_data = devm_kzalloc(&pdev->dev, sizeof(struct amdtp_cl_data), GFP_KERNEL);
index 7dc89dc6b0f0eb6f5fa3792c285bbf0b8ac798c5..0cf35caee9fa048480146c0cdcad0eac7c466280 100644 (file)
@@ -7,6 +7,7 @@
  *  Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
  *  Copyright (c) 2006-2007 Jiri Kosina
  *  Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
+ *  Copyright (c) 2019 Paul Pawlowski <paul@mrarm.io>
  */
 
 /*
@@ -33,6 +34,7 @@
 /* BIT(7) reserved, was: APPLE_IGNORE_HIDINPUT */
 #define APPLE_NUMLOCK_EMULATION        BIT(8)
 #define APPLE_RDESC_BATTERY    BIT(9)
+#define APPLE_BACKLIGHT_CTL    BIT(10)
 
 #define APPLE_FLAG_FKEY                0x01
 
@@ -61,6 +63,12 @@ MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. "
                "(For people who want to keep PC keyboard muscle memory. "
                "[0] = as-is, Mac layout, 1 = swapped, PC layout)");
 
+struct apple_sc_backlight {
+       struct led_classdev cdev;
+       struct hid_device *hdev;
+       unsigned short backlight_off, backlight_on_min, backlight_on_max;
+};
+
 struct apple_sc {
        struct hid_device *hdev;
        unsigned long quirks;
@@ -68,6 +76,7 @@ struct apple_sc {
        unsigned int fn_found;
        DECLARE_BITMAP(pressed_numlock, KEY_CNT);
        struct timer_list battery_timer;
+       struct apple_sc_backlight *backlight;
 };
 
 struct apple_key_translation {
@@ -76,6 +85,61 @@ struct apple_key_translation {
        u8 flags;
 };
 
+static const struct apple_key_translation magic_keyboard_alu_fn_keys[] = {
+       { KEY_BACKSPACE, KEY_DELETE },
+       { KEY_ENTER,    KEY_INSERT },
+       { KEY_F1,       KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
+       { KEY_F2,       KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
+       { KEY_F3,       KEY_SCALE,          APPLE_FLAG_FKEY },
+       { KEY_F4,       KEY_DASHBOARD,      APPLE_FLAG_FKEY },
+       { KEY_F6,       KEY_NUMLOCK,        APPLE_FLAG_FKEY },
+       { KEY_F7,       KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
+       { KEY_F8,       KEY_PLAYPAUSE,      APPLE_FLAG_FKEY },
+       { KEY_F9,       KEY_NEXTSONG,       APPLE_FLAG_FKEY },
+       { KEY_F10,      KEY_MUTE,           APPLE_FLAG_FKEY },
+       { KEY_F11,      KEY_VOLUMEDOWN,     APPLE_FLAG_FKEY },
+       { KEY_F12,      KEY_VOLUMEUP,       APPLE_FLAG_FKEY },
+       { KEY_UP,       KEY_PAGEUP },
+       { KEY_DOWN,     KEY_PAGEDOWN },
+       { KEY_LEFT,     KEY_HOME },
+       { KEY_RIGHT,    KEY_END },
+       { }
+};
+
+static const struct apple_key_translation magic_keyboard_2015_fn_keys[] = {
+       { KEY_BACKSPACE, KEY_DELETE },
+       { KEY_ENTER,    KEY_INSERT },
+       { KEY_F1,       KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
+       { KEY_F2,       KEY_BRIGHTNESSUP,   APPLE_FLAG_FKEY },
+       { KEY_F3,       KEY_SCALE,          APPLE_FLAG_FKEY },
+       { KEY_F4,       KEY_DASHBOARD,      APPLE_FLAG_FKEY },
+       { KEY_F7,       KEY_PREVIOUSSONG,   APPLE_FLAG_FKEY },
+       { KEY_F8,       KEY_PLAYPAUSE,      APPLE_FLAG_FKEY },
+       { KEY_F9,       KEY_NEXTSONG,       APPLE_FLAG_FKEY },
+       { KEY_F10,      KEY_MUTE,           APPLE_FLAG_FKEY },
+       { KEY_F11,      KEY_VOLUMEDOWN,     APPLE_FLAG_FKEY },
+       { KEY_F12,      KEY_VOLUMEUP,       APPLE_FLAG_FKEY },
+       { KEY_UP,       KEY_PAGEUP },
+       { KEY_DOWN,     KEY_PAGEDOWN },
+       { KEY_LEFT,     KEY_HOME },
+       { KEY_RIGHT,    KEY_END },
+       { }
+};
+
+struct apple_backlight_config_report {
+       u8 report_id;
+       u8 version;
+       u16 backlight_off, backlight_on_min, backlight_on_max;
+};
+
+struct apple_backlight_set_report {
+       u8 report_id;
+       u8 version;
+       u16 backlight;
+       u16 rate;
+};
+
+
 static const struct apple_key_translation apple2021_fn_keys[] = {
        { KEY_BACKSPACE, KEY_DELETE },
        { KEY_ENTER,    KEY_INSERT },
@@ -119,6 +183,51 @@ static const struct apple_key_translation macbookair_fn_keys[] = {
        { }
 };
 
+static const struct apple_key_translation macbookpro_no_esc_fn_keys[] = {
+       { KEY_BACKSPACE, KEY_DELETE },
+       { KEY_ENTER,    KEY_INSERT },
+       { KEY_GRAVE,    KEY_ESC },
+       { KEY_1,        KEY_F1 },
+       { KEY_2,        KEY_F2 },
+       { KEY_3,        KEY_F3 },
+       { KEY_4,        KEY_F4 },
+       { KEY_5,        KEY_F5 },
+       { KEY_6,        KEY_F6 },
+       { KEY_7,        KEY_F7 },
+       { KEY_8,        KEY_F8 },
+       { KEY_9,        KEY_F9 },
+       { KEY_0,        KEY_F10 },
+       { KEY_MINUS,    KEY_F11 },
+       { KEY_EQUAL,    KEY_F12 },
+       { KEY_UP,       KEY_PAGEUP },
+       { KEY_DOWN,     KEY_PAGEDOWN },
+       { KEY_LEFT,     KEY_HOME },
+       { KEY_RIGHT,    KEY_END },
+       { }
+};
+
+static const struct apple_key_translation macbookpro_dedicated_esc_fn_keys[] = {
+       { KEY_BACKSPACE, KEY_DELETE },
+       { KEY_ENTER,    KEY_INSERT },
+       { KEY_1,        KEY_F1 },
+       { KEY_2,        KEY_F2 },
+       { KEY_3,        KEY_F3 },
+       { KEY_4,        KEY_F4 },
+       { KEY_5,        KEY_F5 },
+       { KEY_6,        KEY_F6 },
+       { KEY_7,        KEY_F7 },
+       { KEY_8,        KEY_F8 },
+       { KEY_9,        KEY_F9 },
+       { KEY_0,        KEY_F10 },
+       { KEY_MINUS,    KEY_F11 },
+       { KEY_EQUAL,    KEY_F12 },
+       { KEY_UP,       KEY_PAGEUP },
+       { KEY_DOWN,     KEY_PAGEDOWN },
+       { KEY_LEFT,     KEY_HOME },
+       { KEY_RIGHT,    KEY_END },
+       { }
+};
+
 static const struct apple_key_translation apple_fn_keys[] = {
        { KEY_BACKSPACE, KEY_DELETE },
        { KEY_ENTER,    KEY_INSERT },
@@ -202,6 +311,15 @@ static const struct apple_key_translation swapped_fn_leftctrl_keys[] = {
        { }
 };
 
+static inline void apple_setup_key_translation(struct input_dev *input,
+               const struct apple_key_translation *table)
+{
+       const struct apple_key_translation *trans;
+
+       for (trans = table; trans->from; trans++)
+               set_bit(trans->to, input->keybit);
+}
+
 static const struct apple_key_translation *apple_find_translation(
                const struct apple_key_translation *table, u16 from)
 {
@@ -242,10 +360,34 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
        }
 
        if (fnmode) {
-               if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 ||
-                   hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 ||
-                   hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021)
+               if (hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI ||
+                   hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO ||
+                   hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS ||
+                   hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI ||
+                   hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO ||
+                   hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS ||
+                   hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI ||
+                   hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO ||
+                   hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS)
+                       table = magic_keyboard_alu_fn_keys;
+               else if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015 ||
+                        hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015)
+                       table = magic_keyboard_2015_fn_keys;
+               else if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 ||
+                        hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 ||
+                        hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021)
                        table = apple2021_fn_keys;
+               else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 ||
+                        hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680 ||
+                        hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213)
+                               table = macbookpro_no_esc_fn_keys;
+               else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K ||
+                        hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 ||
+                        hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F)
+                               table = macbookpro_dedicated_esc_fn_keys;
+               else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K ||
+                        hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K)
+                               table = apple_fn_keys;
                else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
                                hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
                        table = macbookair_fn_keys;
@@ -452,30 +594,21 @@ static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 
 static void apple_setup_input(struct input_dev *input)
 {
-       const struct apple_key_translation *trans;
-
        set_bit(KEY_NUMLOCK, input->keybit);
 
        /* Enable all needed keys */
-       for (trans = apple_fn_keys; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-       for (trans = powerbook_fn_keys; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-       for (trans = powerbook_numlock_keys; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-       for (trans = apple_iso_keyboard; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-       for (trans = apple2021_fn_keys; trans->from; trans++)
-               set_bit(trans->to, input->keybit);
-
-       if (swap_fn_leftctrl) {
-               for (trans = swapped_fn_leftctrl_keys; trans->from; trans++)
-                       set_bit(trans->to, input->keybit);
-       }
+       apple_setup_key_translation(input, apple_fn_keys);
+       apple_setup_key_translation(input, powerbook_fn_keys);
+       apple_setup_key_translation(input, powerbook_numlock_keys);
+       apple_setup_key_translation(input, apple_iso_keyboard);
+       apple_setup_key_translation(input, magic_keyboard_alu_fn_keys);
+       apple_setup_key_translation(input, magic_keyboard_2015_fn_keys);
+       apple_setup_key_translation(input, apple2021_fn_keys);
+       apple_setup_key_translation(input, macbookpro_no_esc_fn_keys);
+       apple_setup_key_translation(input, macbookpro_dedicated_esc_fn_keys);
+
+       if (swap_fn_leftctrl)
+               apple_setup_key_translation(input, swapped_fn_leftctrl_keys);
 }
 
 static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
@@ -530,6 +663,105 @@ static int apple_input_configured(struct hid_device *hdev,
        return 0;
 }
 
+static bool apple_backlight_check_support(struct hid_device *hdev)
+{
+       int i;
+       unsigned int hid;
+       struct hid_report *report;
+
+       list_for_each_entry(report, &hdev->report_enum[HID_INPUT_REPORT].report_list, list) {
+               for (i = 0; i < report->maxfield; i++) {
+                       hid = report->field[i]->usage->hid;
+                       if ((hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR && (hid & HID_USAGE) == 0xf)
+                               return true;
+               }
+       }
+
+       return false;
+}
+
+static int apple_backlight_set(struct hid_device *hdev, u16 value, u16 rate)
+{
+       int ret = 0;
+       struct apple_backlight_set_report *rep;
+
+       rep = kmalloc(sizeof(*rep), GFP_KERNEL);
+       if (rep == NULL)
+               return -ENOMEM;
+
+       rep->report_id = 0xB0;
+       rep->version = 1;
+       rep->backlight = value;
+       rep->rate = rate;
+
+       ret = hid_hw_raw_request(hdev, 0xB0u, (u8 *) rep, sizeof(*rep),
+                                HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
+
+       kfree(rep);
+       return ret;
+}
+
+static int apple_backlight_led_set(struct led_classdev *led_cdev,
+       enum led_brightness brightness)
+{
+       struct apple_sc_backlight *backlight = container_of(led_cdev,
+                                                           struct apple_sc_backlight, cdev);
+
+       return apple_backlight_set(backlight->hdev, brightness, 0);
+}
+
+static int apple_backlight_init(struct hid_device *hdev)
+{
+       int ret;
+       struct apple_sc *asc = hid_get_drvdata(hdev);
+       struct apple_backlight_config_report *rep;
+
+       if (!apple_backlight_check_support(hdev))
+               return -EINVAL;
+
+       rep = kmalloc(0x200, GFP_KERNEL);
+       if (rep == NULL)
+               return -ENOMEM;
+
+       ret = hid_hw_raw_request(hdev, 0xBFu, (u8 *) rep, sizeof(*rep),
+                                HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
+       if (ret < 0) {
+               hid_err(hdev, "backlight request failed: %d\n", ret);
+               goto cleanup_and_exit;
+       }
+       if (ret < 8 || rep->version != 1) {
+               hid_err(hdev, "backlight config struct: bad version %i\n", rep->version);
+               ret = -EINVAL;
+               goto cleanup_and_exit;
+       }
+
+       hid_dbg(hdev, "backlight config: off=%u, on_min=%u, on_max=%u\n",
+               rep->backlight_off, rep->backlight_on_min, rep->backlight_on_max);
+
+       asc->backlight = devm_kzalloc(&hdev->dev, sizeof(*asc->backlight), GFP_KERNEL);
+       if (!asc->backlight) {
+               ret = -ENOMEM;
+               goto cleanup_and_exit;
+       }
+
+       asc->backlight->hdev = hdev;
+       asc->backlight->cdev.name = "apple::kbd_backlight";
+       asc->backlight->cdev.max_brightness = rep->backlight_on_max;
+       asc->backlight->cdev.brightness_set_blocking = apple_backlight_led_set;
+
+       ret = apple_backlight_set(hdev, 0, 0);
+       if (ret < 0) {
+               hid_err(hdev, "backlight set request failed: %d\n", ret);
+               goto cleanup_and_exit;
+       }
+
+       ret = devm_led_classdev_register(&hdev->dev, &asc->backlight->cdev);
+
+cleanup_and_exit:
+       kfree(rep);
+       return ret;
+}
+
 static int apple_probe(struct hid_device *hdev,
                const struct hid_device_id *id)
 {
@@ -565,6 +797,9 @@ static int apple_probe(struct hid_device *hdev,
                  jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS));
        apple_fetch_battery(hdev);
 
+       if (quirks & APPLE_BACKLIGHT_CTL)
+               apple_backlight_init(hdev);
+
        return 0;
 }
 
@@ -736,6 +971,22 @@ static const struct hid_device_id apple_devices[] = {
                .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
                .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K),
+               .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132),
+               .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680),
+               .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213),
+               .driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K),
+               .driver_data = APPLE_HAS_FN },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F),
+               .driver_data = APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
@@ -748,15 +999,15 @@ static const struct hid_device_id apple_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY),
                .driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021),
-               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
        { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021),
                .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021),
-               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
        { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021),
                .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021),
-               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
+               .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
        { HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021),
                .driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
 
index f1aed5bbd00080429acab1d9ba31eba48794b969..db925794fbe6ef47447088e15fa36c21dea39dea 100644 (file)
@@ -81,6 +81,7 @@ struct hid_report *hid_register_report(struct hid_device *device,
        report_enum->report_id_hash[id] = report;
 
        list_add_tail(&report->list, &report_enum->report_list);
+       INIT_LIST_HEAD(&report->field_entry_list);
 
        return report;
 }
@@ -101,7 +102,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
 
        field = kzalloc((sizeof(struct hid_field) +
                         usages * sizeof(struct hid_usage) +
-                        usages * sizeof(unsigned)), GFP_KERNEL);
+                        3 * usages * sizeof(unsigned int)), GFP_KERNEL);
        if (!field)
                return NULL;
 
@@ -109,6 +110,8 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
        report->field[field->index] = field;
        field->usage = (struct hid_usage *)(field + 1);
        field->value = (s32 *)(field->usage + usages);
+       field->new_value = (s32 *)(field->value + usages);
+       field->usages_priorities = (s32 *)(field->new_value + usages);
        field->report = report;
 
        return field;
@@ -656,6 +659,8 @@ static void hid_free_report(struct hid_report *report)
 {
        unsigned n;
 
+       kfree(report->field_entries);
+
        for (n = 0; n < report->maxfield; n++)
                kfree(report->field[n]);
        kfree(report);
@@ -1525,25 +1530,41 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field,
 }
 
 /*
- * Analyse a received field, and fetch the data from it. The field
- * content is stored for next report processing (we do differential
- * reporting to the layer).
+ * Checks if the given value is valid within this field
  */
+static inline int hid_array_value_is_valid(struct hid_field *field,
+                                          __s32 value)
+{
+       __s32 min = field->logical_minimum;
 
-static void hid_input_field(struct hid_device *hid, struct hid_field *field,
-                           __u8 *data, int interrupt)
+       /*
+        * Value needs to be between logical min and max, and
+        * (value - min) is used as an index in the usage array.
+        * This array is of size field->maxusage
+        */
+       return value >= min &&
+              value <= field->logical_maximum &&
+              value - min < field->maxusage;
+}
+
+/*
+ * Fetch the field from the data. The field content is stored for next
+ * report processing (we do differential reporting to the layer).
+ */
+static void hid_input_fetch_field(struct hid_device *hid,
+                                 struct hid_field *field,
+                                 __u8 *data)
 {
        unsigned n;
        unsigned count = field->report_count;
        unsigned offset = field->report_offset;
        unsigned size = field->report_size;
        __s32 min = field->logical_minimum;
-       __s32 max = field->logical_maximum;
        __s32 *value;
 
-       value = kmalloc_array(count, sizeof(__s32), GFP_ATOMIC);
-       if (!value)
-               return;
+       value = field->new_value;
+       memset(value, 0, count * sizeof(__s32));
+       field->ignored = false;
 
        for (n = 0; n < count; n++) {
 
@@ -1554,35 +1575,228 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
 
                /* Ignore report if ErrorRollOver */
                if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
-                   value[n] >= min && value[n] <= max &&
-                   value[n] - min < field->maxusage &&
-                   field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
-                       goto exit;
+                   hid_array_value_is_valid(field, value[n]) &&
+                   field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) {
+                       field->ignored = true;
+                       return;
+               }
        }
+}
+
+/*
+ * Process a received variable field.
+ */
+
+static void hid_input_var_field(struct hid_device *hid,
+                               struct hid_field *field,
+                               int interrupt)
+{
+       unsigned int count = field->report_count;
+       __s32 *value = field->new_value;
+       unsigned int n;
+
+       for (n = 0; n < count; n++)
+               hid_process_event(hid,
+                                 field,
+                                 &field->usage[n],
+                                 value[n],
+                                 interrupt);
+
+       memcpy(field->value, value, count * sizeof(__s32));
+}
+
+/*
+ * Process a received array field. The field content is stored for
+ * next report processing (we do differential reporting to the layer).
+ */
+
+static void hid_input_array_field(struct hid_device *hid,
+                                 struct hid_field *field,
+                                 int interrupt)
+{
+       unsigned int n;
+       unsigned int count = field->report_count;
+       __s32 min = field->logical_minimum;
+       __s32 *value;
+
+       value = field->new_value;
+
+       /* ErrorRollOver */
+       if (field->ignored)
+               return;
 
        for (n = 0; n < count; n++) {
+               if (hid_array_value_is_valid(field, field->value[n]) &&
+                   search(value, field->value[n], count))
+                       hid_process_event(hid,
+                                         field,
+                                         &field->usage[field->value[n] - min],
+                                         0,
+                                         interrupt);
+
+               if (hid_array_value_is_valid(field, value[n]) &&
+                   search(field->value, value[n], count))
+                       hid_process_event(hid,
+                                         field,
+                                         &field->usage[value[n] - min],
+                                         1,
+                                         interrupt);
+       }
 
-               if (HID_MAIN_ITEM_VARIABLE & field->flags) {
-                       hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
-                       continue;
+       memcpy(field->value, value, count * sizeof(__s32));
+}
+
+/*
+ * Analyse a received report, and fetch the data from it. The field
+ * content is stored for next report processing (we do differential
+ * reporting to the layer).
+ */
+static void hid_process_report(struct hid_device *hid,
+                              struct hid_report *report,
+                              __u8 *data,
+                              int interrupt)
+{
+       unsigned int a;
+       struct hid_field_entry *entry;
+       struct hid_field *field;
+
+       /* first retrieve all incoming values in data */
+       for (a = 0; a < report->maxfield; a++)
+               hid_input_fetch_field(hid, field = report->field[a], data);
+
+       if (!list_empty(&report->field_entry_list)) {
+               /* INPUT_REPORT, we have a priority list of fields */
+               list_for_each_entry(entry,
+                                   &report->field_entry_list,
+                                   list) {
+                       field = entry->field;
+
+                       if (field->flags & HID_MAIN_ITEM_VARIABLE)
+                               hid_process_event(hid,
+                                                 field,
+                                                 &field->usage[entry->index],
+                                                 field->new_value[entry->index],
+                                                 interrupt);
+                       else
+                               hid_input_array_field(hid, field, interrupt);
                }
 
-               if (field->value[n] >= min && field->value[n] <= max
-                       && field->value[n] - min < field->maxusage
-                       && field->usage[field->value[n] - min].hid
-                       && search(value, field->value[n], count))
-                               hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
+               /* we need to do the memcpy at the end for var items */
+               for (a = 0; a < report->maxfield; a++) {
+                       field = report->field[a];
 
-               if (value[n] >= min && value[n] <= max
-                       && value[n] - min < field->maxusage
-                       && field->usage[value[n] - min].hid
-                       && search(field->value, value[n], count))
-                               hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
+                       if (field->flags & HID_MAIN_ITEM_VARIABLE)
+                               memcpy(field->value, field->new_value,
+                                      field->report_count * sizeof(__s32));
+               }
+       } else {
+               /* FEATURE_REPORT, regular processing */
+               for (a = 0; a < report->maxfield; a++) {
+                       field = report->field[a];
+
+                       if (field->flags & HID_MAIN_ITEM_VARIABLE)
+                               hid_input_var_field(hid, field, interrupt);
+                       else
+                               hid_input_array_field(hid, field, interrupt);
+               }
        }
+}
 
-       memcpy(field->value, value, count * sizeof(__s32));
-exit:
-       kfree(value);
+/*
+ * Insert a given usage_index in a field in the list
+ * of processed usages in the report.
+ *
+ * The elements of lower priority score are processed
+ * first.
+ */
+static void __hid_insert_field_entry(struct hid_device *hid,
+                                    struct hid_report *report,
+                                    struct hid_field_entry *entry,
+                                    struct hid_field *field,
+                                    unsigned int usage_index)
+{
+       struct hid_field_entry *next;
+
+       entry->field = field;
+       entry->index = usage_index;
+       entry->priority = field->usages_priorities[usage_index];
+
+       /* insert the element at the correct position */
+       list_for_each_entry(next,
+                           &report->field_entry_list,
+                           list) {
+               /*
+                * the priority of our element is strictly higher
+                * than the next one, insert it before
+                */
+               if (entry->priority > next->priority) {
+                       list_add_tail(&entry->list, &next->list);
+                       return;
+               }
+       }
+
+       /* lowest priority score: insert at the end */
+       list_add_tail(&entry->list, &report->field_entry_list);
+}
+
+static void hid_report_process_ordering(struct hid_device *hid,
+                                       struct hid_report *report)
+{
+       struct hid_field *field;
+       struct hid_field_entry *entries;
+       unsigned int a, u, usages;
+       unsigned int count = 0;
+
+       /* count the number of individual fields in the report */
+       for (a = 0; a < report->maxfield; a++) {
+               field = report->field[a];
+
+               if (field->flags & HID_MAIN_ITEM_VARIABLE)
+                       count += field->report_count;
+               else
+                       count++;
+       }
+
+       /* allocate the memory to process the fields */
+       entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
+       if (!entries)
+               return;
+
+       report->field_entries = entries;
+
+       /*
+        * walk through all fields in the report and
+        * store them by priority order in report->field_entry_list
+        *
+        * - Var elements are individualized (field + usage_index)
+        * - Arrays are taken as one, we can not chose an order for them
+        */
+       usages = 0;
+       for (a = 0; a < report->maxfield; a++) {
+               field = report->field[a];
+
+               if (field->flags & HID_MAIN_ITEM_VARIABLE) {
+                       for (u = 0; u < field->report_count; u++) {
+                               __hid_insert_field_entry(hid, report,
+                                                        &entries[usages],
+                                                        field, u);
+                               usages++;
+                       }
+               } else {
+                       __hid_insert_field_entry(hid, report, &entries[usages],
+                                                field, 0);
+                       usages++;
+               }
+       }
+}
+
+static void hid_process_ordering(struct hid_device *hid)
+{
+       struct hid_report *report;
+       struct hid_report_enum *report_enum = &hid->report_enum[HID_INPUT_REPORT];
+
+       list_for_each_entry(report, &report_enum->report_list, list)
+               hid_report_process_ordering(hid, report);
 }
 
 /*
@@ -1746,7 +1960,6 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
        struct hid_report_enum *report_enum = hid->report_enum + type;
        struct hid_report *report;
        struct hid_driver *hdrv;
-       unsigned int a;
        u32 rsize, csize = size;
        u8 *cdata = data;
        int ret = 0;
@@ -1782,8 +1995,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
        }
 
        if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
-               for (a = 0; a < report->maxfield; a++)
-                       hid_input_field(hid, report->field[a], cdata, interrupt);
+               hid_process_report(hid, report, cdata, interrupt);
                hdrv = hid->driver;
                if (hdrv && hdrv->report)
                        hdrv->report(hid, report);
@@ -1970,6 +2182,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
                return -ENODEV;
        }
 
+       hid_process_ordering(hdev);
+
        if ((hdev->claimed & HID_CLAIMED_INPUT) &&
                        (connect_mask & HID_CONNECT_FF) && hdev->ff_init)
                hdev->ff_init(hdev);
index 0403beb3104b9e47af2c7cb79acf734879e05b24..ddbe0de177e26961c4b3599e60b4ed0dd0b0ae6b 100644 (file)
@@ -58,7 +58,7 @@ static int cbas_ec_query_base(struct cros_ec_device *ec_dev, bool get_state,
        struct cros_ec_command *msg;
        int ret;
 
-       msg = kzalloc(sizeof(*msg) + max(sizeof(u32), sizeof(*params)),
+       msg = kzalloc(struct_size(msg, data, max(sizeof(u32), sizeof(*params))),
                      GFP_KERNEL);
        if (!msg)
                return -ENOMEM;
index 78bd3ddda442623e61651b6bea0987f05e79b680..053853a891c50b07b55baae421275d382c332cfc 100644 (file)
 #define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI   0x0272
 #define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO            0x0273
 #define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS            0x0274
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K 0x027a
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132  0x027b
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680  0x027c
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213  0x027d
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K 0x027e
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223  0x027f
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K 0x0280
+#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F 0x0340
 #define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY   0x030a
 #define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY    0x030b
 #define USB_DEVICE_ID_APPLE_IRCONTROL  0x8240
 
 #define USB_VENDOR_ID_HUION            0x256c
 #define USB_DEVICE_ID_HUION_TABLET     0x006e
-#define USB_DEVICE_ID_HUION_HS64       0x006d
+#define USB_DEVICE_ID_HUION_TABLET2    0x006d
 
 #define USB_VENDOR_ID_IBM                                      0x04b3
 #define USB_DEVICE_ID_IBM_SCROLLPOINT_III                      0x3100
 #define I2C_PRODUCT_ID_RAYDIUM_3118    0x3118
 
 #define USB_VENDOR_ID_RAZER            0x1532
+#define USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE   0x010D
+#define USB_DEVICE_ID_RAZER_BLACKWIDOW            0x010e
+#define USB_DEVICE_ID_RAZER_BLACKWIDOW_CLASSIC    0x011b
 #define USB_DEVICE_ID_RAZER_BLADE_14   0x011D
 
 #define USB_VENDOR_ID_REALTEK          0x0bda
 
 #define USB_VENDOR_ID_SIGMA_MICRO      0x1c4f
 #define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD     0x0002
+#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD2    0x0059
 
 #define USB_VENDOR_ID_SIGMATEL         0x066F
 #define USB_DEVICE_ID_SIGMATEL_STMP3780        0x3780
index 56ec27398a0061d28d0fc74bf9661bd6a3d988d8..c6b27aab90414946c8bac910c89bcb7b617d151e 100644 (file)
@@ -48,6 +48,51 @@ static const struct {
        __s32 y;
 }  hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
 
+struct usage_priority {
+       __u32 usage;                    /* the HID usage associated */
+       bool global;                    /* we assume all usages to be slotted,
+                                        * unless global
+                                        */
+       unsigned int slot_overwrite;    /* for globals: allows to set the usage
+                                        * before or after the slots
+                                        */
+};
+
+/*
+ * hid-input will convert this list into priorities:
+ * the first element will have the highest priority
+ * (the length of the following array) and the last
+ * element the lowest (1).
+ *
+ * hid-input will then shift the priority by 8 bits to leave some space
+ * in case drivers want to interleave other fields.
+ *
+ * To accommodate slotted devices, the slot priority is
+ * defined in the next 8 bits (defined by 0xff - slot).
+ *
+ * If drivers want to add fields before those, hid-input will
+ * leave out the first 8 bits of the priority value.
+ *
+ * This still leaves us 65535 individual priority values.
+ */
+static const struct usage_priority hidinput_usages_priorities[] = {
+       { /* Eraser (eraser touching) must always come before tipswitch */
+         .usage = HID_DG_ERASER,
+       },
+       { /* Invert must always come before In Range */
+         .usage = HID_DG_INVERT,
+       },
+       { /* Is the tip of the tool touching? */
+         .usage = HID_DG_TIPSWITCH,
+       },
+       { /* Tip Pressure might emulate tip switch */
+         .usage = HID_DG_TIPPRESSURE,
+       },
+       { /* In Range needs to come after the other tool states */
+         .usage = HID_DG_INRANGE,
+       },
+};
+
 #define map_abs(c)     hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c))
 #define map_rel(c)     hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c))
 #define map_key(c)     hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c))
@@ -586,11 +631,13 @@ static bool hidinput_field_in_collection(struct hid_device *device, struct hid_f
 }
 
 static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
-                                    struct hid_usage *usage)
+                                    struct hid_usage *usage, unsigned int usage_index)
 {
        struct input_dev *input = hidinput->input;
        struct hid_device *device = input_get_drvdata(input);
+       const struct usage_priority *usage_priority = NULL;
        int max = 0, code;
+       unsigned int i = 0;
        unsigned long *bit = NULL;
 
        field->hidinput = hidinput;
@@ -608,6 +655,28 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                goto ignore;
        }
 
+       /* assign a priority based on the static list declared here */
+       for (i = 0; i < ARRAY_SIZE(hidinput_usages_priorities); i++) {
+               if (usage->hid == hidinput_usages_priorities[i].usage) {
+                       usage_priority = &hidinput_usages_priorities[i];
+
+                       field->usages_priorities[usage_index] =
+                               (ARRAY_SIZE(hidinput_usages_priorities) - i) << 8;
+                       break;
+               }
+       }
+
+       /*
+        * For slotted devices, we need to also add the slot index
+        * in the priority.
+        */
+       if (usage_priority && usage_priority->global)
+               field->usages_priorities[usage_index] |=
+                       usage_priority->slot_overwrite;
+       else
+               field->usages_priorities[usage_index] |=
+                       (0xff - field->slot_idx) << 16;
+
        if (device->driver->input_mapping) {
                int ret = device->driver->input_mapping(device, hidinput, field,
                                usage, &bit, &max);
@@ -828,10 +897,31 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                        break;
 
                case 0x32: /* InRange */
-                       switch (field->physical & 0xff) {
-                       case 0x21: map_key(BTN_TOOL_MOUSE); break;
-                       case 0x22: map_key(BTN_TOOL_FINGER); break;
-                       default: map_key(BTN_TOOL_PEN); break;
+                       switch (field->physical) {
+                       case HID_DG_PUCK:
+                               map_key(BTN_TOOL_MOUSE);
+                               break;
+                       case HID_DG_FINGER:
+                               map_key(BTN_TOOL_FINGER);
+                               break;
+                       default:
+                               /*
+                                * If the physical is not given,
+                                * rely on the application.
+                                */
+                               if (!field->physical) {
+                                       switch (field->application) {
+                                       case HID_DG_TOUCHSCREEN:
+                                       case HID_DG_TOUCHPAD:
+                                               map_key_clear(BTN_TOOL_FINGER);
+                                               break;
+                                       default:
+                                               map_key_clear(BTN_TOOL_PEN);
+                                       }
+                               } else {
+                                       map_key(BTN_TOOL_PEN);
+                               }
+                               break;
                        }
                        break;
 
@@ -1318,9 +1408,38 @@ static void hidinput_handle_scroll(struct hid_usage *usage,
        input_event(input, EV_REL, usage->code, hi_res);
 }
 
+static void hid_report_release_tool(struct hid_report *report, struct input_dev *input,
+                                   unsigned int tool)
+{
+       /* if the given tool is not currently reported, ignore */
+       if (!test_bit(tool, input->key))
+               return;
+
+       /*
+        * if the given tool was previously set, release it,
+        * release any TOUCH and send an EV_SYN
+        */
+       input_event(input, EV_KEY, BTN_TOUCH, 0);
+       input_event(input, EV_KEY, tool, 0);
+       input_event(input, EV_SYN, SYN_REPORT, 0);
+
+       report->tool = 0;
+}
+
+static void hid_report_set_tool(struct hid_report *report, struct input_dev *input,
+                               unsigned int new_tool)
+{
+       if (report->tool != new_tool)
+               hid_report_release_tool(report, input, report->tool);
+
+       input_event(input, EV_KEY, new_tool, 1);
+       report->tool = new_tool;
+}
+
 void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
 {
        struct input_dev *input;
+       struct hid_report *report = field->report;
        unsigned *quirks = &hid->quirks;
 
        if (!usage->type)
@@ -1336,12 +1455,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
 
        input = field->hidinput->input;
 
-       if (usage->type == EV_ABS &&
-           (((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) ||
-            ((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))) {
-               value = field->logical_maximum - value;
-       }
-
        if (usage->hat_min < usage->hat_max || usage->hat_dir) {
                int hat_dir = usage->hat_dir;
                if (!hat_dir)
@@ -1352,61 +1465,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                return;
        }
 
-       if (usage->hid == HID_DG_INVERT) {
-               *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
-               return;
-       }
-
-       if (usage->hid == HID_DG_INRANGE) {
-               if (value) {
-                       input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
-                       return;
-               }
-               input_event(input, usage->type, usage->code, 0);
-               input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
-               return;
-       }
-
-       if (usage->hid == HID_DG_TIPPRESSURE && (*quirks & HID_QUIRK_NOTOUCH)) {
-               int a = field->logical_minimum;
-               int b = field->logical_maximum;
-               input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
-       }
-
-       if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
-               dbg_hid("Maximum Effects - %d\n",value);
-               return;
-       }
-
-       if (usage->hid == (HID_UP_PID | 0x7fUL)) {
-               dbg_hid("PID Pool Report\n");
-               return;
-       }
-
-       if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
-               return;
-
-       if ((usage->type == EV_REL) && (usage->code == REL_WHEEL_HI_RES ||
-                                       usage->code == REL_HWHEEL_HI_RES)) {
-               hidinput_handle_scroll(usage, input, value);
-               return;
-       }
-
-       if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
-                       (usage->code == ABS_VOLUME)) {
-               int count = abs(value);
-               int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
-               int i;
-
-               for (i = 0; i < count; i++) {
-                       input_event(input, EV_KEY, direction, 1);
-                       input_sync(input);
-                       input_event(input, EV_KEY, direction, 0);
-                       input_sync(input);
-               }
-               return;
-       }
-
        /*
         * Ignore out-of-range values as per HID specification,
         * section 5.10 and 6.2.25, when NULL state bit is present.
@@ -1419,7 +1477,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
         * don't specify logical min and max.
         */
        if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
-           (field->logical_minimum < field->logical_maximum)) {
+           field->logical_minimum < field->logical_maximum) {
                if (field->flags & HID_MAIN_ITEM_NULL_STATE &&
                    (value < field->logical_minimum ||
                     value > field->logical_maximum)) {
@@ -1431,6 +1489,123 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                              field->logical_maximum);
        }
 
+       switch (usage->hid) {
+       case HID_DG_ERASER:
+               report->tool_active |= !!value;
+
+               /*
+                * if eraser is set, we must enforce BTN_TOOL_RUBBER
+                * to accommodate for devices not following the spec.
+                */
+               if (value)
+                       hid_report_set_tool(report, input, BTN_TOOL_RUBBER);
+               else if (report->tool != BTN_TOOL_RUBBER)
+                       /* value is off, tool is not rubber, ignore */
+                       return;
+
+               /* let hid-input set BTN_TOUCH */
+               break;
+
+       case HID_DG_INVERT:
+               report->tool_active |= !!value;
+
+               /*
+                * If invert is set, we store BTN_TOOL_RUBBER.
+                */
+               if (value)
+                       hid_report_set_tool(report, input, BTN_TOOL_RUBBER);
+               else if (!report->tool_active)
+                       /* tool_active not set means Invert and Eraser are not set */
+                       hid_report_release_tool(report, input, BTN_TOOL_RUBBER);
+
+               /* no further processing */
+               return;
+
+       case HID_DG_INRANGE:
+               report->tool_active |= !!value;
+
+               if (report->tool_active) {
+                       /*
+                        * if tool is not set but is marked as active,
+                        * assume ours
+                        */
+                       if (!report->tool)
+                               hid_report_set_tool(report, input, usage->code);
+               } else {
+                       hid_report_release_tool(report, input, usage->code);
+               }
+
+               /* reset tool_active for the next event */
+               report->tool_active = false;
+
+               /* no further processing */
+               return;
+
+       case HID_DG_TIPSWITCH:
+               report->tool_active |= !!value;
+
+               /* if tool is set to RUBBER we should ignore the current value */
+               if (report->tool == BTN_TOOL_RUBBER)
+                       return;
+
+               break;
+
+       case HID_DG_TIPPRESSURE:
+               if (*quirks & HID_QUIRK_NOTOUCH) {
+                       int a = field->logical_minimum;
+                       int b = field->logical_maximum;
+
+                       if (value > a + ((b - a) >> 3)) {
+                               input_event(input, EV_KEY, BTN_TOUCH, 1);
+                               report->tool_active = true;
+                       }
+               }
+               break;
+
+       case HID_UP_PID | 0x83UL: /* Simultaneous Effects Max */
+               dbg_hid("Maximum Effects - %d\n",value);
+               return;
+
+       case HID_UP_PID | 0x7fUL:
+               dbg_hid("PID Pool Report\n");
+               return;
+       }
+
+       switch (usage->type) {
+       case EV_KEY:
+               if (usage->code == 0) /* Key 0 is "unassigned", not KEY_UNKNOWN */
+                       return;
+               break;
+
+       case EV_REL:
+               if (usage->code == REL_WHEEL_HI_RES ||
+                   usage->code == REL_HWHEEL_HI_RES) {
+                       hidinput_handle_scroll(usage, input, value);
+                       return;
+               }
+               break;
+
+       case EV_ABS:
+               if ((field->flags & HID_MAIN_ITEM_RELATIVE) &&
+                   usage->code == ABS_VOLUME) {
+                       int count = abs(value);
+                       int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
+                       int i;
+
+                       for (i = 0; i < count; i++) {
+                               input_event(input, EV_KEY, direction, 1);
+                               input_sync(input);
+                               input_event(input, EV_KEY, direction, 0);
+                               input_sync(input);
+                       }
+                       return;
+
+               } else if (((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) ||
+                          ((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))
+                       value = field->logical_maximum - value;
+               break;
+       }
+
        /*
         * Ignore reports for absolute data if the data didn't change. This is
         * not only an optimization but also fixes 'dead' key reports. Some
@@ -1933,12 +2108,63 @@ static struct hid_input *hidinput_match_application(struct hid_report *report)
 static inline void hidinput_configure_usages(struct hid_input *hidinput,
                                             struct hid_report *report)
 {
-       int i, j;
+       int i, j, k;
+       int first_field_index = 0;
+       int slot_collection_index = -1;
+       int prev_collection_index = -1;
+       unsigned int slot_idx = 0;
+       struct hid_field *field;
+
+       /*
+        * First tag all the fields that are part of a slot,
+        * a slot needs to have one Contact ID in the collection
+        */
+       for (i = 0; i < report->maxfield; i++) {
+               field = report->field[i];
+
+               /* ignore fields without usage */
+               if (field->maxusage < 1)
+                       continue;
+
+               /*
+                * janitoring when collection_index changes
+                */
+               if (prev_collection_index != field->usage->collection_index) {
+                       prev_collection_index = field->usage->collection_index;
+                       first_field_index = i;
+               }
+
+               /*
+                * if we already found a Contact ID in the collection,
+                * tag and continue to the next.
+                */
+               if (slot_collection_index == field->usage->collection_index) {
+                       field->slot_idx = slot_idx;
+                       continue;
+               }
+
+               /* check if the current field has Contact ID */
+               for (j = 0; j < field->maxusage; j++) {
+                       if (field->usage[j].hid == HID_DG_CONTACTID) {
+                               slot_collection_index = field->usage->collection_index;
+                               slot_idx++;
+
+                               /*
+                                * mark all previous fields and this one in the
+                                * current collection to be slotted.
+                                */
+                               for (k = first_field_index; k <= i; k++)
+                                       report->field[k]->slot_idx = slot_idx;
+                               break;
+                       }
+               }
+       }
 
        for (i = 0; i < report->maxfield; i++)
                for (j = 0; j < report->field[i]->maxusage; j++)
                        hidinput_configure_usage(hidinput, report->field[i],
-                                                report->field[i]->usage + j);
+                                                report->field[i]->usage + j,
+                                                j);
 }
 
 /*
index c066ba901867bd56ba9bfef66132c638c2b1043a..dc67717d2dabc4f37e98f061f39bdc935f36db4c 100644 (file)
@@ -295,6 +295,14 @@ static const struct hid_device_id hid_have_special_driver[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -930,6 +938,14 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
        { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
        { }
diff --git a/drivers/hid/hid-razer.c b/drivers/hid/hid-razer.c
new file mode 100644 (file)
index 0000000..740df14
--- /dev/null
@@ -0,0 +1,125 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ *  HID driver for gaming keys on Razer Blackwidow gaming keyboards
+ *  Macro Key Keycodes: M1 = 191, M2 = 192, M3 = 193, M4 = 194, M5 = 195
+ *
+ *  Copyright (c) 2021 Jelle van der Waa <jvanderwaa@redhat.com>
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/random.h>
+#include <linux/sched.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+
+#include "hid-ids.h"
+
+#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
+
+#define RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE     91
+
+static bool macro_key_remapping = 1;
+module_param(macro_key_remapping, bool, 0644);
+MODULE_PARM_DESC(macro_key_remapping, " on (Y) off (N)");
+
+
+static unsigned char blackwidow_init[RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE] = {
+       0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04,
+       0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x04, 0x00
+};
+
+static int razer_input_mapping(struct hid_device *hdev,
+               struct hid_input *hi, struct hid_field *field,
+               struct hid_usage *usage, unsigned long **bit, int *max)
+{
+
+       if (!macro_key_remapping)
+               return 0;
+
+       if ((usage->hid & HID_UP_KEYBOARD) != HID_UP_KEYBOARD)
+               return 0;
+
+       switch (usage->hid & ~HID_UP_KEYBOARD) {
+       case 0x68:
+               map_key_clear(KEY_MACRO1);
+               return 1;
+       case 0x69:
+               map_key_clear(KEY_MACRO2);
+               return 1;
+       case 0x6a:
+               map_key_clear(KEY_MACRO3);
+               return 1;
+       case 0x6b:
+               map_key_clear(KEY_MACRO4);
+               return 1;
+       case 0x6c:
+               map_key_clear(KEY_MACRO5);
+               return 1;
+       }
+
+       return 0;
+}
+
+static int razer_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       char *buf;
+       int ret = 0;
+
+       ret = hid_parse(hdev);
+       if (ret)
+               return ret;
+
+       /*
+        * Only send the enable macro keys command for the third device
+        * identified as mouse input.
+        */
+       if (hdev->type == HID_TYPE_USBMOUSE) {
+               buf = kmemdup(blackwidow_init, RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE, GFP_KERNEL);
+               if (buf == NULL)
+                       return -ENOMEM;
+
+               ret = hid_hw_raw_request(hdev, 0, buf, RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE,
+                               HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
+               if (ret != RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE)
+                       hid_err(hdev, "failed to enable macro keys: %d\n", ret);
+
+               kfree(buf);
+       }
+
+       return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+}
+
+static const struct hid_device_id razer_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,
+               USB_DEVICE_ID_RAZER_BLACKWIDOW) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,
+               USB_DEVICE_ID_RAZER_BLACKWIDOW_CLASSIC) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_RAZER,
+               USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, razer_devices);
+
+static struct hid_driver razer_driver = {
+       .name = "razer",
+       .id_table = razer_devices,
+       .input_mapping = razer_input_mapping,
+       .probe = razer_probe,
+};
+module_hid_driver(razer_driver);
+
+MODULE_AUTHOR("Jelle van der Waa <jvanderwaa@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-sigmamicro.c b/drivers/hid/hid-sigmamicro.c
new file mode 100644 (file)
index 0000000..2e7058a
--- /dev/null
@@ -0,0 +1,130 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * HID driver for SiGma Micro-based keyboards
+ *
+ * Copyright (c) 2016 Kinglong Mee
+ * Copyright (c) 2021 Desmond Lim
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+static const __u8 sm_0059_rdesc[] = {
+       0x05, 0x0c,              /* Usage Page (Consumer Devices)       0   */
+       0x09, 0x01,              /* Usage (Consumer Control)            2   */
+       0xa1, 0x01,              /* Collection (Application)            4   */
+       0x85, 0x01,              /*  Report ID (1)                      6   */
+       0x19, 0x00,              /*  Usage Minimum (0)                  8   */
+       0x2a, 0x3c, 0x02,        /*  Usage Maximum (572)                10  */
+       0x15, 0x00,              /*  Logical Minimum (0)                13  */
+       0x26, 0x3c, 0x02,        /*  Logical Maximum (572)              15  */
+       0x95, 0x01,              /*  Report Count (1)                   18  */
+       0x75, 0x10,              /*  Report Size (16)                   20  */
+       0x81, 0x00,              /*  Input (Data,Arr,Abs)               22  */
+       0xc0,                    /* End Collection                      24  */
+       0x05, 0x01,              /* Usage Page (Generic Desktop)        25  */
+       0x09, 0x80,              /* Usage (System Control)              27  */
+       0xa1, 0x01,              /* Collection (Application)            29  */
+       0x85, 0x02,              /*  Report ID (2)                      31  */
+       0x19, 0x81,              /*  Usage Minimum (129)                33  */
+       0x29, 0x83,              /*  Usage Maximum (131)                35  */
+       0x25, 0x01,              /*  Logical Maximum (1)                37  */
+       0x75, 0x01,              /*  Report Size (1)                    39  */
+       0x95, 0x03,              /*  Report Count (3)                   41  */
+       0x81, 0x02,              /*  Input (Data,Var,Abs)               43  */
+       0x95, 0x05,              /*  Report Count (5)                   45  */
+       0x81, 0x01,              /*  Input (Cnst,Arr,Abs)               47  */
+       0xc0,                    /* End Collection                      49  */
+       0x06, 0x00, 0xff,        /* Usage Page (Vendor Defined Page 1)  50  */
+       0x09, 0x01,              /* Usage (Vendor Usage 1)              53  */
+       0xa1, 0x01,              /* Collection (Application)            55  */
+       0x85, 0x03,              /*  Report ID (3)                      57  */
+       0x1a, 0xf1, 0x00,        /*  Usage Minimum (241)                59  */
+       0x2a, 0xf8, 0x00,        /*  Usage Maximum (248)                62  */
+       0x15, 0x00,              /*  Logical Minimum (0)                65  */
+       0x25, 0x01,              /*  Logical Maximum (1)                67  */
+       0x75, 0x01,              /*  Report Size (1)                    69  */
+       0x95, 0x08,              /*  Report Count (8)                   71  */
+       0x81, 0x02,              /*  Input (Data,Var,Abs)               73  */
+       0xc0,                    /* End Collection                      75  */
+       0x05, 0x01,              /* Usage Page (Generic Desktop)        76  */
+       0x09, 0x06,              /* Usage (Keyboard)                    78  */
+       0xa1, 0x01,              /* Collection (Application)            80  */
+       0x85, 0x04,              /*  Report ID (4)                      82  */
+       0x05, 0x07,              /*  Usage Page (Keyboard)              84  */
+       0x19, 0xe0,              /*  Usage Minimum (224)                86  */
+       0x29, 0xe7,              /*  Usage Maximum (231)                88  */
+       0x15, 0x00,              /*  Logical Minimum (0)                90  */
+       0x25, 0x01,              /*  Logical Maximum (1)                92  */
+       0x75, 0x01,              /*  Report Size (1)                    94  */
+       0x95, 0x08,              /*  Report Count (8)                   96  */
+       0x81, 0x00,              /*  Input (Data,Arr,Abs)               98  */
+       0x95, 0x30,              /*  Report Count (48)                  100 */
+       0x75, 0x01,              /*  Report Size (1)                    102 */
+       0x15, 0x00,              /*  Logical Minimum (0)                104 */
+       0x25, 0x01,              /*  Logical Maximum (1)                106 */
+       0x05, 0x07,              /*  Usage Page (Keyboard)              108 */
+       0x19, 0x00,              /*  Usage Minimum (0)                  110 */
+       0x29, 0x2f,              /*  Usage Maximum (47)                 112 */
+       0x81, 0x02,              /*  Input (Data,Var,Abs)               114 */
+       0xc0,                    /* End Collection                      116 */
+       0x05, 0x01,              /* Usage Page (Generic Desktop)        117 */
+       0x09, 0x06,              /* Usage (Keyboard)                    119 */
+       0xa1, 0x01,              /* Collection (Application)            121 */
+       0x85, 0x05,              /*  Report ID (5)                      123 */
+       0x95, 0x38,              /*  Report Count (56)                  125 */
+       0x75, 0x01,              /*  Report Size (1)                    127 */
+       0x15, 0x00,              /*  Logical Minimum (0)                129 */
+       0x25, 0x01,              /*  Logical Maximum (1)                131 */
+       0x05, 0x07,              /*  Usage Page (Keyboard)              133 */
+       0x19, 0x30,              /*  Usage Minimum (48)                 135 */
+       0x29, 0x67,              /*  Usage Maximum (103)                137 */
+       0x81, 0x02,              /*  Input (Data,Var,Abs)               139 */
+       0xc0,                    /* End Collection                      141 */
+       0x05, 0x01,              /* Usage Page (Generic Desktop)        142 */
+       0x09, 0x06,              /* Usage (Keyboard)                    144 */
+       0xa1, 0x01,              /* Collection (Application)            146 */
+       0x85, 0x06,              /*  Report ID (6)                      148 */
+       0x95, 0x38,              /*  Report Count (56)                  150 */
+       0x75, 0x01,              /*  Report Size (1)                    152 */
+       0x15, 0x00,              /*  Logical Minimum (0)                154 */
+       0x25, 0x01,              /*  Logical Maximum (1)                156 */
+       0x05, 0x07,              /*  Usage Page (Keyboard)              158 */
+       0x19, 0x68,              /*  Usage Minimum (104)                160 */
+       0x29, 0x9f,              /*  Usage Maximum (159)                162 */
+       0x81, 0x02,              /*  Input (Data,Var,Abs)               164 */
+       0xc0,                    /* End Collection                      166 */
+};
+
+static __u8 *sm_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+                            unsigned int *rsize)
+{
+       if (*rsize == sizeof(sm_0059_rdesc) &&
+           !memcmp(sm_0059_rdesc, rdesc, *rsize)) {
+               hid_info(hdev, "Fixing up SiGma Micro report descriptor\n");
+               rdesc[99] = 0x02;
+       }
+       return rdesc;
+}
+
+static const struct hid_device_id sm_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_SIGMA_MICRO,
+                        USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD2) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, sm_devices);
+
+static struct hid_driver sm_driver = {
+       .name = "sigmamicro",
+       .id_table = sm_devices,
+       .report_fixup = sm_report_fixup,
+};
+module_hid_driver(sm_driver);
+
+MODULE_AUTHOR("Kinglong Mee <kinglongmee@gmail.com>");
+MODULE_AUTHOR("Desmond Lim <peckishrine@gmail.com>");
+MODULE_DESCRIPTION("SiGma Micro HID driver");
+MODULE_LICENSE("GPL");
index d8ab0139e5cdae30d70191ae08d7a479849b04d2..05147f2d75645f745c47b35786205b4d4ef79e98 100644 (file)
@@ -81,24 +81,6 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
        return rdesc;
 }
 
-static int uclogic_input_mapping(struct hid_device *hdev,
-                                struct hid_input *hi,
-                                struct hid_field *field,
-                                struct hid_usage *usage,
-                                unsigned long **bit,
-                                int *max)
-{
-       struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
-       struct uclogic_params *params = &drvdata->params;
-
-       /* discard the unused pen interface */
-       if (params->pen_unused && (field->application == HID_DG_PEN))
-               return -1;
-
-       /* let hid-core decide what to do */
-       return 0;
-}
-
 static int uclogic_input_configured(struct hid_device *hdev,
                struct hid_input *hi)
 {
@@ -246,100 +228,171 @@ static int uclogic_resume(struct hid_device *hdev)
 }
 #endif
 
+/**
+ * uclogic_raw_event_pen - handle raw pen events (pen HID reports).
+ *
+ * @drvdata:   Driver data.
+ * @data:      Report data buffer, can be modified.
+ * @size:      Report data size, bytes.
+ *
+ * Returns:
+ *     Negative value on error (stops event delivery), zero for success.
+ */
+static int uclogic_raw_event_pen(struct uclogic_drvdata *drvdata,
+                                       u8 *data, int size)
+{
+       struct uclogic_params_pen *pen = &drvdata->params.pen;
+
+       WARN_ON(drvdata == NULL);
+       WARN_ON(data == NULL && size != 0);
+
+       /* If in-range reports are inverted */
+       if (pen->inrange ==
+               UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) {
+               /* Invert the in-range bit */
+               data[1] ^= 0x40;
+       }
+       /*
+        * If report contains fragmented high-resolution pen
+        * coordinates
+        */
+       if (size >= 10 && pen->fragmented_hires) {
+               u8 pressure_low_byte;
+               u8 pressure_high_byte;
+
+               /* Lift pressure bytes */
+               pressure_low_byte = data[6];
+               pressure_high_byte = data[7];
+               /*
+                * Move Y coord to make space for high-order X
+                * coord byte
+                */
+               data[6] = data[5];
+               data[5] = data[4];
+               /* Move high-order X coord byte */
+               data[4] = data[8];
+               /* Move high-order Y coord byte */
+               data[7] = data[9];
+               /* Place pressure bytes */
+               data[8] = pressure_low_byte;
+               data[9] = pressure_high_byte;
+       }
+       /* If we need to emulate in-range detection */
+       if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
+               /* Set in-range bit */
+               data[1] |= 0x40;
+               /* (Re-)start in-range timeout */
+               mod_timer(&drvdata->inrange_timer,
+                               jiffies + msecs_to_jiffies(100));
+       }
+       /* If we report tilt and Y direction is flipped */
+       if (size >= 12 && pen->tilt_y_flipped)
+               data[11] = -data[11];
+
+       return 0;
+}
+
+/**
+ * uclogic_raw_event_frame - handle raw frame events (frame HID reports).
+ *
+ * @drvdata:   Driver data.
+ * @frame:     The parameters of the frame controls to handle.
+ * @data:      Report data buffer, can be modified.
+ * @size:      Report data size, bytes.
+ *
+ * Returns:
+ *     Negative value on error (stops event delivery), zero for success.
+ */
+static int uclogic_raw_event_frame(
+               struct uclogic_drvdata *drvdata,
+               const struct uclogic_params_frame *frame,
+               u8 *data, int size)
+{
+       WARN_ON(drvdata == NULL);
+       WARN_ON(data == NULL && size != 0);
+
+       /* If need to, and can, set pad device ID for Wacom drivers */
+       if (frame->dev_id_byte > 0 && frame->dev_id_byte < size) {
+               data[frame->dev_id_byte] = 0xf;
+       }
+       /* If need to, and can, read rotary encoder state change */
+       if (frame->re_lsb > 0 && frame->re_lsb / 8 < size) {
+               unsigned int byte = frame->re_lsb / 8;
+               unsigned int bit = frame->re_lsb % 8;
+
+               u8 change;
+               u8 prev_state = drvdata->re_state;
+               /* Read Gray-coded state */
+               u8 state = (data[byte] >> bit) & 0x3;
+               /* Encode state change into 2-bit signed integer */
+               if ((prev_state == 1 && state == 0) ||
+                   (prev_state == 2 && state == 3)) {
+                       change = 1;
+               } else if ((prev_state == 2 && state == 0) ||
+                          (prev_state == 1 && state == 3)) {
+                       change = 3;
+               } else {
+                       change = 0;
+               }
+               /* Write change */
+               data[byte] = (data[byte] & ~((u8)3 << bit)) |
+                               (change << bit);
+               /* Remember state */
+               drvdata->re_state = state;
+       }
+
+       return 0;
+}
+
 static int uclogic_raw_event(struct hid_device *hdev,
                                struct hid_report *report,
                                u8 *data, int size)
 {
+       unsigned int report_id = report->id;
        struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
        struct uclogic_params *params = &drvdata->params;
+       struct uclogic_params_pen_subreport *subreport;
+       struct uclogic_params_pen_subreport *subreport_list_end;
+       size_t i;
 
-       /* Tweak pen reports, if necessary */
-       if (!params->pen_unused &&
-           (report->type == HID_INPUT_REPORT) &&
-           (report->id == params->pen.id) &&
-           (size >= 2)) {
-               /* If it's the "virtual" frame controls report */
-               if (params->frame.id != 0 &&
-                   data[1] & params->pen_frame_flag) {
-                       /* Change to virtual frame controls report ID */
-                       data[0] = params->frame.id;
-                       return 0;
-               }
-               /* If in-range reports are inverted */
-               if (params->pen.inrange ==
-                       UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) {
-                       /* Invert the in-range bit */
-                       data[1] ^= 0x40;
-               }
-               /*
-                * If report contains fragmented high-resolution pen
-                * coordinates
-                */
-               if (size >= 10 && params->pen.fragmented_hires) {
-                       u8 pressure_low_byte;
-                       u8 pressure_high_byte;
-
-                       /* Lift pressure bytes */
-                       pressure_low_byte = data[6];
-                       pressure_high_byte = data[7];
-                       /*
-                        * Move Y coord to make space for high-order X
-                        * coord byte
-                        */
-                       data[6] = data[5];
-                       data[5] = data[4];
-                       /* Move high-order X coord byte */
-                       data[4] = data[8];
-                       /* Move high-order Y coord byte */
-                       data[7] = data[9];
-                       /* Place pressure bytes */
-                       data[8] = pressure_low_byte;
-                       data[9] = pressure_high_byte;
-               }
-               /* If we need to emulate in-range detection */
-               if (params->pen.inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
-                       /* Set in-range bit */
-                       data[1] |= 0x40;
-                       /* (Re-)start in-range timeout */
-                       mod_timer(&drvdata->inrange_timer,
-                                       jiffies + msecs_to_jiffies(100));
-               }
-       }
+       /* Do not handle anything but input reports */
+       if (report->type != HID_INPUT_REPORT)
+               return 0;
 
-       /* Tweak frame control reports, if necessary */
-       if ((report->type == HID_INPUT_REPORT) &&
-           (report->id == params->frame.id)) {
-               /* If need to, and can, set pad device ID for Wacom drivers */
-               if (params->frame.dev_id_byte > 0 &&
-                   params->frame.dev_id_byte < size) {
-                       data[params->frame.dev_id_byte] = 0xf;
-               }
-               /* If need to, and can, read rotary encoder state change */
-               if (params->frame.re_lsb > 0 &&
-                   params->frame.re_lsb / 8 < size) {
-                       unsigned int byte = params->frame.re_lsb / 8;
-                       unsigned int bit = params->frame.re_lsb % 8;
-
-                       u8 change;
-                       u8 prev_state = drvdata->re_state;
-                       /* Read Gray-coded state */
-                       u8 state = (data[byte] >> bit) & 0x3;
-                       /* Encode state change into 2-bit signed integer */
-                       if ((prev_state == 1 && state == 0) ||
-                           (prev_state == 2 && state == 3)) {
-                               change = 1;
-                       } else if ((prev_state == 2 && state == 0) ||
-                                  (prev_state == 1 && state == 3)) {
-                               change = 3;
+       while (true) {
+               /* Tweak pen reports, if necessary */
+               if ((report_id == params->pen.id) && (size >= 2)) {
+                       subreport_list_end =
+                               params->pen.subreport_list +
+                               ARRAY_SIZE(params->pen.subreport_list);
+                       /* Try to match a subreport */
+                       for (subreport = params->pen.subreport_list;
+                            subreport < subreport_list_end; subreport++) {
+                               if (subreport->value != 0 &&
+                                   subreport->value == data[1]) {
+                                       break;
+                               }
+                       }
+                       /* If a subreport matched */
+                       if (subreport < subreport_list_end) {
+                               /* Change to subreport ID, and restart */
+                               report_id = data[0] = subreport->id;
+                               continue;
                        } else {
-                               change = 0;
+                               return uclogic_raw_event_pen(drvdata, data, size);
+                       }
+               }
+
+               /* Tweak frame control reports, if necessary */
+               for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
+                       if (report_id == params->frame_list[i].id) {
+                               return uclogic_raw_event_frame(
+                                       drvdata, &params->frame_list[i],
+                                       data, size);
                        }
-                       /* Write change */
-                       data[byte] = (data[byte] & ~((u8)3 << bit)) |
-                                       (change << bit);
-                       /* Remember state */
-                       drvdata->re_state = state;
                }
+
+               break;
        }
 
        return 0;
@@ -373,7 +426,7 @@ static const struct hid_device_id uclogic_devices[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
                                USB_DEVICE_ID_HUION_TABLET) },
        { HID_USB_DEVICE(USB_VENDOR_ID_HUION,
-                               USB_DEVICE_ID_HUION_HS64) },
+                               USB_DEVICE_ID_HUION_TABLET2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TRUST,
                                USB_DEVICE_ID_TRUST_PANORA_TABLET) },
        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
@@ -415,7 +468,6 @@ static struct hid_driver uclogic_driver = {
        .remove = uclogic_remove,
        .report_fixup = uclogic_report_fixup,
        .raw_event = uclogic_raw_event,
-       .input_mapping = uclogic_input_mapping,
        .input_configured = uclogic_input_configured,
 #ifdef CONFIG_PM
        .resume           = uclogic_resume,
index 3e70f969fb8495bb7196e8b6e2aa876378713158..5f50ceb875d6d5ef75d88ec427ed2032910d163a 100644 (file)
@@ -207,8 +207,8 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
         * Generate pen report descriptor
         */
        desc_ptr = uclogic_rdesc_template_apply(
-                               uclogic_rdesc_pen_v1_template_arr,
-                               uclogic_rdesc_pen_v1_template_size,
+                               uclogic_rdesc_v1_pen_template_arr,
+                               uclogic_rdesc_v1_pen_template_size,
                                desc_params, ARRAY_SIZE(desc_params));
        if (desc_ptr == NULL) {
                rc = -ENOMEM;
@@ -221,8 +221,8 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
        memset(pen, 0, sizeof(*pen));
        pen->desc_ptr = desc_ptr;
        desc_ptr = NULL;
-       pen->desc_size = uclogic_rdesc_pen_v1_template_size;
-       pen->id = UCLOGIC_RDESC_PEN_V1_ID;
+       pen->desc_size = uclogic_rdesc_v1_pen_template_size;
+       pen->id = UCLOGIC_RDESC_V1_PEN_ID;
        pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED;
        found = true;
 finish:
@@ -351,8 +351,8 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
         * Generate pen report descriptor
         */
        desc_ptr = uclogic_rdesc_template_apply(
-                               uclogic_rdesc_pen_v2_template_arr,
-                               uclogic_rdesc_pen_v2_template_size,
+                               uclogic_rdesc_v2_pen_template_arr,
+                               uclogic_rdesc_v2_pen_template_size,
                                desc_params, ARRAY_SIZE(desc_params));
        if (desc_ptr == NULL) {
                rc = -ENOMEM;
@@ -365,10 +365,11 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
        memset(pen, 0, sizeof(*pen));
        pen->desc_ptr = desc_ptr;
        desc_ptr = NULL;
-       pen->desc_size = uclogic_rdesc_pen_v2_template_size;
-       pen->id = UCLOGIC_RDESC_PEN_V2_ID;
+       pen->desc_size = uclogic_rdesc_v2_pen_template_size;
+       pen->id = UCLOGIC_RDESC_V2_PEN_ID;
        pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE;
        pen->fragmented_hires = true;
+       pen->tilt_y_flipped = true;
        found = true;
 finish:
        *pfound = found;
@@ -430,8 +431,8 @@ static int uclogic_params_frame_init_with_desc(
 }
 
 /**
- * uclogic_params_frame_init_v1_buttonpad() - initialize abstract buttonpad
- * on a v1 tablet interface.
+ * uclogic_params_frame_init_v1() - initialize v1 tablet interface frame
+ * controls.
  *
  * @frame:     Pointer to the frame parameters to initialize (to be cleaned
  *             up with uclogic_params_frame_cleanup()). Not modified in case
@@ -445,8 +446,7 @@ static int uclogic_params_frame_init_with_desc(
  * Returns:
  *     Zero, if successful. A negative errno code on error.
  */
-static int uclogic_params_frame_init_v1_buttonpad(
-                                       struct uclogic_params_frame *frame,
+static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame,
                                        bool *pfound,
                                        struct hid_device *hdev)
 {
@@ -487,9 +487,9 @@ static int uclogic_params_frame_init_v1_buttonpad(
                hid_dbg(hdev, "generic buttons enabled\n");
                rc = uclogic_params_frame_init_with_desc(
                                frame,
-                               uclogic_rdesc_buttonpad_v1_arr,
-                               uclogic_rdesc_buttonpad_v1_size,
-                               UCLOGIC_RDESC_BUTTONPAD_V1_ID);
+                               uclogic_rdesc_v1_frame_arr,
+                               uclogic_rdesc_v1_frame_size,
+                               UCLOGIC_RDESC_V1_FRAME_ID);
                if (rc != 0)
                        goto cleanup;
                found = true;
@@ -512,10 +512,12 @@ cleanup:
 void uclogic_params_cleanup(struct uclogic_params *params)
 {
        if (!params->invalid) {
+               size_t i;
                kfree(params->desc_ptr);
-               if (!params->pen_unused)
-                       uclogic_params_pen_cleanup(&params->pen);
-               uclogic_params_frame_cleanup(&params->frame);
+               uclogic_params_pen_cleanup(&params->pen);
+               for (i = 0; i < ARRAY_SIZE(params->frame_list); i++)
+                       uclogic_params_frame_cleanup(&params->frame_list[i]);
+
                memset(params, 0, sizeof(*params));
        }
 }
@@ -543,60 +545,53 @@ int uclogic_params_get_desc(const struct uclogic_params *params,
                                __u8 **pdesc,
                                unsigned int *psize)
 {
-       bool common_present;
-       bool pen_present;
-       bool frame_present;
-       unsigned int size;
+       int rc = -ENOMEM;
+       bool present = false;
+       unsigned int size = 0;
        __u8 *desc = NULL;
+       size_t i;
 
        /* Check arguments */
        if (params == NULL || pdesc == NULL || psize == NULL)
                return -EINVAL;
 
-       size = 0;
-
-       common_present = (params->desc_ptr != NULL);
-       pen_present = (!params->pen_unused && params->pen.desc_ptr != NULL);
-       frame_present = (params->frame.desc_ptr != NULL);
-
-       if (common_present)
-               size += params->desc_size;
-       if (pen_present)
-               size += params->pen.desc_size;
-       if (frame_present)
-               size += params->frame.desc_size;
-
-       if (common_present || pen_present || frame_present) {
-               __u8 *p;
-
-               desc = kmalloc(size, GFP_KERNEL);
-               if (desc == NULL)
-                       return -ENOMEM;
-               p = desc;
-
-               if (common_present) {
-                       memcpy(p, params->desc_ptr,
-                               params->desc_size);
-                       p += params->desc_size;
-               }
-               if (pen_present) {
-                       memcpy(p, params->pen.desc_ptr,
-                               params->pen.desc_size);
-                       p += params->pen.desc_size;
-               }
-               if (frame_present) {
-                       memcpy(p, params->frame.desc_ptr,
-                               params->frame.desc_size);
-                       p += params->frame.desc_size;
-               }
+       /* Concatenate descriptors */
+#define ADD_DESC(_desc_ptr, _desc_size) \
+       do {                                                        \
+               unsigned int new_size;                              \
+               __u8 *new_desc;                                     \
+               if ((_desc_ptr) == NULL) {                          \
+                       break;                                      \
+               }                                                   \
+               new_size = size + (_desc_size);                     \
+               new_desc = krealloc(desc, new_size, GFP_KERNEL);    \
+               if (new_desc == NULL) {                             \
+                       goto cleanup;                               \
+               }                                                   \
+               memcpy(new_desc + size, (_desc_ptr), (_desc_size)); \
+               desc = new_desc;                                    \
+               size = new_size;                                    \
+               present = true;                                     \
+       } while (0)
+
+       ADD_DESC(params->desc_ptr, params->desc_size);
+       ADD_DESC(params->pen.desc_ptr, params->pen.desc_size);
+       for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
+               ADD_DESC(params->frame_list[i].desc_ptr,
+                               params->frame_list[i].desc_size);
+       }
 
-               WARN_ON(p != desc + size);
+#undef ADD_DESC
 
+       if (present) {
+               *pdesc = desc;
                *psize = size;
+               desc = NULL;
        }
-
-       *pdesc = desc;
-       return 0;
+       rc = 0;
+cleanup:
+       kfree(desc);
+       return rc;
 }
 
 /**
@@ -679,21 +674,6 @@ cleanup:
        return rc;
 }
 
-/**
- * uclogic_params_init_with_pen_unused() - initialize tablet interface
- * parameters preserving original reports and generic HID processing, but
- * disabling pen usage.
- *
- * @params:            Parameters to initialize (to be cleaned with
- *                     uclogic_params_cleanup()). Not modified in case of
- *                     error. Cannot be NULL.
- */
-static void uclogic_params_init_with_pen_unused(struct uclogic_params *params)
-{
-       memset(params, 0, sizeof(*params));
-       params->pen_unused = true;
-}
-
 /**
  * uclogic_params_huion_init() - initialize a Huion tablet interface and discover
  * its parameters.
@@ -733,8 +713,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
 
        /* If it's not a pen interface */
        if (bInterfaceNumber != 0) {
-               /* TODO: Consider marking the interface invalid */
-               uclogic_params_init_with_pen_unused(&p);
+               uclogic_params_init_invalid(&p);
                goto output;
        }
 
@@ -766,20 +745,22 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
                        goto cleanup;
                } else if (found) {
                        hid_dbg(hdev, "pen v2 parameters found\n");
-                       /* Create v2 buttonpad parameters */
+                       /* Create v2 frame parameters */
                        rc = uclogic_params_frame_init_with_desc(
-                                       &p.frame,
-                                       uclogic_rdesc_buttonpad_v2_arr,
-                                       uclogic_rdesc_buttonpad_v2_size,
-                                       UCLOGIC_RDESC_BUTTONPAD_V2_ID);
+                                       &p.frame_list[0],
+                                       uclogic_rdesc_v2_frame_arr,
+                                       uclogic_rdesc_v2_frame_size,
+                                       UCLOGIC_RDESC_V2_FRAME_ID);
                        if (rc != 0) {
                                hid_err(hdev,
-                                       "failed creating v2 buttonpad parameters: %d\n",
+                                       "failed creating v2 frame parameters: %d\n",
                                        rc);
                                goto cleanup;
                        }
-                       /* Set bitmask marking frame reports in pen reports */
-                       p.pen_frame_flag = 0x20;
+                       /* Link frame button subreports from pen reports */
+                       p.pen.subreport_list[0].value = 0xe0;
+                       p.pen.subreport_list[0].id =
+                               UCLOGIC_RDESC_V2_FRAME_ID;
                        goto output;
                }
                hid_dbg(hdev, "pen v2 parameters not found\n");
@@ -793,19 +774,20 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
                goto cleanup;
        } else if (found) {
                hid_dbg(hdev, "pen v1 parameters found\n");
-               /* Try to probe v1 buttonpad */
-               rc = uclogic_params_frame_init_v1_buttonpad(
-                                               &p.frame,
-                                               &found, hdev);
+               /* Try to probe v1 frame */
+               rc = uclogic_params_frame_init_v1(&p.frame_list[0],
+                                                 &found, hdev);
                if (rc != 0) {
-                       hid_err(hdev, "v1 buttonpad probing failed: %d\n", rc);
+                       hid_err(hdev, "v1 frame probing failed: %d\n", rc);
                        goto cleanup;
                }
-               hid_dbg(hdev, "buttonpad v1 parameters%s found\n",
+               hid_dbg(hdev, "frame v1 parameters%s found\n",
                        (found ? "" : " not"));
                if (found) {
-                       /* Set bitmask marking frame reports */
-                       p.pen_frame_flag = 0x20;
+                       /* Link frame button subreports from pen reports */
+                       p.pen.subreport_list[0].value = 0xe0;
+                       p.pen.subreport_list[0].id =
+                               UCLOGIC_RDESC_V1_FRAME_ID;
                }
                goto output;
        }
@@ -992,7 +974,7 @@ int uclogic_params_init(struct uclogic_params *params,
        case VID_PID(USB_VENDOR_ID_HUION,
                     USB_DEVICE_ID_HUION_TABLET):
        case VID_PID(USB_VENDOR_ID_HUION,
-                    USB_DEVICE_ID_HUION_HS64):
+                    USB_DEVICE_ID_HUION_TABLET2):
        case VID_PID(USB_VENDOR_ID_UCLOGIC,
                     USB_DEVICE_ID_HUION_TABLET):
        case VID_PID(USB_VENDOR_ID_UCLOGIC,
@@ -1032,8 +1014,7 @@ int uclogic_params_init(struct uclogic_params *params,
                                uclogic_params_init_invalid(&p);
                        }
                } else {
-                       /* TODO: Consider marking the interface invalid */
-                       uclogic_params_init_with_pen_unused(&p);
+                       uclogic_params_init_invalid(&p);
                }
                break;
        case VID_PID(USB_VENDOR_ID_UGEE,
@@ -1048,15 +1029,14 @@ int uclogic_params_init(struct uclogic_params *params,
                        }
                        /* Initialize frame parameters */
                        rc = uclogic_params_frame_init_with_desc(
-                               &p.frame,
+                               &p.frame_list[0],
                                uclogic_rdesc_xppen_deco01_frame_arr,
                                uclogic_rdesc_xppen_deco01_frame_size,
                                0);
                        if (rc != 0)
                                goto cleanup;
                } else {
-                       /* TODO: Consider marking the interface invalid */
-                       uclogic_params_init_with_pen_unused(&p);
+                       uclogic_params_init_invalid(&p);
                }
                break;
        case VID_PID(USB_VENDOR_ID_TRUST,
@@ -1075,19 +1055,19 @@ int uclogic_params_init(struct uclogic_params *params,
                        goto cleanup;
                } else if (found) {
                        rc = uclogic_params_frame_init_with_desc(
-                               &p.frame,
+                               &p.frame_list[0],
                                uclogic_rdesc_ugee_g5_frame_arr,
                                uclogic_rdesc_ugee_g5_frame_size,
                                UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
                        if (rc != 0) {
                                hid_err(hdev,
-                                       "failed creating buttonpad parameters: %d\n",
+                                       "failed creating frame parameters: %d\n",
                                        rc);
                                goto cleanup;
                        }
-                       p.frame.re_lsb =
+                       p.frame_list[0].re_lsb =
                                UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB;
-                       p.frame.dev_id_byte =
+                       p.frame_list[0].dev_id_byte =
                                UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
                } else {
                        hid_warn(hdev, "pen parameters not found");
@@ -1109,13 +1089,13 @@ int uclogic_params_init(struct uclogic_params *params,
                        goto cleanup;
                } else if (found) {
                        rc = uclogic_params_frame_init_with_desc(
-                               &p.frame,
-                               uclogic_rdesc_ugee_ex07_buttonpad_arr,
-                               uclogic_rdesc_ugee_ex07_buttonpad_size,
+                               &p.frame_list[0],
+                               uclogic_rdesc_ugee_ex07_frame_arr,
+                               uclogic_rdesc_ugee_ex07_frame_size,
                                0);
                        if (rc != 0) {
                                hid_err(hdev,
-                                       "failed creating buttonpad parameters: %d\n",
+                                       "failed creating frame parameters: %d\n",
                                        rc);
                                goto cleanup;
                        }
index ba48b1c7a0e52fc7dc1bec925c35200c9491eea4..86f616dfbb53dddc576ff6e81972e069f2eb04b2 100644 (file)
@@ -33,6 +33,25 @@ enum uclogic_params_pen_inrange {
 extern const char *uclogic_params_pen_inrange_to_str(
                        enum uclogic_params_pen_inrange inrange);
 
+
+/*
+ * Pen report's subreport data.
+ */
+struct uclogic_params_pen_subreport {
+       /*
+        * The value of the second byte of the pen report indicating this
+        * subreport. If zero, the subreport should be considered invalid and
+        * not matched.
+        */
+       __u8 value;
+
+       /*
+        * The ID to be assigned to the report, if the second byte of the pen
+        * report is equal to "value". Only valid if "value" is not zero.
+        */
+       __u8 id;
+};
+
 /*
  * Tablet interface's pen input parameters.
  *
@@ -54,6 +73,8 @@ struct uclogic_params_pen {
        unsigned int desc_size;
        /* Report ID, if reports should be tweaked, zero if not */
        unsigned int id;
+       /* The list of subreports */
+       struct uclogic_params_pen_subreport subreport_list[1];
        /* Type of in-range reporting, only valid if "id" is not zero */
        enum uclogic_params_pen_inrange inrange;
        /*
@@ -62,6 +83,12 @@ struct uclogic_params_pen {
         * Only valid if "id" is not zero.
         */
        bool fragmented_hires;
+       /*
+        * True if the pen reports tilt in bytes at offset 10 (X) and 11 (Y),
+        * and the Y tilt direction is flipped.
+        * Only valid if "id" is not zero.
+        */
+       bool tilt_y_flipped;
 };
 
 /*
@@ -132,28 +159,16 @@ struct uclogic_params {
         * Only valid, if "desc_ptr" is not NULL.
         */
        unsigned int desc_size;
-       /*
-        * True, if pen usage in report descriptor is invalid, when present.
-        * Only valid, if "invalid" is false.
-        */
-       bool pen_unused;
        /*
         * Pen parameters and optional report descriptor part.
-        * Only valid if "pen_unused" is valid and false.
-        */
-       struct uclogic_params_pen pen;
-       /*
-        * Frame control parameters and optional report descriptor part.
         * Only valid, if "invalid" is false.
         */
-       struct uclogic_params_frame frame;
+       struct uclogic_params_pen pen;
        /*
-        * Bitmask matching frame controls "sub-report" flag in the second
-        * byte of the pen report, or zero if it's not expected.
-        * Only valid if both "pen" and "frame" are valid, and "frame.id" is
-        * not zero.
+        * The list of frame control parameters and optional report descriptor
+        * parts. Only valid, if "invalid" is false.
         */
-       __u8 pen_frame_flag;
+       struct uclogic_params_frame frame_list[1];
 };
 
 /* Initialize a tablet interface and discover its parameters */
@@ -162,39 +177,40 @@ extern int uclogic_params_init(struct uclogic_params *params,
 
 /* Tablet interface parameters *printf format string */
 #define UCLOGIC_PARAMS_FMT_STR \
-               ".invalid = %s\n"                   \
-               ".desc_ptr = %p\n"                  \
-               ".desc_size = %u\n"                 \
-               ".pen_unused = %s\n"                \
-               ".pen.desc_ptr = %p\n"              \
-               ".pen.desc_size = %u\n"             \
-               ".pen.id = %u\n"                    \
-               ".pen.inrange = %s\n"               \
-               ".pen.fragmented_hires = %s\n"      \
-               ".frame.desc_ptr = %p\n"            \
-               ".frame.desc_size = %u\n"           \
-               ".frame.id = %u\n"                  \
-               ".frame.re_lsb = %u\n"              \
-               ".frame.dev_id_byte = %u\n"         \
-               ".pen_frame_flag = 0x%02x\n"
+               ".invalid = %s\n"                               \
+               ".desc_ptr = %p\n"                              \
+               ".desc_size = %u\n"                             \
+               ".pen.desc_ptr = %p\n"                          \
+               ".pen.desc_size = %u\n"                         \
+               ".pen.id = %u\n"                                \
+               ".pen.subreport_list[0] = {0x%02hhx, %hhu}\n"   \
+               ".pen.inrange = %s\n"                           \
+               ".pen.fragmented_hires = %s\n"                  \
+               ".pen.tilt_y_flipped = %s\n"                    \
+               ".frame_list[0].desc_ptr = %p\n"                \
+               ".frame_list[0].desc_size = %u\n"               \
+               ".frame_list[0].id = %u\n"                      \
+               ".frame_list[0].re_lsb = %u\n"                  \
+               ".frame_list[0].dev_id_byte = %u\n"
 
 /* Tablet interface parameters *printf format arguments */
 #define UCLOGIC_PARAMS_FMT_ARGS(_params) \
                ((_params)->invalid ? "true" : "false"),                    \
                (_params)->desc_ptr,                                        \
                (_params)->desc_size,                                       \
-               ((_params)->pen_unused ? "true" : "false"),                 \
                (_params)->pen.desc_ptr,                                    \
                (_params)->pen.desc_size,                                   \
                (_params)->pen.id,                                          \
+               (_params)->pen.subreport_list[0].value,                     \
+               (_params)->pen.subreport_list[0].id,                        \
                uclogic_params_pen_inrange_to_str((_params)->pen.inrange),  \
                ((_params)->pen.fragmented_hires ? "true" : "false"),       \
-               (_params)->frame.desc_ptr,                                  \
-               (_params)->frame.desc_size,                                 \
-               (_params)->frame.id,                                        \
-               (_params)->frame.re_lsb,                                    \
-               (_params)->frame.dev_id_byte,                               \
-               (_params)->pen_frame_flag
+               ((_params)->pen.tilt_y_flipped ? "true" : "false"),         \
+               (_params)->frame_list[0].desc_ptr,                          \
+               (_params)->frame_list[0].desc_size,                         \
+               (_params)->frame_list[0].id,                                \
+               (_params)->frame_list[0].re_lsb,                            \
+               (_params)->frame_list[0].dev_id_byte
 
 /* Get a replacement report descriptor for a tablet's interface. */
 extern int uclogic_params_get_desc(const struct uclogic_params *params,
index 6dd6dcd09c8bc16c8c40d16866f8318f84fba2bc..04644d93bd117cb1f64acc1a0bc93089a8bd22f8 100644 (file)
@@ -532,7 +532,7 @@ const size_t uclogic_rdesc_twha60_fixed1_size =
                        sizeof(uclogic_rdesc_twha60_fixed1_arr);
 
 /* Fixed report descriptor template for (tweaked) v1 pen reports */
-const __u8 uclogic_rdesc_pen_v1_template_arr[] = {
+const __u8 uclogic_rdesc_v1_pen_template_arr[] = {
        0x05, 0x0D,             /*  Usage Page (Digitizer),                 */
        0x09, 0x02,             /*  Usage (Pen),                            */
        0xA1, 0x01,             /*  Collection (Application),               */
@@ -582,11 +582,11 @@ const __u8 uclogic_rdesc_pen_v1_template_arr[] = {
        0xC0                    /*  End Collection                          */
 };
 
-const size_t uclogic_rdesc_pen_v1_template_size =
-                       sizeof(uclogic_rdesc_pen_v1_template_arr);
+const size_t uclogic_rdesc_v1_pen_template_size =
+                       sizeof(uclogic_rdesc_v1_pen_template_arr);
 
 /* Fixed report descriptor template for (tweaked) v2 pen reports */
-const __u8 uclogic_rdesc_pen_v2_template_arr[] = {
+const __u8 uclogic_rdesc_v2_pen_template_arr[] = {
        0x05, 0x0D,             /*  Usage Page (Digitizer),                 */
        0x09, 0x02,             /*  Usage (Pen),                            */
        0xA1, 0x01,             /*  Collection (Application),               */
@@ -633,25 +633,35 @@ const __u8 uclogic_rdesc_pen_v2_template_arr[] = {
        0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM),
                                /*          Logical Maximum (PLACEHOLDER),  */
        0x81, 0x02,             /*          Input (Variable),               */
-       0x81, 0x03,             /*          Input (Constant, Variable),     */
+       0x54,                   /*          Unit Exponent (0),              */
+       0x65, 0x14,             /*          Unit (Degrees),                 */
+       0x35, 0xC4,             /*          Physical Minimum (-60),         */
+       0x45, 0x3C,             /*          Physical Maximum (60),          */
+       0x15, 0xC4,             /*          Logical Minimum (-60),          */
+       0x25, 0x3C,             /*          Logical Maximum (60),           */
+       0x75, 0x08,             /*          Report Size (8),                */
+       0x95, 0x02,             /*          Report Count (2),               */
+       0x09, 0x3D,             /*          Usage (X Tilt),                 */
+       0x09, 0x3E,             /*          Usage (Y Tilt),                 */
+       0x81, 0x02,             /*          Input (Variable),               */
        0xC0,                   /*      End Collection,                     */
        0xC0                    /*  End Collection                          */
 };
 
-const size_t uclogic_rdesc_pen_v2_template_size =
-                       sizeof(uclogic_rdesc_pen_v2_template_arr);
+const size_t uclogic_rdesc_v2_pen_template_size =
+                       sizeof(uclogic_rdesc_v2_pen_template_arr);
 
 /*
- * Expand to the contents of a generic buttonpad report descriptor.
+ * Expand to the contents of a generic frame report descriptor.
  *
- * @_padding:  Padding from the end of button bits at bit 44, until
- *             the end of the report, in bits.
+ * @_id:       The report ID to use.
+ * @_size:     Size of the report to pad to, including report ID, bytes.
  */
-#define UCLOGIC_RDESC_BUTTONPAD_BYTES(_padding) \
+#define UCLOGIC_RDESC_FRAME_BYTES(_id, _size) \
        0x05, 0x01,     /*  Usage Page (Desktop),               */ \
        0x09, 0x07,     /*  Usage (Keypad),                     */ \
        0xA1, 0x01,     /*  Collection (Application),           */ \
-       0x85, 0xF7,     /*      Report ID (247),                */ \
+       0x85, (_id),    /*      Report ID (_id),                */ \
        0x14,           /*      Logical Minimum (0),            */ \
        0x25, 0x01,     /*      Logical Maximum (1),            */ \
        0x75, 0x01,     /*      Report Size (1),                */ \
@@ -679,30 +689,31 @@ const size_t uclogic_rdesc_pen_v2_template_size =
        0xA0,           /*      Collection (Physical),          */ \
        0x05, 0x09,     /*          Usage Page (Button),        */ \
        0x19, 0x01,     /*          Usage Minimum (01h),        */ \
-       0x29, 0x02,     /*          Usage Maximum (02h),        */ \
-       0x95, 0x02,     /*          Report Count (2),           */ \
+       0x29, 0x03,     /*          Usage Maximum (03h),        */ \
+       0x95, 0x03,     /*          Report Count (3),           */ \
        0x81, 0x02,     /*          Input (Variable),           */ \
-       0x95, _padding, /*          Report Count (_padding),    */ \
+       0x95, ((_size) * 8 - 45),                                  \
+                       /*          Report Count (padding),     */ \
        0x81, 0x01,     /*          Input (Constant),           */ \
        0xC0,           /*      End Collection,                 */ \
        0xC0            /*  End Collection                      */
 
-/* Fixed report descriptor for (tweaked) v1 buttonpad reports */
-const __u8 uclogic_rdesc_buttonpad_v1_arr[] = {
-       UCLOGIC_RDESC_BUTTONPAD_BYTES(20)
+/* Fixed report descriptor for (tweaked) v1 frame reports */
+const __u8 uclogic_rdesc_v1_frame_arr[] = {
+       UCLOGIC_RDESC_FRAME_BYTES(UCLOGIC_RDESC_V1_FRAME_ID, 8)
 };
-const size_t uclogic_rdesc_buttonpad_v1_size =
-                       sizeof(uclogic_rdesc_buttonpad_v1_arr);
+const size_t uclogic_rdesc_v1_frame_size =
+                       sizeof(uclogic_rdesc_v1_frame_arr);
 
-/* Fixed report descriptor for (tweaked) v2 buttonpad reports */
-const __u8 uclogic_rdesc_buttonpad_v2_arr[] = {
-       UCLOGIC_RDESC_BUTTONPAD_BYTES(52)
+/* Fixed report descriptor for (tweaked) v2 frame reports */
+const __u8 uclogic_rdesc_v2_frame_arr[] = {
+       UCLOGIC_RDESC_FRAME_BYTES(UCLOGIC_RDESC_V2_FRAME_ID, 12)
 };
-const size_t uclogic_rdesc_buttonpad_v2_size =
-                       sizeof(uclogic_rdesc_buttonpad_v2_arr);
+const size_t uclogic_rdesc_v2_frame_size =
+                       sizeof(uclogic_rdesc_v2_frame_arr);
 
-/* Fixed report descriptor for Ugee EX07 buttonpad */
-const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[] = {
+/* Fixed report descriptor for Ugee EX07 frame */
+const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = {
        0x05, 0x01,             /*  Usage Page (Desktop),                   */
        0x09, 0x07,             /*  Usage (Keypad),                         */
        0xA1, 0x01,             /*  Collection (Application),               */
@@ -725,8 +736,8 @@ const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[] = {
        0xC0,                   /*      End Collection,                     */
        0xC0                    /*  End Collection                          */
 };
-const size_t uclogic_rdesc_ugee_ex07_buttonpad_size =
-                       sizeof(uclogic_rdesc_ugee_ex07_buttonpad_arr);
+const size_t uclogic_rdesc_ugee_ex07_frame_size =
+                       sizeof(uclogic_rdesc_ugee_ex07_frame_arr);
 
 /* Fixed report descriptor for Ugee G5 frame controls */
 const __u8 uclogic_rdesc_ugee_g5_frame_arr[] = {
index c5da51055af3b649420087f4bc3126b84c11429c..3d904c27b86a4a6a025ab20b0292757e4c4e793d 100644 (file)
@@ -104,36 +104,36 @@ enum uclogic_rdesc_pen_ph_id {
        UCLOGIC_RDESC_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID
 
 /* Report ID for v1 pen reports */
-#define UCLOGIC_RDESC_PEN_V1_ID        0x07
+#define UCLOGIC_RDESC_V1_PEN_ID        0x07
 
 /* Fixed report descriptor template for (tweaked) v1 pen reports */
-extern const __u8 uclogic_rdesc_pen_v1_template_arr[];
-extern const size_t uclogic_rdesc_pen_v1_template_size;
+extern const __u8 uclogic_rdesc_v1_pen_template_arr[];
+extern const size_t uclogic_rdesc_v1_pen_template_size;
 
 /* Report ID for v2 pen reports */
-#define UCLOGIC_RDESC_PEN_V2_ID        0x08
+#define UCLOGIC_RDESC_V2_PEN_ID        0x08
 
 /* Fixed report descriptor template for (tweaked) v2 pen reports */
-extern const __u8 uclogic_rdesc_pen_v2_template_arr[];
-extern const size_t uclogic_rdesc_pen_v2_template_size;
+extern const __u8 uclogic_rdesc_v2_pen_template_arr[];
+extern const size_t uclogic_rdesc_v2_pen_template_size;
 
-/* Fixed report descriptor for (tweaked) v1 buttonpad reports */
-extern const __u8 uclogic_rdesc_buttonpad_v1_arr[];
-extern const size_t uclogic_rdesc_buttonpad_v1_size;
+/* Report ID for tweaked v1 frame reports */
+#define UCLOGIC_RDESC_V1_FRAME_ID 0xf7
 
-/* Report ID for tweaked v1 buttonpad reports */
-#define UCLOGIC_RDESC_BUTTONPAD_V1_ID 0xf7
+/* Fixed report descriptor for (tweaked) v1 frame reports */
+extern const __u8 uclogic_rdesc_v1_frame_arr[];
+extern const size_t uclogic_rdesc_v1_frame_size;
 
-/* Fixed report descriptor for (tweaked) v2 buttonpad reports */
-extern const __u8 uclogic_rdesc_buttonpad_v2_arr[];
-extern const size_t uclogic_rdesc_buttonpad_v2_size;
+/* Report ID for tweaked v2 frame reports */
+#define UCLOGIC_RDESC_V2_FRAME_ID 0xf7
 
-/* Report ID for tweaked v2 buttonpad reports */
-#define UCLOGIC_RDESC_BUTTONPAD_V2_ID 0xf7
+/* Fixed report descriptor for (tweaked) v2 frame reports */
+extern const __u8 uclogic_rdesc_v2_frame_arr[];
+extern const size_t uclogic_rdesc_v2_frame_size;
 
-/* Fixed report descriptor for Ugee EX07 buttonpad */
-extern const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[];
-extern const size_t uclogic_rdesc_ugee_ex07_buttonpad_size;
+/* Fixed report descriptor for Ugee EX07 frame */
+extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[];
+extern const size_t uclogic_rdesc_ugee_ex07_frame_size;
 
 /* Fixed report descriptor for XP-Pen Deco 01 frame controls */
 extern const __u8 uclogic_rdesc_xppen_deco01_frame_arr[];
index 6726567d729761397b5bb12a85905fca98fd1e80..c078f09a2318a04f528889bec961ef0a94739b20 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/kernel.h>
 #include <linux/hid.h>
 #include <linux/mutex.h>
+#include <asm/unaligned.h>
 
 #include "../hid-ids.h"
 #include "i2c-hid.h"
 #define I2C_HID_QUIRK_BAD_INPUT_SIZE           BIT(6)
 #define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET    BIT(7)
 
+/* Command opcodes */
+#define I2C_HID_OPCODE_RESET                   0x01
+#define I2C_HID_OPCODE_GET_REPORT              0x02
+#define I2C_HID_OPCODE_SET_REPORT              0x03
+#define I2C_HID_OPCODE_GET_IDLE                        0x04
+#define I2C_HID_OPCODE_SET_IDLE                        0x05
+#define I2C_HID_OPCODE_GET_PROTOCOL            0x06
+#define I2C_HID_OPCODE_SET_PROTOCOL            0x07
+#define I2C_HID_OPCODE_SET_POWER               0x08
 
 /* flags */
 #define I2C_HID_STARTED                0
@@ -84,60 +94,11 @@ struct i2c_hid_desc {
        __le32 reserved;
 } __packed;
 
-struct i2c_hid_cmd {
-       unsigned int registerIndex;
-       __u8 opcode;
-       unsigned int length;
-       bool wait;
-};
-
-union command {
-       u8 data[0];
-       struct cmd {
-               __le16 reg;
-               __u8 reportTypeID;
-               __u8 opcode;
-       } __packed c;
-};
-
-#define I2C_HID_CMD(opcode_) \
-       .opcode = opcode_, .length = 4, \
-       .registerIndex = offsetof(struct i2c_hid_desc, wCommandRegister)
-
-/* fetch HID descriptor */
-static const struct i2c_hid_cmd hid_descr_cmd = { .length = 2 };
-/* fetch report descriptors */
-static const struct i2c_hid_cmd hid_report_descr_cmd = {
-               .registerIndex = offsetof(struct i2c_hid_desc,
-                       wReportDescRegister),
-               .opcode = 0x00,
-               .length = 2 };
-/* commands */
-static const struct i2c_hid_cmd hid_reset_cmd =                { I2C_HID_CMD(0x01),
-                                                         .wait = true };
-static const struct i2c_hid_cmd hid_get_report_cmd =   { I2C_HID_CMD(0x02) };
-static const struct i2c_hid_cmd hid_set_report_cmd =   { I2C_HID_CMD(0x03) };
-static const struct i2c_hid_cmd hid_set_power_cmd =    { I2C_HID_CMD(0x08) };
-static const struct i2c_hid_cmd hid_no_cmd =           { .length = 0 };
-
-/*
- * These definitions are not used here, but are defined by the spec.
- * Keeping them here for documentation purposes.
- *
- * static const struct i2c_hid_cmd hid_get_idle_cmd = { I2C_HID_CMD(0x04) };
- * static const struct i2c_hid_cmd hid_set_idle_cmd = { I2C_HID_CMD(0x05) };
- * static const struct i2c_hid_cmd hid_get_protocol_cmd = { I2C_HID_CMD(0x06) };
- * static const struct i2c_hid_cmd hid_set_protocol_cmd = { I2C_HID_CMD(0x07) };
- */
-
 /* The main device structure */
 struct i2c_hid {
        struct i2c_client       *client;        /* i2c client */
        struct hid_device       *hid;   /* pointer to corresponding HID dev */
-       union {
-               __u8 hdesc_buffer[sizeof(struct i2c_hid_desc)];
-               struct i2c_hid_desc hdesc;      /* the HID Descriptor */
-       };
+       struct i2c_hid_desc hdesc;              /* the HID Descriptor */
        __le16                  wHIDDescRegister; /* location of the i2c
                                                   * register of the HID
                                                   * descriptor. */
@@ -145,7 +106,6 @@ struct i2c_hid {
        u8                      *inbuf;         /* Input buffer */
        u8                      *rawbuf;        /* Raw Input buffer */
        u8                      *cmdbuf;        /* Command buffer */
-       u8                      *argsbuf;       /* Command arguments buffer */
 
        unsigned long           flags;          /* device flags */
        unsigned long           quirks;         /* Various quirks */
@@ -207,196 +167,228 @@ static u32 i2c_hid_lookup_quirk(const u16 idVendor, const u16 idProduct)
        return quirks;
 }
 
-static int __i2c_hid_command(struct i2c_client *client,
-               const struct i2c_hid_cmd *command, u8 reportID,
-               u8 reportType, u8 *args, int args_len,
-               unsigned char *buf_recv, int data_len)
+static int i2c_hid_xfer(struct i2c_hid *ihid,
+                       u8 *send_buf, int send_len, u8 *recv_buf, int recv_len)
 {
-       struct i2c_hid *ihid = i2c_get_clientdata(client);
-       union command *cmd = (union command *)ihid->cmdbuf;
+       struct i2c_client *client = ihid->client;
+       struct i2c_msg msgs[2] = { 0 };
+       int n = 0;
        int ret;
-       struct i2c_msg msg[2];
-       int msg_num = 1;
 
-       int length = command->length;
-       bool wait = command->wait;
-       unsigned int registerIndex = command->registerIndex;
+       if (send_len) {
+               i2c_hid_dbg(ihid, "%s: cmd=%*ph\n",
+                           __func__, send_len, send_buf);
 
-       /* special case for hid_descr_cmd */
-       if (command == &hid_descr_cmd) {
-               cmd->c.reg = ihid->wHIDDescRegister;
-       } else {
-               cmd->data[0] = ihid->hdesc_buffer[registerIndex];
-               cmd->data[1] = ihid->hdesc_buffer[registerIndex + 1];
+               msgs[n].addr = client->addr;
+               msgs[n].flags = (client->flags & I2C_M_TEN) | I2C_M_DMA_SAFE;
+               msgs[n].len = send_len;
+               msgs[n].buf = send_buf;
+               n++;
        }
 
-       if (length > 2) {
-               cmd->c.opcode = command->opcode;
-               cmd->c.reportTypeID = reportID | reportType << 4;
-       }
+       if (recv_len) {
+               msgs[n].addr = client->addr;
+               msgs[n].flags = (client->flags & I2C_M_TEN) |
+                               I2C_M_RD | I2C_M_DMA_SAFE;
+               msgs[n].len = recv_len;
+               msgs[n].buf = recv_buf;
+               n++;
 
-       memcpy(cmd->data + length, args, args_len);
-       length += args_len;
-
-       i2c_hid_dbg(ihid, "%s: cmd=%*ph\n", __func__, length, cmd->data);
-
-       msg[0].addr = client->addr;
-       msg[0].flags = client->flags & I2C_M_TEN;
-       msg[0].len = length;
-       msg[0].buf = cmd->data;
-       if (data_len > 0) {
-               msg[1].addr = client->addr;
-               msg[1].flags = client->flags & I2C_M_TEN;
-               msg[1].flags |= I2C_M_RD;
-               msg[1].len = data_len;
-               msg[1].buf = buf_recv;
-               msg_num = 2;
                set_bit(I2C_HID_READ_PENDING, &ihid->flags);
        }
 
-       if (wait)
-               set_bit(I2C_HID_RESET_PENDING, &ihid->flags);
-
-       ret = i2c_transfer(client->adapter, msg, msg_num);
+       ret = i2c_transfer(client->adapter, msgs, n);
 
-       if (data_len > 0)
+       if (recv_len)
                clear_bit(I2C_HID_READ_PENDING, &ihid->flags);
 
-       if (ret != msg_num)
+       if (ret != n)
                return ret < 0 ? ret : -EIO;
 
-       ret = 0;
+       return 0;
+}
 
-       if (wait && (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET)) {
-               msleep(100);
-       } else if (wait) {
-               i2c_hid_dbg(ihid, "%s: waiting...\n", __func__);
-               if (!wait_event_timeout(ihid->wait,
-                               !test_bit(I2C_HID_RESET_PENDING, &ihid->flags),
-                               msecs_to_jiffies(5000)))
-                       ret = -ENODATA;
-               i2c_hid_dbg(ihid, "%s: finished.\n", __func__);
-       }
+static int i2c_hid_read_register(struct i2c_hid *ihid, __le16 reg,
+                                void *buf, size_t len)
+{
+       *(__le16 *)ihid->cmdbuf = reg;
 
-       return ret;
+       return i2c_hid_xfer(ihid, ihid->cmdbuf, sizeof(__le16), buf, len);
 }
 
-static int i2c_hid_command(struct i2c_client *client,
-               const struct i2c_hid_cmd *command,
-               unsigned char *buf_recv, int data_len)
+static size_t i2c_hid_encode_command(u8 *buf, u8 opcode,
+                                    int report_type, int report_id)
 {
-       return __i2c_hid_command(client, command, 0, 0, NULL, 0,
-                               buf_recv, data_len);
+       size_t length = 0;
+
+       if (report_id < 0x0F) {
+               buf[length++] = report_type << 4 | report_id;
+               buf[length++] = opcode;
+       } else {
+               buf[length++] = report_type << 4 | 0x0F;
+               buf[length++] = opcode;
+               buf[length++] = report_id;
+       }
+
+       return length;
 }
 
-static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
-               u8 reportID, unsigned char *buf_recv, int data_len)
+static int i2c_hid_get_report(struct i2c_hid *ihid,
+                             u8 report_type, u8 report_id,
+                             u8 *recv_buf, size_t recv_len)
 {
-       struct i2c_hid *ihid = i2c_get_clientdata(client);
-       u8 args[3];
-       int ret;
-       int args_len = 0;
-       u16 readRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
+       size_t length = 0;
+       size_t ret_count;
+       int error;
 
        i2c_hid_dbg(ihid, "%s\n", __func__);
 
-       if (reportID >= 0x0F) {
-               args[args_len++] = reportID;
-               reportID = 0x0F;
+       /* Command register goes first */
+       *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
+       length += sizeof(__le16);
+       /* Next is GET_REPORT command */
+       length += i2c_hid_encode_command(ihid->cmdbuf + length,
+                                        I2C_HID_OPCODE_GET_REPORT,
+                                        report_type, report_id);
+       /*
+        * Device will send report data through data register. Because
+        * command can be either 2 or 3 bytes destination for the data
+        * register may be not aligned.
+        */
+       put_unaligned_le16(le16_to_cpu(ihid->hdesc.wDataRegister),
+                          ihid->cmdbuf + length);
+       length += sizeof(__le16);
+
+       /*
+        * In addition to report data device will supply data length
+        * in the first 2 bytes of the response, so adjust .
+        */
+       error = i2c_hid_xfer(ihid, ihid->cmdbuf, length,
+                            ihid->rawbuf, recv_len + sizeof(__le16));
+       if (error) {
+               dev_err(&ihid->client->dev,
+                       "failed to set a report to device: %d\n", error);
+               return error;
        }
 
-       args[args_len++] = readRegister & 0xFF;
-       args[args_len++] = readRegister >> 8;
+       /* The buffer is sufficiently aligned */
+       ret_count = le16_to_cpup((__le16 *)ihid->rawbuf);
 
-       ret = __i2c_hid_command(client, &hid_get_report_cmd, reportID,
-               reportType, args, args_len, buf_recv, data_len);
-       if (ret) {
-               dev_err(&client->dev,
-                       "failed to retrieve report from device.\n");
-               return ret;
+       /* Check for empty report response */
+       if (ret_count <= sizeof(__le16))
+               return 0;
+
+       recv_len = min(recv_len, ret_count - sizeof(__le16));
+       memcpy(recv_buf, ihid->rawbuf + sizeof(__le16), recv_len);
+
+       if (report_id && recv_len != 0 && recv_buf[0] != report_id) {
+               dev_err(&ihid->client->dev,
+                       "device returned incorrect report (%d vs %d expected)\n",
+                       recv_buf[0], report_id);
+               return -EINVAL;
        }
 
-       return 0;
+       return recv_len;
+}
+
+static size_t i2c_hid_format_report(u8 *buf, int report_id,
+                                   const u8 *data, size_t size)
+{
+       size_t length = sizeof(__le16); /* reserve space to store size */
+
+       if (report_id)
+               buf[length++] = report_id;
+
+       memcpy(buf + length, data, size);
+       length += size;
+
+       /* Store overall size in the beginning of the buffer */
+       put_unaligned_le16(length, buf);
+
+       return length;
 }
 
 /**
  * i2c_hid_set_or_send_report: forward an incoming report to the device
- * @client: the i2c_client of the device
- * @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT
- * @reportID: the report ID
+ * @ihid: the i2c hid device
+ * @report_type: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT
+ * @report_id: the report ID
  * @buf: the actual data to transfer, without the report ID
  * @data_len: size of buf
- * @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report
+ * @do_set: true: use SET_REPORT HID command, false: send plain OUTPUT report
  */
-static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType,
-               u8 reportID, unsigned char *buf, size_t data_len, bool use_data)
+static int i2c_hid_set_or_send_report(struct i2c_hid *ihid,
+                                     u8 report_type, u8 report_id,
+                                     const u8 *buf, size_t data_len,
+                                     bool do_set)
 {
-       struct i2c_hid *ihid = i2c_get_clientdata(client);
-       u8 *args = ihid->argsbuf;
-       const struct i2c_hid_cmd *hidcmd;
-       int ret;
-       u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
-       u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
-       u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength);
-       u16 size;
-       int args_len;
-       int index = 0;
+       size_t length = 0;
+       int error;
 
        i2c_hid_dbg(ihid, "%s\n", __func__);
 
        if (data_len > ihid->bufsize)
                return -EINVAL;
 
-       size =          2                       /* size */ +
-                       (reportID ? 1 : 0)      /* reportID */ +
-                       data_len                /* buf */;
-       args_len =      (reportID >= 0x0F ? 1 : 0) /* optional third byte */ +
-                       2                       /* dataRegister */ +
-                       size                    /* args */;
-
-       if (!use_data && maxOutputLength == 0)
+       if (!do_set && le16_to_cpu(ihid->hdesc.wMaxOutputLength) == 0)
                return -ENOSYS;
 
-       if (reportID >= 0x0F) {
-               args[index++] = reportID;
-               reportID = 0x0F;
+       if (do_set) {
+               /* Command register goes first */
+               *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
+               length += sizeof(__le16);
+               /* Next is SET_REPORT command */
+               length += i2c_hid_encode_command(ihid->cmdbuf + length,
+                                                I2C_HID_OPCODE_SET_REPORT,
+                                                report_type, report_id);
+               /*
+                * Report data will go into the data register. Because
+                * command can be either 2 or 3 bytes destination for
+                * the data register may be not aligned.
+               */
+               put_unaligned_le16(le16_to_cpu(ihid->hdesc.wDataRegister),
+                                  ihid->cmdbuf + length);
+               length += sizeof(__le16);
+       } else {
+               /*
+                * With simple "send report" all data goes into the output
+                * register.
+                */
+               *(__le16 *)ihid->cmdbuf = ihid->hdesc.wOutputRegister;
+               length += sizeof(__le16);
        }
 
-       /*
-        * use the data register for feature reports or if the device does not
-        * support the output register
-        */
-       if (use_data) {
-               args[index++] = dataRegister & 0xFF;
-               args[index++] = dataRegister >> 8;
-               hidcmd = &hid_set_report_cmd;
-       } else {
-               args[index++] = outputRegister & 0xFF;
-               args[index++] = outputRegister >> 8;
-               hidcmd = &hid_no_cmd;
+       length += i2c_hid_format_report(ihid->cmdbuf + length,
+                                       report_id, buf, data_len);
+
+       error = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
+       if (error) {
+               dev_err(&ihid->client->dev,
+                       "failed to set a report to device: %d\n", error);
+               return error;
        }
 
-       args[index++] = size & 0xFF;
-       args[index++] = size >> 8;
+       return data_len;
+}
 
-       if (reportID)
-               args[index++] = reportID;
+static int i2c_hid_set_power_command(struct i2c_hid *ihid, int power_state)
+{
+       size_t length;
 
-       memcpy(&args[index], buf, data_len);
+       /* SET_POWER uses command register */
+       *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
+       length = sizeof(__le16);
 
-       ret = __i2c_hid_command(client, hidcmd, reportID,
-               reportType, args, args_len, NULL, 0);
-       if (ret) {
-               dev_err(&client->dev, "failed to set a report to device.\n");
-               return ret;
-       }
+       /* Now the command itself */
+       length += i2c_hid_encode_command(ihid->cmdbuf + length,
+                                        I2C_HID_OPCODE_SET_POWER,
+                                        0, power_state);
 
-       return data_len;
+       return i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
 }
 
-static int i2c_hid_set_power(struct i2c_client *client, int power_state)
+static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state)
 {
-       struct i2c_hid *ihid = i2c_get_clientdata(client);
        int ret;
 
        i2c_hid_dbg(ihid, "%s\n", __func__);
@@ -408,18 +400,17 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
         */
        if (power_state == I2C_HID_PWR_ON &&
            ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) {
-               ret = i2c_hid_command(client, &hid_set_power_cmd, NULL, 0);
+               ret = i2c_hid_set_power_command(ihid, I2C_HID_PWR_ON);
 
                /* Device was already activated */
                if (!ret)
                        goto set_pwr_exit;
        }
 
-       ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state,
-               0, NULL, 0, NULL, 0);
-
+       ret = i2c_hid_set_power_command(ihid, power_state);
        if (ret)
-               dev_err(&client->dev, "failed to change power setting.\n");
+               dev_err(&ihid->client->dev,
+                       "failed to change power setting.\n");
 
 set_pwr_exit:
 
@@ -438,9 +429,49 @@ set_pwr_exit:
        return ret;
 }
 
-static int i2c_hid_hwreset(struct i2c_client *client)
+static int i2c_hid_execute_reset(struct i2c_hid *ihid)
+{
+       size_t length = 0;
+       int ret;
+
+       i2c_hid_dbg(ihid, "resetting...\n");
+
+       /* Prepare reset command. Command register goes first. */
+       *(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
+       length += sizeof(__le16);
+       /* Next is RESET command itself */
+       length += i2c_hid_encode_command(ihid->cmdbuf + length,
+                                        I2C_HID_OPCODE_RESET, 0, 0);
+
+       set_bit(I2C_HID_RESET_PENDING, &ihid->flags);
+
+       ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
+       if (ret) {
+               dev_err(&ihid->client->dev, "failed to reset device.\n");
+               goto out;
+       }
+
+       if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) {
+               msleep(100);
+               goto out;
+       }
+
+       i2c_hid_dbg(ihid, "%s: waiting...\n", __func__);
+       if (!wait_event_timeout(ihid->wait,
+                               !test_bit(I2C_HID_RESET_PENDING, &ihid->flags),
+                               msecs_to_jiffies(5000))) {
+               ret = -ENODATA;
+               goto out;
+       }
+       i2c_hid_dbg(ihid, "%s: finished.\n", __func__);
+
+out:
+       clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
+       return ret;
+}
+
+static int i2c_hid_hwreset(struct i2c_hid *ihid)
 {
-       struct i2c_hid *ihid = i2c_get_clientdata(client);
        int ret;
 
        i2c_hid_dbg(ihid, "%s\n", __func__);
@@ -452,22 +483,21 @@ static int i2c_hid_hwreset(struct i2c_client *client)
         */
        mutex_lock(&ihid->reset_lock);
 
-       ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
+       ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
        if (ret)
                goto out_unlock;
 
-       i2c_hid_dbg(ihid, "resetting...\n");
-
-       ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0);
+       ret = i2c_hid_execute_reset(ihid);
        if (ret) {
-               dev_err(&client->dev, "failed to reset device.\n");
-               i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
+               dev_err(&ihid->client->dev,
+                       "failed to reset device: %d\n", ret);
+               i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
                goto out_unlock;
        }
 
        /* At least some SIS devices need this after reset */
        if (!(ihid->quirks & I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET))
-               ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
+               ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
 
 out_unlock:
        mutex_unlock(&ihid->reset_lock);
@@ -476,9 +506,9 @@ out_unlock:
 
 static void i2c_hid_get_input(struct i2c_hid *ihid)
 {
+       u16 size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
+       u16 ret_size;
        int ret;
-       u32 ret_size;
-       int size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
 
        if (size > ihid->bufsize)
                size = ihid->bufsize;
@@ -493,8 +523,8 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
                return;
        }
 
-       ret_size = ihid->inbuf[0] | ihid->inbuf[1] << 8;
-
+       /* Receiving buffer is properly aligned */
+       ret_size = le16_to_cpup((__le16 *)ihid->inbuf);
        if (!ret_size) {
                /* host or device initiated RESET completed */
                if (test_and_clear_bit(I2C_HID_RESET_PENDING, &ihid->flags))
@@ -502,19 +532,20 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
                return;
        }
 
-       if (ihid->quirks & I2C_HID_QUIRK_BOGUS_IRQ && ret_size == 0xffff) {
-               dev_warn_once(&ihid->client->dev, "%s: IRQ triggered but "
-                             "there's no data\n", __func__);
+       if ((ihid->quirks & I2C_HID_QUIRK_BOGUS_IRQ) && ret_size == 0xffff) {
+               dev_warn_once(&ihid->client->dev,
+                             "%s: IRQ triggered but there's no data\n",
+                             __func__);
                return;
        }
 
-       if ((ret_size > size) || (ret_size < 2)) {
+       if (ret_size > size || ret_size < sizeof(__le16)) {
                if (ihid->quirks & I2C_HID_QUIRK_BAD_INPUT_SIZE) {
-                       ihid->inbuf[0] = size & 0xff;
-                       ihid->inbuf[1] = size >> 8;
+                       *(__le16 *)ihid->inbuf = cpu_to_le16(size);
                        ret_size = size;
                } else {
-                       dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
+                       dev_err(&ihid->client->dev,
+                               "%s: incomplete report (%d/%d)\n",
                                __func__, size, ret_size);
                        return;
                }
@@ -525,8 +556,9 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
        if (test_bit(I2C_HID_STARTED, &ihid->flags)) {
                pm_wakeup_event(&ihid->client->dev, 0);
 
-               hid_input_report(ihid->hid, HID_INPUT_REPORT, ihid->inbuf + 2,
-                               ret_size - 2, 1);
+               hid_input_report(ihid->hid, HID_INPUT_REPORT,
+                               ihid->inbuf + sizeof(__le16),
+                               ret_size - sizeof(__le16), 1);
        }
 
        return;
@@ -572,31 +604,33 @@ static void i2c_hid_free_buffers(struct i2c_hid *ihid)
 {
        kfree(ihid->inbuf);
        kfree(ihid->rawbuf);
-       kfree(ihid->argsbuf);
        kfree(ihid->cmdbuf);
        ihid->inbuf = NULL;
        ihid->rawbuf = NULL;
        ihid->cmdbuf = NULL;
-       ihid->argsbuf = NULL;
        ihid->bufsize = 0;
 }
 
 static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size)
 {
-       /* the worst case is computed from the set_report command with a
-        * reportID > 15 and the maximum report length */
-       int args_len = sizeof(__u8) + /* ReportID */
-                      sizeof(__u8) + /* optional ReportID byte */
-                      sizeof(__u16) + /* data register */
-                      sizeof(__u16) + /* size of the report */
-                      report_size; /* report */
+       /*
+        * The worst case is computed from the set_report command with a
+        * reportID > 15 and the maximum report length.
+        */
+       int cmd_len = sizeof(__le16) +  /* command register */
+                     sizeof(u8) +      /* encoded report type/ID */
+                     sizeof(u8) +      /* opcode */
+                     sizeof(u8) +      /* optional 3rd byte report ID */
+                     sizeof(__le16) +  /* data register */
+                     sizeof(__le16) +  /* report data size */
+                     sizeof(u8) +      /* report ID if numbered report */
+                     report_size;
 
        ihid->inbuf = kzalloc(report_size, GFP_KERNEL);
        ihid->rawbuf = kzalloc(report_size, GFP_KERNEL);
-       ihid->argsbuf = kzalloc(args_len, GFP_KERNEL);
-       ihid->cmdbuf = kzalloc(sizeof(union command) + args_len, GFP_KERNEL);
+       ihid->cmdbuf = kzalloc(cmd_len, GFP_KERNEL);
 
-       if (!ihid->inbuf || !ihid->rawbuf || !ihid->argsbuf || !ihid->cmdbuf) {
+       if (!ihid->inbuf || !ihid->rawbuf || !ihid->cmdbuf) {
                i2c_hid_free_buffers(ihid);
                return -ENOMEM;
        }
@@ -607,43 +641,39 @@ static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size)
 }
 
 static int i2c_hid_get_raw_report(struct hid_device *hid,
-               unsigned char report_number, __u8 *buf, size_t count,
-               unsigned char report_type)
+                                 u8 report_type, u8 report_id,
+                                 u8 *buf, size_t count)
 {
        struct i2c_client *client = hid->driver_data;
        struct i2c_hid *ihid = i2c_get_clientdata(client);
-       size_t ret_count, ask_count;
-       int ret;
+       int ret_count;
 
        if (report_type == HID_OUTPUT_REPORT)
                return -EINVAL;
 
-       /* +2 bytes to include the size of the reply in the query buffer */
-       ask_count = min(count + 2, (size_t)ihid->bufsize);
+       /*
+        * In case of unnumbered reports the response from the device will
+        * not have the report ID that the upper layers expect, so we need
+        * to stash it the buffer ourselves and adjust the data size.
+        */
+       if (!report_id) {
+               buf[0] = 0;
+               buf++;
+               count--;
+       }
 
-       ret = i2c_hid_get_report(client,
+       ret_count = i2c_hid_get_report(ihid,
                        report_type == HID_FEATURE_REPORT ? 0x03 : 0x01,
-                       report_number, ihid->rawbuf, ask_count);
-
-       if (ret < 0)
-               return ret;
+                       report_id, buf, count);
 
-       ret_count = ihid->rawbuf[0] | (ihid->rawbuf[1] << 8);
+       if (ret_count > 0 && !report_id)
+               ret_count++;
 
-       if (ret_count <= 2)
-               return 0;
-
-       ret_count = min(ret_count, ask_count);
-
-       /* The query buffer contains the size, dropping it in the reply */
-       count = min(count, ret_count - 2);
-       memcpy(buf, ihid->rawbuf + 2, count);
-
-       return count;
+       return ret_count;
 }
 
-static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
-               size_t count, unsigned char report_type, bool use_data)
+static int i2c_hid_output_raw_report(struct hid_device *hid, u8 report_type,
+                                    const u8 *buf, size_t count, bool do_set)
 {
        struct i2c_client *client = hid->driver_data;
        struct i2c_hid *ihid = i2c_get_clientdata(client);
@@ -655,28 +685,29 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
 
        mutex_lock(&ihid->reset_lock);
 
-       if (report_id) {
-               buf++;
-               count--;
-       }
-
-       ret = i2c_hid_set_or_send_report(client,
+       /*
+        * Note that both numbered and unnumbered reports passed here
+        * are supposed to have report ID stored in the 1st byte of the
+        * buffer, so we strip it off unconditionally before passing payload
+        * to i2c_hid_set_or_send_report which takes care of encoding
+        * everything properly.
+        */
+       ret = i2c_hid_set_or_send_report(ihid,
                                report_type == HID_FEATURE_REPORT ? 0x03 : 0x02,
-                               report_id, buf, count, use_data);
+                               report_id, buf + 1, count - 1, do_set);
 
-       if (report_id && ret >= 0)
-               ret++; /* add report_id to the number of transfered bytes */
+       if (ret >= 0)
+               ret++; /* add report_id to the number of transferred bytes */
 
        mutex_unlock(&ihid->reset_lock);
 
        return ret;
 }
 
-static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf,
-               size_t count)
+static int i2c_hid_output_report(struct hid_device *hid, u8 *buf, size_t count)
 {
-       return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT,
-                       false);
+       return i2c_hid_output_raw_report(hid, HID_OUTPUT_REPORT, buf, count,
+                                        false);
 }
 
 static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
@@ -685,11 +716,11 @@ static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
 {
        switch (reqtype) {
        case HID_REQ_GET_REPORT:
-               return i2c_hid_get_raw_report(hid, reportnum, buf, len, rtype);
+               return i2c_hid_get_raw_report(hid, rtype, reportnum, buf, len);
        case HID_REQ_SET_REPORT:
                if (buf[0] != reportnum)
                        return -EINVAL;
-               return i2c_hid_output_raw_report(hid, buf, len, rtype, true);
+               return i2c_hid_output_raw_report(hid, rtype, buf, len, true);
        default:
                return -EIO;
        }
@@ -715,7 +746,7 @@ static int i2c_hid_parse(struct hid_device *hid)
        }
 
        do {
-               ret = i2c_hid_hwreset(client);
+               ret = i2c_hid_hwreset(ihid);
                if (ret)
                        msleep(1000);
        } while (tries-- > 0 && ret);
@@ -739,8 +770,9 @@ static int i2c_hid_parse(struct hid_device *hid)
 
                i2c_hid_dbg(ihid, "asking HID report descriptor\n");
 
-               ret = i2c_hid_command(client, &hid_report_descr_cmd,
-                                     rdesc, rsize);
+               ret = i2c_hid_read_register(ihid,
+                                           ihid->hdesc.wReportDescRegister,
+                                           rdesc, rsize);
                if (ret) {
                        hid_err(hid, "reading report descriptor failed\n");
                        kfree(rdesc);
@@ -850,7 +882,7 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
        struct i2c_client *client = ihid->client;
        struct i2c_hid_desc *hdesc = &ihid->hdesc;
        unsigned int dsize;
-       int ret;
+       int error;
 
        /* i2c hid fetch using a fixed descriptor size (30 bytes) */
        if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) {
@@ -859,11 +891,14 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
                        *i2c_hid_get_dmi_i2c_hid_desc_override(client->name);
        } else {
                i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
-               ret = i2c_hid_command(client, &hid_descr_cmd,
-                                     ihid->hdesc_buffer,
-                                     sizeof(struct i2c_hid_desc));
-               if (ret) {
-                       dev_err(&client->dev, "hid_descr_cmd failed\n");
+               error = i2c_hid_read_register(ihid,
+                                             ihid->wHIDDescRegister,
+                                             &ihid->hdesc,
+                                             sizeof(ihid->hdesc));
+               if (error) {
+                       dev_err(&ihid->client->dev,
+                               "failed to fetch HID descriptor: %d\n",
+                               error);
                        return -ENODEV;
                }
        }
@@ -873,7 +908,7 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
         * bytes 2-3 -> bcdVersion (has to be 1.00) */
        /* check bcdVersion == 1.0 */
        if (le16_to_cpu(hdesc->bcdVersion) != 0x0100) {
-               dev_err(&client->dev,
+               dev_err(&ihid->client->dev,
                        "unexpected HID descriptor bcdVersion (0x%04hx)\n",
                        le16_to_cpu(hdesc->bcdVersion));
                return -ENODEV;
@@ -882,11 +917,11 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
        /* Descriptor length should be 30 bytes as per the specification */
        dsize = le16_to_cpu(hdesc->wHIDDescLength);
        if (dsize != sizeof(struct i2c_hid_desc)) {
-               dev_err(&client->dev, "weird size of HID descriptor (%u)\n",
-                       dsize);
+               dev_err(&ihid->client->dev,
+                       "weird size of HID descriptor (%u)\n", dsize);
                return -ENODEV;
        }
-       i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, ihid->hdesc_buffer);
+       i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, &ihid->hdesc);
        return 0;
 }
 
@@ -1052,7 +1087,7 @@ void i2c_hid_core_shutdown(struct i2c_client *client)
 {
        struct i2c_hid *ihid = i2c_get_clientdata(client);
 
-       i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
+       i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
        free_irq(client->irq, ihid);
 
        i2c_hid_core_shutdown_tail(ihid);
@@ -1073,7 +1108,7 @@ static int i2c_hid_core_suspend(struct device *dev)
                return ret;
 
        /* Save some power */
-       i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
+       i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
 
        disable_irq(client->irq);
 
@@ -1121,9 +1156,9 @@ static int i2c_hid_core_resume(struct device *dev)
         * let's still reset them here.
         */
        if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME)
-               ret = i2c_hid_hwreset(client);
+               ret = i2c_hid_hwreset(ihid);
        else
-               ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
+               ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
 
        if (ret)
                return ret;
index e24988586710db038a88e043aefbe459c872e093..16aa030af8453c1029abd447c40135a2d7060ad2 100644 (file)
@@ -661,21 +661,12 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data,
         */
        payload_max_size &= ~(L1_CACHE_BYTES - 1);
 
-       dma_buf = kmalloc(payload_max_size, GFP_KERNEL | GFP_DMA32);
+       dma_buf = dma_alloc_coherent(devc, payload_max_size, &dma_buf_phy, GFP_KERNEL);
        if (!dma_buf) {
                client_data->flag_retry = true;
                return -ENOMEM;
        }
 
-       dma_buf_phy = dma_map_single(devc, dma_buf, payload_max_size,
-                                    DMA_TO_DEVICE);
-       if (dma_mapping_error(devc, dma_buf_phy)) {
-               dev_err(cl_data_to_dev(client_data), "DMA map failed\n");
-               client_data->flag_retry = true;
-               rv = -ENOMEM;
-               goto end_err_dma_buf_release;
-       }
-
        ldr_xfer_dma_frag.fragment.hdr.command = LOADER_CMD_XFER_FRAGMENT;
        ldr_xfer_dma_frag.fragment.xfer_mode = LOADER_XFER_MODE_DIRECT_DMA;
        ldr_xfer_dma_frag.ddr_phys_addr = (u64)dma_buf_phy;
@@ -695,14 +686,7 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data,
                ldr_xfer_dma_frag.fragment.size = fragment_size;
                memcpy(dma_buf, &fw->data[fragment_offset], fragment_size);
 
-               dma_sync_single_for_device(devc, dma_buf_phy,
-                                          payload_max_size,
-                                          DMA_TO_DEVICE);
-
-               /*
-                * Flush cache here because the dma_sync_single_for_device()
-                * does not do for x86.
-                */
+               /* Flush cache to be sure the data is in main memory. */
                clflush_cache_range(dma_buf, payload_max_size);
 
                dev_dbg(cl_data_to_dev(client_data),
@@ -725,15 +709,8 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data,
                fragment_offset += fragment_size;
        }
 
-       dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE);
-       kfree(dma_buf);
-       return 0;
-
 end_err_resp_buf_release:
-       /* Free ISH buffer if not done already, in error case */
-       dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE);
-end_err_dma_buf_release:
-       kfree(dma_buf);
+       dma_free_coherent(devc, payload_max_size, dma_buf, dma_buf_phy);
        return rv;
 }
 
index 7487b0586fe6acd17dd466065e37b2f62983a6f7..4363a63b9775ef27e4193cd507b77394fd854b9e 100644 (file)
@@ -342,12 +342,12 @@ struct hid_item {
  * HID device quirks.
  */
 
-/* 
+/*
  * Increase this if you need to configure more HID quirks at module load time
  */
 #define MAX_USBHID_BOOT_QUIRKS 4
 
-#define HID_QUIRK_INVERT                       BIT(0)
+/* BIT(0) reserved for backward compatibility, was HID_QUIRK_INVERT */
 #define HID_QUIRK_NOTOUCH                      BIT(1)
 #define HID_QUIRK_IGNORE                       BIT(2)
 #define HID_QUIRK_NOGET                                BIT(3)
@@ -476,31 +476,50 @@ struct hid_field {
        unsigned  report_count;         /* number of this field in the report */
        unsigned  report_type;          /* (input,output,feature) */
        __s32    *value;                /* last known value(s) */
+       __s32    *new_value;            /* newly read value(s) */
+       __s32    *usages_priorities;    /* priority of each usage when reading the report
+                                        * bits 8-16 are reserved for hid-input usage
+                                        */
        __s32     logical_minimum;
        __s32     logical_maximum;
        __s32     physical_minimum;
        __s32     physical_maximum;
        __s32     unit_exponent;
        unsigned  unit;
+       bool      ignored;              /* this field is ignored in this event */
        struct hid_report *report;      /* associated report */
        unsigned index;                 /* index into report->field[] */
        /* hidinput data */
        struct hid_input *hidinput;     /* associated input structure */
        __u16 dpad;                     /* dpad input code */
+       unsigned int slot_idx;          /* slot index in a report */
 };
 
 #define HID_MAX_FIELDS 256
 
+struct hid_field_entry {
+       struct list_head list;
+       struct hid_field *field;
+       unsigned int index;
+       __s32 priority;
+};
+
 struct hid_report {
        struct list_head list;
        struct list_head hidinput_list;
+       struct list_head field_entry_list;              /* ordered list of input fields */
        unsigned int id;                                /* id of this report */
        unsigned int type;                              /* report type */
        unsigned int application;                       /* application usage for this report */
        struct hid_field *field[HID_MAX_FIELDS];        /* fields of the report */
+       struct hid_field_entry *field_entries;          /* allocated memory of input field_entry */
        unsigned maxfield;                              /* maximum valid field index */
        unsigned size;                                  /* size of the report (bits) */
        struct hid_device *device;                      /* associated device */
+
+       /* tool related state */
+       bool tool_active;                               /* whether the current tool is active */
+       unsigned int tool;                              /* BTN_TOOL_* */
 };
 
 #define HID_MAX_IDS 256