HID: uclogic: Designate current protocol v1
[linux-2.6-block.git] / drivers / hid / hid-uclogic-params.c
CommitLineData
9614219e
NK
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * HID driver for UC-Logic devices not fully compliant with HID standard
4 * - tablet initialization and parameter retrieval
5 *
6 * Copyright (c) 2018 Nikolai Kondrashov
7 */
8
9/*
10 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the Free
12 * Software Foundation; either version 2 of the License, or (at your option)
13 * any later version.
14 */
15
16#include "hid-uclogic-params.h"
17#include "hid-uclogic-rdesc.h"
18#include "usbhid/usbhid.h"
19#include "hid-ids.h"
20#include <linux/ctype.h>
21#include <asm/unaligned.h>
22
23/**
24 * Convert a pen in-range reporting type to a string.
25 *
26 * @inrange: The in-range reporting type to convert.
27 *
28 * Returns:
29 * The string representing the type, or NULL if the type is unknown.
30 */
31const char *uclogic_params_pen_inrange_to_str(
32 enum uclogic_params_pen_inrange inrange)
33{
34 switch (inrange) {
35 case UCLOGIC_PARAMS_PEN_INRANGE_NORMAL:
36 return "normal";
37 case UCLOGIC_PARAMS_PEN_INRANGE_INVERTED:
38 return "inverted";
39 default:
40 return NULL;
41 }
42}
43
44/**
45 * uclogic_params_get_str_desc - retrieve a string descriptor from a HID
46 * device interface, putting it into a kmalloc-allocated buffer as is, without
47 * character encoding conversion.
48 *
49 * @pbuf: Location for the kmalloc-allocated buffer pointer containing
50 * the retrieved descriptor. Not modified in case of error.
51 * Can be NULL to have retrieved descriptor discarded.
52 * @hdev: The HID device of the tablet interface to retrieve the string
53 * descriptor from. Cannot be NULL.
54 * @idx: Index of the string descriptor to request from the device.
55 * @len: Length of the buffer to allocate and the data to retrieve.
56 *
57 * Returns:
58 * number of bytes retrieved (<= len),
59 * -EPIPE, if the descriptor was not found, or
60 * another negative errno code in case of other error.
61 */
62static int uclogic_params_get_str_desc(__u8 **pbuf, struct hid_device *hdev,
63 __u8 idx, size_t len)
64{
65 int rc;
66 struct usb_device *udev = hid_to_usb_dev(hdev);
67 __u8 *buf = NULL;
68
69 /* Check arguments */
70 if (hdev == NULL) {
71 rc = -EINVAL;
72 goto cleanup;
73 }
74
75 buf = kmalloc(len, GFP_KERNEL);
76 if (buf == NULL) {
77 rc = -ENOMEM;
78 goto cleanup;
79 }
80
81 rc = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
82 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
83 (USB_DT_STRING << 8) + idx,
84 0x0409, buf, len,
85 USB_CTRL_GET_TIMEOUT);
86 if (rc == -EPIPE) {
87 hid_dbg(hdev, "string descriptor #%hhu not found\n", idx);
88 goto cleanup;
89 } else if (rc < 0) {
90 hid_err(hdev,
91 "failed retrieving string descriptor #%hhu: %d\n",
92 idx, rc);
93 goto cleanup;
94 }
95
96 if (pbuf != NULL) {
97 *pbuf = buf;
98 buf = NULL;
99 }
100
101cleanup:
102 kfree(buf);
103 return rc;
104}
105
106/**
107 * uclogic_params_pen_cleanup - free resources used by struct
108 * uclogic_params_pen (tablet interface's pen input parameters).
109 * Can be called repeatedly.
110 *
111 * @pen: Pen input parameters to cleanup. Cannot be NULL.
112 */
113static void uclogic_params_pen_cleanup(struct uclogic_params_pen *pen)
114{
115 kfree(pen->desc_ptr);
116 memset(pen, 0, sizeof(*pen));
117}
118
119/**
eecb5b84
NK
120 * uclogic_params_pen_init_v1() - initialize tablet interface pen
121 * input and retrieve its parameters from the device, using v1 protocol.
9614219e
NK
122 *
123 * @pen: Pointer to the pen parameters to initialize (to be
124 * cleaned up with uclogic_params_pen_cleanup()). Not modified in
125 * case of error, or if parameters are not found. Cannot be NULL.
126 * @pfound: Location for a flag which is set to true if the parameters
127 * were found, and to false if not (e.g. device was
128 * incompatible). Not modified in case of error. Cannot be NULL.
129 * @hdev: The HID device of the tablet interface to initialize and get
130 * parameters from. Cannot be NULL.
131 *
132 * Returns:
133 * Zero, if successful. A negative errno code on error.
134 */
eecb5b84
NK
135static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
136 bool *pfound,
137 struct hid_device *hdev)
9614219e
NK
138{
139 int rc;
140 bool found = false;
141 /* Buffer for (part of) the string descriptor */
142 __u8 *buf = NULL;
143 /* Minimum descriptor length required, maximum seen so far is 18 */
144 const int len = 12;
145 s32 resolution;
146 /* Pen report descriptor template parameters */
147 s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM];
148 __u8 *desc_ptr = NULL;
149
150 /* Check arguments */
151 if (pen == NULL || pfound == NULL || hdev == NULL) {
152 rc = -EINVAL;
153 goto cleanup;
154 }
155
156 /*
157 * Read string descriptor containing pen input parameters.
158 * The specific string descriptor and data were discovered by sniffing
159 * the Windows driver traffic.
160 * NOTE: This enables fully-functional tablet mode.
161 */
162 rc = uclogic_params_get_str_desc(&buf, hdev, 100, len);
163 if (rc == -EPIPE) {
164 hid_dbg(hdev,
165 "string descriptor with pen parameters not found, assuming not compatible\n");
166 goto finish;
167 } else if (rc < 0) {
168 hid_err(hdev, "failed retrieving pen parameters: %d\n", rc);
169 goto cleanup;
170 } else if (rc != len) {
171 hid_dbg(hdev,
172 "string descriptor with pen parameters has invalid length (got %d, expected %d), assuming not compatible\n",
173 rc, len);
174 goto finish;
175 }
176
177 /*
178 * Fill report descriptor parameters from the string descriptor
179 */
180 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] =
181 get_unaligned_le16(buf + 2);
182 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] =
183 get_unaligned_le16(buf + 4);
184 desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] =
185 get_unaligned_le16(buf + 8);
186 resolution = get_unaligned_le16(buf + 10);
187 if (resolution == 0) {
188 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0;
189 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0;
190 } else {
191 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] =
192 desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 /
193 resolution;
194 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] =
195 desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 /
196 resolution;
197 }
198 kfree(buf);
199 buf = NULL;
200
201 /*
202 * Generate pen report descriptor
203 */
204 desc_ptr = uclogic_rdesc_template_apply(
eecb5b84
NK
205 uclogic_rdesc_pen_v1_template_arr,
206 uclogic_rdesc_pen_v1_template_size,
9614219e
NK
207 desc_params, ARRAY_SIZE(desc_params));
208 if (desc_ptr == NULL) {
209 rc = -ENOMEM;
210 goto cleanup;
211 }
212
213 /*
214 * Fill-in the parameters
215 */
216 memset(pen, 0, sizeof(*pen));
217 pen->desc_ptr = desc_ptr;
218 desc_ptr = NULL;
eecb5b84
NK
219 pen->desc_size = uclogic_rdesc_pen_v1_template_size;
220 pen->id = UCLOGIC_RDESC_PEN_V1_ID;
9614219e
NK
221 pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED;
222 found = true;
223finish:
224 *pfound = found;
225 rc = 0;
226cleanup:
227 kfree(desc_ptr);
228 kfree(buf);
229 return rc;
230}
231
232/**
233 * uclogic_params_frame_cleanup - free resources used by struct
234 * uclogic_params_frame (tablet interface's frame controls input parameters).
235 * Can be called repeatedly.
236 *
237 * @frame: Frame controls input parameters to cleanup. Cannot be NULL.
238 */
239static void uclogic_params_frame_cleanup(struct uclogic_params_frame *frame)
240{
241 kfree(frame->desc_ptr);
242 memset(frame, 0, sizeof(*frame));
243}
244
245/**
246 * uclogic_params_frame_init_with_desc() - initialize tablet's frame control
247 * parameters with a static report descriptor.
248 *
249 * @frame: Pointer to the frame parameters to initialize (to be cleaned
250 * up with uclogic_params_frame_cleanup()). Not modified in case
251 * of error. Cannot be NULL.
252 * @desc_ptr: Report descriptor pointer. Can be NULL, if desc_size is zero.
253 * @desc_size: Report descriptor size.
254 * @id: Report ID used for frame reports, if they should be tweaked,
255 * zero if not.
256 *
257 * Returns:
258 * Zero, if successful. A negative errno code on error.
259 */
260static int uclogic_params_frame_init_with_desc(
261 struct uclogic_params_frame *frame,
262 const __u8 *desc_ptr,
263 size_t desc_size,
264 unsigned int id)
265{
266 __u8 *copy_desc_ptr;
267
268 if (frame == NULL || (desc_ptr == NULL && desc_size != 0))
269 return -EINVAL;
270
271 copy_desc_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
272 if (copy_desc_ptr == NULL)
273 return -ENOMEM;
274
275 memset(frame, 0, sizeof(*frame));
276 frame->desc_ptr = copy_desc_ptr;
277 frame->desc_size = desc_size;
278 frame->id = id;
279 return 0;
280}
281
282/**
eecb5b84
NK
283 * uclogic_params_frame_init_v1_buttonpad() - initialize abstract buttonpad
284 * on a v1 tablet interface.
9614219e
NK
285 *
286 * @frame: Pointer to the frame parameters to initialize (to be cleaned
287 * up with uclogic_params_frame_cleanup()). Not modified in case
288 * of error, or if parameters are not found. Cannot be NULL.
289 * @pfound: Location for a flag which is set to true if the parameters
290 * were found, and to false if not (e.g. device was
291 * incompatible). Not modified in case of error. Cannot be NULL.
292 * @hdev: The HID device of the tablet interface to initialize and get
293 * parameters from. Cannot be NULL.
294 *
295 * Returns:
296 * Zero, if successful. A negative errno code on error.
297 */
eecb5b84 298static int uclogic_params_frame_init_v1_buttonpad(
9614219e
NK
299 struct uclogic_params_frame *frame,
300 bool *pfound,
301 struct hid_device *hdev)
302{
303 int rc;
304 bool found = false;
305 struct usb_device *usb_dev = hid_to_usb_dev(hdev);
306 char *str_buf = NULL;
307 const size_t str_len = 16;
308
309 /* Check arguments */
310 if (frame == NULL || pfound == NULL || hdev == NULL) {
311 rc = -EINVAL;
312 goto cleanup;
313 }
314
315 /*
316 * Enable generic button mode
317 */
318 str_buf = kzalloc(str_len, GFP_KERNEL);
319 if (str_buf == NULL) {
320 rc = -ENOMEM;
321 goto cleanup;
322 }
323
324 rc = usb_string(usb_dev, 123, str_buf, str_len);
325 if (rc == -EPIPE) {
326 hid_dbg(hdev,
327 "generic button -enabling string descriptor not found\n");
328 } else if (rc < 0) {
329 goto cleanup;
330 } else if (strncmp(str_buf, "HK On", rc) != 0) {
331 hid_dbg(hdev,
332 "invalid response to enabling generic buttons: \"%s\"\n",
333 str_buf);
334 } else {
335 hid_dbg(hdev, "generic buttons enabled\n");
336 rc = uclogic_params_frame_init_with_desc(
337 frame,
eecb5b84
NK
338 uclogic_rdesc_buttonpad_v1_arr,
339 uclogic_rdesc_buttonpad_v1_size,
340 UCLOGIC_RDESC_BUTTONPAD_V1_ID);
9614219e
NK
341 if (rc != 0)
342 goto cleanup;
343 found = true;
344 }
345
346 *pfound = found;
347 rc = 0;
348cleanup:
349 kfree(str_buf);
350 return rc;
351}
352
353/**
354 * uclogic_params_cleanup - free resources used by struct uclogic_params
355 * (tablet interface's parameters).
356 * Can be called repeatedly.
357 *
358 * @params: Input parameters to cleanup. Cannot be NULL.
359 */
360void uclogic_params_cleanup(struct uclogic_params *params)
361{
362 if (!params->invalid) {
363 kfree(params->desc_ptr);
364 if (!params->pen_unused)
365 uclogic_params_pen_cleanup(&params->pen);
366 uclogic_params_frame_cleanup(&params->frame);
367 memset(params, 0, sizeof(*params));
368 }
369}
370
371/**
372 * Get a replacement report descriptor for a tablet's interface.
373 *
374 * @params: The parameters of a tablet interface to get report
375 * descriptor for. Cannot be NULL.
376 * @pdesc: Location for the resulting, kmalloc-allocated report
377 * descriptor pointer, or for NULL, if there's no replacement
378 * report descriptor. Not modified in case of error. Cannot be
379 * NULL.
380 * @psize: Location for the resulting report descriptor size, not set if
381 * there's no replacement report descriptor. Not modified in case
382 * of error. Cannot be NULL.
383 *
384 * Returns:
385 * Zero, if successful.
386 * -EINVAL, if invalid arguments are supplied.
387 * -ENOMEM, if failed to allocate memory.
388 */
389int uclogic_params_get_desc(const struct uclogic_params *params,
390 __u8 **pdesc,
391 unsigned int *psize)
392{
393 bool common_present;
394 bool pen_present;
395 bool frame_present;
396 unsigned int size;
397 __u8 *desc = NULL;
398
399 /* Check arguments */
400 if (params == NULL || pdesc == NULL || psize == NULL)
401 return -EINVAL;
402
403 size = 0;
404
405 common_present = (params->desc_ptr != NULL);
406 pen_present = (!params->pen_unused && params->pen.desc_ptr != NULL);
407 frame_present = (params->frame.desc_ptr != NULL);
408
409 if (common_present)
410 size += params->desc_size;
411 if (pen_present)
412 size += params->pen.desc_size;
413 if (frame_present)
414 size += params->frame.desc_size;
415
416 if (common_present || pen_present || frame_present) {
417 __u8 *p;
418
419 desc = kmalloc(size, GFP_KERNEL);
420 if (desc == NULL)
421 return -ENOMEM;
422 p = desc;
423
424 if (common_present) {
425 memcpy(p, params->desc_ptr,
426 params->desc_size);
427 p += params->desc_size;
428 }
429 if (pen_present) {
430 memcpy(p, params->pen.desc_ptr,
431 params->pen.desc_size);
432 p += params->pen.desc_size;
433 }
434 if (frame_present) {
435 memcpy(p, params->frame.desc_ptr,
436 params->frame.desc_size);
437 p += params->frame.desc_size;
438 }
439
440 WARN_ON(p != desc + size);
441
442 *psize = size;
443 }
444
445 *pdesc = desc;
446 return 0;
447}
448
449/**
450 * uclogic_params_init_invalid() - initialize tablet interface parameters,
451 * specifying the interface is invalid.
452 *
453 * @params: Parameters to initialize (to be cleaned with
454 * uclogic_params_cleanup()). Cannot be NULL.
455 */
456static void uclogic_params_init_invalid(struct uclogic_params *params)
457{
458 params->invalid = true;
459}
460
461/**
462 * uclogic_params_init_with_opt_desc() - initialize tablet interface
463 * parameters with an optional replacement report descriptor. Only modify
464 * report descriptor, if the original report descriptor matches the expected
465 * size.
466 *
467 * @params: Parameters to initialize (to be cleaned with
468 * uclogic_params_cleanup()). Not modified in case of
469 * error. Cannot be NULL.
470 * @hdev: The HID device of the tablet interface create the
471 * parameters for. Cannot be NULL.
472 * @orig_desc_size: Expected size of the original report descriptor to
473 * be replaced.
474 * @desc_ptr: Pointer to the replacement report descriptor.
475 * Can be NULL, if desc_size is zero.
476 * @desc_size: Size of the replacement report descriptor.
477 *
478 * Returns:
479 * Zero, if successful. -EINVAL if an invalid argument was passed.
480 * -ENOMEM, if failed to allocate memory.
481 */
482static int uclogic_params_init_with_opt_desc(struct uclogic_params *params,
483 struct hid_device *hdev,
484 unsigned int orig_desc_size,
485 __u8 *desc_ptr,
486 unsigned int desc_size)
487{
488 __u8 *desc_copy_ptr = NULL;
489 unsigned int desc_copy_size;
490 int rc;
491
492 /* Check arguments */
493 if (params == NULL || hdev == NULL ||
494 (desc_ptr == NULL && desc_size != 0)) {
495 rc = -EINVAL;
496 goto cleanup;
497 }
498
499 /* Replace report descriptor, if it matches */
500 if (hdev->dev_rsize == orig_desc_size) {
501 hid_dbg(hdev,
502 "device report descriptor matches the expected size, replacing\n");
503 desc_copy_ptr = kmemdup(desc_ptr, desc_size, GFP_KERNEL);
504 if (desc_copy_ptr == NULL) {
505 rc = -ENOMEM;
506 goto cleanup;
507 }
508 desc_copy_size = desc_size;
509 } else {
510 hid_dbg(hdev,
511 "device report descriptor doesn't match the expected size (%u != %u), preserving\n",
512 hdev->dev_rsize, orig_desc_size);
513 desc_copy_ptr = NULL;
514 desc_copy_size = 0;
515 }
516
517 /* Output parameters */
518 memset(params, 0, sizeof(*params));
519 params->desc_ptr = desc_copy_ptr;
520 desc_copy_ptr = NULL;
521 params->desc_size = desc_copy_size;
522
523 rc = 0;
524cleanup:
525 kfree(desc_copy_ptr);
526 return rc;
527}
528
529/**
530 * uclogic_params_init_with_pen_unused() - initialize tablet interface
531 * parameters preserving original reports and generic HID processing, but
532 * disabling pen usage.
533 *
534 * @params: Parameters to initialize (to be cleaned with
535 * uclogic_params_cleanup()). Not modified in case of
536 * error. Cannot be NULL.
537 */
538static void uclogic_params_init_with_pen_unused(struct uclogic_params *params)
539{
540 memset(params, 0, sizeof(*params));
541 params->pen_unused = true;
542}
543
544/**
545 * uclogic_params_init() - initialize a Huion tablet interface and discover
546 * its parameters.
547 *
548 * @params: Parameters to fill in (to be cleaned with
549 * uclogic_params_cleanup()). Not modified in case of error.
550 * 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 */
557static int uclogic_params_huion_init(struct uclogic_params *params,
558 struct hid_device *hdev)
559{
560 int rc;
561 struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
562 __u8 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
563 bool found;
564 /* The resulting parameters (noop) */
565 struct uclogic_params p = {0, };
566
567 /* Check arguments */
568 if (params == NULL || hdev == NULL) {
569 rc = -EINVAL;
570 goto cleanup;
571 }
572
573 /* If it's not a pen interface */
574 if (bInterfaceNumber != 0) {
575 /* TODO: Consider marking the interface invalid */
576 uclogic_params_init_with_pen_unused(&p);
577 goto output;
578 }
579
eecb5b84
NK
580 /* Try to probe v1 pen parameters */
581 rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
9614219e
NK
582 if (rc != 0) {
583 hid_err(hdev,
eecb5b84 584 "failed probing pen v1 parameters: %d\n", rc);
9614219e
NK
585 goto cleanup;
586 } else if (found) {
eecb5b84
NK
587 hid_dbg(hdev, "pen v1 parameters found\n");
588 /* Try to probe v1 buttonpad */
589 rc = uclogic_params_frame_init_v1_buttonpad(
9614219e
NK
590 &p.frame,
591 &found, hdev);
592 if (rc != 0) {
593 hid_err(hdev, "v1 buttonpad probing failed: %d\n", rc);
594 goto cleanup;
595 }
eecb5b84 596 hid_dbg(hdev, "buttonpad v1 parameters%s found\n",
9614219e
NK
597 (found ? "" : " not"));
598 if (found) {
599 /* Set bitmask marking frame reports */
600 p.pen_frame_flag = 0x20;
601 }
602 goto output;
603 }
eecb5b84 604 hid_dbg(hdev, "pen v1 parameters not found\n");
9614219e
NK
605
606 uclogic_params_init_invalid(&p);
607
608output:
609 /* Output parameters */
610 memcpy(params, &p, sizeof(*params));
611 memset(&p, 0, sizeof(p));
612 rc = 0;
613cleanup:
614 uclogic_params_cleanup(&p);
615 return rc;
616}
617
618/**
619 * uclogic_params_init() - initialize a tablet interface and discover its
620 * parameters.
621 *
622 * @params: Parameters to fill in (to be cleaned with
623 * uclogic_params_cleanup()). Not modified in case of error.
624 * Cannot be NULL.
625 * @hdev: The HID device of the tablet interface to initialize and get
626 * parameters from. Cannot be NULL.
627 *
628 * Returns:
629 * Zero, if successful. A negative errno code on error.
630 */
631int uclogic_params_init(struct uclogic_params *params,
632 struct hid_device *hdev)
633{
634 int rc;
635 struct usb_device *udev = hid_to_usb_dev(hdev);
636 __u8 bNumInterfaces = udev->config->desc.bNumInterfaces;
637 struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
638 __u8 bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber;
639 bool found;
640 /* The resulting parameters (noop) */
641 struct uclogic_params p = {0, };
642
643 /* Check arguments */
644 if (params == NULL || hdev == NULL) {
645 rc = -EINVAL;
646 goto cleanup;
647 }
648
649 /*
650 * Set replacement report descriptor if the original matches the
651 * specified size. Otherwise keep interface unchanged.
652 */
653#define WITH_OPT_DESC(_orig_desc_token, _new_desc_token) \
654 uclogic_params_init_with_opt_desc( \
655 &p, hdev, \
656 UCLOGIC_RDESC_##_orig_desc_token##_SIZE, \
657 uclogic_rdesc_##_new_desc_token##_arr, \
658 uclogic_rdesc_##_new_desc_token##_size)
659
660#define VID_PID(_vid, _pid) \
661 (((__u32)(_vid) << 16) | ((__u32)(_pid) & U16_MAX))
662
663 /*
664 * Handle specific interfaces for specific tablets.
665 *
666 * Observe the following logic:
667 *
668 * If the interface is recognized as producing certain useful input:
669 * Mark interface as valid.
670 * Output interface parameters.
671 * Else, if the interface is recognized as *not* producing any useful
672 * input:
673 * Mark interface as invalid.
674 * Else:
675 * Mark interface as valid.
676 * Output noop parameters.
677 *
678 * Rule of thumb: it is better to disable a broken interface than let
679 * it spew garbage input.
680 */
681
682 switch (VID_PID(hdev->vendor, hdev->product)) {
683 case VID_PID(USB_VENDOR_ID_UCLOGIC,
684 USB_DEVICE_ID_UCLOGIC_TABLET_PF1209):
685 rc = WITH_OPT_DESC(PF1209_ORIG, pf1209_fixed);
686 if (rc != 0)
687 goto cleanup;
688 break;
689 case VID_PID(USB_VENDOR_ID_UCLOGIC,
690 USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U):
691 rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp4030u_fixed);
692 if (rc != 0)
693 goto cleanup;
694 break;
695 case VID_PID(USB_VENDOR_ID_UCLOGIC,
696 USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U):
697 rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp5540u_fixed);
698 if (rc != 0)
699 goto cleanup;
700 break;
701 case VID_PID(USB_VENDOR_ID_UCLOGIC,
702 USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U):
703 rc = WITH_OPT_DESC(WPXXXXU_ORIG, wp8060u_fixed);
704 if (rc != 0)
705 goto cleanup;
706 break;
707 case VID_PID(USB_VENDOR_ID_UCLOGIC,
708 USB_DEVICE_ID_UCLOGIC_TABLET_WP1062):
709 rc = WITH_OPT_DESC(WP1062_ORIG, wp1062_fixed);
710 if (rc != 0)
711 goto cleanup;
712 break;
713 case VID_PID(USB_VENDOR_ID_UCLOGIC,
714 USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850):
715 switch (bInterfaceNumber) {
716 case 0:
717 rc = WITH_OPT_DESC(TWHL850_ORIG0, twhl850_fixed0);
718 if (rc != 0)
719 goto cleanup;
720 break;
721 case 1:
722 rc = WITH_OPT_DESC(TWHL850_ORIG1, twhl850_fixed1);
723 if (rc != 0)
724 goto cleanup;
725 break;
726 case 2:
727 rc = WITH_OPT_DESC(TWHL850_ORIG2, twhl850_fixed2);
728 if (rc != 0)
729 goto cleanup;
730 break;
731 }
732 break;
733 case VID_PID(USB_VENDOR_ID_UCLOGIC,
734 USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60):
735 /*
736 * If it is not a three-interface version, which is known to
737 * respond to initialization.
738 */
739 if (bNumInterfaces != 3) {
740 switch (bInterfaceNumber) {
741 case 0:
742 rc = WITH_OPT_DESC(TWHA60_ORIG0,
743 twha60_fixed0);
744 if (rc != 0)
745 goto cleanup;
746 break;
747 case 1:
748 rc = WITH_OPT_DESC(TWHA60_ORIG1,
749 twha60_fixed1);
750 if (rc != 0)
751 goto cleanup;
752 break;
753 }
754 break;
755 }
756 /* FALL THROUGH */
757 case VID_PID(USB_VENDOR_ID_HUION,
758 USB_DEVICE_ID_HUION_TABLET):
759 case VID_PID(USB_VENDOR_ID_UCLOGIC,
760 USB_DEVICE_ID_HUION_TABLET):
761 case VID_PID(USB_VENDOR_ID_UCLOGIC,
762 USB_DEVICE_ID_YIYNOVA_TABLET):
763 case VID_PID(USB_VENDOR_ID_UCLOGIC,
764 USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_81):
765 case VID_PID(USB_VENDOR_ID_UCLOGIC,
766 USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3):
767 case VID_PID(USB_VENDOR_ID_UCLOGIC,
768 USB_DEVICE_ID_UCLOGIC_UGEE_TABLET_45):
769 rc = uclogic_params_huion_init(&p, hdev);
770 if (rc != 0)
771 goto cleanup;
772 break;
773 case VID_PID(USB_VENDOR_ID_UGTIZER,
774 USB_DEVICE_ID_UGTIZER_TABLET_GP0610):
775 case VID_PID(USB_VENDOR_ID_UGEE,
776 USB_DEVICE_ID_UGEE_TABLET_EX07S):
777 /* If this is the pen interface */
778 if (bInterfaceNumber == 1) {
eecb5b84
NK
779 /* Probe v1 pen parameters */
780 rc = uclogic_params_pen_init_v1(&p.pen, &found, hdev);
9614219e
NK
781 if (rc != 0) {
782 hid_err(hdev, "pen probing failed: %d\n", rc);
783 goto cleanup;
784 }
785 if (!found) {
786 hid_warn(hdev, "pen parameters not found");
787 uclogic_params_init_invalid(&p);
788 }
789 } else {
790 /* TODO: Consider marking the interface invalid */
791 uclogic_params_init_with_pen_unused(&p);
792 }
793 break;
794 }
795
796#undef VID_PID
797#undef WITH_OPT_DESC
798
799 /* Output parameters */
800 memcpy(params, &p, sizeof(*params));
801 memset(&p, 0, sizeof(p));
802 rc = 0;
803cleanup:
804 uclogic_params_cleanup(&p);
805 return rc;
806}