Merge tag 'v5.15.62' into rpi-5.15.y
[platform/kernel/linux-rpi.git] / drivers / hid / hid-uclogic-params.c
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_pen_v1_template_arr,
211                                 uclogic_rdesc_pen_v1_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_pen_v1_template_size;
225         pen->id = UCLOGIC_RDESC_PEN_V1_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_pen_v2_template_arr,
355                                 uclogic_rdesc_pen_v2_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_pen_v2_template_size;
369         pen->id = UCLOGIC_RDESC_PEN_V2_ID;
370         pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE;
371         pen->fragmented_hires = true;
372         found = true;
373 finish:
374         *pfound = found;
375         rc = 0;
376 cleanup:
377         kfree(desc_ptr);
378         kfree(buf);
379         return rc;
380 }
381
382 /**
383  * uclogic_params_frame_cleanup - free resources used by struct
384  * uclogic_params_frame (tablet interface's frame controls input parameters).
385  * Can be called repeatedly.
386  *
387  * @frame:      Frame controls input parameters to cleanup. Cannot be NULL.
388  */
389 static void uclogic_params_frame_cleanup(struct uclogic_params_frame *frame)
390 {
391         kfree(frame->desc_ptr);
392         memset(frame, 0, sizeof(*frame));
393 }
394
395 /**
396  * uclogic_params_frame_init_with_desc() - initialize tablet's frame control
397  * parameters with a static report descriptor.
398  *
399  * @frame:      Pointer to the frame parameters to initialize (to be cleaned
400  *              up with uclogic_params_frame_cleanup()). Not modified in case
401  *              of error. Cannot be NULL.
402  * @desc_ptr:   Report descriptor pointer. Can be NULL, if desc_size is zero.
403  * @desc_size:  Report descriptor size.
404  * @id:         Report ID used for frame reports, if they should be tweaked,
405  *              zero if not.
406  *
407  * Returns:
408  *      Zero, if successful. A negative errno code on error.
409  */
410 static int uclogic_params_frame_init_with_desc(
411                                         struct uclogic_params_frame *frame,
412                                         const __u8 *desc_ptr,
413                                         size_t desc_size,
414                                         unsigned int id)
415 {
416         __u8 *copy_desc_ptr;
417
418         if (frame == NULL || (desc_ptr == NULL && desc_size != 0))
419                 return -EINVAL;
420
421         copy_desc_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
422         if (copy_desc_ptr == NULL)
423                 return -ENOMEM;
424
425         memset(frame, 0, sizeof(*frame));
426         frame->desc_ptr = copy_desc_ptr;
427         frame->desc_size = desc_size;
428         frame->id = id;
429         return 0;
430 }
431
432 /**
433  * uclogic_params_frame_init_v1_buttonpad() - initialize abstract buttonpad
434  * on a v1 tablet interface.
435  *
436  * @frame:      Pointer to the frame parameters to initialize (to be cleaned
437  *              up with uclogic_params_frame_cleanup()). Not modified in case
438  *              of error, or if parameters are not found. Cannot be NULL.
439  * @pfound:     Location for a flag which is set to true if the parameters
440  *              were found, and to false if not (e.g. device was
441  *              incompatible). Not modified in case of error. Cannot be NULL.
442  * @hdev:       The HID device of the tablet interface to initialize and get
443  *              parameters from. Cannot be NULL.
444  *
445  * Returns:
446  *      Zero, if successful. A negative errno code on error.
447  */
448 static int uclogic_params_frame_init_v1_buttonpad(
449                                         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_buttonpad_v1_arr,
491                                 uclogic_rdesc_buttonpad_v1_size,
492                                 UCLOGIC_RDESC_BUTTONPAD_V1_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                 kfree(params->desc_ptr);
516                 if (!params->pen_unused)
517                         uclogic_params_pen_cleanup(&params->pen);
518                 uclogic_params_frame_cleanup(&params->frame);
519                 memset(params, 0, sizeof(*params));
520         }
521 }
522
523 /**
524  * uclogic_params_get_desc() - Get a replacement report descriptor for a
525  *                             tablet's interface.
526  *
527  * @params:     The parameters of a tablet interface to get report
528  *              descriptor for. Cannot be NULL.
529  * @pdesc:      Location for the resulting, kmalloc-allocated report
530  *              descriptor pointer, or for NULL, if there's no replacement
531  *              report descriptor. Not modified in case of error. Cannot be
532  *              NULL.
533  * @psize:      Location for the resulting report descriptor size, not set if
534  *              there's no replacement report descriptor. Not modified in case
535  *              of error. Cannot be NULL.
536  *
537  * Returns:
538  *      Zero, if successful.
539  *      -EINVAL, if invalid arguments are supplied.
540  *      -ENOMEM, if failed to allocate memory.
541  */
542 int uclogic_params_get_desc(const struct uclogic_params *params,
543                                 __u8 **pdesc,
544                                 unsigned int *psize)
545 {
546         bool common_present;
547         bool pen_present;
548         bool frame_present;
549         unsigned int size;
550         __u8 *desc = NULL;
551
552         /* Check arguments */
553         if (params == NULL || pdesc == NULL || psize == NULL)
554                 return -EINVAL;
555
556         size = 0;
557
558         common_present = (params->desc_ptr != NULL);
559         pen_present = (!params->pen_unused && params->pen.desc_ptr != NULL);
560         frame_present = (params->frame.desc_ptr != NULL);
561
562         if (common_present)
563                 size += params->desc_size;
564         if (pen_present)
565                 size += params->pen.desc_size;
566         if (frame_present)
567                 size += params->frame.desc_size;
568
569         if (common_present || pen_present || frame_present) {
570                 __u8 *p;
571
572                 desc = kmalloc(size, GFP_KERNEL);
573                 if (desc == NULL)
574                         return -ENOMEM;
575                 p = desc;
576
577                 if (common_present) {
578                         memcpy(p, params->desc_ptr,
579                                 params->desc_size);
580                         p += params->desc_size;
581                 }
582                 if (pen_present) {
583                         memcpy(p, params->pen.desc_ptr,
584                                 params->pen.desc_size);
585                         p += params->pen.desc_size;
586                 }
587                 if (frame_present) {
588                         memcpy(p, params->frame.desc_ptr,
589                                 params->frame.desc_size);
590                         p += params->frame.desc_size;
591                 }
592
593                 WARN_ON(p != desc + size);
594
595                 *psize = size;
596         }
597
598         *pdesc = desc;
599         return 0;
600 }
601
602 /**
603  * uclogic_params_init_invalid() - initialize tablet interface parameters,
604  * specifying the interface is invalid.
605  *
606  * @params:             Parameters to initialize (to be cleaned with
607  *                      uclogic_params_cleanup()). Cannot be NULL.
608  */
609 static void uclogic_params_init_invalid(struct uclogic_params *params)
610 {
611         params->invalid = true;
612 }
613
614 /**
615  * uclogic_params_init_with_opt_desc() - initialize tablet interface
616  * parameters with an optional replacement report descriptor. Only modify
617  * report descriptor, if the original report descriptor matches the expected
618  * size.
619  *
620  * @params:             Parameters to initialize (to be cleaned with
621  *                      uclogic_params_cleanup()). Not modified in case of
622  *                      error. Cannot be NULL.
623  * @hdev:               The HID device of the tablet interface create the
624  *                      parameters for. Cannot be NULL.
625  * @orig_desc_size:     Expected size of the original report descriptor to
626  *                      be replaced.
627  * @desc_ptr:           Pointer to the replacement report descriptor.
628  *                      Can be NULL, if desc_size is zero.
629  * @desc_size:          Size of the replacement report descriptor.
630  *
631  * Returns:
632  *      Zero, if successful. -EINVAL if an invalid argument was passed.
633  *      -ENOMEM, if failed to allocate memory.
634  */
635 static int uclogic_params_init_with_opt_desc(struct uclogic_params *params,
636                                              struct hid_device *hdev,
637                                              unsigned int orig_desc_size,
638                                              __u8 *desc_ptr,
639                                              unsigned int desc_size)
640 {
641         __u8 *desc_copy_ptr = NULL;
642         unsigned int desc_copy_size;
643         int rc;
644
645         /* Check arguments */
646         if (params == NULL || hdev == NULL ||
647             (desc_ptr == NULL && desc_size != 0)) {
648                 rc = -EINVAL;
649                 goto cleanup;
650         }
651
652         /* Replace report descriptor, if it matches */
653         if (hdev->dev_rsize == orig_desc_size) {
654                 hid_dbg(hdev,
655                         "device report descriptor matches the expected size, replacing\n");
656                 desc_copy_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
657                 if (desc_copy_ptr == NULL) {
658                         rc = -ENOMEM;
659                         goto cleanup;
660                 }
661                 desc_copy_size = desc_size;
662         } else {
663                 hid_dbg(hdev,
664                         "device report descriptor doesn't match the expected size (%u != %u), preserving\n",
665                         hdev->dev_rsize, orig_desc_size);
666                 desc_copy_ptr = NULL;
667                 desc_copy_size = 0;
668         }
669
670         /* Output parameters */
671         memset(params, 0, sizeof(*params));
672         params->desc_ptr = desc_copy_ptr;
673         desc_copy_ptr = NULL;
674         params->desc_size = desc_copy_size;
675
676         rc = 0;
677 cleanup:
678         kfree(desc_copy_ptr);
679         return rc;
680 }
681
682 /**
683  * uclogic_params_init_with_pen_unused() - initialize tablet interface
684  * parameters preserving original reports and generic HID processing, but
685  * disabling pen usage.
686  *
687  * @params:             Parameters to initialize (to be cleaned with
688  *                      uclogic_params_cleanup()). Not modified in case of
689  *                      error. Cannot be NULL.
690  */
691 static void uclogic_params_init_with_pen_unused(struct uclogic_params *params)
692 {
693         memset(params, 0, sizeof(*params));
694         params->pen_unused = true;
695 }
696
697 /**
698  * uclogic_params_huion_init() - initialize a Huion tablet interface and discover
699  * its parameters.
700  *
701  * @params:     Parameters to fill in (to be cleaned with
702  *              uclogic_params_cleanup()). Not modified in case of error.
703  *              Cannot be NULL.
704  * @hdev:       The HID device of the tablet interface to initialize and get
705  *              parameters from. Cannot be NULL.
706  *
707  * Returns:
708  *      Zero, if successful. A negative errno code on error.
709  */
710 static int uclogic_params_huion_init(struct uclogic_params *params,
711                                      struct hid_device *hdev)
712 {
713         int rc;
714         struct usb_device *udev;
715         struct usb_interface *iface;
716         __u8 bInterfaceNumber;
717         bool found;
718         /* The resulting parameters (noop) */
719         struct uclogic_params p = {0, };
720         static const char transition_ver[] = "HUION_T153_160607";
721         char *ver_ptr = NULL;
722         const size_t ver_len = sizeof(transition_ver) + 1;
723
724         /* Check arguments */
725         if (params == NULL || hdev == NULL) {
726                 rc = -EINVAL;
727                 goto cleanup;
728         }
729
730         udev = hid_to_usb_dev(hdev);
731         iface = to_usb_interface(hdev->dev.parent);
732         bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
733
734         /* If it's not a pen interface */
735         if (bInterfaceNumber != 0) {
736                 /* TODO: Consider marking the interface invalid */
737                 uclogic_params_init_with_pen_unused(&p);
738                 goto output;
739         }
740
741         /* Try to get firmware version */
742         ver_ptr = kzalloc(ver_len, GFP_KERNEL);
743         if (ver_ptr == NULL) {
744                 rc = -ENOMEM;
745                 goto cleanup;
746         }
747         rc = usb_string(udev, 201, ver_ptr, ver_len);
748         if (rc == -EPIPE) {
749                 *ver_ptr = '\0';
750         } else if (rc < 0) {
751                 hid_err(hdev,
752                         "failed retrieving Huion firmware version: %d\n", rc);
753                 goto cleanup;
754         }
755
756         /* If this is a transition firmware */
757         if (strcmp(ver_ptr, transition_ver) == 0) {
758                 hid_dbg(hdev,
759                         "transition firmware detected, not probing pen v2 parameters\n");
760         } else {
761                 /* Try to probe v2 pen parameters */
762                 rc = uclogic_params_pen_init_v2(&p.pen, &found, hdev);
763                 if (rc != 0) {
764                         hid_err(hdev,
765                                 "failed probing pen v2 parameters: %d\n", rc);
766                         goto cleanup;
767                 } else if (found) {
768                         hid_dbg(hdev, "pen v2 parameters found\n");
769                         /* Create v2 buttonpad parameters */
770                         rc = uclogic_params_frame_init_with_desc(
771                                         &p.frame,
772                                         uclogic_rdesc_buttonpad_v2_arr,
773                                         uclogic_rdesc_buttonpad_v2_size,
774                                         UCLOGIC_RDESC_BUTTONPAD_V2_ID);
775                         if (rc != 0) {
776                                 hid_err(hdev,
777                                         "failed creating v2 buttonpad parameters: %d\n",
778                                         rc);
779                                 goto cleanup;
780                         }
781                         /* Set bitmask marking frame reports in pen reports */
782                         p.pen_frame_flag = 0x20;
783                         goto output;
784                 }
785                 hid_dbg(hdev, "pen v2 parameters not found\n");
786         }
787
788         /* Try to probe v1 pen parameters */
789         rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
790         if (rc != 0) {
791                 hid_err(hdev,
792                         "failed probing pen v1 parameters: %d\n", rc);
793                 goto cleanup;
794         } else if (found) {
795                 hid_dbg(hdev, "pen v1 parameters found\n");
796                 /* Try to probe v1 buttonpad */
797                 rc = uclogic_params_frame_init_v1_buttonpad(
798                                                 &p.frame,
799                                                 &found, hdev);
800                 if (rc != 0) {
801                         hid_err(hdev, "v1 buttonpad probing failed: %d\n", rc);
802                         goto cleanup;
803                 }
804                 hid_dbg(hdev, "buttonpad v1 parameters%s found\n",
805                         (found ? "" : " not"));
806                 if (found) {
807                         /* Set bitmask marking frame reports */
808                         p.pen_frame_flag = 0x20;
809                 }
810                 goto output;
811         }
812         hid_dbg(hdev, "pen v1 parameters not found\n");
813
814         uclogic_params_init_invalid(&p);
815
816 output:
817         /* Output parameters */
818         memcpy(params, &p, sizeof(*params));
819         memset(&p, 0, sizeof(p));
820         rc = 0;
821 cleanup:
822         kfree(ver_ptr);
823         uclogic_params_cleanup(&p);
824         return rc;
825 }
826
827 /**
828  * uclogic_params_init() - initialize a tablet interface and discover its
829  * parameters.
830  *
831  * @params:     Parameters to fill in (to be cleaned with
832  *              uclogic_params_cleanup()). Not modified in case of error.
833  *              Cannot be NULL.
834  * @hdev:       The HID device of the tablet interface to initialize and get
835  *              parameters from. Cannot be NULL. Must be using the USB low-level
836  *              driver, i.e. be an actual USB tablet.
837  *
838  * Returns:
839  *      Zero, if successful. A negative errno code on error.
840  */
841 int uclogic_params_init(struct uclogic_params *params,
842                         struct hid_device *hdev)
843 {
844         int rc;
845         struct usb_device *udev;
846         __u8  bNumInterfaces;
847         struct usb_interface *iface;
848         __u8 bInterfaceNumber;
849         bool found;
850         /* The resulting parameters (noop) */
851         struct uclogic_params p = {0, };
852
853         /* Check arguments */
854         if (params == NULL || hdev == NULL || !hid_is_usb(hdev)) {
855                 rc = -EINVAL;
856                 goto cleanup;
857         }
858
859         udev = hid_to_usb_dev(hdev);
860         bNumInterfaces = udev->config->desc.bNumInterfaces;
861         iface = to_usb_interface(hdev->dev.parent);
862         bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
863
864         /*
865          * Set replacement report descriptor if the original matches the
866          * specified size. Otherwise keep interface unchanged.
867          */
868 #define WITH_OPT_DESC(_orig_desc_token, _new_desc_token) \
869         uclogic_params_init_with_opt_desc(                  \
870                 &p, hdev,                                   \
871                 UCLOGIC_RDESC_##_orig_desc_token##_SIZE,    \
872                 uclogic_rdesc_##_new_desc_token##_arr,      \
873                 uclogic_rdesc_##_new_desc_token##_size)
874
875 #define VID_PID(_vid, _pid) \
876         (((__u32)(_vid) << 16) | ((__u32)(_pid) & U16_MAX))
877
878         /*
879          * Handle specific interfaces for specific tablets.
880          *
881          * Observe the following logic:
882          *
883          * If the interface is recognized as producing certain useful input:
884          *      Mark interface as valid.
885          *      Output interface parameters.
886          * Else, if the interface is recognized as *not* producing any useful
887          * input:
888          *      Mark interface as invalid.
889          * Else:
890          *      Mark interface as valid.
891          *      Output noop parameters.
892          *
893          * Rule of thumb: it is better to disable a broken interface than let
894          *                it spew garbage input.
895          */
896
897         switch (VID_PID(hdev->vendor, hdev->product)) {
898         case VID_PID(USB_VENDOR_ID_UCLOGIC,
899                      USB_DEVICE_ID_UCLOGIC_TABLET_PF1209):
900                 rc = WITH_OPT_DESC(PF1209_ORIG, pf1209_fixed);
901                 if (rc != 0)
902                         goto cleanup;
903                 break;
904         case VID_PID(USB_VENDOR_ID_UCLOGIC,
905                      USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U):
906                 rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp4030u_fixed);
907                 if (rc != 0)
908                         goto cleanup;
909                 break;
910         case VID_PID(USB_VENDOR_ID_UCLOGIC,
911                      USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U):
912                 if (hdev->dev_rsize == UCLOGIC_RDESC_WP5540U_V2_ORIG_SIZE) {
913                         if (bInterfaceNumber == 0) {
914                                 /* Try to probe v1 pen parameters */
915                                 rc = uclogic_params_pen_init_v1(&p.pen,
916                                                                 &found, hdev);
917                                 if (rc != 0) {
918                                         hid_err(hdev,
919                                                 "pen probing failed: %d\n",
920                                                 rc);
921                                         goto cleanup;
922                                 }
923                                 if (!found) {
924                                         hid_warn(hdev,
925                                                  "pen parameters not found");
926                                 }
927                         } else {
928                                 uclogic_params_init_invalid(&p);
929                         }
930                 } else {
931                         rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp5540u_fixed);
932                         if (rc != 0)
933                                 goto cleanup;
934                 }
935                 break;
936         case VID_PID(USB_VENDOR_ID_UCLOGIC,
937                      USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U):
938                 rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp8060u_fixed);
939                 if (rc != 0)
940                         goto cleanup;
941                 break;
942         case VID_PID(USB_VENDOR_ID_UCLOGIC,
943                      USB_DEVICE_ID_UCLOGIC_TABLET_WP1062):
944                 rc = WITH_OPT_DESC(WP1062_ORIG, wp1062_fixed);
945                 if (rc != 0)
946                         goto cleanup;
947                 break;
948         case VID_PID(USB_VENDOR_ID_UCLOGIC,
949                      USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850):
950                 switch (bInterfaceNumber) {
951                 case 0:
952                         rc = WITH_OPT_DESC(TWHL850_ORIG0, twhl850_fixed0);
953                         if (rc != 0)
954                                 goto cleanup;
955                         break;
956                 case 1:
957                         rc = WITH_OPT_DESC(TWHL850_ORIG1, twhl850_fixed1);
958                         if (rc != 0)
959                                 goto cleanup;
960                         break;
961                 case 2:
962                         rc = WITH_OPT_DESC(TWHL850_ORIG2, twhl850_fixed2);
963                         if (rc != 0)
964                                 goto cleanup;
965                         break;
966                 }
967                 break;
968         case VID_PID(USB_VENDOR_ID_UCLOGIC,
969                      USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60):
970                 /*
971                  * If it is not a three-interface version, which is known to
972                  * respond to initialization.
973                  */
974                 if (bNumInterfaces != 3) {
975                         switch (bInterfaceNumber) {
976                         case 0:
977                                 rc = WITH_OPT_DESC(TWHA60_ORIG0,
978                                                         twha60_fixed0);
979                                 if (rc != 0)
980                                         goto cleanup;
981                                 break;
982                         case 1:
983                                 rc = WITH_OPT_DESC(TWHA60_ORIG1,
984                                                         twha60_fixed1);
985                                 if (rc != 0)
986                                         goto cleanup;
987                                 break;
988                         }
989                         break;
990                 }
991                 fallthrough;
992         case VID_PID(USB_VENDOR_ID_HUION,
993                      USB_DEVICE_ID_HUION_TABLET):
994         case VID_PID(USB_VENDOR_ID_HUION,
995                      USB_DEVICE_ID_HUION_HS64):
996         case VID_PID(USB_VENDOR_ID_UCLOGIC,
997                      USB_DEVICE_ID_HUION_TABLET):
998         case VID_PID(USB_VENDOR_ID_UCLOGIC,
999                      USB_DEVICE_ID_YIYNOVA_TABLET):
1000         case VID_PID(USB_VENDOR_ID_UCLOGIC,
1001                      USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81):
1002         case VID_PID(USB_VENDOR_ID_UCLOGIC,
1003                      USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3):
1004         case VID_PID(USB_VENDOR_ID_UCLOGIC,
1005                      USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45):
1006         case VID_PID(USB_VENDOR_ID_UCLOGIC,
1007                      USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_47):
1008                 rc = uclogic_params_huion_init(&p, hdev);
1009                 if (rc != 0)
1010                         goto cleanup;
1011                 break;
1012         case VID_PID(USB_VENDOR_ID_UGTIZER,
1013                      USB_DEVICE_ID_UGTIZER_TABLET_GP0610):
1014         case VID_PID(USB_VENDOR_ID_UGTIZER,
1015                      USB_DEVICE_ID_UGTIZER_TABLET_GT5040):
1016         case VID_PID(USB_VENDOR_ID_UGEE,
1017                      USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540):
1018         case VID_PID(USB_VENDOR_ID_UGEE,
1019                      USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640):
1020         case VID_PID(USB_VENDOR_ID_UGEE,
1021                      USB_DEVICE_ID_UGEE_TABLET_RAINBOW_CV720):
1022                 /* If this is the pen 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                         if (!found) {
1031                                 hid_warn(hdev, "pen parameters not found");
1032                                 uclogic_params_init_invalid(&p);
1033                         }
1034                 } else {
1035                         /* TODO: Consider marking the interface invalid */
1036                         uclogic_params_init_with_pen_unused(&p);
1037                 }
1038                 break;
1039         case VID_PID(USB_VENDOR_ID_UGEE,
1040                      USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01):
1041                 /* If this is the pen and frame interface */
1042                 if (bInterfaceNumber == 1) {
1043                         /* Probe v1 pen parameters */
1044                         rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1045                         if (rc != 0) {
1046                                 hid_err(hdev, "pen probing failed: %d\n", rc);
1047                                 goto cleanup;
1048                         }
1049                         /* Initialize frame parameters */
1050                         rc = uclogic_params_frame_init_with_desc(
1051                                 &p.frame,
1052                                 uclogic_rdesc_xppen_deco01_frame_arr,
1053                                 uclogic_rdesc_xppen_deco01_frame_size,
1054                                 0);
1055                         if (rc != 0)
1056                                 goto cleanup;
1057                 } else {
1058                         /* TODO: Consider marking the interface invalid */
1059                         uclogic_params_init_with_pen_unused(&p);
1060                 }
1061                 break;
1062         case VID_PID(USB_VENDOR_ID_TRUST,
1063                      USB_DEVICE_ID_TRUST_PANORA_TABLET):
1064         case VID_PID(USB_VENDOR_ID_UGEE,
1065                      USB_DEVICE_ID_UGEE_TABLET_G5):
1066                 /* Ignore non-pen interfaces */
1067                 if (bInterfaceNumber != 1) {
1068                         uclogic_params_init_invalid(&p);
1069                         break;
1070                 }
1071
1072                 rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1073                 if (rc != 0) {
1074                         hid_err(hdev, "pen probing failed: %d\n", rc);
1075                         goto cleanup;
1076                 } else if (found) {
1077                         rc = uclogic_params_frame_init_with_desc(
1078                                 &p.frame,
1079                                 uclogic_rdesc_ugee_g5_frame_arr,
1080                                 uclogic_rdesc_ugee_g5_frame_size,
1081                                 UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
1082                         if (rc != 0) {
1083                                 hid_err(hdev,
1084                                         "failed creating buttonpad parameters: %d\n",
1085                                         rc);
1086                                 goto cleanup;
1087                         }
1088                         p.frame.re_lsb =
1089                                 UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB;
1090                         p.frame.dev_id_byte =
1091                                 UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
1092                 } else {
1093                         hid_warn(hdev, "pen parameters not found");
1094                         uclogic_params_init_invalid(&p);
1095                 }
1096
1097                 break;
1098         case VID_PID(USB_VENDOR_ID_UGEE,
1099                      USB_DEVICE_ID_UGEE_TABLET_EX07S):
1100                 /* Ignore non-pen interfaces */
1101                 if (bInterfaceNumber != 1) {
1102                         uclogic_params_init_invalid(&p);
1103                         break;
1104                 }
1105
1106                 rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
1107                 if (rc != 0) {
1108                         hid_err(hdev, "pen probing failed: %d\n", rc);
1109                         goto cleanup;
1110                 } else if (found) {
1111                         rc = uclogic_params_frame_init_with_desc(
1112                                 &p.frame,
1113                                 uclogic_rdesc_ugee_ex07_buttonpad_arr,
1114                                 uclogic_rdesc_ugee_ex07_buttonpad_size,
1115                                 0);
1116                         if (rc != 0) {
1117                                 hid_err(hdev,
1118                                         "failed creating buttonpad parameters: %d\n",
1119                                         rc);
1120                                 goto cleanup;
1121                         }
1122                 } else {
1123                         hid_warn(hdev, "pen parameters not found");
1124                         uclogic_params_init_invalid(&p);
1125                 }
1126
1127                 break;
1128         }
1129
1130 #undef VID_PID
1131 #undef WITH_OPT_DESC
1132
1133         /* Output parameters */
1134         memcpy(params, &p, sizeof(*params));
1135         memset(&p, 0, sizeof(p));
1136         rc = 0;
1137 cleanup:
1138         uclogic_params_cleanup(&p);
1139         return rc;
1140 }