Merge branch 'for-6.6/logitech' into for-linus
authorBenjamin Tissoires <bentiss@kernel.org>
Thu, 31 Aug 2023 08:40:46 +0000 (10:40 +0200)
committerBenjamin Tissoires <bentiss@kernel.org>
Thu, 31 Aug 2023 08:41:52 +0000 (10:41 +0200)
Various new device ID addition and a couple of HID++
fixes to tackle the last few opened bugs (Nikita Zhandarovich
and Benjamin Tissoires)

18 files changed:
.mailmap
Documentation/devicetree/bindings/input/ilitek,ili9882t.yaml [new file with mode: 0644]
Documentation/hid/hidintro.rst [new file with mode: 0644]
Documentation/hid/hidreport-parsing.rst [new file with mode: 0644]
Documentation/hid/index.rst
MAINTAINERS
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-cp2112.c
drivers/hid/hid-google-stadiaff.c [new file with mode: 0644]
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-multitouch.c
drivers/hid/hid-nvidia-shield.c
drivers/hid/hid-uclogic-core.c
drivers/hid/i2c-hid/i2c-hid-of-elan.c
include/linux/hid.h
include/linux/string_choices.h

index 1bce47a..cea6991 100644 (file)
--- a/.mailmap
+++ b/.mailmap
@@ -119,6 +119,9 @@ Daniel Borkmann <daniel@iogearbox.net> <dborkmann@redhat.com>
 Daniel Borkmann <daniel@iogearbox.net> <dborkman@redhat.com>
 Daniel Borkmann <daniel@iogearbox.net> <dxchgb@gmail.com>
 David Brownell <david-b@pacbell.net>
+David Rheinsberg <david@readahead.eu> <dh.herrmann@gmail.com>
+David Rheinsberg <david@readahead.eu> <dh.herrmann@googlemail.com>
+David Rheinsberg <david@readahead.eu> <david.rheinsberg@gmail.com>
 David Woodhouse <dwmw2@shinybook.infradead.org>
 Dengcheng Zhu <dzhu@wavecomp.com> <dczhu@mips.com>
 Dengcheng Zhu <dzhu@wavecomp.com> <dengcheng.zhu@gmail.com>
diff --git a/Documentation/devicetree/bindings/input/ilitek,ili9882t.yaml b/Documentation/devicetree/bindings/input/ilitek,ili9882t.yaml
new file mode 100644 (file)
index 0000000..c5d9e0e
--- /dev/null
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
+%YAML 1.2
+---
+$id: http://devicetree.org/schemas/input/ilitek,ili9882t.yaml#
+$schema: http://devicetree.org/meta-schemas/core.yaml#
+
+title: Ilitek ili9882t touchscreen controller
+
+maintainers:
+  - Cong Yang <yangcong5@huaqin.corp-partner.google.com>
+
+description:
+  Supports the Ilitek ili9882t touchscreen controller.
+  This touchscreen controller uses the i2c-hid protocol with a reset GPIO.
+
+allOf:
+  - $ref: /schemas/input/touchscreen/touchscreen.yaml#
+
+properties:
+  compatible:
+    const: ilitek,ili9882t
+
+  reg:
+    const: 0x41
+
+  interrupts:
+    maxItems: 1
+
+  panel: true
+
+  reset-gpios:
+    maxItems: 1
+    description: Reset GPIO.
+
+  vccio-supply:
+    description: The 1.8V supply to the touchscreen.
+
+required:
+  - compatible
+  - reg
+  - interrupts
+  - panel
+  - vccio-supply
+
+additionalProperties: false
+
+examples:
+  - |
+    #include <dt-bindings/gpio/gpio.h>
+    #include <dt-bindings/interrupt-controller/irq.h>
+
+    i2c {
+      #address-cells = <1>;
+      #size-cells = <0>;
+
+      touchscreen: touchscreen@41 {
+        compatible = "ilitek,ili9882t";
+        reg = <0x41>;
+
+        interrupt-parent = <&pio>;
+        interrupts = <12 IRQ_TYPE_LEVEL_LOW>;
+
+        panel = <&panel>;
+        reset-gpios = <&pio 60 GPIO_ACTIVE_LOW>;
+        vccio-supply = <&mt6366_vio18_reg>;
+      };
+    };
diff --git a/Documentation/hid/hidintro.rst b/Documentation/hid/hidintro.rst
new file mode 100644 (file)
index 0000000..73523e3
--- /dev/null
@@ -0,0 +1,524 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+======================================
+Introduction to HID report descriptors
+======================================
+
+This chapter is meant to give a broad overview of what HID report
+descriptors are, and of how a casual (non-kernel) programmer can deal
+with HID devices that are not working well with Linux.
+
+.. contents::
+    :local:
+    :depth: 2
+
+.. toctree::
+   :maxdepth: 2
+
+   hidreport-parsing
+
+
+Introduction
+============
+
+HID stands for Human Interface Device, and can be whatever device you
+are using to interact with a computer, be it a mouse, a touchpad, a
+tablet, a microphone.
+
+Many HID devices work out the box, even if their hardware is different.
+For example, mice can have any number of buttons; they may have a
+wheel; movement sensitivity differs between different models, and so
+on. Nonetheless, most of the time everything just works, without the
+need to have specialized code in the kernel for every mouse model
+developed since 1970.
+
+This is because modern HID devices do advertise their capabilities
+through the *HID report descriptor*, a fixed set of bytes describing
+exactly what *HID reports* may be sent between the device and the host
+and the meaning of each individual bit in those reports. For example,
+a HID Report Descriptor may specify that "in a report with ID 3 the
+bits from 8 to 15 is the delta x coordinate of a mouse".
+
+The HID report itself then merely carries the actual data values
+without any extra meta information. Note that HID reports may be sent
+from the device ("Input Reports", i.e. input events), to the device
+("Output Reports" to e.g. change LEDs) or used for device configuration
+("Feature reports"). A device may support one or more HID reports.
+
+The HID subsystem is in charge of parsing the HID report descriptors,
+and converts HID events into normal input device interfaces (see
+Documentation/hid/hid-transport.rst). Devices may misbehave because the
+HID report descriptor provided by the device is wrong, or because it
+needs to be dealt with in a special way, or because some special
+device or interaction mode is not handled by the default code.
+
+The format of HID report descriptors is described by two documents,
+available from the `USB Implementers Forum <https://www.usb.org/>`_
+`HID web page <https://www.usb.org/hid>`_ address:
+
+ * the `HID USB Device Class Definition
+   <https://www.usb.org/document-library/device-class-definition-hid-111>`_ (HID Spec from now on)
+ * the `HID Usage Tables <https://usb.org/document-library/hid-usage-tables-14>`_ (HUT from now on)
+
+The HID subsystem can deal with different transport drivers
+(USB, I2C, Bluetooth, etc.). See Documentation/hid/hid-transport.rst.
+
+Parsing HID report descriptors
+==============================
+
+The current list of HID devices can be found at ``/sys/bus/hid/devices/``.
+For each device, say ``/sys/bus/hid/devices/0003\:093A\:2510.0002/``,
+one can read the corresponding report descriptor::
+
+  $ hexdump -C /sys/bus/hid/devices/0003\:093A\:2510.0002/report_descriptor
+  00000000  05 01 09 02 a1 01 09 01  a1 00 05 09 19 01 29 03  |..............).|
+  00000010  15 00 25 01 75 01 95 03  81 02 75 05 95 01 81 01  |..%.u.....u.....|
+  00000020  05 01 09 30 09 31 09 38  15 81 25 7f 75 08 95 03  |...0.1.8..%.u...|
+  00000030  81 06 c0 c0                                       |....|
+  00000034
+
+Optional: the HID report descriptor can be read also by
+directly accessing the hidraw driver [#hidraw]_.
+
+The basic structure of HID report descriptors is defined in the HID
+spec, while HUT "defines constants that can be interpreted by an
+application to identify the purpose and meaning of a data field in a
+HID report". Each entry is defined by at least two bytes, where the
+first one defines what type of value is following and is described in
+the HID spec, while the second one carries the actual value and is
+described in the HUT.
+
+HID report descriptors can, in principle, be painstakingly parsed by
+hand, byte by byte.
+
+A short introduction on how to do this is sketched in
+Documentation/hid/hidreport-parsing.rst; you only need to understand it
+if you need to patch HID report descriptors.
+
+In practice you should not parse HID report descriptors by hand; rather,
+you should use an existing parser. Among all the available ones
+
+  * the online `USB Descriptor and Request Parser
+    <http://eleccelerator.com/usbdescreqparser/>`_;
+  * `hidrdd <https://github.com/abend0c1/hidrdd>`_,
+    that provides very detailed and somewhat verbose descriptions
+    (verbosity can be useful if you are not familiar with HID report
+    descriptors);
+  * `hid-tools <https://gitlab.freedesktop.org/libevdev/hid-tools>`_,
+    a complete utility set that allows, among other things,
+    to record and replay the raw HID reports and to debug
+    and replay HID devices.
+    It is being actively developed by the Linux HID subsystem maintainers.
+
+Parsing the mouse HID report descriptor with `hid-tools
+<https://gitlab.freedesktop.org/libevdev/hid-tools>`_ leads to
+(explanations interposed)::
+
+    $ ./hid-decode /sys/bus/hid/devices/0003\:093A\:2510.0002/report_descriptor
+    # device 0:0
+    # 0x05, 0x01,                   // Usage Page (Generic Desktop)        0
+    # 0x09, 0x02,                   // Usage (Mouse)                       2
+    # 0xa1, 0x01,                   // Collection (Application)            4
+    # 0x09, 0x01,                   // Usage (Pointer)                     6
+    # 0xa1, 0x00,                   // Collection (Physical)               8
+    # 0x05, 0x09,                   // Usage Page (Button)                10
+
+what follows is a button ::
+
+    # 0x19, 0x01,                   // Usage Minimum (1)                  12
+    # 0x29, 0x03,                   // Usage Maximum (3)                  14
+
+first button is button number 1, last button is button number 3 ::
+
+    # 0x15, 0x00,                   // Logical Minimum (0)                16
+    # 0x25, 0x01,                   // Logical Maximum (1)                18
+
+each button can send values from 0 up to including 1
+(i.e. they are binary buttons) ::
+
+    # 0x75, 0x01,                   // Report Size (1)                    20
+
+each button is sent as exactly one bit ::
+
+    # 0x95, 0x03,                   // Report Count (3)                   22
+
+and there are three of those bits (matching the three buttons) ::
+
+    # 0x81, 0x02,                   // Input (Data,Var,Abs)               24
+
+it's actual Data (not constant padding), they represent
+a single variable (Var) and their values are Absolute (not relative);
+See HID spec Sec. 6.2.2.5 "Input, Output, and Feature Items" ::
+
+    # 0x75, 0x05,                   // Report Size (5)                    26
+
+five additional padding bits, needed to reach a byte ::
+
+    # 0x95, 0x01,                   // Report Count (1)                   28
+
+those five bits are repeated only once ::
+
+    # 0x81, 0x01,                   // Input (Cnst,Arr,Abs)               30
+
+and take Constant (Cnst) values i.e. they can be ignored. ::
+
+    # 0x05, 0x01,                   // Usage Page (Generic Desktop)       32
+    # 0x09, 0x30,                   // Usage (X)                          34
+    # 0x09, 0x31,                   // Usage (Y)                          36
+    # 0x09, 0x38,                   // Usage (Wheel)                      38
+
+The mouse has also two physical positions (Usage (X), Usage (Y))
+and a wheel (Usage (Wheel)) ::
+
+    # 0x15, 0x81,                   // Logical Minimum (-127)             40
+    # 0x25, 0x7f,                   // Logical Maximum (127)              42
+
+each of them can send values ranging from -127 up to including 127 ::
+
+    # 0x75, 0x08,                   // Report Size (8)                    44
+
+which is represented by eight bits ::
+
+    # 0x95, 0x03,                   // Report Count (3)                   46
+
+and there are three of those eight bits, matching X, Y and Wheel. ::
+
+    # 0x81, 0x06,                   // Input (Data,Var,Rel)               48
+
+This time the data values are Relative (Rel), i.e. they represent
+the change from the previously sent report (event) ::
+
+    # 0xc0,                         // End Collection                     50
+    # 0xc0,                         // End Collection                     51
+    #
+    R: 52 05 01 09 02 a1 01 09 01 a1 00 05 09 19 01 29 03 15 00 25 01 75 01 95 03 81 02 75 05 95 01 81 01 05 01 09 30 09 31 09 38 15 81 25 7f 75 08 95 03 81 06 c0 c0
+    N: device 0:0
+    I: 3 0001 0001
+
+
+This Report Descriptor tells us that the mouse input will be
+transmitted using four bytes: the first one for the buttons (three
+bits used, five for padding), the last three for the mouse X, Y and
+wheel changes, respectively.
+
+Indeed, for any event, the mouse will send a *report* of four bytes.
+We can check the values sent by resorting e.g. to the `hid-recorder`
+tool, from `hid-tools <https://gitlab.freedesktop.org/libevdev/hid-tools>`_:
+The sequence of bytes sent by clicking and releasing button 1, then button 2, then button 3 is::
+
+  $ sudo ./hid-recorder /dev/hidraw1
+
+  ....
+  output of hid-decode
+  ....
+
+  #  Button: 1  0  0 | # | X:   0 | Y:    0 | Wheel:    0
+  E: 000000.000000 4 01 00 00 00
+  #  Button: 0  0  0 | # | X:   0 | Y:    0 | Wheel:    0
+  E: 000000.183949 4 00 00 00 00
+  #  Button: 0  1  0 | # | X:   0 | Y:    0 | Wheel:    0
+  E: 000001.959698 4 02 00 00 00
+  #  Button: 0  0  0 | # | X:   0 | Y:    0 | Wheel:    0
+  E: 000002.103899 4 00 00 00 00
+  #  Button: 0  0  1 | # | X:   0 | Y:    0 | Wheel:    0
+  E: 000004.855799 4 04 00 00 00
+  #  Button: 0  0  0 | # | X:    0 | Y:    0 | Wheel:    0
+  E: 000005.103864 4 00 00 00 00
+
+This example shows that when button 2 is clicked,
+the bytes ``02 00 00 00`` are sent, and the immediately subsequent
+event (``00 00 00 00``) is the release of button 2 (no buttons are
+pressed, remember that the data values are *absolute*).
+
+If instead one clicks and holds button 1, then clicks and holds button
+2, releases button 1, and finally releases button 2, the reports are::
+
+  #  Button: 1  0  0 | # | X:    0 | Y:    0 | Wheel:    0
+  E: 000044.175830 4 01 00 00 00
+  #  Button: 1  1  0 | # | X:    0 | Y:    0 | Wheel:    0
+  E: 000045.975997 4 03 00 00 00
+  #  Button: 0  1  0 | # | X:    0 | Y:    0 | Wheel:    0
+  E: 000047.407930 4 02 00 00 00
+  #  Button: 0  0  0 | # | X:    0 | Y:    0 | Wheel:    0
+  E: 000049.199919 4 00 00 00 00
+
+where with ``03 00 00 00`` both buttons are pressed, and with the
+subsequent ``02 00 00 00`` button 1 is released while button 2 is still
+active.
+
+Output, Input and Feature Reports
+---------------------------------
+
+HID devices can have Input Reports, like in the mouse example, Output
+Reports, and Feature Reports. "Output" means that the information is
+sent to the device. For example, a joystick with force feedback will
+have some output; the led of a keyboard would need an output as well.
+"Input" means that data come from the device.
+
+"Feature"s are not meant to be consumed by the end user and define
+configuration options for the device. They can be queried from the host;
+when declared as *Volatile* they should be changed by the host.
+
+
+Collections, Report IDs and Evdev events
+========================================
+
+A single device can logically group data into different independent
+sets, called a *Collection*. Collections can be nested and there are
+different types of collections (see the HID spec 6.2.2.6
+"Collection, End Collection Items" for details).
+
+Different reports are identified by means of different *Report ID*
+fields, i.e. a number identifying the structure of the immediately
+following report.
+Whenever a Report ID is needed it is transmitted as the first byte of
+any report. A device with only one supported HID report (like the mouse
+example above) may omit the report ID.
+
+Consider the following HID report descriptor::
+
+  05 01 09 02 A1 01 85 01 05 09 19 01 29 05 15 00
+  25 01 95 05 75 01 81 02 95 01 75 03 81 01 05 01
+  09 30 09 31 16 00 F8 26 FF 07 75 0C 95 02 81 06
+  09 38 15 80 25 7F 75 08 95 01 81 06 05 0C 0A 38
+  02 15 80 25 7F 75 08 95 01 81 06 C0 05 01 09 02
+  A1 01 85 02 05 09 19 01 29 05 15 00 25 01 95 05
+  75 01 81 02 95 01 75 03 81 01 05 01 09 30 09 31
+  16 00 F8 26 FF 07 75 0C 95 02 81 06 09 38 15 80
+  25 7F 75 08 95 01 81 06 05 0C 0A 38 02 15 80 25
+  7F 75 08 95 01 81 06 C0 05 01 09 07 A1 01 85 05
+  05 07 15 00 25 01 09 29 09 3E 09 4B 09 4E 09 E3
+  09 E8 09 E8 09 E8 75 01 95 08 81 02 95 00 81 01
+  C0 05 0C 09 01 A1 01 85 06 15 00 25 01 75 01 95
+  01 09 3F 81 06 09 3F 81 06 09 3F 81 06 09 3F 81
+  06 09 3F 81 06 09 3F 81 06 09 3F 81 06 09 3F 81
+  06 C0 05 0C 09 01 A1 01 85 03 09 05 15 00 26 FF
+  00 75 08 95 02 B1 02 C0
+
+After parsing it (try to parse it on your own using the suggested
+tools!) one can see that the device presents two ``Mouse`` Application
+Collections (with reports identified by Reports IDs 1 and 2,
+respectively), a ``Keypad`` Application Collection (whose report is
+identified by the Report ID 5) and two ``Consumer Controls`` Application
+Collections, (with Report IDs 6 and 3, respectively). Note, however,
+that a device can have different Report IDs for the same Application
+Collection.
+
+The data sent will begin with the Report ID byte, and will be followed
+by the corresponding information. For example, the data transmitted for
+the last consumer control::
+
+  0x05, 0x0C,        // Usage Page (Consumer)
+  0x09, 0x01,        // Usage (Consumer Control)
+  0xA1, 0x01,        // Collection (Application)
+  0x85, 0x03,        //   Report ID (3)
+  0x09, 0x05,        //   Usage (Headphone)
+  0x15, 0x00,        //   Logical Minimum (0)
+  0x26, 0xFF, 0x00,  //   Logical Maximum (255)
+  0x75, 0x08,        //   Report Size (8)
+  0x95, 0x02,        //   Report Count (2)
+  0xB1, 0x02,        //   Feature (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile)
+  0xC0,              // End Collection
+
+will be of three bytes: the first for the Report ID (3), the next two
+for the headphone, with two (``Report Count (2)``) bytes
+(``Report Size (8)``), each ranging from 0 (``Logical Minimum (0)``)
+to 255 (``Logical Maximum (255)``).
+
+All the Input data sent by the device should be translated into
+corresponding Evdev events, so that the remaining part of the stack can
+know what is going on, e.g. the bit for the first button translates into
+the ``EV_KEY/BTN_LEFT`` evdev event and relative X movement translates
+into the ``EV_REL/REL_X`` evdev event".
+
+Events
+======
+
+In Linux, one ``/dev/input/event*`` is created for each ``Application
+Collection``. Going back to the mouse example, and repeating the
+sequence where one clicks and holds button 1, then clicks and holds
+button 2, releases button 1, and finally releases button 2, one gets::
+
+  $ sudo libinput record /dev/input/event1
+  # libinput record
+  version: 1
+  ndevices: 1
+  libinput:
+    version: "1.23.0"
+    git: "unknown"
+  system:
+    os: "opensuse-tumbleweed:20230619"
+    kernel: "6.3.7-1-default"
+    dmi: "dmi:bvnHP:bvrU77Ver.01.05.00:bd03/24/2022:br5.0:efr20.29:svnHP:pnHPEliteBook64514inchG9NotebookPC:pvr:rvnHP:rn89D2:rvrKBCVersion14.1D.00:cvnHP:ct10:cvr:sku5Y3J1EA#ABZ:"
+  devices:
+  - node: /dev/input/event1
+    evdev:
+      # Name: PixArt HP USB Optical Mouse
+      # ID: bus 0x3 vendor 0x3f0 product 0x94a version 0x111
+      # Supported Events:
+      # Event type 0 (EV_SYN)
+      # Event type 1 (EV_KEY)
+      #   Event code 272 (BTN_LEFT)
+      #   Event code 273 (BTN_RIGHT)
+      #   Event code 274 (BTN_MIDDLE)
+      # Event type 2 (EV_REL)
+      #   Event code 0 (REL_X)
+      #   Event code 1 (REL_Y)
+      #   Event code 8 (REL_WHEEL)
+      #   Event code 11 (REL_WHEEL_HI_RES)
+      # Event type 4 (EV_MSC)
+      #   Event code 4 (MSC_SCAN)
+      # Properties:
+      name: "PixArt HP USB Optical Mouse"
+      id: [3, 1008, 2378, 273]
+      codes:
+       0: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15] # EV_SYN
+       1: [272, 273, 274] # EV_KEY
+       2: [0, 1, 8, 11] # EV_REL
+       4: [4] # EV_MSC
+      properties: []
+    hid: [
+      0x05, 0x01, 0x09, 0x02, 0xa1, 0x01, 0x09, 0x01, 0xa1, 0x00, 0x05, 0x09, 0x19, 0x01, 0x29, 0x03,
+      0x15, 0x00, 0x25, 0x01, 0x95, 0x08, 0x75, 0x01, 0x81, 0x02, 0x05, 0x01, 0x09, 0x30, 0x09, 0x31,
+      0x09, 0x38, 0x15, 0x81, 0x25, 0x7f, 0x75, 0x08, 0x95, 0x03, 0x81, 0x06, 0xc0, 0xc0
+    ]
+    udev:
+      properties:
+      - ID_INPUT=1
+      - ID_INPUT_MOUSE=1
+      - LIBINPUT_DEVICE_GROUP=3/3f0/94a:usb-0000:05:00.3-2
+    quirks:
+    events:
+    # Current time is 12:31:56
+    - evdev:
+      - [  0,     0,   4,   4,      30] # EV_MSC / MSC_SCAN                 30 (obfuscated)
+      - [  0,     0,   1, 272,       1] # EV_KEY / BTN_LEFT                  1
+      - [  0,     0,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +0ms
+    - evdev:
+      - [  1, 207892,  4,   4,      30] # EV_MSC / MSC_SCAN                 30 (obfuscated)
+      - [  1, 207892,  1, 273,       1] # EV_KEY / BTN_RIGHT                 1
+      - [  1, 207892,  0,   0,       0] # ------------ SYN_REPORT (0) ---------- +1207ms
+    - evdev:
+      - [  2, 367823,  4,   4,      30] # EV_MSC / MSC_SCAN                 30 (obfuscated)
+      - [  2, 367823,  1, 272,       0] # EV_KEY / BTN_LEFT                  0
+      - [  2, 367823,  0,   0,       0] # ------------ SYN_REPORT (0) ---------- +1160ms
+    # Current time is 12:32:00
+    - evdev:
+      - [  3, 247617,  4,   4,      30] # EV_MSC / MSC_SCAN                 30 (obfuscated)
+      - [  3, 247617,  1, 273,       0] # EV_KEY / BTN_RIGHT                 0
+      - [  3, 247617,   0,   0,       0] # ------------ SYN_REPORT (0) ---------- +880ms
+
+Note: if ``libinput record`` is not available on your system try using
+``evemu-record``.
+
+When something does not work
+============================
+
+There can be a number of reasons why a device does not behave
+correctly. For example
+
+* The HID report descriptor provided by the HID device may be wrong
+  because e.g.
+
+  * it does not follow the standard, so that the kernel
+    will not able to make sense of the HID report descriptor;
+  * the HID report descriptor *does not match* what is actually
+    sent by the device (this can be verified by reading the raw HID
+    data);
+* the HID report descriptor may need some "quirks" (see later on).
+
+As a consequence, a ``/dev/input/event*`` may not be created
+for each Application Collection, and/or the events
+there may not match what you would expect.
+
+
+Quirks
+------
+
+There are some known peculiarities of HID devices that the kernel
+knows how to fix - these are called the HID quirks and a list of those
+is available in `include/linux/hid.h`.
+
+Should this be the case, it should be enough to add the required quirk
+in the kernel, for the HID device at hand. This can be done in the file
+`drivers/hid/hid-quirks.c`. How to do it should be relatively
+straightforward after looking into the file.
+
+The list of currently defined quirks, from `include/linux/hid.h`, is
+
+.. kernel-doc:: include/linux/hid.h
+   :doc: HID quirks
+
+Quirks for USB devices can be specified while loading the usbhid module,
+see ``modinfo usbhid``, although the proper fix should go into
+hid-quirks.c and **be submitted upstream**.
+See Documentation/process/submitting-patches.rst for guidelines on how
+to submit a patch. Quirks for other busses need to go into hid-quirks.c.
+
+Fixing HID report descriptors
+-----------------------------
+
+Should you need to patch HID report descriptors the easiest way is to
+resort to eBPF, as described in Documentation/hid/hid-bpf.rst.
+
+Basically, you can change any byte of the original HID report
+descriptor. The examples in samples/hid should be a good starting point
+for your code, see e.g. `samples/hid/hid_mouse.bpf.c`::
+
+  SEC("fmod_ret/hid_bpf_rdesc_fixup")
+  int BPF_PROG(hid_rdesc_fixup, struct hid_bpf_ctx *hctx)
+  {
+    ....
+       data[39] = 0x31;
+       data[41] = 0x30;
+    return 0;
+  }
+
+Of course this can be also done within the kernel source code, see e.g.
+`drivers/hid/hid-aureal.c` or `drivers/hid/hid-samsung.c` for a slightly
+more complex file.
+
+Check Documentation/hid/hidreport-parsing.rst if you need any help
+navigating the HID manuals and understanding the exact meaning of
+the HID report descriptor hex numbers.
+
+Whatever solution you come up with, please remember to **submit the
+fix to the HID maintainers**, so that it can be directly integrated in
+the kernel and that particular HID device will start working for
+everyone else. See Documentation/process/submitting-patches.rst for
+guidelines on how to do this.
+
+
+Modifying the transmitted data on the fly
+-----------------------------------------
+
+Using eBPF it is also possible to modify the data exchanged with the
+device. See again the examples in `samples/hid`.
+
+Again, **please post your fix**, so that it can be integrated in the
+kernel!
+
+Writing a specialized driver
+----------------------------
+
+This should really be your last resort.
+
+
+.. rubric:: Footnotes
+
+.. [#hidraw] read hidraw: see Documentation/hid/hidraw.rst and
+  file `samples/hidraw/hid-example.c` for an example.
+  The output of ``hid-example`` would be, for the same mouse::
+
+    $ sudo ./hid-example
+    Report Descriptor Size: 52
+    Report Descriptor:
+    5 1 9 2 a1 1 9 1 a1 0 5 9 19 1 29 3 15 0 25 1 75 1 95 3 81 2 75 5 95 1 81 1 5 1 9 30 9 31 9 38 15 81 25 7f 75 8 95 3 81 6 c0 c0
+
+    Raw Name: PixArt USB Optical Mouse
+    Raw Phys: usb-0000:05:00.4-2.3/input0
+    Raw Info:
+            bustype: 3 (USB)
+            vendor: 0x093a
+            product: 0x2510
+    ...
diff --git a/Documentation/hid/hidreport-parsing.rst b/Documentation/hid/hidreport-parsing.rst
new file mode 100644 (file)
index 0000000..1d3c17f
--- /dev/null
@@ -0,0 +1,49 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+========================================
+Manual parsing of HID report descriptors
+========================================
+
+Consider again the mouse HID report descriptor
+introduced in Documentation/hid/hidintro.rst::
+
+  $ hexdump -C /sys/bus/hid/devices/0003\:093A\:2510.0002/report_descriptor
+  00000000  05 01 09 02 a1 01 09 01  a1 00 05 09 19 01 29 03  |..............).|
+  00000010  15 00 25 01 75 01 95 03  81 02 75 05 95 01 81 01  |..%.u.....u.....|
+  00000020  05 01 09 30 09 31 09 38  15 81 25 7f 75 08 95 03  |...0.1.8..%.u...|
+  00000030  81 06 c0 c0                                       |....|
+  00000034
+
+and try to parse it by hand.
+
+Start with the first number, 0x05: it carries 2 bits for the
+length of the item, 2 bits for the type of the item and 4 bits for the
+function::
+
+  +----------+
+  | 00000101 |
+  +----------+
+          ^^
+          ---- Length of data (see HID spec 6.2.2.2)
+        ^^
+        ------ Type of the item (see HID spec 6.2.2.2, then jump to 6.2.2.7)
+    ^^^^
+    --------- Function of the item (see HID spec 6.2.2.7, then HUT Sec 3)
+
+In our case, the length is 1 byte, the type is ``Global`` and the
+function is ``Usage Page``, thus for parsing the value 0x01 in the second byte
+we need to refer to HUT Sec 3.
+
+The second number is the actual data, and its meaning can be found in
+the HUT. We have a ``Usage Page``, thus we need to refer to HUT
+Sec. 3, "Usage Pages"; from there, one sees that ``0x01`` stands for
+``Generic Desktop Page``.
+
+Moving now to the second two bytes, and following the same scheme,
+``0x09`` (i.e. ``00001001``) will be followed by one byte (``01``)
+and is a ``Local`` item (``10``). Thus, the meaning of the remaining four bits
+(``0000``) is given in the HID spec Sec. 6.2.2.8 "Local Items", so that
+we have a ``Usage``. From HUT, Sec. 4, "Generic Desktop Page",  we see that
+0x02 stands for ``Mouse``.
+
+The following numbers can be parsed in the same way.
index b2028f3..af02cf7 100644 (file)
@@ -7,6 +7,7 @@ Human Interface Devices (HID)
 .. toctree::
    :maxdepth: 1
 
+   hidintro
    hiddev
    hidraw
    hid-sensor
index 3be1bdf..23f3456 100644 (file)
@@ -21778,7 +21778,7 @@ F:      Documentation/admin-guide/ufs.rst
 F:     fs/ufs/
 
 UHID USERSPACE HID IO DRIVER
-M:     David Rheinsberg <david.rheinsberg@gmail.com>
+M:     David Rheinsberg <david@readahead.eu>
 L:     linux-input@vger.kernel.org
 S:     Maintained
 F:     drivers/hid/uhid.c
@@ -22902,7 +22902,7 @@ S:      Maintained
 F:     drivers/rtc/rtc-sd3078.c
 
 WIIMOTE HID DRIVER
-M:     David Rheinsberg <david.rheinsberg@gmail.com>
+M:     David Rheinsberg <david@readahead.eu>
 L:     linux-input@vger.kernel.org
 S:     Maintained
 F:     drivers/hid/hid-wiimote*
index e11c1c8..545e81c 100644 (file)
@@ -412,6 +412,13 @@ config HID_GOOGLE_HAMMER
        help
        Say Y here if you have a Google Hammer device.
 
+config HID_GOOGLE_STADIA_FF
+       tristate "Google Stadia force feedback"
+       select INPUT_FF_MEMLESS
+       help
+       Say Y here if you want to enable force feedback support for the Google
+       Stadia controller.
+
 config HID_VIVALDI
        tristate "Vivaldi Keyboard"
        select HID_VIVALDI_COMMON
index 7a9e160..8a06d0f 100644 (file)
@@ -55,6 +55,7 @@ obj-$(CONFIG_HID_GFRM)                += hid-gfrm.o
 obj-$(CONFIG_HID_GLORIOUS)  += hid-glorious.o
 obj-$(CONFIG_HID_VIVALDI_COMMON) += hid-vivaldi-common.o
 obj-$(CONFIG_HID_GOOGLE_HAMMER)        += hid-google-hammer.o
+obj-$(CONFIG_HID_GOOGLE_STADIA_FF)     += hid-google-stadiaff.o
 obj-$(CONFIG_HID_VIVALDI)      += hid-vivaldi.o
 obj-$(CONFIG_HID_GT683R)       += hid-gt683r.o
 obj-$(CONFIG_HID_GYRATION)     += hid-gyration.o
index 27cadad..54c33a2 100644 (file)
  *   https://www.silabs.com/documents/public/application-notes/an495-cp2112-interface-specification.pdf
  */
 
-#include <linux/gpio/consumer.h>
-#include <linux/gpio/machine.h>
+#include <linux/bitops.h>
 #include <linux/gpio/driver.h>
 #include <linux/hid.h>
 #include <linux/hidraw.h>
 #include <linux/i2c.h>
 #include <linux/module.h>
 #include <linux/nls.h>
+#include <linux/string_choices.h>
 #include <linux/usb/ch9.h>
 #include "hid-ids.h"
 
@@ -31,6 +31,8 @@
 #define CP2112_GPIO_CONFIG_LENGTH              5
 #define CP2112_GPIO_GET_LENGTH                 2
 #define CP2112_GPIO_SET_LENGTH                 3
+#define CP2112_GPIO_MAX_GPIO                   8
+#define CP2112_GPIO_ALL_GPIO_MASK              GENMASK(7, 0)
 
 enum {
        CP2112_GPIO_CONFIG              = 0x02,
@@ -163,19 +165,17 @@ struct cp2112_device {
        atomic_t read_avail;
        atomic_t xfer_avail;
        struct gpio_chip gc;
-       struct irq_chip irq;
        u8 *in_out_buffer;
        struct mutex lock;
 
-       struct gpio_desc *desc[8];
        bool gpio_poll;
        struct delayed_work gpio_poll_worker;
        unsigned long irq_mask;
        u8 gpio_prev_state;
 };
 
-static int gpio_push_pull = 0xFF;
-module_param(gpio_push_pull, int, S_IRUGO | S_IWUSR);
+static int gpio_push_pull = CP2112_GPIO_ALL_GPIO_MASK;
+module_param(gpio_push_pull, int, 0644);
 MODULE_PARM_DESC(gpio_push_pull, "GPIO push-pull configuration bitmask");
 
 static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
@@ -197,7 +197,7 @@ static int cp2112_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
                goto exit;
        }
 
-       buf[1] &= ~(1 << offset);
+       buf[1] &= ~BIT(offset);
        buf[2] = gpio_push_pull;
 
        ret = hid_hw_raw_request(hdev, CP2112_GPIO_CONFIG, buf,
@@ -227,8 +227,8 @@ static void cp2112_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
        mutex_lock(&dev->lock);
 
        buf[0] = CP2112_GPIO_SET;
-       buf[1] = value ? 0xff : 0;
-       buf[2] = 1 << offset;
+       buf[1] = value ? CP2112_GPIO_ALL_GPIO_MASK : 0;
+       buf[2] = BIT(offset);
 
        ret = hid_hw_raw_request(hdev, CP2112_GPIO_SET, buf,
                                 CP2112_GPIO_SET_LENGTH, HID_FEATURE_REPORT,
@@ -532,15 +532,13 @@ static int cp2112_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs,
        hid_dbg(hdev, "I2C %d messages\n", num);
 
        if (num == 1) {
+               hid_dbg(hdev, "I2C %s %#04x len %d\n",
+                       str_read_write(msgs->flags & I2C_M_RD), msgs->addr, msgs->len);
                if (msgs->flags & I2C_M_RD) {
-                       hid_dbg(hdev, "I2C read %#04x len %d\n",
-                               msgs->addr, msgs->len);
                        read_length = msgs->len;
                        read_buf = msgs->buf;
                        count = cp2112_read_req(buf, msgs->addr, msgs->len);
                } else {
-                       hid_dbg(hdev, "I2C write %#04x len %d\n",
-                               msgs->addr, msgs->len);
                        count = cp2112_i2c_write_req(buf, msgs->addr,
                                                     msgs->buf, msgs->len);
                }
@@ -648,7 +646,7 @@ static int cp2112_xfer(struct i2c_adapter *adap, u16 addr,
        int ret;
 
        hid_dbg(hdev, "%s addr 0x%x flags 0x%x cmd 0x%x size %d\n",
-               read_write == I2C_SMBUS_WRITE ? "write" : "read",
+               str_write_read(read_write == I2C_SMBUS_WRITE),
                addr, flags, command, size);
 
        switch (size) {
@@ -895,7 +893,7 @@ static ssize_t name##_show(struct device *kdev, \
        int ret = cp2112_get_usb_config(hdev, &cfg); \
        if (ret) \
                return ret; \
-       return scnprintf(buf, PAGE_SIZE, format, ##__VA_ARGS__); \
+       return sysfs_emit(buf, format, ##__VA_ARGS__); \
 } \
 static DEVICE_ATTR_RW(name);
 
@@ -946,18 +944,10 @@ CP2112_CONFIG_ATTR(release_version, ({
 
 #undef CP2112_CONFIG_ATTR
 
-struct cp2112_pstring_attribute {
-       struct device_attribute attr;
-       unsigned char report;
-};
-
-static ssize_t pstr_store(struct device *kdev,
-                         struct device_attribute *kattr, const char *buf,
-                         size_t count)
+static ssize_t pstr_store(struct device *kdev, struct device_attribute *kattr,
+                         const char *buf, size_t count, int number)
 {
        struct hid_device *hdev = to_hid_device(kdev);
-       struct cp2112_pstring_attribute *attr =
-               container_of(kattr, struct cp2112_pstring_attribute, attr);
        struct cp2112_string_report report;
        int ret;
 
@@ -965,7 +955,7 @@ static ssize_t pstr_store(struct device *kdev,
 
        ret = utf8s_to_utf16s(buf, count, UTF16_LITTLE_ENDIAN,
                              report.string, ARRAY_SIZE(report.string));
-       report.report = attr->report;
+       report.report = number;
        report.length = ret * sizeof(report.string[0]) + 2;
        report.type = USB_DT_STRING;
 
@@ -983,17 +973,15 @@ static ssize_t pstr_store(struct device *kdev,
        return count;
 }
 
-static ssize_t pstr_show(struct device *kdev,
-                        struct device_attribute *kattr, char *buf)
+static ssize_t pstr_show(struct device *kdev, struct device_attribute *kattr,
+                        char *buf, int number)
 {
        struct hid_device *hdev = to_hid_device(kdev);
-       struct cp2112_pstring_attribute *attr =
-               container_of(kattr, struct cp2112_pstring_attribute, attr);
        struct cp2112_string_report report;
        u8 length;
        int ret;
 
-       ret = cp2112_hid_get(hdev, attr->report, (u8 *)&report.contents,
+       ret = cp2112_hid_get(hdev, number, (u8 *)&report.contents,
                             sizeof(report.contents), HID_FEATURE_REPORT);
        if (ret < 3) {
                hid_err(hdev, "error reading %s string: %d\n", kattr->attr.name,
@@ -1018,10 +1006,16 @@ static ssize_t pstr_show(struct device *kdev,
 }
 
 #define CP2112_PSTR_ATTR(name, _report) \
-static struct cp2112_pstring_attribute dev_attr_##name = { \
-       .attr = __ATTR(name, (S_IWUSR | S_IRUGO), pstr_show, pstr_store), \
-       .report = _report, \
-};
+static ssize_t name##_store(struct device *kdev, struct device_attribute *kattr, \
+                           const char *buf, size_t count) \
+{ \
+       return pstr_store(kdev, kattr, buf, count, _report); \
+} \
+static ssize_t name##_show(struct device *kdev, struct device_attribute *kattr, char *buf) \
+{ \
+       return pstr_show(kdev, kattr, buf, _report); \
+} \
+static DEVICE_ATTR_RW(name);
 
 CP2112_PSTR_ATTR(manufacturer, CP2112_MANUFACTURER_STRING);
 CP2112_PSTR_ATTR(product,      CP2112_PRODUCT_STRING);
@@ -1036,9 +1030,9 @@ static const struct attribute_group cp2112_attr_group = {
                &dev_attr_max_power.attr,
                &dev_attr_power_mode.attr,
                &dev_attr_release_version.attr,
-               &dev_attr_manufacturer.attr.attr,
-               &dev_attr_product.attr.attr,
-               &dev_attr_serial.attr.attr,
+               &dev_attr_manufacturer.attr,
+               &dev_attr_product.attr,
+               &dev_attr_serial.attr,
                NULL
        }
 };
@@ -1063,7 +1057,7 @@ static void chmod_sysfs_attrs(struct hid_device *hdev)
        }
 
        for (attr = cp2112_attr_group.attrs; *attr; ++attr) {
-               umode_t mode = (buf[1] & 1) ? S_IWUSR | S_IRUGO : S_IRUGO;
+               umode_t mode = (buf[1] & 1) ? 0644 : 0444;
                ret = sysfs_chmod_file(&hdev->dev.kobj, *attr, mode);
                if (ret < 0)
                        hid_err(hdev, "error chmoding sysfs file %s\n",
@@ -1080,16 +1074,20 @@ static void cp2112_gpio_irq_mask(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct cp2112_device *dev = gpiochip_get_data(gc);
+       irq_hw_number_t hwirq = irqd_to_hwirq(d);
 
-       __clear_bit(d->hwirq, &dev->irq_mask);
+       __clear_bit(hwirq, &dev->irq_mask);
+       gpiochip_disable_irq(gc, hwirq);
 }
 
 static void cp2112_gpio_irq_unmask(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct cp2112_device *dev = gpiochip_get_data(gc);
+       irq_hw_number_t hwirq = irqd_to_hwirq(d);
 
-       __set_bit(d->hwirq, &dev->irq_mask);
+       gpiochip_enable_irq(gc, hwirq);
+       __set_bit(hwirq, &dev->irq_mask);
 }
 
 static void cp2112_gpio_poll_callback(struct work_struct *work)
@@ -1098,7 +1096,6 @@ static void cp2112_gpio_poll_callback(struct work_struct *work)
                                                 gpio_poll_worker.work);
        struct irq_data *d;
        u8 gpio_mask;
-       u8 virqs = (u8)dev->irq_mask;
        u32 irq_type;
        int irq, virq, ret;
 
@@ -1109,15 +1106,10 @@ static void cp2112_gpio_poll_callback(struct work_struct *work)
                goto exit;
 
        gpio_mask = ret;
-
-       while (virqs) {
-               virq = ffs(virqs) - 1;
-               virqs &= ~BIT(virq);
-
-               if (!dev->gc.to_irq)
-                       break;
-
-               irq = dev->gc.to_irq(&dev->gc, virq);
+       for_each_set_bit(virq, &dev->irq_mask, CP2112_GPIO_MAX_GPIO) {
+               irq = irq_find_mapping(dev->gc.irq.domain, virq);
+               if (!irq)
+                       continue;
 
                d = irq_get_irq_data(irq);
                if (!d)
@@ -1175,6 +1167,7 @@ static void cp2112_gpio_irq_shutdown(struct irq_data *d)
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
        struct cp2112_device *dev = gpiochip_get_data(gc);
 
+       cp2112_gpio_irq_mask(d);
        cancel_delayed_work_sync(&dev->gpio_poll_worker);
 }
 
@@ -1183,50 +1176,17 @@ static int cp2112_gpio_irq_type(struct irq_data *d, unsigned int type)
        return 0;
 }
 
-static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev,
-                                             int pin)
-{
-       int ret;
-
-       if (dev->desc[pin])
-               return -EINVAL;
-
-       dev->desc[pin] = gpiochip_request_own_desc(&dev->gc, pin,
-                                                  "HID/I2C:Event",
-                                                  GPIO_ACTIVE_HIGH,
-                                                  GPIOD_IN);
-       if (IS_ERR(dev->desc[pin])) {
-               dev_err(dev->gc.parent, "Failed to request GPIO\n");
-               return PTR_ERR(dev->desc[pin]);
-       }
-
-       ret = cp2112_gpio_direction_input(&dev->gc, pin);
-       if (ret < 0) {
-               dev_err(dev->gc.parent, "Failed to set GPIO to input dir\n");
-               goto err_desc;
-       }
-
-       ret = gpiochip_lock_as_irq(&dev->gc, pin);
-       if (ret) {
-               dev_err(dev->gc.parent, "Failed to lock GPIO as interrupt\n");
-               goto err_desc;
-       }
-
-       ret = gpiod_to_irq(dev->desc[pin]);
-       if (ret < 0) {
-               dev_err(dev->gc.parent, "Failed to translate GPIO to IRQ\n");
-               goto err_lock;
-       }
-
-       return ret;
-
-err_lock:
-       gpiochip_unlock_as_irq(&dev->gc, pin);
-err_desc:
-       gpiochip_free_own_desc(dev->desc[pin]);
-       dev->desc[pin] = NULL;
-       return ret;
-}
+static const struct irq_chip cp2112_gpio_irqchip = {
+       .name = "cp2112-gpio",
+       .irq_startup = cp2112_gpio_irq_startup,
+       .irq_shutdown = cp2112_gpio_irq_shutdown,
+       .irq_ack = cp2112_gpio_irq_ack,
+       .irq_mask = cp2112_gpio_irq_mask,
+       .irq_unmask = cp2112_gpio_irq_unmask,
+       .irq_set_type = cp2112_gpio_irq_type,
+       .flags = IRQCHIP_MASK_ON_SUSPEND | IRQCHIP_IMMUTABLE,
+       GPIOCHIP_IRQ_RESOURCE_HELPERS,
+};
 
 static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
 {
@@ -1333,21 +1293,12 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id)
        dev->gc.set                     = cp2112_gpio_set;
        dev->gc.get                     = cp2112_gpio_get;
        dev->gc.base                    = -1;
-       dev->gc.ngpio                   = 8;
+       dev->gc.ngpio                   = CP2112_GPIO_MAX_GPIO;
        dev->gc.can_sleep               = 1;
        dev->gc.parent                  = &hdev->dev;
 
-       dev->irq.name = "cp2112-gpio";
-       dev->irq.irq_startup = cp2112_gpio_irq_startup;
-       dev->irq.irq_shutdown = cp2112_gpio_irq_shutdown;
-       dev->irq.irq_ack = cp2112_gpio_irq_ack;
-       dev->irq.irq_mask = cp2112_gpio_irq_mask;
-       dev->irq.irq_unmask = cp2112_gpio_irq_unmask;
-       dev->irq.irq_set_type = cp2112_gpio_irq_type;
-       dev->irq.flags = IRQCHIP_MASK_ON_SUSPEND;
-
        girq = &dev->gc.irq;
-       girq->chip = &dev->irq;
+       gpio_irq_chip_set_chip(girq, &cp2112_gpio_irqchip);
        /* The event comes from the outside so no parent handler */
        girq->parent_handler = NULL;
        girq->num_parents = 0;
@@ -1389,7 +1340,6 @@ err_hid_stop:
 static void cp2112_remove(struct hid_device *hdev)
 {
        struct cp2112_device *dev = hid_get_drvdata(hdev);
-       int i;
 
        sysfs_remove_group(&hdev->dev.kobj, &cp2112_attr_group);
        i2c_del_adapter(&dev->adap);
@@ -1399,11 +1349,6 @@ static void cp2112_remove(struct hid_device *hdev)
                cancel_delayed_work_sync(&dev->gpio_poll_worker);
        }
 
-       for (i = 0; i < ARRAY_SIZE(dev->desc); i++) {
-               gpiochip_unlock_as_irq(&dev->gc, i);
-               gpiochip_free_own_desc(dev->desc[i]);
-       }
-
        gpiochip_remove(&dev->gc);
        /* i2c_del_adapter has finished removing all i2c devices from our
         * adapter. Well behaved devices should no longer call our cp2112_xfer
diff --git a/drivers/hid/hid-google-stadiaff.c b/drivers/hid/hid-google-stadiaff.c
new file mode 100644 (file)
index 0000000..3731575
--- /dev/null
@@ -0,0 +1,158 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Stadia controller rumble support.
+ *
+ * Copyright 2023 Google LLC
+ */
+
+#include <linux/hid.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+
+#include "hid-ids.h"
+
+#define STADIA_FF_REPORT_ID 5
+
+struct stadiaff_device {
+       struct hid_device *hid;
+       struct hid_report *report;
+       spinlock_t lock;
+       bool removed;
+       uint16_t strong_magnitude;
+       uint16_t weak_magnitude;
+       struct work_struct work;
+};
+
+static void stadiaff_work(struct work_struct *work)
+{
+       struct stadiaff_device *stadiaff =
+               container_of(work, struct stadiaff_device, work);
+       struct hid_field *rumble_field = stadiaff->report->field[0];
+       unsigned long flags;
+
+       spin_lock_irqsave(&stadiaff->lock, flags);
+       rumble_field->value[0] = stadiaff->strong_magnitude;
+       rumble_field->value[1] = stadiaff->weak_magnitude;
+       spin_unlock_irqrestore(&stadiaff->lock, flags);
+
+       hid_hw_request(stadiaff->hid, stadiaff->report, HID_REQ_SET_REPORT);
+}
+
+static int stadiaff_play(struct input_dev *dev, void *data,
+                        struct ff_effect *effect)
+{
+       struct hid_device *hid = input_get_drvdata(dev);
+       struct stadiaff_device *stadiaff = hid_get_drvdata(hid);
+       unsigned long flags;
+
+       spin_lock_irqsave(&stadiaff->lock, flags);
+       if (!stadiaff->removed) {
+               stadiaff->strong_magnitude = effect->u.rumble.strong_magnitude;
+               stadiaff->weak_magnitude = effect->u.rumble.weak_magnitude;
+               schedule_work(&stadiaff->work);
+       }
+       spin_unlock_irqrestore(&stadiaff->lock, flags);
+
+       return 0;
+}
+
+static int stadiaff_init(struct hid_device *hid)
+{
+       struct stadiaff_device *stadiaff;
+       struct hid_report *report;
+       struct hid_input *hidinput;
+       struct input_dev *dev;
+       int error;
+
+       if (list_empty(&hid->inputs)) {
+               hid_err(hid, "no inputs found\n");
+               return -ENODEV;
+       }
+       hidinput = list_entry(hid->inputs.next, struct hid_input, list);
+       dev = hidinput->input;
+
+       report = hid_validate_values(hid, HID_OUTPUT_REPORT,
+                                    STADIA_FF_REPORT_ID, 0, 2);
+       if (!report)
+               return -ENODEV;
+
+       stadiaff = devm_kzalloc(&hid->dev, sizeof(struct stadiaff_device),
+                               GFP_KERNEL);
+       if (!stadiaff)
+               return -ENOMEM;
+
+       hid_set_drvdata(hid, stadiaff);
+
+       input_set_capability(dev, EV_FF, FF_RUMBLE);
+
+       error = input_ff_create_memless(dev, NULL, stadiaff_play);
+       if (error)
+               return error;
+
+       stadiaff->removed = false;
+       stadiaff->hid = hid;
+       stadiaff->report = report;
+       INIT_WORK(&stadiaff->work, stadiaff_work);
+       spin_lock_init(&stadiaff->lock);
+
+       hid_info(hid, "Force Feedback for Google Stadia controller\n");
+
+       return 0;
+}
+
+static int stadia_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+       int ret;
+
+       ret = hid_parse(hdev);
+       if (ret) {
+               hid_err(hdev, "parse failed\n");
+               return ret;
+       }
+
+       ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+       if (ret) {
+               hid_err(hdev, "hw start failed\n");
+               return ret;
+       }
+
+       ret = stadiaff_init(hdev);
+       if (ret) {
+               hid_err(hdev, "force feedback init failed\n");
+               hid_hw_stop(hdev);
+               return ret;
+       }
+
+       return 0;
+}
+
+static void stadia_remove(struct hid_device *hid)
+{
+       struct stadiaff_device *stadiaff = hid_get_drvdata(hid);
+       unsigned long flags;
+
+       spin_lock_irqsave(&stadiaff->lock, flags);
+       stadiaff->removed = true;
+       spin_unlock_irqrestore(&stadiaff->lock, flags);
+
+       cancel_work_sync(&stadiaff->work);
+       hid_hw_stop(hid);
+}
+
+static const struct hid_device_id stadia_devices[] = {
+       { HID_USB_DEVICE(USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_STADIA) },
+       { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_STADIA) },
+       { }
+};
+MODULE_DEVICE_TABLE(hid, stadia_devices);
+
+static struct hid_driver stadia_driver = {
+       .name = "stadia",
+       .id_table = stadia_devices,
+       .probe = stadia_probe,
+       .remove = stadia_remove,
+};
+module_hid_driver(stadia_driver);
+
+MODULE_LICENSE("GPL");
index 7ac7deb..7e49999 100644 (file)
 #define USB_DEVICE_ID_GOOGLE_DON       0x5050
 #define USB_DEVICE_ID_GOOGLE_EEL       0x5057
 #define USB_DEVICE_ID_GOOGLE_JEWEL     0x5061
+#define USB_DEVICE_ID_GOOGLE_STADIA    0x9400
 
 #define USB_VENDOR_ID_GOTOP            0x08f2
 #define USB_DEVICE_ID_SUPER_Q2         0x007f
index 851ee86..40a5645 100644 (file)
@@ -988,6 +988,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                        return;
 
                case 0x3c: /* Invert */
+                       device->quirks &= ~HID_QUIRK_NOINVERT;
                        map_key_clear(BTN_TOOL_RUBBER);
                        break;
 
@@ -1013,9 +1014,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
                case 0x45: /* ERASER */
                        /*
                         * This event is reported when eraser tip touches the surface.
-                        * Actual eraser (BTN_TOOL_RUBBER) is set by Invert usage when
-                        * tool gets in proximity.
+                        * Actual eraser (BTN_TOOL_RUBBER) is set and released either
+                        * by Invert if tool reports proximity or by Eraser directly.
                         */
+                       if (!test_bit(BTN_TOOL_RUBBER, input->keybit)) {
+                               device->quirks |= HID_QUIRK_NOINVERT;
+                               set_bit(BTN_TOOL_RUBBER, input->keybit);
+                       }
                        map_key_clear(BTN_TOUCH);
                        break;
 
@@ -1580,6 +1585,15 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
                else if (report->tool != BTN_TOOL_RUBBER)
                        /* value is off, tool is not rubber, ignore */
                        return;
+               else if (*quirks & HID_QUIRK_NOINVERT &&
+                        !test_bit(BTN_TOUCH, input->key)) {
+                       /*
+                        * There is no invert to release the tool, let hid_input
+                        * send BTN_TOUCH with scancode and release the tool after.
+                        */
+                       hid_report_release_tool(report, input, BTN_TOOL_RUBBER);
+                       return;
+               }
 
                /* let hid-input set BTN_TOUCH */
                break;
index e31be0c..521b2ff 100644 (file)
@@ -1594,7 +1594,6 @@ static void mt_post_parse(struct mt_device *td, struct mt_application *app)
 static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
 {
        struct mt_device *td = hid_get_drvdata(hdev);
-       char *name;
        const char *suffix = NULL;
        struct mt_report_data *rdata;
        struct mt_application *mt_application = NULL;
@@ -1645,15 +1644,9 @@ static int mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
                break;
        }
 
-       if (suffix) {
-               name = devm_kzalloc(&hi->input->dev,
-                                   strlen(hdev->name) + strlen(suffix) + 2,
-                                   GFP_KERNEL);
-               if (name) {
-                       sprintf(name, "%s %s", hdev->name, suffix);
-                       hi->input->name = name;
-               }
-       }
+       if (suffix)
+               hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
+                                                "%s %s", hdev->name, suffix);
 
        return 0;
 }
index a928ad2..084179a 100644 (file)
@@ -164,7 +164,7 @@ static struct input_dev *shield_allocate_input_dev(struct hid_device *hdev,
        idev->id.product = hdev->product;
        idev->id.version = hdev->version;
        idev->uniq = hdev->uniq;
-       idev->name = devm_kasprintf(&idev->dev, GFP_KERNEL, "%s %s", hdev->name,
+       idev->name = devm_kasprintf(&hdev->dev, GFP_KERNEL, "%s %s", hdev->name,
                                    name_suffix);
        if (!idev->name)
                goto err_name;
index f67835f..ad74cbc 100644 (file)
@@ -85,10 +85,8 @@ static int uclogic_input_configured(struct hid_device *hdev,
 {
        struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
        struct uclogic_params *params = &drvdata->params;
-       char *name;
        const char *suffix = NULL;
        struct hid_field *field;
-       size_t len;
        size_t i;
        const struct uclogic_params_frame *frame;
 
@@ -146,14 +144,9 @@ static int uclogic_input_configured(struct hid_device *hdev,
                }
        }
 
-       if (suffix) {
-               len = strlen(hdev->name) + 2 + strlen(suffix);
-               name = devm_kzalloc(&hi->input->dev, len, GFP_KERNEL);
-               if (name) {
-                       snprintf(name, len, "%s %s", hdev->name, suffix);
-                       hi->input->name = name;
-               }
-       }
+       if (suffix)
+               hi->input->name = devm_kasprintf(&hdev->dev, GFP_KERNEL,
+                                                "%s %s", hdev->name, suffix);
 
        return 0;
 }
index 029045d..31abab5 100644 (file)
 #include "i2c-hid.h"
 
 struct elan_i2c_hid_chip_data {
-       unsigned int post_gpio_reset_delay_ms;
+       unsigned int post_gpio_reset_on_delay_ms;
+       unsigned int post_gpio_reset_off_delay_ms;
        unsigned int post_power_delay_ms;
        u16 hid_descriptor_address;
+       const char *main_supply_name;
 };
 
 struct i2c_hid_of_elan {
@@ -38,9 +40,11 @@ static int elan_i2c_hid_power_up(struct i2chid_ops *ops)
                container_of(ops, struct i2c_hid_of_elan, ops);
        int ret;
 
-       ret = regulator_enable(ihid_elan->vcc33);
-       if (ret)
-               return ret;
+       if (ihid_elan->vcc33) {
+               ret = regulator_enable(ihid_elan->vcc33);
+               if (ret)
+                       return ret;
+       }
 
        ret = regulator_enable(ihid_elan->vccio);
        if (ret) {
@@ -52,8 +56,8 @@ static int elan_i2c_hid_power_up(struct i2chid_ops *ops)
                msleep(ihid_elan->chip_data->post_power_delay_ms);
 
        gpiod_set_value_cansleep(ihid_elan->reset_gpio, 0);
-       if (ihid_elan->chip_data->post_gpio_reset_delay_ms)
-               msleep(ihid_elan->chip_data->post_gpio_reset_delay_ms);
+       if (ihid_elan->chip_data->post_gpio_reset_on_delay_ms)
+               msleep(ihid_elan->chip_data->post_gpio_reset_on_delay_ms);
 
        return 0;
 }
@@ -64,8 +68,12 @@ static void elan_i2c_hid_power_down(struct i2chid_ops *ops)
                container_of(ops, struct i2c_hid_of_elan, ops);
 
        gpiod_set_value_cansleep(ihid_elan->reset_gpio, 1);
+       if (ihid_elan->chip_data->post_gpio_reset_off_delay_ms)
+               msleep(ihid_elan->chip_data->post_gpio_reset_off_delay_ms);
+
        regulator_disable(ihid_elan->vccio);
-       regulator_disable(ihid_elan->vcc33);
+       if (ihid_elan->vcc33)
+               regulator_disable(ihid_elan->vcc33);
 }
 
 static int i2c_hid_of_elan_probe(struct i2c_client *client)
@@ -89,24 +97,42 @@ static int i2c_hid_of_elan_probe(struct i2c_client *client)
        if (IS_ERR(ihid_elan->vccio))
                return PTR_ERR(ihid_elan->vccio);
 
-       ihid_elan->vcc33 = devm_regulator_get(&client->dev, "vcc33");
-       if (IS_ERR(ihid_elan->vcc33))
-               return PTR_ERR(ihid_elan->vcc33);
-
        ihid_elan->chip_data = device_get_match_data(&client->dev);
 
+       if (ihid_elan->chip_data->main_supply_name) {
+               ihid_elan->vcc33 = devm_regulator_get(&client->dev,
+                                                     ihid_elan->chip_data->main_supply_name);
+               if (IS_ERR(ihid_elan->vcc33))
+                       return PTR_ERR(ihid_elan->vcc33);
+       }
+
        return i2c_hid_core_probe(client, &ihid_elan->ops,
                                  ihid_elan->chip_data->hid_descriptor_address, 0);
 }
 
 static const struct elan_i2c_hid_chip_data elan_ekth6915_chip_data = {
        .post_power_delay_ms = 1,
-       .post_gpio_reset_delay_ms = 300,
+       .post_gpio_reset_on_delay_ms = 300,
+       .hid_descriptor_address = 0x0001,
+       .main_supply_name = "vcc33",
+};
+
+static const struct elan_i2c_hid_chip_data ilitek_ili9882t_chip_data = {
+       .post_power_delay_ms = 1,
+       .post_gpio_reset_on_delay_ms = 200,
+       .post_gpio_reset_off_delay_ms = 65,
        .hid_descriptor_address = 0x0001,
+       /*
+        * this touchscreen is tightly integrated with the panel and assumes
+        * that the relevant power rails (other than the IO rail) have already
+        * been turned on by the panel driver because we're a panel follower.
+        */
+       .main_supply_name = NULL,
 };
 
 static const struct of_device_id elan_i2c_hid_of_match[] = {
        { .compatible = "elan,ekth6915", .data = &elan_ekth6915_chip_data },
+       { .compatible = "ilitek,ili9882t", .data = &ilitek_ili9882t_chip_data },
        { }
 };
 MODULE_DEVICE_TABLE(of, elan_i2c_hid_of_match);
index 39e21e3..964ca1f 100644 (file)
@@ -341,6 +341,29 @@ struct hid_item {
  */
 #define MAX_USBHID_BOOT_QUIRKS 4
 
+/**
+ * DOC: HID quirks
+ * | @HID_QUIRK_NOTOUCH:
+ * | @HID_QUIRK_IGNORE: ignore this device
+ * | @HID_QUIRK_NOGET:
+ * | @HID_QUIRK_HIDDEV_FORCE:
+ * | @HID_QUIRK_BADPAD:
+ * | @HID_QUIRK_MULTI_INPUT:
+ * | @HID_QUIRK_HIDINPUT_FORCE:
+ * | @HID_QUIRK_ALWAYS_POLL:
+ * | @HID_QUIRK_INPUT_PER_APP:
+ * | @HID_QUIRK_X_INVERT:
+ * | @HID_QUIRK_Y_INVERT:
+ * | @HID_QUIRK_SKIP_OUTPUT_REPORTS:
+ * | @HID_QUIRK_SKIP_OUTPUT_REPORT_ID:
+ * | @HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP:
+ * | @HID_QUIRK_HAVE_SPECIAL_DRIVER:
+ * | @HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE:
+ * | @HID_QUIRK_FULLSPEED_INTERVAL:
+ * | @HID_QUIRK_NO_INIT_REPORTS:
+ * | @HID_QUIRK_NO_IGNORE:
+ * | @HID_QUIRK_NO_INPUT_SYNC:
+ */
 /* BIT(0) reserved for backward compatibility, was HID_QUIRK_INVERT */
 #define HID_QUIRK_NOTOUCH                      BIT(1)
 #define HID_QUIRK_IGNORE                       BIT(2)
@@ -360,6 +383,7 @@ struct hid_item {
 #define HID_QUIRK_NO_OUTPUT_REPORTS_ON_INTR_EP BIT(18)
 #define HID_QUIRK_HAVE_SPECIAL_DRIVER          BIT(19)
 #define HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE BIT(20)
+#define HID_QUIRK_NOINVERT                     BIT(21)
 #define HID_QUIRK_FULLSPEED_INTERVAL           BIT(28)
 #define HID_QUIRK_NO_INIT_REPORTS              BIT(29)
 #define HID_QUIRK_NO_IGNORE                    BIT(30)
@@ -555,9 +579,9 @@ struct hid_input {
        struct hid_report *report;
        struct input_dev *input;
        const char *name;
-       bool registered;
        struct list_head reports;       /* the list of reports */
        unsigned int application;       /* application usage for this input */
+       bool registered;
 };
 
 enum hid_type {
index 4812022..3c10919 100644 (file)
@@ -30,6 +30,7 @@ static inline const char *str_read_write(bool v)
 {
        return v ? "read" : "write";
 }
+#define str_write_read(v)              str_read_write(!(v))
 
 static inline const char *str_on_off(bool v)
 {