HID: uclogic: Add frame type quirk
authorJosé Expósito <jose.exposito89@gmail.com>
Mon, 26 Dec 2022 12:54:49 +0000 (13:54 +0100)
committerJiri Kosina <jkosina@suse.cz>
Wed, 18 Jan 2023 08:44:57 +0000 (09:44 +0100)
The report descriptor used to get information about UGEE v2 devices is
incorrect in the XP-PEN Deco Pro SW. It indicates that the device frame
is of type UCLOGIC_PARAMS_FRAME_BUTTONS but the device has a frame of
type UCLOGIC_PARAMS_FRAME_MOUSE.

Here is the original report descriptor:

  0x0e 0x03 0xc8 0xb3 0x34 0x65 0x08 0x00 0xff 0x1f 0xd8 0x13 0x00 0x00
                                     ^ This byte should be 2

Add a quirk to be able to fix the reported frame type.

Tested-by: Mia Kanashi <chad@redpilled.dev>
Tested-by: Andreas Grosse <andig.mail@t-online.de>
Signed-off-by: José Expósito <jose.exposito89@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-uclogic-core.c
drivers/hid/hid-uclogic-params.c
drivers/hid/hid-uclogic-params.h

index 7fa6fe0..7a5480b 100644 (file)
 
 #include "hid-ids.h"
 
-/* Driver data */
-struct uclogic_drvdata {
-       /* Interface parameters */
-       struct uclogic_params params;
-       /* Pointer to the replacement report descriptor. NULL if none. */
-       __u8 *desc_ptr;
-       /*
-        * Size of the replacement report descriptor.
-        * Only valid if desc_ptr is not NULL
-        */
-       unsigned int desc_size;
-       /* Pen input device */
-       struct input_dev *pen_input;
-       /* In-range timer */
-       struct timer_list inrange_timer;
-       /* Last rotary encoder state, or U8_MAX for none */
-       u8 re_state;
-};
-
 /**
  * uclogic_inrange_timeout - handle pen in-range state timeout.
  * Emulate input events normally generated when pen goes out of range for
@@ -202,6 +183,7 @@ static int uclogic_probe(struct hid_device *hdev,
        }
        timer_setup(&drvdata->inrange_timer, uclogic_inrange_timeout, 0);
        drvdata->re_state = U8_MAX;
+       drvdata->quirks = id->driver_data;
        hid_set_drvdata(hdev, drvdata);
 
        /* Initialize the device and retrieve interface parameters */
index cd1233d..2d46d4d 100644 (file)
@@ -1298,6 +1298,7 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
                                       struct hid_device *hdev)
 {
        int rc = 0;
+       struct uclogic_drvdata *drvdata;
        struct usb_interface *iface;
        __u8 bInterfaceNumber;
        const int str_desc_len = 12;
@@ -1316,6 +1317,7 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
                goto cleanup;
        }
 
+       drvdata = hid_get_drvdata(hdev);
        iface = to_usb_interface(hdev->dev.parent);
        bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
 
@@ -1382,6 +1384,9 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
        p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID;
 
        /* Initialize the frame interface */
+       if (drvdata->quirks & UCLOGIC_MOUSE_FRAME_QUIRK)
+               frame_type = UCLOGIC_PARAMS_FRAME_MOUSE;
+
        switch (frame_type) {
        case UCLOGIC_PARAMS_FRAME_DIAL:
        case UCLOGIC_PARAMS_FRAME_MOUSE:
index a97477c..10a05c7 100644 (file)
@@ -19,6 +19,8 @@
 #include <linux/usb.h>
 #include <linux/hid.h>
 
+#define UCLOGIC_MOUSE_FRAME_QUIRK      BIT(0)
+
 /* Types of pen in-range reporting */
 enum uclogic_params_pen_inrange {
        /* Normal reports: zero - out of proximity, one - in proximity */
@@ -215,6 +217,27 @@ struct uclogic_params {
        struct uclogic_params_frame frame_list[3];
 };
 
+/* Driver data */
+struct uclogic_drvdata {
+       /* Interface parameters */
+       struct uclogic_params params;
+       /* Pointer to the replacement report descriptor. NULL if none. */
+       __u8 *desc_ptr;
+       /*
+        * Size of the replacement report descriptor.
+        * Only valid if desc_ptr is not NULL
+        */
+       unsigned int desc_size;
+       /* Pen input device */
+       struct input_dev *pen_input;
+       /* In-range timer */
+       struct timer_list inrange_timer;
+       /* Last rotary encoder state, or U8_MAX for none */
+       u8 re_state;
+       /* Device quirks */
+       unsigned long quirks;
+};
+
 /* Initialize a tablet interface and discover its parameters */
 extern int uclogic_params_init(struct uclogic_params *params,
                                struct hid_device *hdev);