]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
HID: uclogic: Support multiple frame input devices
authorNikolai Kondrashov <spbnick@gmail.com>
Sat, 19 Feb 2022 10:01:57 +0000 (11:01 +0100)
committerJiri Kosina <jkosina@suse.cz>
Tue, 1 Mar 2022 14:28:14 +0000 (15:28 +0100)
Add support for multiple frame input devices and their parameters to
the UC-Logic driver. This prepares for creating a separate input device
for Huion HS610 virtual touch ring reports.

Signed-off-by: Nikolai Kondrashov <spbnick@gmail.com>
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 a02edeb30a35d7519955d1e9a5a1d28ec9bd08a2..05147f2d75645f745c47b35786205b4d4ef79e98 100644 (file)
@@ -296,17 +296,18 @@ static int uclogic_raw_event_pen(struct uclogic_drvdata *drvdata,
  * 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,
-                                       u8 *data, int size)
+static int uclogic_raw_event_frame(
+               struct uclogic_drvdata *drvdata,
+               const struct uclogic_params_frame *frame,
+               u8 *data, int size)
 {
-       struct uclogic_params_frame *frame = &drvdata->params.frame;
-
        WARN_ON(drvdata == NULL);
        WARN_ON(data == NULL && size != 0);
 
@@ -352,6 +353,7 @@ static int uclogic_raw_event(struct hid_device *hdev,
        struct uclogic_params *params = &drvdata->params;
        struct uclogic_params_pen_subreport *subreport;
        struct uclogic_params_pen_subreport *subreport_list_end;
+       size_t i;
 
        /* Do not handle anything but input reports */
        if (report->type != HID_INPUT_REPORT)
@@ -382,8 +384,13 @@ static int uclogic_raw_event(struct hid_device *hdev,
                }
 
                /* Tweak frame control reports, if necessary */
-               if (report_id == params->frame.id)
-                       return uclogic_raw_event_frame(drvdata, data, size);
+               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);
+                       }
+               }
 
                break;
        }
index f667347ad0df26f2cf9052c6aa51635259b7b179..5f50ceb875d6d5ef75d88ec427ed2032910d163a 100644 (file)
@@ -512,9 +512,12 @@ cleanup:
 void uclogic_params_cleanup(struct uclogic_params *params)
 {
        if (!params->invalid) {
+               size_t i;
                kfree(params->desc_ptr);
                uclogic_params_pen_cleanup(&params->pen);
-               uclogic_params_frame_cleanup(&params->frame);
+               for (i = 0; i < ARRAY_SIZE(params->frame_list); i++)
+                       uclogic_params_frame_cleanup(&params->frame_list[i]);
+
                memset(params, 0, sizeof(*params));
        }
 }
@@ -542,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.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;
 }
 
 /**
@@ -751,7 +747,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
                        hid_dbg(hdev, "pen v2 parameters found\n");
                        /* Create v2 frame parameters */
                        rc = uclogic_params_frame_init_with_desc(
-                                       &p.frame,
+                                       &p.frame_list[0],
                                        uclogic_rdesc_v2_frame_arr,
                                        uclogic_rdesc_v2_frame_size,
                                        UCLOGIC_RDESC_V2_FRAME_ID);
@@ -779,7 +775,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
        } else if (found) {
                hid_dbg(hdev, "pen v1 parameters found\n");
                /* Try to probe v1 frame */
-               rc = uclogic_params_frame_init_v1(&p.frame,
+               rc = uclogic_params_frame_init_v1(&p.frame_list[0],
                                                  &found, hdev);
                if (rc != 0) {
                        hid_err(hdev, "v1 frame probing failed: %d\n", rc);
@@ -1033,7 +1029,7 @@ 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);
@@ -1059,7 +1055,7 @@ 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);
@@ -1069,9 +1065,9 @@ int uclogic_params_init(struct uclogic_params *params,
                                        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");
@@ -1093,7 +1089,7 @@ 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_ex07_frame_arr,
                                uclogic_rdesc_ugee_ex07_frame_size,
                                0);
index c18569591b7579dbfb964b31e040d3d49eac19e8..86f616dfbb53dddc576ff6e81972e069f2eb04b2 100644 (file)
@@ -165,10 +165,10 @@ struct uclogic_params {
         */
        struct uclogic_params_pen pen;
        /*
-        * Frame control parameters and optional report descriptor part.
-        * Only valid, if "invalid" is false.
+        * The list of frame control parameters and optional report descriptor
+        * parts. Only valid, if "invalid" is false.
         */
-       struct uclogic_params_frame frame;
+       struct uclogic_params_frame frame_list[1];
 };
 
 /* Initialize a tablet interface and discover its parameters */
@@ -187,11 +187,11 @@ extern int uclogic_params_init(struct uclogic_params *params,
                ".pen.inrange = %s\n"                           \
                ".pen.fragmented_hires = %s\n"                  \
                ".pen.tilt_y_flipped = %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"
+               ".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) \
@@ -206,11 +206,11 @@ extern int uclogic_params_init(struct uclogic_params *params,
                uclogic_params_pen_inrange_to_str((_params)->pen.inrange),  \
                ((_params)->pen.fragmented_hires ? "true" : "false"),       \
                ((_params)->pen.tilt_y_flipped ? "true" : "false"),         \
-               (_params)->frame.desc_ptr,                                  \
-               (_params)->frame.desc_size,                                 \
-               (_params)->frame.id,                                        \
-               (_params)->frame.re_lsb,                                    \
-               (_params)->frame.dev_id_byte
+               (_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,