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