1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  *  HID driver for UC-Logic devices not fully compliant with HID standard
4  *  - tablet initialization and parameter retrieval
5  *
6  *  Copyright (c) 2018 Nikolai Kondrashov
7  */
8 
9 /*
10  * This program is free software; you can redistribute it and/or modify it
11  * under the terms of the GNU General Public License as published by the Free
12  * Software Foundation; either version 2 of the License, or (at your option)
13  * any later version.
14  */
15 
16 #include "hid-uclogic-params.h"
17 #include "hid-uclogic-rdesc.h"
18 #include "usbhid/usbhid.h"
19 #include "hid-ids.h"
20 #include <linux/ctype.h>
21 #include <asm/unaligned.h>
22 
23 /**
24  * uclogic_params_pen_inrange_to_str() - Convert a pen in-range reporting type
25  *                                       to a string.
26  *
27  * @inrange:	The in-range reporting type to convert.
28  *
29  * Returns:
30  *	The string representing the type, or NULL if the type is unknown.
31  */
32 static const char *uclogic_params_pen_inrange_to_str(
33 				enum uclogic_params_pen_inrange inrange)
34 {
35 	switch (inrange) {
36 	case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL:
37 		return "normal";
38 	case UCLOGIC_PARAMS_PEN_INRANGE_INVERTED:
39 		return "inverted";
40 	case UCLOGIC_PARAMS_PEN_INRANGE_NONE:
41 		return "none";
42 	default:
43 		return NULL;
44 	}
45 }
46 
47 /**
48  * Dump tablet interface pen parameters with hid_dbg(), indented with one tab.
49  *
50  * @hdev:	The HID device the pen parameters describe.
51  * @pen:	The pen parameters to dump.
52  */
53 static void uclogic_params_pen_hid_dbg(const struct hid_device *hdev,
54 					const struct uclogic_params_pen *pen)
55 {
56 	size_t i;
57 
58 	hid_dbg(hdev, "\t.usage_invalid = %s\n",
59 		(pen->usage_invalid ? "true" : "false"));
60 	hid_dbg(hdev, "\t.desc_ptr = %p\n", pen->desc_ptr);
61 	hid_dbg(hdev, "\t.desc_size = %u\n", pen->desc_size);
62 	hid_dbg(hdev, "\t.id = %u\n", pen->id);
63 	hid_dbg(hdev, "\t.subreport_list = {\n");
64 	for (i = 0; i < ARRAY_SIZE(pen->subreport_list); i++) {
65 		hid_dbg(hdev, "\t\t{0x%02hhx, %hhu}%s\n",
66 			pen->subreport_list[i].value,
67 			pen->subreport_list[i].id,
68 			i < (ARRAY_SIZE(pen->subreport_list) - 1) ? "," : "");
69 	}
70 	hid_dbg(hdev, "\t}\n");
71 	hid_dbg(hdev, "\t.inrange = %s\n",
72 		uclogic_params_pen_inrange_to_str(pen->inrange));
73 	hid_dbg(hdev, "\t.fragmented_hires = %s\n",
74 		(pen->fragmented_hires ? "true" : "false"));
75 	hid_dbg(hdev, "\t.tilt_y_flipped = %s\n",
76 		(pen->tilt_y_flipped ? "true" : "false"));
77 }
78 
79 /**
80  * Dump tablet interface frame parameters with hid_dbg(), indented with two
81  * tabs.
82  *
83  * @hdev:	The HID device the pen parameters describe.
84  * @frame:	The frame parameters to dump.
85  */
86 static void uclogic_params_frame_hid_dbg(
87 				const struct hid_device *hdev,
88 				const struct uclogic_params_frame *frame)
89 {
90 	hid_dbg(hdev, "\t\t.desc_ptr = %p\n", frame->desc_ptr);
91 	hid_dbg(hdev, "\t\t.desc_size = %u\n", frame->desc_size);
92 	hid_dbg(hdev, "\t\t.id = %u\n", frame->id);
93 	hid_dbg(hdev, "\t\t.suffix = %s\n", frame->suffix);
94 	hid_dbg(hdev, "\t\t.re_lsb = %u\n", frame->re_lsb);
95 	hid_dbg(hdev, "\t\t.dev_id_byte = %u\n", frame->dev_id_byte);
96 	hid_dbg(hdev, "\t\t.touch_byte = %u\n", frame->touch_byte);
97 	hid_dbg(hdev, "\t\t.touch_max = %hhd\n", frame->touch_max);
98 	hid_dbg(hdev, "\t\t.touch_flip_at = %hhd\n",
99 		frame->touch_flip_at);
100 	hid_dbg(hdev, "\t\t.bitmap_dial_byte = %u\n",
101 		frame->bitmap_dial_byte);
102 }
103 
104 /**
105  * Dump tablet interface parameters with hid_dbg().
106  *
107  * @hdev:	The HID device the parameters describe.
108  * @params:	The parameters to dump.
109  */
110 void uclogic_params_hid_dbg(const struct hid_device *hdev,
111 				const struct uclogic_params *params)
112 {
113 	size_t i;
114 
115 	hid_dbg(hdev, ".invalid = %s\n",
116 		params->invalid ? "true" : "false");
117 	hid_dbg(hdev, ".desc_ptr = %p\n", params->desc_ptr);
118 	hid_dbg(hdev, ".desc_size = %u\n", params->desc_size);
119 	hid_dbg(hdev, ".pen = {\n");
120 	uclogic_params_pen_hid_dbg(hdev, &params->pen);
121 	hid_dbg(hdev, "\t}\n");
122 	hid_dbg(hdev, ".frame_list = {\n");
123 	for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
124 		hid_dbg(hdev, "\t{\n");
125 		uclogic_params_frame_hid_dbg(hdev, &params->frame_list[i]);
126 		hid_dbg(hdev, "\t}%s\n",
127 			i < (ARRAY_SIZE(params->frame_list) - 1) ? "," : "");
128 	}
129 	hid_dbg(hdev, "}\n");
130 }
131 
132 /**
133  * uclogic_params_get_str_desc - retrieve a string descriptor from a HID
134  * device interface, putting it into a kmalloc-allocated buffer as is, without
135  * character encoding conversion.
136  *
137  * @pbuf:	Location for the kmalloc-allocated buffer pointer containing
138  *		the retrieved descriptor. Not modified in case of error.
139  *		Can be NULL to have retrieved descriptor discarded.
140  * @hdev:	The HID device of the tablet interface to retrieve the string
141  *		descriptor from. Cannot be NULL.
142  * @idx:	Index of the string descriptor to request from the device.
143  * @len:	Length of the buffer to allocate and the data to retrieve.
144  *
145  * Returns:
146  *	number of bytes retrieved (<= len),
147  *	-EPIPE, if the descriptor was not found, or
148  *	another negative errno code in case of other error.
149  */
150 static int uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev,
151 					__u8 idx, size_t len)
152 {
153 	int rc;
154 	struct usb_device *udev;
155 	__u8 *buf = NULL;
156 
157 	/* Check arguments */
158 	if (hdev == NULL) {
159 		rc = -EINVAL;
160 		goto cleanup;
161 	}
162 
163 	udev = hid_to_usb_dev(hdev);
164 
165 	buf = kmalloc(len, GFP_KERNEL);
166 	if (buf == NULL) {
167 		rc = -ENOMEM;
168 		goto cleanup;
169 	}
170 
171 	rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
172 				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
173 				(USB_DT_STRING << 8) + idx,
174 				0x0409, buf, len,
175 				USB_CTRL_GET_TIMEOUT);
176 	if (rc == -EPIPE) {
177 		hid_dbg(hdev, "string descriptor #%hhu not found\n", idx);
178 		goto cleanup;
179 	} else if (rc < 0) {
180 		hid_err(hdev,
181 			"failed retrieving string descriptor #%u: %d\n",
182 			idx, rc);
183 		goto cleanup;
184 	}
185 
186 	if (pbuf != NULL) {
187 		*pbuf = buf;
188 		buf = NULL;
189 	}
190 
191 cleanup:
192 	kfree(buf);
193 	return rc;
194 }
195 
196 /**
197  * uclogic_params_pen_cleanup - free resources used by struct
198  * uclogic_params_pen (tablet interface's pen input parameters).
199  * Can be called repeatedly.
200  *
201  * @pen:	Pen input parameters to cleanup. Cannot be NULL.
202  */
203 static void uclogic_params_pen_cleanup(struct uclogic_params_pen *pen)
204 {
205 	kfree(pen->desc_ptr);
206 	memset(pen, 0, sizeof(*pen));
207 }
208 
209 /**
210  * uclogic_params_pen_init_v1() - initialize tablet interface pen
211  * input and retrieve its parameters from the device, using v1 protocol.
212  *
213  * @pen:	Pointer to the pen parameters to initialize (to be
214  *		cleaned up with uclogic_params_pen_cleanup()). Not modified in
215  *		case of error, or if parameters are not found. Cannot be NULL.
216  * @pfound:	Location for a flag which is set to true if the parameters
217  *		were found, and to false if not (e.g. device was
218  *		incompatible). Not modified in case of error. Cannot be NULL.
219  * @hdev:	The HID device of the tablet interface to initialize and get
220  *		parameters from. Cannot be NULL.
221  *
222  * Returns:
223  *	Zero, if successful. A negative errno code on error.
224  */
225 static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
226 				      bool *pfound,
227 				      struct hid_device *hdev)
228 {
229 	int rc;
230 	bool found = false;
231 	/* Buffer for (part of) the string descriptor */
232 	__u8 *buf = NULL;
233 	/* Minimum descriptor length required, maximum seen so far is 18 */
234 	const int len = 12;
235 	s32 resolution;
236 	/* Pen report descriptor template parameters */
237 	s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
238 	__u8 *desc_ptr = NULL;
239 
240 	/* Check arguments */
241 	if (pen == NULL || pfound == NULL || hdev == NULL) {
242 		rc = -EINVAL;
243 		goto cleanup;
244 	}
245 
246 	/*
247 	 * Read string descriptor containing pen input parameters.
248 	 * The specific string descriptor and data were discovered by sniffing
249 	 * the Windows driver traffic.
250 	 * NOTE: This enables fully-functional tablet mode.
251 	 */
252 	rc = uclogic_params_get_str_desc(&buf, hdev, 100, len);
253 	if (rc == -EPIPE) {
254 		hid_dbg(hdev,
255 			"string descriptor with pen parameters not found, assuming not compatible\n");
256 		goto finish;
257 	} else if (rc < 0) {
258 		hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
259 		goto cleanup;
260 	} else if (rc != len) {
261 		hid_dbg(hdev,
262 			"string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n",
263 			rc, len);
264 		goto finish;
265 	}
266 
267 	/*
268 	 * Fill report descriptor parameters from the string descriptor
269 	 */
270 	desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
271 		get_unaligned_le16(buf + 2);
272 	desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
273 		get_unaligned_le16(buf + 4);
274 	desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
275 		get_unaligned_le16(buf + 8);
276 	resolution = get_unaligned_le16(buf + 10);
277 	if (resolution == 0) {
278 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
279 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
280 	} else {
281 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
282 			desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
283 			resolution;
284 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
285 			desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
286 			resolution;
287 	}
288 	kfree(buf);
289 	buf = NULL;
290 
291 	/*
292 	 * Generate pen report descriptor
293 	 */
294 	desc_ptr = uclogic_rdesc_template_apply(
295 				uclogic_rdesc_v1_pen_template_arr,
296 				uclogic_rdesc_v1_pen_template_size,
297 				desc_params, ARRAY_SIZE(desc_params));
298 	if (desc_ptr == NULL) {
299 		rc = -ENOMEM;
300 		goto cleanup;
301 	}
302 
303 	/*
304 	 * Fill-in the parameters
305 	 */
306 	memset(pen, 0, sizeof(*pen));
307 	pen->desc_ptr = desc_ptr;
308 	desc_ptr = NULL;
309 	pen->desc_size = uclogic_rdesc_v1_pen_template_size;
310 	pen->id = UCLOGIC_RDESC_V1_PEN_ID;
311 	pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED;
312 	found = true;
313 finish:
314 	*pfound = found;
315 	rc = 0;
316 cleanup:
317 	kfree(desc_ptr);
318 	kfree(buf);
319 	return rc;
320 }
321 
322 /**
323  * uclogic_params_get_le24() - get a 24-bit little-endian number from a
324  * buffer.
325  *
326  * @p:	The pointer to the number buffer.
327  *
328  * Returns:
329  *	The retrieved number
330  */
331 static s32 uclogic_params_get_le24(const void *p)
332 {
333 	const __u8 *b = p;
334 	return b[0] | (b[1] << 8UL) | (b[2] << 16UL);
335 }
336 
337 /**
338  * uclogic_params_pen_init_v2() - initialize tablet interface pen
339  * input and retrieve its parameters from the device, using v2 protocol.
340  *
341  * @pen:		Pointer to the pen parameters to initialize (to be
342  *			cleaned up with uclogic_params_pen_cleanup()). Not
343  *			modified in case of error, or if parameters are not
344  *			found. Cannot be NULL.
345  * @pfound:		Location for a flag which is set to true if the
346  *			parameters were found, and to false if not (e.g.
347  *			device was incompatible). Not modified in case of
348  *			error. Cannot be NULL.
349  * @pparams_ptr:	Location for a kmalloc'ed pointer to the retrieved raw
350  *			parameters, which could be used to identify the tablet
351  *			to some extent. Should be freed with kfree after use.
352  *			NULL, if not needed. Not modified in case of error.
353  *			Only set if *pfound is set to true.
354  * @pparams_len:	Location for the length of the retrieved raw
355  *			parameters. NULL, if not needed. Not modified in case
356  *			of error. Only set if *pfound is set to true.
357  * @hdev:		The HID device of the tablet interface to initialize
358  *			and get parameters from. Cannot be NULL.
359  *
360  * Returns:
361  *	Zero, if successful. A negative errno code on error.
362  */
363 static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
364 					bool *pfound,
365 					__u8 **pparams_ptr,
366 					size_t *pparams_len,
367 					struct hid_device *hdev)
368 {
369 	int rc;
370 	bool found = false;
371 	/* Buffer for (part of) the parameter string descriptor */
372 	__u8 *buf = NULL;
373 	/* Parameter string descriptor required length */
374 	const int params_len_min = 18;
375 	/* Parameter string descriptor accepted length */
376 	const int params_len_max = 32;
377 	/* Parameter string descriptor received length */
378 	int params_len;
379 	size_t i;
380 	s32 resolution;
381 	/* Pen report descriptor template parameters */
382 	s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
383 	__u8 *desc_ptr = NULL;
384 
385 	/* Check arguments */
386 	if (pen == NULL || pfound == NULL || hdev == NULL) {
387 		rc = -EINVAL;
388 		goto cleanup;
389 	}
390 
391 	/*
392 	 * Read string descriptor containing pen input parameters.
393 	 * The specific string descriptor and data were discovered by sniffing
394 	 * the Windows driver traffic.
395 	 * NOTE: This enables fully-functional tablet mode.
396 	 */
397 	rc = uclogic_params_get_str_desc(&buf, hdev, 200, params_len_max);
398 	if (rc == -EPIPE) {
399 		hid_dbg(hdev,
400 			"string descriptor with pen parameters not found, assuming not compatible\n");
401 		goto finish;
402 	} else if (rc < 0) {
403 		hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
404 		goto cleanup;
405 	} else if (rc < params_len_min) {
406 		hid_dbg(hdev,
407 			"string descriptor with pen parameters is too short (got %d, expected at least %d), assuming not compatible\n",
408 			rc, params_len_min);
409 		goto finish;
410 	}
411 
412 	params_len = rc;
413 
414 	/*
415 	 * Check it's not just a catch-all UTF-16LE-encoded ASCII
416 	 * string (such as the model name) some tablets put into all
417 	 * unknown string descriptors.
418 	 */
419 	for (i = 2;
420 	     i < params_len &&
421 		(buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0);
422 	     i += 2);
423 	if (i >= params_len) {
424 		hid_dbg(hdev,
425 			"string descriptor with pen parameters seems to contain only text, assuming not compatible\n");
426 		goto finish;
427 	}
428 
429 	/*
430 	 * Fill report descriptor parameters from the string descriptor
431 	 */
432 	desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
433 		uclogic_params_get_le24(buf + 2);
434 	desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
435 		uclogic_params_get_le24(buf + 5);
436 	desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
437 		get_unaligned_le16(buf + 8);
438 	resolution = get_unaligned_le16(buf + 10);
439 	if (resolution == 0) {
440 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
441 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
442 	} else {
443 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
444 			desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
445 			resolution;
446 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
447 			desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
448 			resolution;
449 	}
450 
451 	/*
452 	 * Generate pen report descriptor
453 	 */
454 	desc_ptr = uclogic_rdesc_template_apply(
455 				uclogic_rdesc_v2_pen_template_arr,
456 				uclogic_rdesc_v2_pen_template_size,
457 				desc_params, ARRAY_SIZE(desc_params));
458 	if (desc_ptr == NULL) {
459 		rc = -ENOMEM;
460 		goto cleanup;
461 	}
462 
463 	/*
464 	 * Fill-in the parameters
465 	 */
466 	memset(pen, 0, sizeof(*pen));
467 	pen->desc_ptr = desc_ptr;
468 	desc_ptr = NULL;
469 	pen->desc_size = uclogic_rdesc_v2_pen_template_size;
470 	pen->id = UCLOGIC_RDESC_V2_PEN_ID;
471 	pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE;
472 	pen->fragmented_hires = true;
473 	pen->tilt_y_flipped = true;
474 	found = true;
475 	if (pparams_ptr != NULL) {
476 		*pparams_ptr = buf;
477 		buf = NULL;
478 	}
479 	if (pparams_len != NULL)
480 		*pparams_len = params_len;
481 
482 finish:
483 	*pfound = found;
484 	rc = 0;
485 cleanup:
486 	kfree(desc_ptr);
487 	kfree(buf);
488 	return rc;
489 }
490 
491 /**
492  * uclogic_params_frame_cleanup - free resources used by struct
493  * uclogic_params_frame (tablet interface's frame controls input parameters).
494  * Can be called repeatedly.
495  *
496  * @frame:	Frame controls input parameters to cleanup. Cannot be NULL.
497  */
498 static void uclogic_params_frame_cleanup(struct uclogic_params_frame *frame)
499 {
500 	kfree(frame->desc_ptr);
501 	memset(frame, 0, sizeof(*frame));
502 }
503 
504 /**
505  * uclogic_params_frame_init_with_desc() - initialize tablet's frame control
506  * parameters with a static report descriptor.
507  *
508  * @frame:	Pointer to the frame parameters to initialize (to be cleaned
509  *		up with uclogic_params_frame_cleanup()). Not modified in case
510  *		of error. Cannot be NULL.
511  * @desc_ptr:	Report descriptor pointer. Can be NULL, if desc_size is zero.
512  * @desc_size:	Report descriptor size.
513  * @id:		Report ID used for frame reports, if they should be tweaked,
514  *		zero if not.
515  *
516  * Returns:
517  *	Zero, if successful. A negative errno code on error.
518  */
519 static int uclogic_params_frame_init_with_desc(
520 					struct uclogic_params_frame *frame,
521 					const __u8 *desc_ptr,
522 					size_t desc_size,
523 					unsigned int id)
524 {
525 	__u8 *copy_desc_ptr;
526 
527 	if (frame == NULL || (desc_ptr == NULL && desc_size != 0))
528 		return -EINVAL;
529 
530 	copy_desc_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
531 	if (copy_desc_ptr == NULL)
532 		return -ENOMEM;
533 
534 	memset(frame, 0, sizeof(*frame));
535 	frame->desc_ptr = copy_desc_ptr;
536 	frame->desc_size = desc_size;
537 	frame->id = id;
538 	return 0;
539 }
540 
541 /**
542  * uclogic_params_frame_init_v1() - initialize v1 tablet interface frame
543  * controls.
544  *
545  * @frame:	Pointer to the frame parameters to initialize (to be cleaned
546  *		up with uclogic_params_frame_cleanup()). Not modified in case
547  *		of error, or if parameters are not found. Cannot be NULL.
548  * @pfound:	Location for a flag which is set to true if the parameters
549  *		were found, and to false if not (e.g. device was
550  *		incompatible). Not modified in case of error. Cannot be NULL.
551  * @hdev:	The HID device of the tablet interface to initialize and get
552  *		parameters from. Cannot be NULL.
553  *
554  * Returns:
555  *	Zero, if successful. A negative errno code on error.
556  */
557 static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame,
558 					bool *pfound,
559 					struct hid_device *hdev)
560 {
561 	int rc;
562 	bool found = false;
563 	struct usb_device *usb_dev;
564 	char *str_buf = NULL;
565 	const size_t str_len = 16;
566 
567 	/* Check arguments */
568 	if (frame == NULL || pfound == NULL || hdev == NULL) {
569 		rc = -EINVAL;
570 		goto cleanup;
571 	}
572 
573 	usb_dev = hid_to_usb_dev(hdev);
574 
575 	/*
576 	 * Enable generic button mode
577 	 */
578 	str_buf = kzalloc(str_len, GFP_KERNEL);
579 	if (str_buf == NULL) {
580 		rc = -ENOMEM;
581 		goto cleanup;
582 	}
583 
584 	rc = usb_string(usb_dev, 123, str_buf, str_len);
585 	if (rc == -EPIPE) {
586 		hid_dbg(hdev,
587 			"generic button -enabling string descriptor not found\n");
588 	} else if (rc < 0) {
589 		goto cleanup;
590 	} else if (strncmp(str_buf, "HK On", rc) != 0) {
591 		hid_dbg(hdev,
592 			"invalid response to enabling generic buttons: \"%s\"\n",
593 			str_buf);
594 	} else {
595 		hid_dbg(hdev, "generic buttons enabled\n");
596 		rc = uclogic_params_frame_init_with_desc(
597 				frame,
598 				uclogic_rdesc_v1_frame_arr,
599 				uclogic_rdesc_v1_frame_size,
600 				UCLOGIC_RDESC_V1_FRAME_ID);
601 		if (rc != 0)
602 			goto cleanup;
603 		found = true;
604 	}
605 
606 	*pfound = found;
607 	rc = 0;
608 cleanup:
609 	kfree(str_buf);
610 	return rc;
611 }
612 
613 /**
614  * uclogic_params_cleanup - free resources used by struct uclogic_params
615  * (tablet interface's parameters).
616  * Can be called repeatedly.
617  *
618  * @params:	Input parameters to cleanup. Cannot be NULL.
619  */
620 void uclogic_params_cleanup(struct uclogic_params *params)
621 {
622 	if (!params->invalid) {
623 		size_t i;
624 		kfree(params->desc_ptr);
625 		uclogic_params_pen_cleanup(&params->pen);
626 		for (i = 0; i < ARRAY_SIZE(params->frame_list); i++)
627 			uclogic_params_frame_cleanup(&params->frame_list[i]);
628 
629 		memset(params, 0, sizeof(*params));
630 	}
631 }
632 
633 /**
634  * uclogic_params_get_desc() - Get a replacement report descriptor for a
635  *                             tablet's interface.
636  *
637  * @params:	The parameters of a tablet interface to get report
638  *		descriptor for. Cannot be NULL.
639  * @pdesc:	Location for the resulting, kmalloc-allocated report
640  *		descriptor pointer, or for NULL, if there's no replacement
641  *		report descriptor. Not modified in case of error. Cannot be
642  *		NULL.
643  * @psize:	Location for the resulting report descriptor size, not set if
644  *		there's no replacement report descriptor. Not modified in case
645  *		of error. Cannot be NULL.
646  *
647  * Returns:
648  *	Zero, if successful.
649  *	-EINVAL, if invalid arguments are supplied.
650  *	-ENOMEM, if failed to allocate memory.
651  */
652 int uclogic_params_get_desc(const struct uclogic_params *params,
653 				__u8 **pdesc,
654 				unsigned int *psize)
655 {
656 	int rc = -ENOMEM;
657 	bool present = false;
658 	unsigned int size = 0;
659 	__u8 *desc = NULL;
660 	size_t i;
661 
662 	/* Check arguments */
663 	if (params == NULL || pdesc == NULL || psize == NULL)
664 		return -EINVAL;
665 
666 	/* Concatenate descriptors */
667 #define ADD_DESC(_desc_ptr, _desc_size) \
668 	do {                                                        \
669 		unsigned int new_size;                              \
670 		__u8 *new_desc;                                     \
671 		if ((_desc_ptr) == NULL) {                          \
672 			break;                                      \
673 		}                                                   \
674 		new_size = size + (_desc_size);                     \
675 		new_desc = krealloc(desc, new_size, GFP_KERNEL);    \
676 		if (new_desc == NULL) {                             \
677 			goto cleanup;                               \
678 		}                                                   \
679 		memcpy(new_desc + size, (_desc_ptr), (_desc_size)); \
680 		desc = new_desc;                                    \
681 		size = new_size;                                    \
682 		present = true;                                     \
683 	} while (0)
684 
685 	ADD_DESC(params->desc_ptr, params->desc_size);
686 	ADD_DESC(params->pen.desc_ptr, params->pen.desc_size);
687 	for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
688 		ADD_DESC(params->frame_list[i].desc_ptr,
689 				params->frame_list[i].desc_size);
690 	}
691 
692 #undef ADD_DESC
693 
694 	if (present) {
695 		*pdesc = desc;
696 		*psize = size;
697 		desc = NULL;
698 	}
699 	rc = 0;
700 cleanup:
701 	kfree(desc);
702 	return rc;
703 }
704 
705 /**
706  * uclogic_params_init_invalid() - initialize tablet interface parameters,
707  * specifying the interface is invalid.
708  *
709  * @params:		Parameters to initialize (to be cleaned with
710  *			uclogic_params_cleanup()). Cannot be NULL.
711  */
712 static void uclogic_params_init_invalid(struct uclogic_params *params)
713 {
714 	params->invalid = true;
715 }
716 
717 /**
718  * uclogic_params_init_with_opt_desc() - initialize tablet interface
719  * parameters with an optional replacement report descriptor. Only modify
720  * report descriptor, if the original report descriptor matches the expected
721  * size.
722  *
723  * @params:		Parameters to initialize (to be cleaned with
724  *			uclogic_params_cleanup()). Not modified in case of
725  *			error. Cannot be NULL.
726  * @hdev:		The HID device of the tablet interface create the
727  *			parameters for. Cannot be NULL.
728  * @orig_desc_size:	Expected size of the original report descriptor to
729  *			be replaced.
730  * @desc_ptr:		Pointer to the replacement report descriptor.
731  *			Can be NULL, if desc_size is zero.
732  * @desc_size:		Size of the replacement report descriptor.
733  *
734  * Returns:
735  *	Zero, if successful. -EINVAL if an invalid argument was passed.
736  *	-ENOMEM, if failed to allocate memory.
737  */
738 static int uclogic_params_init_with_opt_desc(struct uclogic_params *params,
739 					     struct hid_device *hdev,
740 					     unsigned int orig_desc_size,
741 					     __u8 *desc_ptr,
742 					     unsigned int desc_size)
743 {
744 	__u8 *desc_copy_ptr = NULL;
745 	unsigned int desc_copy_size;
746 	int rc;
747 
748 	/* Check arguments */
749 	if (params == NULL || hdev == NULL ||
750 	    (desc_ptr == NULL && desc_size != 0)) {
751 		rc = -EINVAL;
752 		goto cleanup;
753 	}
754 
755 	/* Replace report descriptor, if it matches */
756 	if (hdev->dev_rsize == orig_desc_size) {
757 		hid_dbg(hdev,
758 			"device report descriptor matches the expected size, replacing\n");
759 		desc_copy_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
760 		if (desc_copy_ptr == NULL) {
761 			rc = -ENOMEM;
762 			goto cleanup;
763 		}
764 		desc_copy_size = desc_size;
765 	} else {
766 		hid_dbg(hdev,
767 			"device report descriptor doesn't match the expected size (%u != %u), preserving\n",
768 			hdev->dev_rsize, orig_desc_size);
769 		desc_copy_ptr = NULL;
770 		desc_copy_size = 0;
771 	}
772 
773 	/* Output parameters */
774 	memset(params, 0, sizeof(*params));
775 	params->desc_ptr = desc_copy_ptr;
776 	desc_copy_ptr = NULL;
777 	params->desc_size = desc_copy_size;
778 
779 	rc = 0;
780 cleanup:
781 	kfree(desc_copy_ptr);
782 	return rc;
783 }
784 
785 /**
786  * uclogic_params_huion_init() - initialize a Huion tablet interface and discover
787  * its parameters.
788  *
789  * @params:	Parameters to fill in (to be cleaned with
790  *		uclogic_params_cleanup()). Not modified in case of error.
791  *		Cannot be NULL.
792  * @hdev:	The HID device of the tablet interface to initialize and get
793  *		parameters from. Cannot be NULL.
794  *
795  * Returns:
796  *	Zero, if successful. A negative errno code on error.
797  */
798 static int uclogic_params_huion_init(struct uclogic_params *params,
799 				     struct hid_device *hdev)
800 {
801 	int rc;
802 	struct usb_device *udev;
803 	struct usb_interface *iface;
804 	__u8 bInterfaceNumber;
805 	bool found;
806 	/* The resulting parameters (noop) */
807 	struct uclogic_params p = {0, };
808 	static const char transition_ver[] = "HUION_T153_160607";
809 	char *ver_ptr = NULL;
810 	const size_t ver_len = sizeof(transition_ver) + 1;
811 	__u8 *params_ptr = NULL;
812 	size_t params_len = 0;
813 	/* Parameters string descriptor of a model with touch ring (HS610) */
814 	const __u8 touch_ring_model_params_buf[] = {
815 		0x13, 0x03, 0x70, 0xC6, 0x00, 0x06, 0x7C, 0x00,
816 		0xFF, 0x1F, 0xD8, 0x13, 0x03, 0x0D, 0x10, 0x01,
817 		0x04, 0x3C, 0x3E
818 	};
819 
820 	/* Check arguments */
821 	if (params == NULL || hdev == NULL) {
822 		rc = -EINVAL;
823 		goto cleanup;
824 	}
825 
826 	udev = hid_to_usb_dev(hdev);
827 	iface = to_usb_interface(hdev->dev.parent);
828 	bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
829 
830 	/* If it's a custom keyboard interface */
831 	if (bInterfaceNumber == 1) {
832 		/* Keep everything intact, but mark pen usage invalid */
833 		p.pen.usage_invalid = true;
834 		goto output;
835 	/* Else, if it's not a pen interface */
836 	} else if (bInterfaceNumber != 0) {
837 		uclogic_params_init_invalid(&p);
838 		goto output;
839 	}
840 
841 	/* Try to get firmware version */
842 	ver_ptr = kzalloc(ver_len, GFP_KERNEL);
843 	if (ver_ptr == NULL) {
844 		rc = -ENOMEM;
845 		goto cleanup;
846 	}
847 	rc = usb_string(udev, 201, ver_ptr, ver_len);
848 	if (rc == -EPIPE) {
849 		*ver_ptr = '\0';
850 	} else if (rc < 0) {
851 		hid_err(hdev,
852 			"failed retrieving Huion firmware version: %d\n", rc);
853 		goto cleanup;
854 	}
855 
856 	/* If this is a transition firmware */
857 	if (strcmp(ver_ptr, transition_ver) == 0) {
858 		hid_dbg(hdev,
859 			"transition firmware detected, not probing pen v2 parameters\n");
860 	} else {
861 		/* Try to probe v2 pen parameters */
862 		rc = uclogic_params_pen_init_v2(&p.pen, &found,
863 						&params_ptr, &params_len,
864 						hdev);
865 		if (rc != 0) {
866 			hid_err(hdev,
867 				"failed probing pen v2 parameters: %d\n", rc);
868 			goto cleanup;
869 		} else if (found) {
870 			hid_dbg(hdev, "pen v2 parameters found\n");
871 			/* Create v2 frame button parameters */
872 			rc = uclogic_params_frame_init_with_desc(
873 					&p.frame_list[0],
874 					uclogic_rdesc_v2_frame_buttons_arr,
875 					uclogic_rdesc_v2_frame_buttons_size,
876 					UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID);
877 			if (rc != 0) {
878 				hid_err(hdev,
879 					"failed creating v2 frame button parameters: %d\n",
880 					rc);
881 				goto cleanup;
882 			}
883 
884 			/* Link from pen sub-report */
885 			p.pen.subreport_list[0].value = 0xe0;
886 			p.pen.subreport_list[0].id =
887 				UCLOGIC_RDESC_V2_FRAME_BUTTONS_ID;
888 
889 			/* If this is the model with touch ring */
890 			if (params_ptr != NULL &&
891 			    params_len == sizeof(touch_ring_model_params_buf) &&
892 			    memcmp(params_ptr, touch_ring_model_params_buf,
893 				   params_len) == 0) {
894 				/* Create touch ring parameters */
895 				rc = uclogic_params_frame_init_with_desc(
896 					&p.frame_list[1],
897 					uclogic_rdesc_v2_frame_touch_ring_arr,
898 					uclogic_rdesc_v2_frame_touch_ring_size,
899 					UCLOGIC_RDESC_V2_FRAME_TOUCH_ID);
900 				if (rc != 0) {
901 					hid_err(hdev,
902 						"failed creating v2 frame touch ring parameters: %d\n",
903 						rc);
904 					goto cleanup;
905 				}
906 				p.frame_list[1].suffix = "Touch Ring";
907 				p.frame_list[1].dev_id_byte =
908 					UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE;
909 				p.frame_list[1].touch_byte = 5;
910 				p.frame_list[1].touch_max = 12;
911 				p.frame_list[1].touch_flip_at = 7;
912 			} else {
913 				/* Create touch strip parameters */
914 				rc = uclogic_params_frame_init_with_desc(
915 					&p.frame_list[1],
916 					uclogic_rdesc_v2_frame_touch_strip_arr,
917 					uclogic_rdesc_v2_frame_touch_strip_size,
918 					UCLOGIC_RDESC_V2_FRAME_TOUCH_ID);
919 				if (rc != 0) {
920 					hid_err(hdev,
921 						"failed creating v2 frame touch strip parameters: %d\n",
922 						rc);
923 					goto cleanup;
924 				}
925 				p.frame_list[1].suffix = "Touch Strip";
926 				p.frame_list[1].dev_id_byte =
927 					UCLOGIC_RDESC_V2_FRAME_TOUCH_DEV_ID_BYTE;
928 				p.frame_list[1].touch_byte = 5;
929 				p.frame_list[1].touch_max = 8;
930 			}
931 
932 			/* Link from pen sub-report */
933 			p.pen.subreport_list[1].value = 0xf0;
934 			p.pen.subreport_list[1].id =
935 				UCLOGIC_RDESC_V2_FRAME_TOUCH_ID;
936 
937 			/* Create v2 frame dial parameters */
938 			rc = uclogic_params_frame_init_with_desc(
939 					&p.frame_list[2],
940 					uclogic_rdesc_v2_frame_dial_arr,
941 					uclogic_rdesc_v2_frame_dial_size,
942 					UCLOGIC_RDESC_V2_FRAME_DIAL_ID);
943 			if (rc != 0) {
944 				hid_err(hdev,
945 					"failed creating v2 frame dial parameters: %d\n",
946 					rc);
947 				goto cleanup;
948 			}
949 			p.frame_list[2].suffix = "Dial";
950 			p.frame_list[2].dev_id_byte =
951 				UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE;
952 			p.frame_list[2].bitmap_dial_byte = 5;
953 
954 			/* Link from pen sub-report */
955 			p.pen.subreport_list[2].value = 0xf1;
956 			p.pen.subreport_list[2].id =
957 				UCLOGIC_RDESC_V2_FRAME_DIAL_ID;
958 
959 			goto output;
960 		}
961 		hid_dbg(hdev, "pen v2 parameters not found\n");
962 	}
963 
964 	/* Try to probe v1 pen parameters */
965 	rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
966 	if (rc != 0) {
967 		hid_err(hdev,
968 			"failed probing pen v1 parameters: %d\n", rc);
969 		goto cleanup;
970 	} else if (found) {
971 		hid_dbg(hdev, "pen v1 parameters found\n");
972 		/* Try to probe v1 frame */
973 		rc = uclogic_params_frame_init_v1(&p.frame_list[0],
974 						  &found, hdev);
975 		if (rc != 0) {
976 			hid_err(hdev, "v1 frame probing failed: %d\n", rc);
977 			goto cleanup;
978 		}
979 		hid_dbg(hdev, "frame v1 parameters%s found\n",
980 			(found ? "" : " not"));
981 		if (found) {
982 			/* Link frame button subreports from pen reports */
983 			p.pen.subreport_list[0].value = 0xe0;
984 			p.pen.subreport_list[0].id =
985 				UCLOGIC_RDESC_V1_FRAME_ID;
986 		}
987 		goto output;
988 	}
989 	hid_dbg(hdev, "pen v1 parameters not found\n");
990 
991 	uclogic_params_init_invalid(&p);
992 
993 output:
994 	/* Output parameters */
995 	memcpy(params, &p, sizeof(*params));
996 	memset(&p, 0, sizeof(p));
997 	rc = 0;
998 cleanup:
999 	kfree(params_ptr);
1000 	kfree(ver_ptr);
1001 	uclogic_params_cleanup(&p);
1002 	return rc;
1003 }
1004 
1005 /**
1006  * uclogic_params_init() - initialize a tablet interface and discover its
1007  * parameters.
1008  *
1009  * @params:	Parameters to fill in (to be cleaned with
1010  *		uclogic_params_cleanup()). Not modified in case of error.
1011  *		Cannot be NULL.
1012  * @hdev:	The HID device of the tablet interface to initialize and get
1013  *		parameters from. Cannot be NULL. Must be using the USB low-level
1014  *		driver, i.e. be an actual USB tablet.
1015  *
1016  * Returns:
1017  *	Zero, if successful. A negative errno code on error.
1018  */
1019 int uclogic_params_init(struct uclogic_params *params,
1020 			struct hid_device *hdev)
1021 {
1022 	int rc;
1023 	struct usb_device *udev;
1024 	__u8  bNumInterfaces;
1025 	struct usb_interface *iface;
1026 	__u8 bInterfaceNumber;
1027 	bool found;
1028 	/* The resulting parameters (noop) */
1029 	struct uclogic_params p = {0, };
1030 
1031 	/* Check arguments */
1032 	if (params == NULL || hdev == NULL || !hid_is_usb(hdev)) {
1033 		rc = -EINVAL;
1034 		goto cleanup;
1035 	}
1036 
1037 	udev = hid_to_usb_dev(hdev);
1038 	bNumInterfaces = udev->config->desc.bNumInterfaces;
1039 	iface = to_usb_interface(hdev->dev.parent);
1040 	bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
1041 
1042 	/*
1043 	 * Set replacement report descriptor if the original matches the
1044 	 * specified size. Otherwise keep interface unchanged.
1045 	 */
1046 #define WITH_OPT_DESC(_orig_desc_token, _new_desc_token) \
1047 	uclogic_params_init_with_opt_desc(                  \
1048 		&p, hdev,                                   \
1049 		UCLOGIC_RDESC_##_orig_desc_token##_SIZE,    \
1050 		uclogic_rdesc_##_new_desc_token##_arr,      \
1051 		uclogic_rdesc_##_new_desc_token##_size)
1052 
1053 #define VID_PID(_vid, _pid) \
1054 	(((__u32)(_vid) << 16) | ((__u32)(_pid) & U16_MAX))
1055 
1056 	/*
1057 	 * Handle specific interfaces for specific tablets.
1058 	 *
1059 	 * Observe the following logic:
1060 	 *
1061 	 * If the interface is recognized as producing certain useful input:
1062 	 *	Mark interface as valid.
1063 	 *	Output interface parameters.
1064 	 * Else, if the interface is recognized as *not* producing any useful
1065 	 * input:
1066 	 *	Mark interface as invalid.
1067 	 * Else:
1068 	 *	Mark interface as valid.
1069 	 *	Output noop parameters.
1070 	 *
1071 	 * Rule of thumb: it is better to disable a broken interface than let
1072 	 *		  it spew garbage input.
1073 	 */
1074 
1075 	switch (VID_PID(hdev->vendor, hdev->product)) {
1076 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1077 		     USB_DEVICE_ID_UCLOGIC_TABLET_PF1209):
1078 		rc = WITH_OPT_DESC(PF1209_ORIG, pf1209_fixed);
1079 		if (rc != 0)
1080 			goto cleanup;
1081 		break;
1082 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1083 		     USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U):
1084 		rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp4030u_fixed);
1085 		if (rc != 0)
1086 			goto cleanup;
1087 		break;
1088 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1089 		     USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U):
1090 		if (hdev->dev_rsize == UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE) {
1091 			if (bInterfaceNumber == 0) {
1092 				/* Try to probe v1 pen parameters */
1093 				rc = uclogic_params_pen_init_v1(&p.pen,
1094 								&found, hdev);
1095 				if (rc != 0) {
1096 					hid_err(hdev,
1097 						"pen probing failed: %d\n",
1098 						rc);
1099 					goto cleanup;
1100 				}
1101 				if (!found) {
1102 					hid_warn(hdev,
1103 						 "pen parameters not found");
1104 				}
1105 			} else {
1106 				uclogic_params_init_invalid(&p);
1107 			}
1108 		} else {
1109 			rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp5540u_fixed);
1110 			if (rc != 0)
1111 				goto cleanup;
1112 		}
1113 		break;
1114 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1115 		     USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U):
1116 		rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp8060u_fixed);
1117 		if (rc != 0)
1118 			goto cleanup;
1119 		break;
1120 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1121 		     USB_DEVICE_ID_UCLOGIC_TABLET_WP1062):
1122 		rc = WITH_OPT_DESC(WP1062_ORIG, wp1062_fixed);
1123 		if (rc != 0)
1124 			goto cleanup;
1125 		break;
1126 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1127 		     USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850):
1128 		switch (bInterfaceNumber) {
1129 		case 0:
1130 			rc = WITH_OPT_DESC(TWHL850_ORIG0, twhl850_fixed0);
1131 			if (rc != 0)
1132 				goto cleanup;
1133 			break;
1134 		case 1:
1135 			rc = WITH_OPT_DESC(TWHL850_ORIG1, twhl850_fixed1);
1136 			if (rc != 0)
1137 				goto cleanup;
1138 			break;
1139 		case 2:
1140 			rc = WITH_OPT_DESC(TWHL850_ORIG2, twhl850_fixed2);
1141 			if (rc != 0)
1142 				goto cleanup;
1143 			break;
1144 		}
1145 		break;
1146 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1147 		     USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60):
1148 		/*
1149 		 * If it is not a three-interface version, which is known to
1150 		 * respond to initialization.
1151 		 */
1152 		if (bNumInterfaces != 3) {
1153 			switch (bInterfaceNumber) {
1154 			case 0:
1155 				rc = WITH_OPT_DESC(TWHA60_ORIG0,
1156 							twha60_fixed0);
1157 				if (rc != 0)
1158 					goto cleanup;
1159 				break;
1160 			case 1:
1161 				rc = WITH_OPT_DESC(TWHA60_ORIG1,
1162 							twha60_fixed1);
1163 				if (rc != 0)
1164 					goto cleanup;
1165 				break;
1166 			}
1167 			break;
1168 		}
1169 		fallthrough;
1170 	case VID_PID(USB_VENDOR_ID_HUION,
1171 		     USB_DEVICE_ID_HUION_TABLET):
1172 	case VID_PID(USB_VENDOR_ID_HUION,
1173 		     USB_DEVICE_ID_HUION_TABLET2):
1174 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1175 		     USB_DEVICE_ID_HUION_TABLET):
1176 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1177 		     USB_DEVICE_ID_YIYNOVA_TABLET):
1178 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1179 		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81):
1180 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1181 		     USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3):
1182 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1183 		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45):
1184 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
1185 		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47):
1186 		rc = uclogic_params_huion_init(&p, hdev);
1187 		if (rc != 0)
1188 			goto cleanup;
1189 		break;
1190 	case VID_PID(USB_VENDOR_ID_UGTIZER,
1191 		     USB_DEVICE_ID_UGTIZER_TABLET_GP0610):
1192 	case VID_PID(USB_VENDOR_ID_UGTIZER,
1193 		     USB_DEVICE_ID_UGTIZER_TABLET_GT5040):
1194 	case VID_PID(USB_VENDOR_ID_UGEE,
1195 		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
1196 	case VID_PID(USB_VENDOR_ID_UGEE,
1197 		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
1198 	case VID_PID(USB_VENDOR_ID_UGEE,
1199 		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06):
1200 	case VID_PID(USB_VENDOR_ID_UGEE,
1201 		     USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
1202 		/* If this is the pen interface */
1203 		if (bInterfaceNumber == 1) {
1204 			/* Probe v1 pen parameters */
1205 			rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1206 			if (rc != 0) {
1207 				hid_err(hdev, "pen probing failed: %d\n", rc);
1208 				goto cleanup;
1209 			}
1210 			if (!found) {
1211 				hid_warn(hdev, "pen parameters not found");
1212 				uclogic_params_init_invalid(&p);
1213 			}
1214 		} else {
1215 			uclogic_params_init_invalid(&p);
1216 		}
1217 		break;
1218 	case VID_PID(USB_VENDOR_ID_UGEE,
1219 		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01):
1220 		/* If this is the pen and frame interface */
1221 		if (bInterfaceNumber == 1) {
1222 			/* Probe v1 pen parameters */
1223 			rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1224 			if (rc != 0) {
1225 				hid_err(hdev, "pen probing failed: %d\n", rc);
1226 				goto cleanup;
1227 			}
1228 			/* Initialize frame parameters */
1229 			rc = uclogic_params_frame_init_with_desc(
1230 				&p.frame_list[0],
1231 				uclogic_rdesc_xppen_deco01_frame_arr,
1232 				uclogic_rdesc_xppen_deco01_frame_size,
1233 				0);
1234 			if (rc != 0)
1235 				goto cleanup;
1236 		} else {
1237 			uclogic_params_init_invalid(&p);
1238 		}
1239 		break;
1240 	case VID_PID(USB_VENDOR_ID_TRUST,
1241 		     USB_DEVICE_ID_TRUST_PANORA_TABLET):
1242 	case VID_PID(USB_VENDOR_ID_UGEE,
1243 		     USB_DEVICE_ID_UGEE_TABLET_G5):
1244 		/* Ignore non-pen interfaces */
1245 		if (bInterfaceNumber != 1) {
1246 			uclogic_params_init_invalid(&p);
1247 			break;
1248 		}
1249 
1250 		rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1251 		if (rc != 0) {
1252 			hid_err(hdev, "pen probing failed: %d\n", rc);
1253 			goto cleanup;
1254 		} else if (found) {
1255 			rc = uclogic_params_frame_init_with_desc(
1256 				&p.frame_list[0],
1257 				uclogic_rdesc_ugee_g5_frame_arr,
1258 				uclogic_rdesc_ugee_g5_frame_size,
1259 				UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
1260 			if (rc != 0) {
1261 				hid_err(hdev,
1262 					"failed creating frame parameters: %d\n",
1263 					rc);
1264 				goto cleanup;
1265 			}
1266 			p.frame_list[0].re_lsb =
1267 				UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB;
1268 			p.frame_list[0].dev_id_byte =
1269 				UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
1270 		} else {
1271 			hid_warn(hdev, "pen parameters not found");
1272 			uclogic_params_init_invalid(&p);
1273 		}
1274 
1275 		break;
1276 	case VID_PID(USB_VENDOR_ID_UGEE,
1277 		     USB_DEVICE_ID_UGEE_TABLET_EX07S):
1278 		/* Ignore non-pen interfaces */
1279 		if (bInterfaceNumber != 1) {
1280 			uclogic_params_init_invalid(&p);
1281 			break;
1282 		}
1283 
1284 		rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1285 		if (rc != 0) {
1286 			hid_err(hdev, "pen probing failed: %d\n", rc);
1287 			goto cleanup;
1288 		} else if (found) {
1289 			rc = uclogic_params_frame_init_with_desc(
1290 				&p.frame_list[0],
1291 				uclogic_rdesc_ugee_ex07_frame_arr,
1292 				uclogic_rdesc_ugee_ex07_frame_size,
1293 				0);
1294 			if (rc != 0) {
1295 				hid_err(hdev,
1296 					"failed creating frame parameters: %d\n",
1297 					rc);
1298 				goto cleanup;
1299 			}
1300 		} else {
1301 			hid_warn(hdev, "pen parameters not found");
1302 			uclogic_params_init_invalid(&p);
1303 		}
1304 
1305 		break;
1306 	}
1307 
1308 #undef VID_PID
1309 #undef WITH_OPT_DESC
1310 
1311 	/* Output parameters */
1312 	memcpy(params, &p, sizeof(*params));
1313 	memset(&p, 0, sizeof(p));
1314 	rc = 0;
1315 cleanup:
1316 	uclogic_params_cleanup(&p);
1317 	return rc;
1318 }
1319