[PATCH for-5.18/uclogic 9/9] HID: uclogic: Support multiple frame input devices

From: José Expósito
Date: Sat Feb 19 2022 - 05:02:37 EST


From: Nikolai Kondrashov <spbnick@xxxxxxxxx>

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@xxxxxxxxx>
Signed-off-by: José Expósito <jose.exposito89@xxxxxxxxx>
---
drivers/hid/hid-uclogic-core.c | 19 ++++--
drivers/hid/hid-uclogic-params.c | 100 +++++++++++++++----------------
drivers/hid/hid-uclogic-params.h | 26 ++++----
3 files changed, 74 insertions(+), 71 deletions(-)

diff --git a/drivers/hid/hid-uclogic-core.c b/drivers/hid/hid-uclogic-core.c
index a02edeb30a35..05147f2d7564 100644
--- a/drivers/hid/hid-uclogic-core.c
+++ b/drivers/hid/hid-uclogic-core.c
@@ -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;
}
diff --git a/drivers/hid/hid-uclogic-params.c b/drivers/hid/hid-uclogic-params.c
index f667347ad0df..5f50ceb875d6 100644
--- a/drivers/hid/hid-uclogic-params.c
+++ b/drivers/hid/hid-uclogic-params.c
@@ -512,9 +512,12 @@ static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame,
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);
diff --git a/drivers/hid/hid-uclogic-params.h b/drivers/hid/hid-uclogic-params.h
index c18569591b75..86f616dfbb53 100644
--- a/drivers/hid/hid-uclogic-params.h
+++ b/drivers/hid/hid-uclogic-params.h
@@ -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,
--
2.25.1