HID: uclogic: Support multiple frame input devices

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>
This commit is contained in:
Nikolai Kondrashov 2022-02-19 11:01:57 +01:00 committed by Jiri Kosina
parent 2daaeff382
commit 337fa051d9
3 changed files with 75 additions and 72 deletions

View 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). * uclogic_raw_event_frame - handle raw frame events (frame HID reports).
* *
* @drvdata: Driver data. * @drvdata: Driver data.
* @frame: The parameters of the frame controls to handle.
* @data: Report data buffer, can be modified. * @data: Report data buffer, can be modified.
* @size: Report data size, bytes. * @size: Report data size, bytes.
* *
* Returns: * Returns:
* Negative value on error (stops event delivery), zero for success. * Negative value on error (stops event delivery), zero for success.
*/ */
static int uclogic_raw_event_frame(struct uclogic_drvdata *drvdata, static int uclogic_raw_event_frame(
u8 *data, int size) 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(drvdata == NULL);
WARN_ON(data == NULL && size != 0); 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 *params = &drvdata->params;
struct uclogic_params_pen_subreport *subreport; struct uclogic_params_pen_subreport *subreport;
struct uclogic_params_pen_subreport *subreport_list_end; struct uclogic_params_pen_subreport *subreport_list_end;
size_t i;
/* Do not handle anything but input reports */ /* Do not handle anything but input reports */
if (report->type != HID_INPUT_REPORT) 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 */ /* Tweak frame control reports, if necessary */
if (report_id == params->frame.id) for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
return uclogic_raw_event_frame(drvdata, data, size); if (report_id == params->frame_list[i].id) {
return uclogic_raw_event_frame(
drvdata, &params->frame_list[i],
data, size);
}
}
break; break;
} }

View File

@ -512,9 +512,12 @@ cleanup:
void uclogic_params_cleanup(struct uclogic_params *params) void uclogic_params_cleanup(struct uclogic_params *params)
{ {
if (!params->invalid) { if (!params->invalid) {
size_t i;
kfree(params->desc_ptr); kfree(params->desc_ptr);
uclogic_params_pen_cleanup(&params->pen); 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)); memset(params, 0, sizeof(*params));
} }
} }
@ -542,60 +545,53 @@ int uclogic_params_get_desc(const struct uclogic_params *params,
__u8 **pdesc, __u8 **pdesc,
unsigned int *psize) unsigned int *psize)
{ {
bool common_present; int rc = -ENOMEM;
bool pen_present; bool present = false;
bool frame_present; unsigned int size = 0;
unsigned int size;
__u8 *desc = NULL; __u8 *desc = NULL;
size_t i;
/* Check arguments */ /* Check arguments */
if (params == NULL || pdesc == NULL || psize == NULL) if (params == NULL || pdesc == NULL || psize == NULL)
return -EINVAL; return -EINVAL;
size = 0; /* 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)
common_present = (params->desc_ptr != NULL); ADD_DESC(params->desc_ptr, params->desc_size);
pen_present = (params->pen.desc_ptr != NULL); ADD_DESC(params->pen.desc_ptr, params->pen.desc_size);
frame_present = (params->frame.desc_ptr != NULL); for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
ADD_DESC(params->frame_list[i].desc_ptr,
if (common_present) params->frame_list[i].desc_size);
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;
}
WARN_ON(p != desc + size);
*psize = size;
} }
*pdesc = desc; #undef ADD_DESC
return 0;
if (present) {
*pdesc = desc;
*psize = size;
desc = NULL;
}
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"); hid_dbg(hdev, "pen v2 parameters found\n");
/* Create v2 frame parameters */ /* Create v2 frame parameters */
rc = uclogic_params_frame_init_with_desc( rc = uclogic_params_frame_init_with_desc(
&p.frame, &p.frame_list[0],
uclogic_rdesc_v2_frame_arr, uclogic_rdesc_v2_frame_arr,
uclogic_rdesc_v2_frame_size, uclogic_rdesc_v2_frame_size,
UCLOGIC_RDESC_V2_FRAME_ID); UCLOGIC_RDESC_V2_FRAME_ID);
@ -779,7 +775,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
} else if (found) { } else if (found) {
hid_dbg(hdev, "pen v1 parameters found\n"); hid_dbg(hdev, "pen v1 parameters found\n");
/* Try to probe v1 frame */ /* 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); &found, hdev);
if (rc != 0) { if (rc != 0) {
hid_err(hdev, "v1 frame probing failed: %d\n", rc); 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 */ /* Initialize frame parameters */
rc = uclogic_params_frame_init_with_desc( rc = uclogic_params_frame_init_with_desc(
&p.frame, &p.frame_list[0],
uclogic_rdesc_xppen_deco01_frame_arr, uclogic_rdesc_xppen_deco01_frame_arr,
uclogic_rdesc_xppen_deco01_frame_size, uclogic_rdesc_xppen_deco01_frame_size,
0); 0);
@ -1059,7 +1055,7 @@ int uclogic_params_init(struct uclogic_params *params,
goto cleanup; goto cleanup;
} else if (found) { } else if (found) {
rc = uclogic_params_frame_init_with_desc( rc = uclogic_params_frame_init_with_desc(
&p.frame, &p.frame_list[0],
uclogic_rdesc_ugee_g5_frame_arr, uclogic_rdesc_ugee_g5_frame_arr,
uclogic_rdesc_ugee_g5_frame_size, uclogic_rdesc_ugee_g5_frame_size,
UCLOGIC_RDESC_UGEE_G5_FRAME_ID); UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
@ -1069,9 +1065,9 @@ int uclogic_params_init(struct uclogic_params *params,
rc); rc);
goto cleanup; goto cleanup;
} }
p.frame.re_lsb = p.frame_list[0].re_lsb =
UCLOGIC_RDESC_UGEE_G5_FRAME_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; UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
} else { } else {
hid_warn(hdev, "pen parameters not found"); hid_warn(hdev, "pen parameters not found");
@ -1093,7 +1089,7 @@ int uclogic_params_init(struct uclogic_params *params,
goto cleanup; goto cleanup;
} else if (found) { } else if (found) {
rc = uclogic_params_frame_init_with_desc( rc = uclogic_params_frame_init_with_desc(
&p.frame, &p.frame_list[0],
uclogic_rdesc_ugee_ex07_frame_arr, uclogic_rdesc_ugee_ex07_frame_arr,
uclogic_rdesc_ugee_ex07_frame_size, uclogic_rdesc_ugee_ex07_frame_size,
0); 0);

View File

@ -165,10 +165,10 @@ struct uclogic_params {
*/ */
struct uclogic_params_pen pen; struct uclogic_params_pen pen;
/* /*
* Frame control parameters and optional report descriptor part. * The list of frame control parameters and optional report descriptor
* Only valid, if "invalid" is false. * 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 */ /* 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.inrange = %s\n" \
".pen.fragmented_hires = %s\n" \ ".pen.fragmented_hires = %s\n" \
".pen.tilt_y_flipped = %s\n" \ ".pen.tilt_y_flipped = %s\n" \
".frame.desc_ptr = %p\n" \ ".frame_list[0].desc_ptr = %p\n" \
".frame.desc_size = %u\n" \ ".frame_list[0].desc_size = %u\n" \
".frame.id = %u\n" \ ".frame_list[0].id = %u\n" \
".frame.re_lsb = %u\n" \ ".frame_list[0].re_lsb = %u\n" \
".frame.dev_id_byte = %u\n" ".frame_list[0].dev_id_byte = %u\n"
/* Tablet interface parameters *printf format arguments */ /* Tablet interface parameters *printf format arguments */
#define UCLOGIC_PARAMS_FMT_ARGS(_params) \ #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), \ uclogic_params_pen_inrange_to_str((_params)->pen.inrange), \
((_params)->pen.fragmented_hires ? "true" : "false"), \ ((_params)->pen.fragmented_hires ? "true" : "false"), \
((_params)->pen.tilt_y_flipped ? "true" : "false"), \ ((_params)->pen.tilt_y_flipped ? "true" : "false"), \
(_params)->frame.desc_ptr, \ (_params)->frame_list[0].desc_ptr, \
(_params)->frame.desc_size, \ (_params)->frame_list[0].desc_size, \
(_params)->frame.id, \ (_params)->frame_list[0].id, \
(_params)->frame.re_lsb, \ (_params)->frame_list[0].re_lsb, \
(_params)->frame.dev_id_byte (_params)->frame_list[0].dev_id_byte
/* Get a replacement report descriptor for a tablet's interface. */ /* Get a replacement report descriptor for a tablet's interface. */
extern int uclogic_params_get_desc(const struct uclogic_params *params, extern int uclogic_params_get_desc(const struct uclogic_params *params,