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