Commit b146dbbd authored by Jiri Kosina's avatar Jiri Kosina
Browse files

Merge branch 'for-5.18/uclogic' into for-linus

- integration of first part of DIGImend [1] patches in order to vastly
  improve Linux support of tablets (Nikolai Kondrashov, José Expósito)

[1] https://github.com/DIGImend/digimend-kernel-drivers
parents bda3c85a 337fa051
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -614,7 +614,7 @@

#define USB_VENDOR_ID_HUION		0x256c
#define USB_DEVICE_ID_HUION_TABLET	0x006e
#define USB_DEVICE_ID_HUION_HS64	0x006d
#define USB_DEVICE_ID_HUION_TABLET2	0x006d

#define USB_VENDOR_ID_IBM					0x04b3
#define USB_DEVICE_ID_IBM_SCROLLPOINT_III			0x3100
+155 −103
Original line number Diff line number Diff line
@@ -81,24 +81,6 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
	return rdesc;
}

static int uclogic_input_mapping(struct hid_device *hdev,
				 struct hid_input *hi,
				 struct hid_field *field,
				 struct hid_usage *usage,
				 unsigned long **bit,
				 int *max)
{
	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
	struct uclogic_params *params = &drvdata->params;

	/* discard the unused pen interface */
	if (params->pen_unused && (field->application == HID_DG_PEN))
		return -1;

	/* let hid-core decide what to do */
	return 0;
}

static int uclogic_input_configured(struct hid_device *hdev,
		struct hid_input *hi)
{
@@ -246,27 +228,26 @@ static int uclogic_resume(struct hid_device *hdev)
}
#endif

static int uclogic_raw_event(struct hid_device *hdev,
				struct hid_report *report,
/**
 * uclogic_raw_event_pen - handle raw pen events (pen HID reports).
 *
 * @drvdata:	Driver data.
 * @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_pen(struct uclogic_drvdata *drvdata,
					u8 *data, int size)
{
	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
	struct uclogic_params *params = &drvdata->params;
	struct uclogic_params_pen *pen = &drvdata->params.pen;

	WARN_ON(drvdata == NULL);
	WARN_ON(data == NULL && size != 0);

	/* Tweak pen reports, if necessary */
	if (!params->pen_unused &&
	    (report->type == HID_INPUT_REPORT) &&
	    (report->id == params->pen.id) &&
	    (size >= 2)) {
		/* If it's the "virtual" frame controls report */
		if (params->frame.id != 0 &&
		    data[1] & params->pen_frame_flag) {
			/* Change to virtual frame controls report ID */
			data[0] = params->frame.id;
			return 0;
		}
	/* If in-range reports are inverted */
		if (params->pen.inrange ==
	if (pen->inrange ==
		UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) {
		/* Invert the in-range bit */
		data[1] ^= 0x40;
@@ -275,7 +256,7 @@ static int uclogic_raw_event(struct hid_device *hdev,
	 * If report contains fragmented high-resolution pen
	 * coordinates
	 */
		if (size >= 10 && params->pen.fragmented_hires) {
	if (size >= 10 && pen->fragmented_hires) {
		u8 pressure_low_byte;
		u8 pressure_high_byte;

@@ -297,28 +278,47 @@ static int uclogic_raw_event(struct hid_device *hdev,
		data[9] = pressure_high_byte;
	}
	/* If we need to emulate in-range detection */
		if (params->pen.inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
	if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
		/* Set in-range bit */
		data[1] |= 0x40;
		/* (Re-)start in-range timeout */
		mod_timer(&drvdata->inrange_timer,
				jiffies + msecs_to_jiffies(100));
	}
	/* If we report tilt and Y direction is flipped */
	if (size >= 12 && pen->tilt_y_flipped)
		data[11] = -data[11];

	return 0;
}

	/* Tweak frame control reports, if necessary */
	if ((report->type == HID_INPUT_REPORT) &&
	    (report->id == params->frame.id)) {
/**
 * 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,
		const struct uclogic_params_frame *frame,
		u8 *data, int size)
{
	WARN_ON(drvdata == NULL);
	WARN_ON(data == NULL && size != 0);

	/* If need to, and can, set pad device ID for Wacom drivers */
		if (params->frame.dev_id_byte > 0 &&
		    params->frame.dev_id_byte < size) {
			data[params->frame.dev_id_byte] = 0xf;
	if (frame->dev_id_byte > 0 && frame->dev_id_byte < size) {
		data[frame->dev_id_byte] = 0xf;
	}
	/* If need to, and can, read rotary encoder state change */
		if (params->frame.re_lsb > 0 &&
		    params->frame.re_lsb / 8 < size) {
			unsigned int byte = params->frame.re_lsb / 8;
			unsigned int bit = params->frame.re_lsb % 8;
	if (frame->re_lsb > 0 && frame->re_lsb / 8 < size) {
		unsigned int byte = frame->re_lsb / 8;
		unsigned int bit = frame->re_lsb % 8;

		u8 change;
		u8 prev_state = drvdata->re_state;
@@ -340,6 +340,59 @@ static int uclogic_raw_event(struct hid_device *hdev,
		/* Remember state */
		drvdata->re_state = state;
	}

	return 0;
}

static int uclogic_raw_event(struct hid_device *hdev,
				struct hid_report *report,
				u8 *data, int size)
{
	unsigned int report_id = report->id;
	struct uclogic_drvdata *drvdata = hid_get_drvdata(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)
		return 0;

	while (true) {
		/* Tweak pen reports, if necessary */
		if ((report_id == params->pen.id) && (size >= 2)) {
			subreport_list_end =
				params->pen.subreport_list +
				ARRAY_SIZE(params->pen.subreport_list);
			/* Try to match a subreport */
			for (subreport = params->pen.subreport_list;
			     subreport < subreport_list_end; subreport++) {
				if (subreport->value != 0 &&
				    subreport->value == data[1]) {
					break;
				}
			}
			/* If a subreport matched */
			if (subreport < subreport_list_end) {
				/* Change to subreport ID, and restart */
				report_id = data[0] = subreport->id;
				continue;
			} else {
				return uclogic_raw_event_pen(drvdata, data, size);
			}
		}

		/* Tweak frame control reports, if necessary */
		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;
	}

	return 0;
@@ -373,7 +426,7 @@ static const struct hid_device_id uclogic_devices[] = {
	{ HID_USB_DEVICE(USB_VENDOR_ID_HUION,
				USB_DEVICE_ID_HUION_TABLET) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_HUION,
				USB_DEVICE_ID_HUION_HS64) },
				USB_DEVICE_ID_HUION_TABLET2) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_TRUST,
				USB_DEVICE_ID_TRUST_PANORA_TABLET) },
	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
@@ -415,7 +468,6 @@ static struct hid_driver uclogic_driver = {
	.remove = uclogic_remove,
	.report_fixup = uclogic_report_fixup,
	.raw_event = uclogic_raw_event,
	.input_mapping = uclogic_input_mapping,
	.input_configured = uclogic_input_configured,
#ifdef CONFIG_PM
	.resume	          = uclogic_resume,
+89 −109
Original line number Diff line number Diff line
@@ -207,8 +207,8 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
	 * Generate pen report descriptor
	 */
	desc_ptr = uclogic_rdesc_template_apply(
				uclogic_rdesc_pen_v1_template_arr,
				uclogic_rdesc_pen_v1_template_size,
				uclogic_rdesc_v1_pen_template_arr,
				uclogic_rdesc_v1_pen_template_size,
				desc_params, ARRAY_SIZE(desc_params));
	if (desc_ptr == NULL) {
		rc = -ENOMEM;
@@ -221,8 +221,8 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
	memset(pen, 0, sizeof(*pen));
	pen->desc_ptr = desc_ptr;
	desc_ptr = NULL;
	pen->desc_size = uclogic_rdesc_pen_v1_template_size;
	pen->id = UCLOGIC_RDESC_PEN_V1_ID;
	pen->desc_size = uclogic_rdesc_v1_pen_template_size;
	pen->id = UCLOGIC_RDESC_V1_PEN_ID;
	pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED;
	found = true;
finish:
@@ -351,8 +351,8 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
	 * Generate pen report descriptor
	 */
	desc_ptr = uclogic_rdesc_template_apply(
				uclogic_rdesc_pen_v2_template_arr,
				uclogic_rdesc_pen_v2_template_size,
				uclogic_rdesc_v2_pen_template_arr,
				uclogic_rdesc_v2_pen_template_size,
				desc_params, ARRAY_SIZE(desc_params));
	if (desc_ptr == NULL) {
		rc = -ENOMEM;
@@ -365,10 +365,11 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
	memset(pen, 0, sizeof(*pen));
	pen->desc_ptr = desc_ptr;
	desc_ptr = NULL;
	pen->desc_size = uclogic_rdesc_pen_v2_template_size;
	pen->id = UCLOGIC_RDESC_PEN_V2_ID;
	pen->desc_size = uclogic_rdesc_v2_pen_template_size;
	pen->id = UCLOGIC_RDESC_V2_PEN_ID;
	pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE;
	pen->fragmented_hires = true;
	pen->tilt_y_flipped = true;
	found = true;
finish:
	*pfound = found;
@@ -430,8 +431,8 @@ static int uclogic_params_frame_init_with_desc(
}

/**
 * uclogic_params_frame_init_v1_buttonpad() - initialize abstract buttonpad
 * on a v1 tablet interface.
 * uclogic_params_frame_init_v1() - initialize v1 tablet interface frame
 * controls.
 *
 * @frame:	Pointer to the frame parameters to initialize (to be cleaned
 *		up with uclogic_params_frame_cleanup()). Not modified in case
@@ -445,8 +446,7 @@ static int uclogic_params_frame_init_with_desc(
 * Returns:
 *	Zero, if successful. A negative errno code on error.
 */
static int uclogic_params_frame_init_v1_buttonpad(
					struct uclogic_params_frame *frame,
static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame,
					bool *pfound,
					struct hid_device *hdev)
{
@@ -487,9 +487,9 @@ static int uclogic_params_frame_init_v1_buttonpad(
		hid_dbg(hdev, "generic buttons enabled\n");
		rc = uclogic_params_frame_init_with_desc(
				frame,
				uclogic_rdesc_buttonpad_v1_arr,
				uclogic_rdesc_buttonpad_v1_size,
				UCLOGIC_RDESC_BUTTONPAD_V1_ID);
				uclogic_rdesc_v1_frame_arr,
				uclogic_rdesc_v1_frame_size,
				UCLOGIC_RDESC_V1_FRAME_ID);
		if (rc != 0)
			goto cleanup;
		found = true;
@@ -512,10 +512,12 @@ static int uclogic_params_frame_init_v1_buttonpad(
void uclogic_params_cleanup(struct uclogic_params *params)
{
	if (!params->invalid) {
		size_t i;
		kfree(params->desc_ptr);
		if (!params->pen_unused)
		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));
	}
}
@@ -543,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_unused && 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;
		}

		WARN_ON(p != 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);
	}

#undef ADD_DESC

	if (present) {
		*pdesc = desc;
		*psize = size;
		desc = NULL;
	}

	*pdesc = desc;
	return 0;
	rc = 0;
cleanup:
	kfree(desc);
	return rc;
}

/**
@@ -679,21 +674,6 @@ static int uclogic_params_init_with_opt_desc(struct uclogic_params *params,
	return rc;
}

/**
 * uclogic_params_init_with_pen_unused() - initialize tablet interface
 * parameters preserving original reports and generic HID processing, but
 * disabling pen usage.
 *
 * @params:		Parameters to initialize (to be cleaned with
 *			uclogic_params_cleanup()). Not modified in case of
 *			error. Cannot be NULL.
 */
static void uclogic_params_init_with_pen_unused(struct uclogic_params *params)
{
	memset(params, 0, sizeof(*params));
	params->pen_unused = true;
}

/**
 * uclogic_params_huion_init() - initialize a Huion tablet interface and discover
 * its parameters.
@@ -733,8 +713,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params,

	/* If it's not a pen interface */
	if (bInterfaceNumber != 0) {
		/* TODO: Consider marking the interface invalid */
		uclogic_params_init_with_pen_unused(&p);
		uclogic_params_init_invalid(&p);
		goto output;
	}

@@ -766,20 +745,22 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
			goto cleanup;
		} else if (found) {
			hid_dbg(hdev, "pen v2 parameters found\n");
			/* Create v2 buttonpad parameters */
			/* Create v2 frame parameters */
			rc = uclogic_params_frame_init_with_desc(
					&p.frame,
					uclogic_rdesc_buttonpad_v2_arr,
					uclogic_rdesc_buttonpad_v2_size,
					UCLOGIC_RDESC_BUTTONPAD_V2_ID);
					&p.frame_list[0],
					uclogic_rdesc_v2_frame_arr,
					uclogic_rdesc_v2_frame_size,
					UCLOGIC_RDESC_V2_FRAME_ID);
			if (rc != 0) {
				hid_err(hdev,
					"failed creating v2 buttonpad parameters: %d\n",
					"failed creating v2 frame parameters: %d\n",
					rc);
				goto cleanup;
			}
			/* Set bitmask marking frame reports in pen reports */
			p.pen_frame_flag = 0x20;
			/* Link frame button subreports from pen reports */
			p.pen.subreport_list[0].value = 0xe0;
			p.pen.subreport_list[0].id =
				UCLOGIC_RDESC_V2_FRAME_ID;
			goto output;
		}
		hid_dbg(hdev, "pen v2 parameters not found\n");
@@ -793,19 +774,20 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
		goto cleanup;
	} else if (found) {
		hid_dbg(hdev, "pen v1 parameters found\n");
		/* Try to probe v1 buttonpad */
		rc = uclogic_params_frame_init_v1_buttonpad(
						&p.frame,
		/* Try to probe v1 frame */
		rc = uclogic_params_frame_init_v1(&p.frame_list[0],
						  &found, hdev);
		if (rc != 0) {
			hid_err(hdev, "v1 buttonpad probing failed: %d\n", rc);
			hid_err(hdev, "v1 frame probing failed: %d\n", rc);
			goto cleanup;
		}
		hid_dbg(hdev, "buttonpad v1 parameters%s found\n",
		hid_dbg(hdev, "frame v1 parameters%s found\n",
			(found ? "" : " not"));
		if (found) {
			/* Set bitmask marking frame reports */
			p.pen_frame_flag = 0x20;
			/* Link frame button subreports from pen reports */
			p.pen.subreport_list[0].value = 0xe0;
			p.pen.subreport_list[0].id =
				UCLOGIC_RDESC_V1_FRAME_ID;
		}
		goto output;
	}
@@ -992,7 +974,7 @@ int uclogic_params_init(struct uclogic_params *params,
	case VID_PID(USB_VENDOR_ID_HUION,
		     USB_DEVICE_ID_HUION_TABLET):
	case VID_PID(USB_VENDOR_ID_HUION,
		     USB_DEVICE_ID_HUION_HS64):
		     USB_DEVICE_ID_HUION_TABLET2):
	case VID_PID(USB_VENDOR_ID_UCLOGIC,
		     USB_DEVICE_ID_HUION_TABLET):
	case VID_PID(USB_VENDOR_ID_UCLOGIC,
@@ -1032,8 +1014,7 @@ int uclogic_params_init(struct uclogic_params *params,
				uclogic_params_init_invalid(&p);
			}
		} else {
			/* TODO: Consider marking the interface invalid */
			uclogic_params_init_with_pen_unused(&p);
			uclogic_params_init_invalid(&p);
		}
		break;
	case VID_PID(USB_VENDOR_ID_UGEE,
@@ -1048,15 +1029,14 @@ 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);
			if (rc != 0)
				goto cleanup;
		} else {
			/* TODO: Consider marking the interface invalid */
			uclogic_params_init_with_pen_unused(&p);
			uclogic_params_init_invalid(&p);
		}
		break;
	case VID_PID(USB_VENDOR_ID_TRUST,
@@ -1075,19 +1055,19 @@ 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);
			if (rc != 0) {
				hid_err(hdev,
					"failed creating buttonpad parameters: %d\n",
					"failed creating frame parameters: %d\n",
					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");
@@ -1109,13 +1089,13 @@ int uclogic_params_init(struct uclogic_params *params,
			goto cleanup;
		} else if (found) {
			rc = uclogic_params_frame_init_with_desc(
				&p.frame,
				uclogic_rdesc_ugee_ex07_buttonpad_arr,
				uclogic_rdesc_ugee_ex07_buttonpad_size,
				&p.frame_list[0],
				uclogic_rdesc_ugee_ex07_frame_arr,
				uclogic_rdesc_ugee_ex07_frame_size,
				0);
			if (rc != 0) {
				hid_err(hdev,
					"failed creating buttonpad parameters: %d\n",
					"failed creating frame parameters: %d\n",
					rc);
				goto cleanup;
			}
+54 −38
Original line number Diff line number Diff line
@@ -33,6 +33,25 @@ enum uclogic_params_pen_inrange {
extern const char *uclogic_params_pen_inrange_to_str(
			enum uclogic_params_pen_inrange inrange);


/*
 * Pen report's subreport data.
 */
struct uclogic_params_pen_subreport {
	/*
	 * The value of the second byte of the pen report indicating this
	 * subreport. If zero, the subreport should be considered invalid and
	 * not matched.
	 */
	__u8 value;

	/*
	 * The ID to be assigned to the report, if the second byte of the pen
	 * report is equal to "value". Only valid if "value" is not zero.
	 */
	__u8 id;
};

/*
 * Tablet interface's pen input parameters.
 *
@@ -54,6 +73,8 @@ struct uclogic_params_pen {
	unsigned int desc_size;
	/* Report ID, if reports should be tweaked, zero if not */
	unsigned int id;
	/* The list of subreports */
	struct uclogic_params_pen_subreport subreport_list[1];
	/* Type of in-range reporting, only valid if "id" is not zero */
	enum uclogic_params_pen_inrange inrange;
	/*
@@ -62,6 +83,12 @@ struct uclogic_params_pen {
	 * Only valid if "id" is not zero.
	 */
	bool fragmented_hires;
	/*
	 * True if the pen reports tilt in bytes at offset 10 (X) and 11 (Y),
	 * and the Y tilt direction is flipped.
	 * Only valid if "id" is not zero.
	 */
	bool tilt_y_flipped;
};

/*
@@ -132,28 +159,16 @@ struct uclogic_params {
	 * Only valid, if "desc_ptr" is not NULL.
	 */
	unsigned int desc_size;
	/*
	 * True, if pen usage in report descriptor is invalid, when present.
	 * Only valid, if "invalid" is false.
	 */
	bool pen_unused;
	/*
	 * Pen parameters and optional report descriptor part.
	 * Only valid if "pen_unused" is valid and false.
	 */
	struct uclogic_params_pen pen;
	/*
	 * Frame control parameters and optional report descriptor part.
	 * Only valid, if "invalid" is false.
	 */
	struct uclogic_params_frame frame;
	struct uclogic_params_pen pen;
	/*
	 * Bitmask matching frame controls "sub-report" flag in the second
	 * byte of the pen report, or zero if it's not expected.
	 * Only valid if both "pen" and "frame" are valid, and "frame.id" is
	 * not zero.
	 * The list of frame control parameters and optional report descriptor
	 * parts. Only valid, if "invalid" is false.
	 */
	__u8 pen_frame_flag;
	struct uclogic_params_frame frame_list[1];
};

/* Initialize a tablet interface and discover its parameters */
@@ -165,36 +180,37 @@ extern int uclogic_params_init(struct uclogic_params *params,
		".invalid = %s\n"                               \
		".desc_ptr = %p\n"                              \
		".desc_size = %u\n"                             \
		".pen_unused = %s\n"                \
		".pen.desc_ptr = %p\n"                          \
		".pen.desc_size = %u\n"                         \
		".pen.id = %u\n"                                \
		".pen.subreport_list[0] = {0x%02hhx, %hhu}\n"   \
		".pen.inrange = %s\n"                           \
		".pen.fragmented_hires = %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"         \
		".pen_frame_flag = 0x%02x\n"
		".pen.tilt_y_flipped = %s\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) \
		((_params)->invalid ? "true" : "false"),                    \
		(_params)->desc_ptr,                                        \
		(_params)->desc_size,                                       \
		((_params)->pen_unused ? "true" : "false"),                 \
		(_params)->pen.desc_ptr,                                    \
		(_params)->pen.desc_size,                                   \
		(_params)->pen.id,                                          \
		(_params)->pen.subreport_list[0].value,                     \
		(_params)->pen.subreport_list[0].id,                        \
		uclogic_params_pen_inrange_to_str((_params)->pen.inrange),  \
		((_params)->pen.fragmented_hires ? "true" : "false"),       \
		(_params)->frame.desc_ptr,                                  \
		(_params)->frame.desc_size,                                 \
		(_params)->frame.id,                                        \
		(_params)->frame.re_lsb,                                    \
		(_params)->frame.dev_id_byte,                               \
		(_params)->pen_frame_flag
		((_params)->pen.tilt_y_flipped ? "true" : "false"),         \
		(_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,
+40 −29

File changed.

Preview size limit exceeded, changes collapsed.

Loading