xref: /linux/drivers/hid/hid-uclogic-params.c (revision 26fbb4c8c7c3ee9a4c3b4de555a8587b5a19154e)
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  * Convert a pen in-range reporting type to a string.
25  *
26  * @inrange:	The in-range reporting type to convert.
27  *
28  * Returns:
29  *	The string representing the type, or NULL if the type is unknown.
30  */
31 const char *uclogic_params_pen_inrange_to_str(
32 			enum uclogic_params_pen_inrange inrange)
33 {
34 	switch (inrange) {
35 	case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL:
36 		return "normal";
37 	case UCLOGIC_PARAMS_PEN_INRANGE_INVERTED:
38 		return "inverted";
39 	case UCLOGIC_PARAMS_PEN_INRANGE_NONE:
40 		return "none";
41 	default:
42 		return NULL;
43 	}
44 }
45 
46 /**
47  * uclogic_params_get_str_desc - retrieve a string descriptor from a HID
48  * device interface, putting it into a kmalloc-allocated buffer as is, without
49  * character encoding conversion.
50  *
51  * @pbuf:	Location for the kmalloc-allocated buffer pointer containing
52  *		the retrieved descriptor. Not modified in case of error.
53  *		Can be NULL to have retrieved descriptor discarded.
54  * @hdev:	The HID device of the tablet interface to retrieve the string
55  *		descriptor from. Cannot be NULL.
56  * @idx:	Index of the string descriptor to request from the device.
57  * @len:	Length of the buffer to allocate and the data to retrieve.
58  *
59  * Returns:
60  *	number of bytes retrieved (<= len),
61  *	-EPIPE, if the descriptor was not found, or
62  *	another negative errno code in case of other error.
63  */
64 static int uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev,
65 					__u8 idx, size_t len)
66 {
67 	int rc;
68 	struct usb_device *udev = hid_to_usb_dev(hdev);
69 	__u8 *buf = NULL;
70 
71 	/* Check arguments */
72 	if (hdev == NULL) {
73 		rc = -EINVAL;
74 		goto cleanup;
75 	}
76 
77 	buf = kmalloc(len, GFP_KERNEL);
78 	if (buf == NULL) {
79 		rc = -ENOMEM;
80 		goto cleanup;
81 	}
82 
83 	rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
84 				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
85 				(USB_DT_STRING << 8) + idx,
86 				0x0409, buf, len,
87 				USB_CTRL_GET_TIMEOUT);
88 	if (rc == -EPIPE) {
89 		hid_dbg(hdev, "string descriptor #%hhu not found\n", idx);
90 		goto cleanup;
91 	} else if (rc < 0) {
92 		hid_err(hdev,
93 			"failed retrieving string descriptor #%u: %d\n",
94 			idx, rc);
95 		goto cleanup;
96 	}
97 
98 	if (pbuf != NULL) {
99 		*pbuf = buf;
100 		buf = NULL;
101 	}
102 
103 cleanup:
104 	kfree(buf);
105 	return rc;
106 }
107 
108 /**
109  * uclogic_params_pen_cleanup - free resources used by struct
110  * uclogic_params_pen (tablet interface's pen input parameters).
111  * Can be called repeatedly.
112  *
113  * @pen:	Pen input parameters to cleanup. Cannot be NULL.
114  */
115 static void uclogic_params_pen_cleanup(struct uclogic_params_pen *pen)
116 {
117 	kfree(pen->desc_ptr);
118 	memset(pen, 0, sizeof(*pen));
119 }
120 
121 /**
122  * uclogic_params_pen_init_v1() - initialize tablet interface pen
123  * input and retrieve its parameters from the device, using v1 protocol.
124  *
125  * @pen:	Pointer to the pen parameters to initialize (to be
126  *		cleaned up with uclogic_params_pen_cleanup()). Not modified in
127  *		case of error, or if parameters are not found. Cannot be NULL.
128  * @pfound:	Location for a flag which is set to true if the parameters
129  *		were found, and to false if not (e.g. device was
130  *		incompatible). Not modified in case of error. Cannot be NULL.
131  * @hdev:	The HID device of the tablet interface to initialize and get
132  *		parameters from. Cannot be NULL.
133  *
134  * Returns:
135  *	Zero, if successful. A negative errno code on error.
136  */
137 static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
138 				      bool *pfound,
139 				      struct hid_device *hdev)
140 {
141 	int rc;
142 	bool found = false;
143 	/* Buffer for (part of) the string descriptor */
144 	__u8 *buf = NULL;
145 	/* Minimum descriptor length required, maximum seen so far is 18 */
146 	const int len = 12;
147 	s32 resolution;
148 	/* Pen report descriptor template parameters */
149 	s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
150 	__u8 *desc_ptr = NULL;
151 
152 	/* Check arguments */
153 	if (pen == NULL || pfound == NULL || hdev == NULL) {
154 		rc = -EINVAL;
155 		goto cleanup;
156 	}
157 
158 	/*
159 	 * Read string descriptor containing pen input parameters.
160 	 * The specific string descriptor and data were discovered by sniffing
161 	 * the Windows driver traffic.
162 	 * NOTE: This enables fully-functional tablet mode.
163 	 */
164 	rc = uclogic_params_get_str_desc(&buf, hdev, 100, len);
165 	if (rc == -EPIPE) {
166 		hid_dbg(hdev,
167 			"string descriptor with pen parameters not found, assuming not compatible\n");
168 		goto finish;
169 	} else if (rc < 0) {
170 		hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
171 		goto cleanup;
172 	} else if (rc != len) {
173 		hid_dbg(hdev,
174 			"string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n",
175 			rc, len);
176 		goto finish;
177 	}
178 
179 	/*
180 	 * Fill report descriptor parameters from the string descriptor
181 	 */
182 	desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
183 		get_unaligned_le16(buf + 2);
184 	desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
185 		get_unaligned_le16(buf + 4);
186 	desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
187 		get_unaligned_le16(buf + 8);
188 	resolution = get_unaligned_le16(buf + 10);
189 	if (resolution == 0) {
190 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
191 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
192 	} else {
193 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
194 			desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
195 			resolution;
196 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
197 			desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
198 			resolution;
199 	}
200 	kfree(buf);
201 	buf = NULL;
202 
203 	/*
204 	 * Generate pen report descriptor
205 	 */
206 	desc_ptr = uclogic_rdesc_template_apply(
207 				uclogic_rdesc_pen_v1_template_arr,
208 				uclogic_rdesc_pen_v1_template_size,
209 				desc_params, ARRAY_SIZE(desc_params));
210 	if (desc_ptr == NULL) {
211 		rc = -ENOMEM;
212 		goto cleanup;
213 	}
214 
215 	/*
216 	 * Fill-in the parameters
217 	 */
218 	memset(pen, 0, sizeof(*pen));
219 	pen->desc_ptr = desc_ptr;
220 	desc_ptr = NULL;
221 	pen->desc_size = uclogic_rdesc_pen_v1_template_size;
222 	pen->id = UCLOGIC_RDESC_PEN_V1_ID;
223 	pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED;
224 	found = true;
225 finish:
226 	*pfound = found;
227 	rc = 0;
228 cleanup:
229 	kfree(desc_ptr);
230 	kfree(buf);
231 	return rc;
232 }
233 
234 /**
235  * uclogic_params_get_le24() - get a 24-bit little-endian number from a
236  * buffer.
237  *
238  * @p:	The pointer to the number buffer.
239  *
240  * Returns:
241  *	The retrieved number
242  */
243 static s32 uclogic_params_get_le24(const void *p)
244 {
245 	const __u8 *b = p;
246 	return b[0] | (b[1] << 8UL) | (b[2] << 16UL);
247 }
248 
249 /**
250  * uclogic_params_pen_init_v2() - initialize tablet interface pen
251  * input and retrieve its parameters from the device, using v2 protocol.
252  *
253  * @pen:	Pointer to the pen parameters to initialize (to be
254  *		cleaned up with uclogic_params_pen_cleanup()). Not modified in
255  *		case of error, or if parameters are not found. Cannot be NULL.
256  * @pfound:	Location for a flag which is set to true if the parameters
257  *		were found, and to false if not (e.g. device was
258  *		incompatible). Not modified in case of error. Cannot be NULL.
259  * @hdev:	The HID device of the tablet interface to initialize and get
260  *		parameters from. Cannot be NULL.
261  *
262  * Returns:
263  *	Zero, if successful. A negative errno code on error.
264  */
265 static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
266 					bool *pfound,
267 					struct hid_device *hdev)
268 {
269 	int rc;
270 	bool found = false;
271 	/* Buffer for (part of) the string descriptor */
272 	__u8 *buf = NULL;
273 	/* Descriptor length required */
274 	const int len = 18;
275 	s32 resolution;
276 	/* Pen report descriptor template parameters */
277 	s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
278 	__u8 *desc_ptr = NULL;
279 
280 	/* Check arguments */
281 	if (pen == NULL || pfound == NULL || hdev == NULL) {
282 		rc = -EINVAL;
283 		goto cleanup;
284 	}
285 
286 	/*
287 	 * Read string descriptor containing pen input parameters.
288 	 * The specific string descriptor and data were discovered by sniffing
289 	 * the Windows driver traffic.
290 	 * NOTE: This enables fully-functional tablet mode.
291 	 */
292 	rc = uclogic_params_get_str_desc(&buf, hdev, 200, len);
293 	if (rc == -EPIPE) {
294 		hid_dbg(hdev,
295 			"string descriptor with pen parameters not found, assuming not compatible\n");
296 		goto finish;
297 	} else if (rc < 0) {
298 		hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
299 		goto cleanup;
300 	} else if (rc != len) {
301 		hid_dbg(hdev,
302 			"string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n",
303 			rc, len);
304 		goto finish;
305 	} else {
306 		size_t i;
307 		/*
308 		 * Check it's not just a catch-all UTF-16LE-encoded ASCII
309 		 * string (such as the model name) some tablets put into all
310 		 * unknown string descriptors.
311 		 */
312 		for (i = 2;
313 		     i < len &&
314 			(buf[i] >= 0x20 && buf[i] < 0x7f && buf[i + 1] == 0);
315 		     i += 2);
316 		if (i >= len) {
317 			hid_dbg(hdev,
318 				"string descriptor with pen parameters seems to contain only text, assuming not compatible\n");
319 			goto finish;
320 		}
321 	}
322 
323 	/*
324 	 * Fill report descriptor parameters from the string descriptor
325 	 */
326 	desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
327 		uclogic_params_get_le24(buf + 2);
328 	desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
329 		uclogic_params_get_le24(buf + 5);
330 	desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
331 		get_unaligned_le16(buf + 8);
332 	resolution = get_unaligned_le16(buf + 10);
333 	if (resolution == 0) {
334 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
335 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
336 	} else {
337 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
338 			desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
339 			resolution;
340 		desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
341 			desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
342 			resolution;
343 	}
344 	kfree(buf);
345 	buf = NULL;
346 
347 	/*
348 	 * Generate pen report descriptor
349 	 */
350 	desc_ptr = uclogic_rdesc_template_apply(
351 				uclogic_rdesc_pen_v2_template_arr,
352 				uclogic_rdesc_pen_v2_template_size,
353 				desc_params, ARRAY_SIZE(desc_params));
354 	if (desc_ptr == NULL) {
355 		rc = -ENOMEM;
356 		goto cleanup;
357 	}
358 
359 	/*
360 	 * Fill-in the parameters
361 	 */
362 	memset(pen, 0, sizeof(*pen));
363 	pen->desc_ptr = desc_ptr;
364 	desc_ptr = NULL;
365 	pen->desc_size = uclogic_rdesc_pen_v2_template_size;
366 	pen->id = UCLOGIC_RDESC_PEN_V2_ID;
367 	pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE;
368 	pen->fragmented_hires = true;
369 	found = true;
370 finish:
371 	*pfound = found;
372 	rc = 0;
373 cleanup:
374 	kfree(desc_ptr);
375 	kfree(buf);
376 	return rc;
377 }
378 
379 /**
380  * uclogic_params_frame_cleanup - free resources used by struct
381  * uclogic_params_frame (tablet interface's frame controls input parameters).
382  * Can be called repeatedly.
383  *
384  * @frame:	Frame controls input parameters to cleanup. Cannot be NULL.
385  */
386 static void uclogic_params_frame_cleanup(struct uclogic_params_frame *frame)
387 {
388 	kfree(frame->desc_ptr);
389 	memset(frame, 0, sizeof(*frame));
390 }
391 
392 /**
393  * uclogic_params_frame_init_with_desc() - initialize tablet's frame control
394  * parameters with a static report descriptor.
395  *
396  * @frame:	Pointer to the frame parameters to initialize (to be cleaned
397  *		up with uclogic_params_frame_cleanup()). Not modified in case
398  *		of error. Cannot be NULL.
399  * @desc_ptr:	Report descriptor pointer. Can be NULL, if desc_size is zero.
400  * @desc_size:	Report descriptor size.
401  * @id:		Report ID used for frame reports, if they should be tweaked,
402  *		zero if not.
403  *
404  * Returns:
405  *	Zero, if successful. A negative errno code on error.
406  */
407 static int uclogic_params_frame_init_with_desc(
408 					struct uclogic_params_frame *frame,
409 					const __u8 *desc_ptr,
410 					size_t desc_size,
411 					unsigned int id)
412 {
413 	__u8 *copy_desc_ptr;
414 
415 	if (frame == NULL || (desc_ptr == NULL && desc_size != 0))
416 		return -EINVAL;
417 
418 	copy_desc_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
419 	if (copy_desc_ptr == NULL)
420 		return -ENOMEM;
421 
422 	memset(frame, 0, sizeof(*frame));
423 	frame->desc_ptr = copy_desc_ptr;
424 	frame->desc_size = desc_size;
425 	frame->id = id;
426 	return 0;
427 }
428 
429 /**
430  * uclogic_params_frame_init_v1_buttonpad() - initialize abstract buttonpad
431  * on a v1 tablet interface.
432  *
433  * @frame:	Pointer to the frame parameters to initialize (to be cleaned
434  *		up with uclogic_params_frame_cleanup()). Not modified in case
435  *		of error, or if parameters are not found. Cannot be NULL.
436  * @pfound:	Location for a flag which is set to true if the parameters
437  *		were found, and to false if not (e.g. device was
438  *		incompatible). Not modified in case of error. Cannot be NULL.
439  * @hdev:	The HID device of the tablet interface to initialize and get
440  *		parameters from. Cannot be NULL.
441  *
442  * Returns:
443  *	Zero, if successful. A negative errno code on error.
444  */
445 static int uclogic_params_frame_init_v1_buttonpad(
446 					struct uclogic_params_frame *frame,
447 					bool *pfound,
448 					struct hid_device *hdev)
449 {
450 	int rc;
451 	bool found = false;
452 	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
453 	char *str_buf = NULL;
454 	const size_t str_len = 16;
455 
456 	/* Check arguments */
457 	if (frame == NULL || pfound == NULL || hdev == NULL) {
458 		rc = -EINVAL;
459 		goto cleanup;
460 	}
461 
462 	/*
463 	 * Enable generic button mode
464 	 */
465 	str_buf = kzalloc(str_len, GFP_KERNEL);
466 	if (str_buf == NULL) {
467 		rc = -ENOMEM;
468 		goto cleanup;
469 	}
470 
471 	rc = usb_string(usb_dev, 123, str_buf, str_len);
472 	if (rc == -EPIPE) {
473 		hid_dbg(hdev,
474 			"generic button -enabling string descriptor not found\n");
475 	} else if (rc < 0) {
476 		goto cleanup;
477 	} else if (strncmp(str_buf, "HK On", rc) != 0) {
478 		hid_dbg(hdev,
479 			"invalid response to enabling generic buttons: \"%s\"\n",
480 			str_buf);
481 	} else {
482 		hid_dbg(hdev, "generic buttons enabled\n");
483 		rc = uclogic_params_frame_init_with_desc(
484 				frame,
485 				uclogic_rdesc_buttonpad_v1_arr,
486 				uclogic_rdesc_buttonpad_v1_size,
487 				UCLOGIC_RDESC_BUTTONPAD_V1_ID);
488 		if (rc != 0)
489 			goto cleanup;
490 		found = true;
491 	}
492 
493 	*pfound = found;
494 	rc = 0;
495 cleanup:
496 	kfree(str_buf);
497 	return rc;
498 }
499 
500 /**
501  * uclogic_params_cleanup - free resources used by struct uclogic_params
502  * (tablet interface's parameters).
503  * Can be called repeatedly.
504  *
505  * @params:	Input parameters to cleanup. Cannot be NULL.
506  */
507 void uclogic_params_cleanup(struct uclogic_params *params)
508 {
509 	if (!params->invalid) {
510 		kfree(params->desc_ptr);
511 		if (!params->pen_unused)
512 			uclogic_params_pen_cleanup(&params->pen);
513 		uclogic_params_frame_cleanup(&params->frame);
514 		memset(params, 0, sizeof(*params));
515 	}
516 }
517 
518 /**
519  * Get a replacement report descriptor for a tablet's interface.
520  *
521  * @params:	The parameters of a tablet interface to get report
522  *		descriptor for. Cannot be NULL.
523  * @pdesc:	Location for the resulting, kmalloc-allocated report
524  *		descriptor pointer, or for NULL, if there's no replacement
525  *		report descriptor. Not modified in case of error. Cannot be
526  *		NULL.
527  * @psize:	Location for the resulting report descriptor size, not set if
528  *		there's no replacement report descriptor. Not modified in case
529  *		of error. Cannot be NULL.
530  *
531  * Returns:
532  *	Zero, if successful.
533  *	-EINVAL, if invalid arguments are supplied.
534  *	-ENOMEM, if failed to allocate memory.
535  */
536 int uclogic_params_get_desc(const struct uclogic_params *params,
537 				__u8 **pdesc,
538 				unsigned int *psize)
539 {
540 	bool common_present;
541 	bool pen_present;
542 	bool frame_present;
543 	unsigned int size;
544 	__u8 *desc = NULL;
545 
546 	/* Check arguments */
547 	if (params == NULL || pdesc == NULL || psize == NULL)
548 		return -EINVAL;
549 
550 	size = 0;
551 
552 	common_present = (params->desc_ptr != NULL);
553 	pen_present = (!params->pen_unused && params->pen.desc_ptr != NULL);
554 	frame_present = (params->frame.desc_ptr != NULL);
555 
556 	if (common_present)
557 		size += params->desc_size;
558 	if (pen_present)
559 		size += params->pen.desc_size;
560 	if (frame_present)
561 		size += params->frame.desc_size;
562 
563 	if (common_present || pen_present || frame_present) {
564 		__u8 *p;
565 
566 		desc = kmalloc(size, GFP_KERNEL);
567 		if (desc == NULL)
568 			return -ENOMEM;
569 		p = desc;
570 
571 		if (common_present) {
572 			memcpy(p, params->desc_ptr,
573 				params->desc_size);
574 			p += params->desc_size;
575 		}
576 		if (pen_present) {
577 			memcpy(p, params->pen.desc_ptr,
578 				params->pen.desc_size);
579 			p += params->pen.desc_size;
580 		}
581 		if (frame_present) {
582 			memcpy(p, params->frame.desc_ptr,
583 				params->frame.desc_size);
584 			p += params->frame.desc_size;
585 		}
586 
587 		WARN_ON(p != desc + size);
588 
589 		*psize = size;
590 	}
591 
592 	*pdesc = desc;
593 	return 0;
594 }
595 
596 /**
597  * uclogic_params_init_invalid() - initialize tablet interface parameters,
598  * specifying the interface is invalid.
599  *
600  * @params:		Parameters to initialize (to be cleaned with
601  *			uclogic_params_cleanup()). Cannot be NULL.
602  */
603 static void uclogic_params_init_invalid(struct uclogic_params *params)
604 {
605 	params->invalid = true;
606 }
607 
608 /**
609  * uclogic_params_init_with_opt_desc() - initialize tablet interface
610  * parameters with an optional replacement report descriptor. Only modify
611  * report descriptor, if the original report descriptor matches the expected
612  * size.
613  *
614  * @params:		Parameters to initialize (to be cleaned with
615  *			uclogic_params_cleanup()). Not modified in case of
616  *			error. Cannot be NULL.
617  * @hdev:		The HID device of the tablet interface create the
618  *			parameters for. Cannot be NULL.
619  * @orig_desc_size:	Expected size of the original report descriptor to
620  *			be replaced.
621  * @desc_ptr:		Pointer to the replacement report descriptor.
622  *			Can be NULL, if desc_size is zero.
623  * @desc_size:		Size of the replacement report descriptor.
624  *
625  * Returns:
626  *	Zero, if successful. -EINVAL if an invalid argument was passed.
627  *	-ENOMEM, if failed to allocate memory.
628  */
629 static int uclogic_params_init_with_opt_desc(struct uclogic_params *params,
630 					     struct hid_device *hdev,
631 					     unsigned int orig_desc_size,
632 					     __u8 *desc_ptr,
633 					     unsigned int desc_size)
634 {
635 	__u8 *desc_copy_ptr = NULL;
636 	unsigned int desc_copy_size;
637 	int rc;
638 
639 	/* Check arguments */
640 	if (params == NULL || hdev == NULL ||
641 	    (desc_ptr == NULL && desc_size != 0)) {
642 		rc = -EINVAL;
643 		goto cleanup;
644 	}
645 
646 	/* Replace report descriptor, if it matches */
647 	if (hdev->dev_rsize == orig_desc_size) {
648 		hid_dbg(hdev,
649 			"device report descriptor matches the expected size, replacing\n");
650 		desc_copy_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
651 		if (desc_copy_ptr == NULL) {
652 			rc = -ENOMEM;
653 			goto cleanup;
654 		}
655 		desc_copy_size = desc_size;
656 	} else {
657 		hid_dbg(hdev,
658 			"device report descriptor doesn't match the expected size (%u != %u), preserving\n",
659 			hdev->dev_rsize, orig_desc_size);
660 		desc_copy_ptr = NULL;
661 		desc_copy_size = 0;
662 	}
663 
664 	/* Output parameters */
665 	memset(params, 0, sizeof(*params));
666 	params->desc_ptr = desc_copy_ptr;
667 	desc_copy_ptr = NULL;
668 	params->desc_size = desc_copy_size;
669 
670 	rc = 0;
671 cleanup:
672 	kfree(desc_copy_ptr);
673 	return rc;
674 }
675 
676 /**
677  * uclogic_params_init_with_pen_unused() - initialize tablet interface
678  * parameters preserving original reports and generic HID processing, but
679  * disabling pen usage.
680  *
681  * @params:		Parameters to initialize (to be cleaned with
682  *			uclogic_params_cleanup()). Not modified in case of
683  *			error. Cannot be NULL.
684  */
685 static void uclogic_params_init_with_pen_unused(struct uclogic_params *params)
686 {
687 	memset(params, 0, sizeof(*params));
688 	params->pen_unused = true;
689 }
690 
691 /**
692  * uclogic_params_init() - initialize a Huion tablet interface and discover
693  * its parameters.
694  *
695  * @params:	Parameters to fill in (to be cleaned with
696  *		uclogic_params_cleanup()). Not modified in case of error.
697  *		Cannot be NULL.
698  * @hdev:	The HID device of the tablet interface to initialize and get
699  *		parameters from. Cannot be NULL.
700  *
701  * Returns:
702  *	Zero, if successful. A negative errno code on error.
703  */
704 static int uclogic_params_huion_init(struct uclogic_params *params,
705 				     struct hid_device *hdev)
706 {
707 	int rc;
708 	struct usb_device *udev = hid_to_usb_dev(hdev);
709 	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
710 	__u8 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
711 	bool found;
712 	/* The resulting parameters (noop) */
713 	struct uclogic_params p = {0, };
714 	static const char transition_ver[] = "HUION_T153_160607";
715 	char *ver_ptr = NULL;
716 	const size_t ver_len = sizeof(transition_ver) + 1;
717 
718 	/* Check arguments */
719 	if (params == NULL || hdev == NULL) {
720 		rc = -EINVAL;
721 		goto cleanup;
722 	}
723 
724 	/* If it's not a pen interface */
725 	if (bInterfaceNumber != 0) {
726 		/* TODO: Consider marking the interface invalid */
727 		uclogic_params_init_with_pen_unused(&p);
728 		goto output;
729 	}
730 
731 	/* Try to get firmware version */
732 	ver_ptr = kzalloc(ver_len, GFP_KERNEL);
733 	if (ver_ptr == NULL) {
734 		rc = -ENOMEM;
735 		goto cleanup;
736 	}
737 	rc = usb_string(udev, 201, ver_ptr, ver_len);
738 	if (rc == -EPIPE) {
739 		*ver_ptr = '\0';
740 	} else if (rc < 0) {
741 		hid_err(hdev,
742 			"failed retrieving Huion firmware version: %d\n", rc);
743 		goto cleanup;
744 	}
745 
746 	/* If this is a transition firmware */
747 	if (strcmp(ver_ptr, transition_ver) == 0) {
748 		hid_dbg(hdev,
749 			"transition firmware detected, not probing pen v2 parameters\n");
750 	} else {
751 		/* Try to probe v2 pen parameters */
752 		rc = uclogic_params_pen_init_v2(&p.pen, &found, hdev);
753 		if (rc != 0) {
754 			hid_err(hdev,
755 				"failed probing pen v2 parameters: %d\n", rc);
756 			goto cleanup;
757 		} else if (found) {
758 			hid_dbg(hdev, "pen v2 parameters found\n");
759 			/* Create v2 buttonpad parameters */
760 			rc = uclogic_params_frame_init_with_desc(
761 					&p.frame,
762 					uclogic_rdesc_buttonpad_v2_arr,
763 					uclogic_rdesc_buttonpad_v2_size,
764 					UCLOGIC_RDESC_BUTTONPAD_V2_ID);
765 			if (rc != 0) {
766 				hid_err(hdev,
767 					"failed creating v2 buttonpad parameters: %d\n",
768 					rc);
769 				goto cleanup;
770 			}
771 			/* Set bitmask marking frame reports in pen reports */
772 			p.pen_frame_flag = 0x20;
773 			goto output;
774 		}
775 		hid_dbg(hdev, "pen v2 parameters not found\n");
776 	}
777 
778 	/* Try to probe v1 pen parameters */
779 	rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
780 	if (rc != 0) {
781 		hid_err(hdev,
782 			"failed probing pen v1 parameters: %d\n", rc);
783 		goto cleanup;
784 	} else if (found) {
785 		hid_dbg(hdev, "pen v1 parameters found\n");
786 		/* Try to probe v1 buttonpad */
787 		rc = uclogic_params_frame_init_v1_buttonpad(
788 						&p.frame,
789 						&found, hdev);
790 		if (rc != 0) {
791 			hid_err(hdev, "v1 buttonpad probing failed: %d\n", rc);
792 			goto cleanup;
793 		}
794 		hid_dbg(hdev, "buttonpad v1 parameters%s found\n",
795 			(found ? "" : " not"));
796 		if (found) {
797 			/* Set bitmask marking frame reports */
798 			p.pen_frame_flag = 0x20;
799 		}
800 		goto output;
801 	}
802 	hid_dbg(hdev, "pen v1 parameters not found\n");
803 
804 	uclogic_params_init_invalid(&p);
805 
806 output:
807 	/* Output parameters */
808 	memcpy(params, &p, sizeof(*params));
809 	memset(&p, 0, sizeof(p));
810 	rc = 0;
811 cleanup:
812 	kfree(ver_ptr);
813 	uclogic_params_cleanup(&p);
814 	return rc;
815 }
816 
817 /**
818  * uclogic_params_init() - initialize a tablet interface and discover its
819  * parameters.
820  *
821  * @params:	Parameters to fill in (to be cleaned with
822  *		uclogic_params_cleanup()). Not modified in case of error.
823  *		Cannot be NULL.
824  * @hdev:	The HID device of the tablet interface to initialize and get
825  *		parameters from. Cannot be NULL. Must be using the USB low-level
826  *		driver, i.e. be an actual USB tablet.
827  *
828  * Returns:
829  *	Zero, if successful. A negative errno code on error.
830  */
831 int uclogic_params_init(struct uclogic_params *params,
832 			struct hid_device *hdev)
833 {
834 	int rc;
835 	struct usb_device *udev = hid_to_usb_dev(hdev);
836 	__u8  bNumInterfaces = udev->config->desc.bNumInterfaces;
837 	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
838 	__u8 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
839 	bool found;
840 	/* The resulting parameters (noop) */
841 	struct uclogic_params p = {0, };
842 
843 	/* Check arguments */
844 	if (params == NULL || hdev == NULL ||
845 	    !hid_is_using_ll_driver(hdev, &usb_hid_driver)) {
846 		rc = -EINVAL;
847 		goto cleanup;
848 	}
849 
850 	/*
851 	 * Set replacement report descriptor if the original matches the
852 	 * specified size. Otherwise keep interface unchanged.
853 	 */
854 #define WITH_OPT_DESC(_orig_desc_token, _new_desc_token) \
855 	uclogic_params_init_with_opt_desc(                  \
856 		&p, hdev,                                   \
857 		UCLOGIC_RDESC_##_orig_desc_token##_SIZE,    \
858 		uclogic_rdesc_##_new_desc_token##_arr,      \
859 		uclogic_rdesc_##_new_desc_token##_size)
860 
861 #define VID_PID(_vid, _pid) \
862 	(((__u32)(_vid) << 16) | ((__u32)(_pid) & U16_MAX))
863 
864 	/*
865 	 * Handle specific interfaces for specific tablets.
866 	 *
867 	 * Observe the following logic:
868 	 *
869 	 * If the interface is recognized as producing certain useful input:
870 	 *	Mark interface as valid.
871 	 *	Output interface parameters.
872 	 * Else, if the interface is recognized as *not* producing any useful
873 	 * input:
874 	 *	Mark interface as invalid.
875 	 * Else:
876 	 *	Mark interface as valid.
877 	 *	Output noop parameters.
878 	 *
879 	 * Rule of thumb: it is better to disable a broken interface than let
880 	 *		  it spew garbage input.
881 	 */
882 
883 	switch (VID_PID(hdev->vendor, hdev->product)) {
884 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
885 		     USB_DEVICE_ID_UCLOGIC_TABLET_PF1209):
886 		rc = WITH_OPT_DESC(PF1209_ORIG, pf1209_fixed);
887 		if (rc != 0)
888 			goto cleanup;
889 		break;
890 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
891 		     USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U):
892 		rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp4030u_fixed);
893 		if (rc != 0)
894 			goto cleanup;
895 		break;
896 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
897 		     USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U):
898 		if (hdev->dev_rsize == UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE) {
899 			if (bInterfaceNumber == 0) {
900 				/* Try to probe v1 pen parameters */
901 				rc = uclogic_params_pen_init_v1(&p.pen,
902 								&found, hdev);
903 				if (rc != 0) {
904 					hid_err(hdev,
905 						"pen probing failed: %d\n",
906 						rc);
907 					goto cleanup;
908 				}
909 				if (!found) {
910 					hid_warn(hdev,
911 						 "pen parameters not found");
912 				}
913 			} else {
914 				uclogic_params_init_invalid(&p);
915 			}
916 		} else {
917 			rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp5540u_fixed);
918 			if (rc != 0)
919 				goto cleanup;
920 		}
921 		break;
922 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
923 		     USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U):
924 		rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp8060u_fixed);
925 		if (rc != 0)
926 			goto cleanup;
927 		break;
928 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
929 		     USB_DEVICE_ID_UCLOGIC_TABLET_WP1062):
930 		rc = WITH_OPT_DESC(WP1062_ORIG, wp1062_fixed);
931 		if (rc != 0)
932 			goto cleanup;
933 		break;
934 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
935 		     USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850):
936 		switch (bInterfaceNumber) {
937 		case 0:
938 			rc = WITH_OPT_DESC(TWHL850_ORIG0, twhl850_fixed0);
939 			if (rc != 0)
940 				goto cleanup;
941 			break;
942 		case 1:
943 			rc = WITH_OPT_DESC(TWHL850_ORIG1, twhl850_fixed1);
944 			if (rc != 0)
945 				goto cleanup;
946 			break;
947 		case 2:
948 			rc = WITH_OPT_DESC(TWHL850_ORIG2, twhl850_fixed2);
949 			if (rc != 0)
950 				goto cleanup;
951 			break;
952 		}
953 		break;
954 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
955 		     USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60):
956 		/*
957 		 * If it is not a three-interface version, which is known to
958 		 * respond to initialization.
959 		 */
960 		if (bNumInterfaces != 3) {
961 			switch (bInterfaceNumber) {
962 			case 0:
963 				rc = WITH_OPT_DESC(TWHA60_ORIG0,
964 							twha60_fixed0);
965 				if (rc != 0)
966 					goto cleanup;
967 				break;
968 			case 1:
969 				rc = WITH_OPT_DESC(TWHA60_ORIG1,
970 							twha60_fixed1);
971 				if (rc != 0)
972 					goto cleanup;
973 				break;
974 			}
975 			break;
976 		}
977 		fallthrough;
978 	case VID_PID(USB_VENDOR_ID_HUION,
979 		     USB_DEVICE_ID_HUION_TABLET):
980 	case VID_PID(USB_VENDOR_ID_HUION,
981 		     USB_DEVICE_ID_HUION_HS64):
982 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
983 		     USB_DEVICE_ID_HUION_TABLET):
984 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
985 		     USB_DEVICE_ID_YIYNOVA_TABLET):
986 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
987 		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81):
988 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
989 		     USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3):
990 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
991 		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45):
992 	case VID_PID(USB_VENDOR_ID_UCLOGIC,
993 		     USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47):
994 		rc = uclogic_params_huion_init(&p, hdev);
995 		if (rc != 0)
996 			goto cleanup;
997 		break;
998 	case VID_PID(USB_VENDOR_ID_UGTIZER,
999 		     USB_DEVICE_ID_UGTIZER_TABLET_GP0610):
1000 	case VID_PID(USB_VENDOR_ID_UGTIZER,
1001 		     USB_DEVICE_ID_UGTIZER_TABLET_GT5040):
1002 	case VID_PID(USB_VENDOR_ID_UGEE,
1003 		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
1004 	case VID_PID(USB_VENDOR_ID_UGEE,
1005 		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
1006 	case VID_PID(USB_VENDOR_ID_UGEE,
1007 		     USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
1008 		/* If this is the pen interface */
1009 		if (bInterfaceNumber == 1) {
1010 			/* Probe v1 pen parameters */
1011 			rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1012 			if (rc != 0) {
1013 				hid_err(hdev, "pen probing failed: %d\n", rc);
1014 				goto cleanup;
1015 			}
1016 			if (!found) {
1017 				hid_warn(hdev, "pen parameters not found");
1018 				uclogic_params_init_invalid(&p);
1019 			}
1020 		} else {
1021 			/* TODO: Consider marking the interface invalid */
1022 			uclogic_params_init_with_pen_unused(&p);
1023 		}
1024 		break;
1025 	case VID_PID(USB_VENDOR_ID_UGEE,
1026 		     USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01):
1027 		/* If this is the pen and frame interface */
1028 		if (bInterfaceNumber == 1) {
1029 			/* Probe v1 pen parameters */
1030 			rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1031 			if (rc != 0) {
1032 				hid_err(hdev, "pen probing failed: %d\n", rc);
1033 				goto cleanup;
1034 			}
1035 			/* Initialize frame parameters */
1036 			rc = uclogic_params_frame_init_with_desc(
1037 				&p.frame,
1038 				uclogic_rdesc_xppen_deco01_frame_arr,
1039 				uclogic_rdesc_xppen_deco01_frame_size,
1040 				0);
1041 			if (rc != 0)
1042 				goto cleanup;
1043 		} else {
1044 			/* TODO: Consider marking the interface invalid */
1045 			uclogic_params_init_with_pen_unused(&p);
1046 		}
1047 		break;
1048 	case VID_PID(USB_VENDOR_ID_UGEE,
1049 		     USB_DEVICE_ID_UGEE_TABLET_G5):
1050 		/* Ignore non-pen interfaces */
1051 		if (bInterfaceNumber != 1) {
1052 			uclogic_params_init_invalid(&p);
1053 			break;
1054 		}
1055 
1056 		rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1057 		if (rc != 0) {
1058 			hid_err(hdev, "pen probing failed: %d\n", rc);
1059 			goto cleanup;
1060 		} else if (found) {
1061 			rc = uclogic_params_frame_init_with_desc(
1062 				&p.frame,
1063 				uclogic_rdesc_ugee_g5_frame_arr,
1064 				uclogic_rdesc_ugee_g5_frame_size,
1065 				UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
1066 			if (rc != 0) {
1067 				hid_err(hdev,
1068 					"failed creating buttonpad parameters: %d\n",
1069 					rc);
1070 				goto cleanup;
1071 			}
1072 			p.frame.re_lsb =
1073 				UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB;
1074 			p.frame.dev_id_byte =
1075 				UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
1076 		} else {
1077 			hid_warn(hdev, "pen parameters not found");
1078 			uclogic_params_init_invalid(&p);
1079 		}
1080 
1081 		break;
1082 	case VID_PID(USB_VENDOR_ID_UGEE,
1083 		     USB_DEVICE_ID_UGEE_TABLET_EX07S):
1084 		/* Ignore non-pen interfaces */
1085 		if (bInterfaceNumber != 1) {
1086 			uclogic_params_init_invalid(&p);
1087 			break;
1088 		}
1089 
1090 		rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1091 		if (rc != 0) {
1092 			hid_err(hdev, "pen probing failed: %d\n", rc);
1093 			goto cleanup;
1094 		} else if (found) {
1095 			rc = uclogic_params_frame_init_with_desc(
1096 				&p.frame,
1097 				uclogic_rdesc_ugee_ex07_buttonpad_arr,
1098 				uclogic_rdesc_ugee_ex07_buttonpad_size,
1099 				0);
1100 			if (rc != 0) {
1101 				hid_err(hdev,
1102 					"failed creating buttonpad parameters: %d\n",
1103 					rc);
1104 				goto cleanup;
1105 			}
1106 		} else {
1107 			hid_warn(hdev, "pen parameters not found");
1108 			uclogic_params_init_invalid(&p);
1109 		}
1110 
1111 		break;
1112 	}
1113 
1114 #undef VID_PID
1115 #undef WITH_OPT_DESC
1116 
1117 	/* Output parameters */
1118 	memcpy(params, &p, sizeof(*params));
1119 	memset(&p, 0, sizeof(p));
1120 	rc = 0;
1121 cleanup:
1122 	uclogic_params_cleanup(&p);
1123 	return rc;
1124 }
1125