Commit 337fa051 authored by Nikolai Kondrashov's avatar Nikolai Kondrashov Committed by Jiri Kosina
Browse files

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: default avatarNikolai Kondrashov <spbnick@gmail.com>
Signed-off-by: default avatarJosé Expósito <jose.exposito89@gmail.com>
Signed-off-by: default avatarJiri Kosina <jkosina@suse.cz>
parent 2daaeff3
Loading
Loading
Loading
Loading
+13 −6
Original line number Original line Diff line number Diff line
@@ -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(
		struct uclogic_drvdata *drvdata,
		const struct uclogic_params_frame *frame,
		u8 *data, int size)
		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;
	}
	}
+48 −52
Original line number Original line Diff line number Diff line
@@ -512,9 +512,12 @@ static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame,
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) \
	common_present = (params->desc_ptr != NULL);
	do {                                                        \
	pen_present = (params->pen.desc_ptr != NULL);
		unsigned int new_size;                              \
	frame_present = (params->frame.desc_ptr != NULL);
		__u8 *new_desc;                                     \

		if ((_desc_ptr) == NULL) {                          \
	if (common_present)
			break;                                      \
		size += params->desc_size;
		}                                                   \
	if (pen_present)
		new_size = size + (_desc_size);                     \
		size += params->pen.desc_size;
		new_desc = krealloc(desc, new_size, GFP_KERNEL);    \
	if (frame_present)
		if (new_desc == NULL) {                             \
		size += params->frame.desc_size;
			goto cleanup;                               \

		}                                                   \
	if (common_present || pen_present || frame_present) {
		memcpy(new_desc + size, (_desc_ptr), (_desc_size)); \
		__u8 *p;
		desc = new_desc;                                    \

		size = new_size;                                    \
		desc = kmalloc(size, GFP_KERNEL);
		present = true;                                     \
		if (desc == NULL)
	} while (0)
			return -ENOMEM;

		p = desc;
	ADD_DESC(params->desc_ptr, params->desc_size);

	ADD_DESC(params->pen.desc_ptr, params->pen.desc_size);
		if (common_present) {
	for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
			memcpy(p, params->desc_ptr,
		ADD_DESC(params->frame_list[i].desc_ptr,
				params->desc_size);
				params->frame_list[i].desc_size);
			p += params->desc_size;
	}
		}

		if (pen_present) {
#undef ADD_DESC
			memcpy(p, params->pen.desc_ptr,

				params->pen.desc_size);
	if (present) {
			p += params->pen.desc_size;
		*pdesc = desc;
		}
		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;
		*psize = size;
		desc = NULL;
	}
	}

	rc = 0;
	*pdesc = desc;
cleanup:
	return 0;
	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);
+13 −13
Original line number Original line Diff line number Diff line
@@ -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,