HID: uclogic: Parse the UGEE v2 frame type
authorJosé Expósito <jose.exposito89@gmail.com>
Mon, 15 Aug 2022 14:29:52 +0000 (16:29 +0200)
committerJiri Kosina <jkosina@suse.cz>
Thu, 25 Aug 2022 08:26:31 +0000 (10:26 +0200)
The string descriptor returned by UGEE v2 devices contains a byte
indicating the device frame type.

The values discovered so far are:

 - 0: Frame with buttons, present in the XP-PEN Deco L.
 - 1: Frame with buttons and dial, present in the PARBLO A610 PRO.
 - 2: Frame with buttons and a mouse, shaped as a dial + touchpad.
      Present in the XP-PEN Deco Pro S.

Parse the frame type and add KUnit tests.

Tested-by: Jouke Witteveen <j.witteveen@gmail.com>
Signed-off-by: José Expósito <jose.exposito89@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-uclogic-params-test.c
drivers/hid/hid-uclogic-params.c
drivers/hid/hid-uclogic-params.h

index 9f043f2..57ef5d3 100644 (file)
@@ -7,6 +7,7 @@
  */
 
 #include <kunit/test.h>
+#include "./hid-uclogic-params.h"
 #include "./hid-uclogic-rdesc.h"
 
 #define MAX_STR_DESC_SIZE 14
@@ -17,6 +18,7 @@ struct uclogic_parse_ugee_v2_desc_case {
        const __u8 str_desc[MAX_STR_DESC_SIZE];
        size_t str_desc_size;
        const s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
+       enum uclogic_params_frame_type frame_type;
 };
 
 static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[] = {
@@ -26,6 +28,7 @@ static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[]
                .str_desc = {},
                .str_desc_size = 0,
                .desc_params = {},
+               .frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS,
        },
        {
                .name = "resolution_with_value_0",
@@ -48,6 +51,7 @@ static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[]
                        [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF,
                        [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08,
                },
+               .frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS,
        },
        /* XP-PEN Deco L str_desc: Frame with 8 buttons */
        {
@@ -71,6 +75,7 @@ static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[]
                        [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF,
                        [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08,
                },
+               .frame_type = UCLOGIC_PARAMS_FRAME_BUTTONS,
        },
        /* PARBLO A610 PRO str_desc: Frame with 9 buttons and dial */
        {
@@ -94,6 +99,31 @@ static struct uclogic_parse_ugee_v2_desc_case uclogic_parse_ugee_v2_desc_cases[]
                        [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF,
                        [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x09,
                },
+               .frame_type = UCLOGIC_PARAMS_FRAME_DIAL,
+       },
+       /* XP-PEN Deco Pro S str_desc: Frame with 8 buttons and mouse */
+       {
+               .name = "frame_type_mouse",
+               .res = 0,
+               .str_desc = {
+                       0x0E, 0x03,
+                       0xC8, 0xB3,
+                       0x34, 0x65,
+                       0x08,
+                       0x02,
+                       0xFF, 0x1F,
+                       0xD8, 0x13,
+               },
+               .str_desc_size = 12,
+               .desc_params = {
+                       [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xB3C8,
+                       [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0x2363,
+                       [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0x6534,
+                       [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0x13EC,
+                       [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0x1FFF,
+                       [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0x08,
+               },
+               .frame_type = UCLOGIC_PARAMS_FRAME_MOUSE,
        },
 };
 
@@ -110,12 +140,14 @@ static void uclogic_parse_ugee_v2_desc_test(struct kunit *test)
 {
        int res;
        s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
+       enum uclogic_params_frame_type frame_type;
        const struct uclogic_parse_ugee_v2_desc_case *params = test->param_value;
 
        res = uclogic_params_parse_ugee_v2_desc(params->str_desc,
                                                params->str_desc_size,
                                                desc_params,
-                                               ARRAY_SIZE(desc_params));
+                                               ARRAY_SIZE(desc_params),
+                                               &frame_type);
        KUNIT_ASSERT_EQ(test, res, params->res);
 
        if (res)
@@ -139,6 +171,7 @@ static void uclogic_parse_ugee_v2_desc_test(struct kunit *test)
        KUNIT_EXPECT_EQ(test,
                        params->desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM],
                        desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM]);
+       KUNIT_EXPECT_EQ(test, params->frame_type, frame_type);
 }
 
 static struct kunit_case hid_uclogic_params_test_cases[] = {
index 182e6f8..7845dd5 100644 (file)
@@ -1064,6 +1064,7 @@ cleanup:
  * @str_desc_size:     Size of the string descriptor.
  * @desc_params:       Output description params list.
  * @desc_params_size:  Size of the output description params list.
+ * @frame_type:                Output frame type.
  *
  * Returns:
  *     Zero, if successful. A negative errno code on error.
@@ -1071,7 +1072,8 @@ cleanup:
 static int uclogic_params_parse_ugee_v2_desc(const __u8 *str_desc,
                                             size_t str_desc_size,
                                             s32 *desc_params,
-                                            size_t desc_params_size)
+                                            size_t desc_params_size,
+                                            enum uclogic_params_frame_type *frame_type)
 {
        s32 pen_x_lm, pen_y_lm;
        s32 pen_x_pm, pen_y_pm;
@@ -1091,6 +1093,7 @@ static int uclogic_params_parse_ugee_v2_desc(const __u8 *str_desc,
        pen_x_lm = get_unaligned_le16(str_desc + 2);
        pen_y_lm = get_unaligned_le16(str_desc + 4);
        frame_num_buttons = str_desc[6];
+       *frame_type = str_desc[7];
        pen_pressure_lm = get_unaligned_le16(str_desc + 8);
 
        resolution = get_unaligned_le16(str_desc + 10);
@@ -1176,6 +1179,7 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
        __u8 *str_desc = NULL;
        __u8 *rdesc_pen = NULL;
        s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
+       enum uclogic_params_frame_type frame_type;
        __u8 magic_arr[] = {
                0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
        };
@@ -1219,7 +1223,8 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
 
        rc = uclogic_params_parse_ugee_v2_desc(str_desc, str_desc_len,
                                               desc_params,
-                                              ARRAY_SIZE(desc_params));
+                                              ARRAY_SIZE(desc_params),
+                                              &frame_type);
        if (rc)
                goto cleanup;
 
@@ -1243,8 +1248,14 @@ 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 */
-       rc = uclogic_params_ugee_v2_init_frame_buttons(&p, desc_params,
-                                                      ARRAY_SIZE(desc_params));
+       switch (frame_type) {
+       case UCLOGIC_PARAMS_FRAME_BUTTONS:
+       default:
+               rc = uclogic_params_ugee_v2_init_frame_buttons(&p, desc_params,
+                                                              ARRAY_SIZE(desc_params));
+               break;
+       }
+
        if (rc)
                goto cleanup;
 
index 5bef8da..a97477c 100644 (file)
@@ -29,6 +29,16 @@ enum uclogic_params_pen_inrange {
        UCLOGIC_PARAMS_PEN_INRANGE_NONE,
 };
 
+/* Types of frames */
+enum uclogic_params_frame_type {
+       /* Frame with buttons */
+       UCLOGIC_PARAMS_FRAME_BUTTONS = 0,
+       /* Frame with buttons and a dial */
+       UCLOGIC_PARAMS_FRAME_DIAL,
+       /* Frame with buttons and a mouse (shaped as a dial + touchpad) */
+       UCLOGIC_PARAMS_FRAME_MOUSE,
+};
+
 /*
  * Pen report's subreport data.
  */