1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/device.h>
16#include <linux/hid.h>
17#include <linux/module.h>
18#include <linux/usb.h>
19#include <asm/unaligned.h>
20#include "usbhid/usbhid.h"
21
22#include "hid-ids.h"
23
24
25#define WPXXXXU_RDESC_ORIG_SIZE 212
26
27
28static __u8 wp4030u_rdesc_fixed[] = {
29 0x05, 0x0D,
30 0x09, 0x02,
31 0xA1, 0x01,
32 0x85, 0x09,
33 0x09, 0x20,
34 0xA0,
35 0x75, 0x01,
36 0x09, 0x42,
37 0x09, 0x44,
38 0x09, 0x46,
39 0x14,
40 0x25, 0x01,
41 0x95, 0x03,
42 0x81, 0x02,
43 0x95, 0x05,
44 0x81, 0x01,
45 0x75, 0x10,
46 0x95, 0x01,
47 0x14,
48 0xA4,
49 0x05, 0x01,
50 0x55, 0xFD,
51 0x65, 0x13,
52 0x34,
53 0x09, 0x30,
54 0x46, 0xA0, 0x0F,
55 0x26, 0xFF, 0x7F,
56 0x81, 0x02,
57 0x09, 0x31,
58 0x46, 0xB8, 0x0B,
59 0x26, 0xFF, 0x7F,
60 0x81, 0x02,
61 0xB4,
62 0x09, 0x30,
63 0x26, 0xFF, 0x03,
64 0x81, 0x02,
65 0xC0,
66 0xC0
67};
68
69
70static __u8 wp5540u_rdesc_fixed[] = {
71 0x05, 0x0D,
72 0x09, 0x02,
73 0xA1, 0x01,
74 0x85, 0x09,
75 0x09, 0x20,
76 0xA0,
77 0x75, 0x01,
78 0x09, 0x42,
79 0x09, 0x44,
80 0x09, 0x46,
81 0x14,
82 0x25, 0x01,
83 0x95, 0x03,
84 0x81, 0x02,
85 0x95, 0x05,
86 0x81, 0x01,
87 0x75, 0x10,
88 0x95, 0x01,
89 0x14,
90 0xA4,
91 0x05, 0x01,
92 0x55, 0xFD,
93 0x65, 0x13,
94 0x34,
95 0x09, 0x30,
96 0x46, 0x7C, 0x15,
97 0x26, 0xFF, 0x7F,
98 0x81, 0x02,
99 0x09, 0x31,
100 0x46, 0xA0, 0x0F,
101 0x26, 0xFF, 0x7F,
102 0x81, 0x02,
103 0xB4,
104 0x09, 0x30,
105 0x26, 0xFF, 0x03,
106 0x81, 0x02,
107 0xC0,
108 0xC0,
109 0x05, 0x01,
110 0x09, 0x02,
111 0xA1, 0x01,
112 0x85, 0x08,
113 0x09, 0x01,
114 0xA0,
115 0x75, 0x01,
116 0x05, 0x09,
117 0x19, 0x01,
118 0x29, 0x03,
119 0x14,
120 0x25, 0x01,
121 0x95, 0x03,
122 0x81, 0x02,
123 0x95, 0x05,
124 0x81, 0x01,
125 0x05, 0x01,
126 0x75, 0x08,
127 0x09, 0x30,
128 0x09, 0x31,
129 0x15, 0x81,
130 0x25, 0x7F,
131 0x95, 0x02,
132 0x81, 0x06,
133 0x09, 0x38,
134 0x15, 0xFF,
135 0x25, 0x01,
136 0x95, 0x01,
137 0x81, 0x06,
138 0x81, 0x01,
139 0xC0,
140 0xC0
141};
142
143
144static __u8 wp8060u_rdesc_fixed[] = {
145 0x05, 0x0D,
146 0x09, 0x02,
147 0xA1, 0x01,
148 0x85, 0x09,
149 0x09, 0x20,
150 0xA0,
151 0x75, 0x01,
152 0x09, 0x42,
153 0x09, 0x44,
154 0x09, 0x46,
155 0x14,
156 0x25, 0x01,
157 0x95, 0x03,
158 0x81, 0x02,
159 0x95, 0x05,
160 0x81, 0x01,
161 0x75, 0x10,
162 0x95, 0x01,
163 0x14,
164 0xA4,
165 0x05, 0x01,
166 0x55, 0xFD,
167 0x65, 0x13,
168 0x34,
169 0x09, 0x30,
170 0x46, 0x40, 0x1F,
171 0x26, 0xFF, 0x7F,
172 0x81, 0x02,
173 0x09, 0x31,
174 0x46, 0x70, 0x17,
175 0x26, 0xFF, 0x7F,
176 0x81, 0x02,
177 0xB4,
178 0x09, 0x30,
179 0x26, 0xFF, 0x03,
180 0x81, 0x02,
181 0xC0,
182 0xC0,
183 0x05, 0x01,
184 0x09, 0x02,
185 0xA1, 0x01,
186 0x85, 0x08,
187 0x09, 0x01,
188 0xA0,
189 0x75, 0x01,
190 0x05, 0x09,
191 0x19, 0x01,
192 0x29, 0x03,
193 0x14,
194 0x25, 0x01,
195 0x95, 0x03,
196 0x81, 0x02,
197 0x95, 0x05,
198 0x81, 0x01,
199 0x05, 0x01,
200 0x75, 0x08,
201 0x09, 0x30,
202 0x09, 0x31,
203 0x15, 0x81,
204 0x25, 0x7F,
205 0x95, 0x02,
206 0x81, 0x06,
207 0x09, 0x38,
208 0x15, 0xFF,
209 0x25, 0x01,
210 0x95, 0x01,
211 0x81, 0x06,
212 0x81, 0x01,
213 0xC0,
214 0xC0
215};
216
217
218#define WP1062_RDESC_ORIG_SIZE 254
219
220
221static __u8 wp1062_rdesc_fixed[] = {
222 0x05, 0x0D,
223 0x09, 0x02,
224 0xA1, 0x01,
225 0x85, 0x09,
226 0x09, 0x20,
227 0xA0,
228 0x75, 0x01,
229 0x09, 0x42,
230 0x09, 0x44,
231 0x09, 0x46,
232 0x14,
233 0x25, 0x01,
234 0x95, 0x03,
235 0x81, 0x02,
236 0x95, 0x04,
237 0x81, 0x01,
238 0x09, 0x32,
239 0x95, 0x01,
240 0x81, 0x02,
241 0x75, 0x10,
242 0x95, 0x01,
243 0x14,
244 0xA4,
245 0x05, 0x01,
246 0x55, 0xFD,
247 0x65, 0x13,
248 0x34,
249 0x09, 0x30,
250 0x46, 0x10, 0x27,
251 0x26, 0x20, 0x4E,
252 0x81, 0x02,
253 0x09, 0x31,
254 0x46, 0xB7, 0x19,
255 0x26, 0x6E, 0x33,
256 0x81, 0x02,
257 0xB4,
258 0x09, 0x30,
259 0x26, 0xFF, 0x03,
260 0x81, 0x02,
261 0xC0,
262 0xC0
263};
264
265
266#define PF1209_RDESC_ORIG_SIZE 234
267
268
269static __u8 pf1209_rdesc_fixed[] = {
270 0x05, 0x0D,
271 0x09, 0x02,
272 0xA1, 0x01,
273 0x85, 0x09,
274 0x09, 0x20,
275 0xA0,
276 0x75, 0x01,
277 0x09, 0x42,
278 0x09, 0x44,
279 0x09, 0x46,
280 0x14,
281 0x25, 0x01,
282 0x95, 0x03,
283 0x81, 0x02,
284 0x95, 0x05,
285 0x81, 0x01,
286 0x75, 0x10,
287 0x95, 0x01,
288 0x14,
289 0xA4,
290 0x05, 0x01,
291 0x55, 0xFD,
292 0x65, 0x13,
293 0x34,
294 0x09, 0x30,
295 0x46, 0xE0, 0x2E,
296 0x26, 0xFF, 0x7F,
297 0x81, 0x02,
298 0x09, 0x31,
299 0x46, 0x28, 0x23,
300 0x26, 0xFF, 0x7F,
301 0x81, 0x02,
302 0xB4,
303 0x09, 0x30,
304 0x26, 0xFF, 0x03,
305 0x81, 0x02,
306 0xC0,
307 0xC0,
308 0x05, 0x01,
309 0x09, 0x02,
310 0xA1, 0x01,
311 0x85, 0x08,
312 0x09, 0x01,
313 0xA0,
314 0x75, 0x01,
315 0x05, 0x09,
316 0x19, 0x01,
317 0x29, 0x03,
318 0x14,
319 0x25, 0x01,
320 0x95, 0x03,
321 0x81, 0x02,
322 0x95, 0x05,
323 0x81, 0x01,
324 0x05, 0x01,
325 0x75, 0x08,
326 0x09, 0x30,
327 0x09, 0x31,
328 0x15, 0x81,
329 0x25, 0x7F,
330 0x95, 0x02,
331 0x81, 0x06,
332 0x09, 0x38,
333 0x15, 0xFF,
334 0x25, 0x01,
335 0x95, 0x01,
336 0x81, 0x06,
337 0x81, 0x01,
338 0xC0,
339 0xC0
340};
341
342
343#define TWHL850_RDESC_ORIG_SIZE0 182
344#define TWHL850_RDESC_ORIG_SIZE1 161
345#define TWHL850_RDESC_ORIG_SIZE2 92
346
347
348static __u8 twhl850_rdesc_fixed0[] = {
349 0x05, 0x0D,
350 0x09, 0x02,
351 0xA1, 0x01,
352 0x85, 0x09,
353 0x09, 0x20,
354 0xA0,
355 0x14,
356 0x25, 0x01,
357 0x75, 0x01,
358 0x95, 0x03,
359 0x09, 0x42,
360 0x09, 0x44,
361 0x09, 0x46,
362 0x81, 0x02,
363 0x81, 0x03,
364 0x95, 0x01,
365 0x09, 0x32,
366 0x81, 0x02,
367 0x81, 0x03,
368 0x75, 0x10,
369 0xA4,
370 0x05, 0x01,
371 0x65, 0x13,
372 0x55, 0xFD,
373 0x34,
374 0x09, 0x30,
375 0x46, 0x40, 0x1F,
376 0x26, 0x00, 0x7D,
377 0x81, 0x02,
378 0x09, 0x31,
379 0x46, 0x88, 0x13,
380 0x26, 0x20, 0x4E,
381 0x81, 0x02,
382 0xB4,
383 0x09, 0x30,
384 0x26, 0xFF, 0x03,
385 0x81, 0x02,
386 0xC0,
387 0xC0
388};
389
390
391static __u8 twhl850_rdesc_fixed1[] = {
392 0x05, 0x01,
393 0x09, 0x02,
394 0xA1, 0x01,
395 0x85, 0x01,
396 0x09, 0x01,
397 0xA0,
398 0x05, 0x09,
399 0x75, 0x01,
400 0x95, 0x03,
401 0x19, 0x01,
402 0x29, 0x03,
403 0x14,
404 0x25, 0x01,
405 0x81, 0x02,
406 0x95, 0x05,
407 0x81, 0x03,
408 0x05, 0x01,
409 0x09, 0x30,
410 0x09, 0x31,
411 0x16, 0x00, 0x80,
412 0x26, 0xFF, 0x7F,
413 0x75, 0x10,
414 0x95, 0x02,
415 0x81, 0x06,
416 0x09, 0x38,
417 0x15, 0xFF,
418 0x25, 0x01,
419 0x95, 0x01,
420 0x75, 0x08,
421 0x81, 0x06,
422 0x81, 0x03,
423 0xC0,
424 0xC0
425};
426
427
428static __u8 twhl850_rdesc_fixed2[] = {
429 0x05, 0x01,
430 0x09, 0x06,
431 0xA1, 0x01,
432 0x85, 0x03,
433 0x05, 0x07,
434 0x14,
435 0x19, 0xE0,
436 0x29, 0xE7,
437 0x25, 0x01,
438 0x75, 0x01,
439 0x95, 0x08,
440 0x81, 0x02,
441 0x18,
442 0x29, 0xFF,
443 0x26, 0xFF, 0x00,
444 0x75, 0x08,
445 0x95, 0x06,
446 0x80,
447 0xC0
448};
449
450
451#define TWHA60_RDESC_ORIG_SIZE0 254
452#define TWHA60_RDESC_ORIG_SIZE1 139
453
454
455static __u8 twha60_rdesc_fixed0[] = {
456 0x05, 0x0D,
457 0x09, 0x02,
458 0xA1, 0x01,
459 0x85, 0x09,
460 0x09, 0x20,
461 0xA0,
462 0x75, 0x01,
463 0x09, 0x42,
464 0x09, 0x44,
465 0x09, 0x46,
466 0x14,
467 0x25, 0x01,
468 0x95, 0x03,
469 0x81, 0x02,
470 0x95, 0x04,
471 0x81, 0x01,
472 0x09, 0x32,
473 0x95, 0x01,
474 0x81, 0x02,
475 0x75, 0x10,
476 0x95, 0x01,
477 0x14,
478 0xA4,
479 0x05, 0x01,
480 0x55, 0xFD,
481 0x65, 0x13,
482 0x34,
483 0x09, 0x30,
484 0x46, 0x10, 0x27,
485 0x27, 0x3F, 0x9C,
486 0x00, 0x00,
487 0x81, 0x02,
488 0x09, 0x31,
489 0x46, 0x6A, 0x18,
490 0x26, 0xA7, 0x61,
491 0x81, 0x02,
492 0xB4,
493 0x09, 0x30,
494 0x26, 0xFF, 0x03,
495 0x81, 0x02,
496 0xC0,
497 0xC0
498};
499
500
501static __u8 twha60_rdesc_fixed1[] = {
502 0x05, 0x01,
503 0x09, 0x06,
504 0xA1, 0x01,
505 0x85, 0x05,
506 0x05, 0x07,
507 0x14,
508 0x25, 0x01,
509 0x75, 0x01,
510 0x95, 0x08,
511 0x81, 0x01,
512 0x95, 0x0C,
513 0x19, 0x3A,
514 0x29, 0x45,
515 0x81, 0x02,
516 0x95, 0x0C,
517 0x19, 0x68,
518 0x29, 0x73,
519 0x81, 0x02,
520 0x95, 0x08,
521 0x81, 0x01,
522 0xC0
523};
524
525
526#define UCLOGIC_PH_HEAD 0xFE, 0xED, 0x1D
527
528
529enum uclogic_ph_id {
530 UCLOGIC_PH_ID_X_LM,
531 UCLOGIC_PH_ID_X_PM,
532 UCLOGIC_PH_ID_Y_LM,
533 UCLOGIC_PH_ID_Y_PM,
534 UCLOGIC_PH_ID_PRESSURE_LM,
535 UCLOGIC_PH_ID_NUM
536};
537
538
539#define UCLOGIC_PH(_ID) UCLOGIC_PH_HEAD, UCLOGIC_PH_ID_##_ID
540#define UCLOGIC_PEN_REPORT_ID 0x07
541
542
543static const __u8 uclogic_tablet_rdesc_template[] = {
544 0x05, 0x0D,
545 0x09, 0x02,
546 0xA1, 0x01,
547 0x85, 0x07,
548 0x09, 0x20,
549 0xA0,
550 0x14,
551 0x25, 0x01,
552 0x75, 0x01,
553 0x09, 0x42,
554 0x09, 0x44,
555 0x09, 0x46,
556 0x95, 0x03,
557 0x81, 0x02,
558 0x95, 0x03,
559 0x81, 0x03,
560 0x09, 0x32,
561 0x95, 0x01,
562 0x81, 0x02,
563 0x95, 0x01,
564 0x81, 0x03,
565 0x75, 0x10,
566 0x95, 0x01,
567 0xA4,
568 0x05, 0x01,
569 0x65, 0x13,
570 0x55, 0xFD,
571 0x34,
572 0x09, 0x30,
573 0x27, UCLOGIC_PH(X_LM),
574 0x47, UCLOGIC_PH(X_PM),
575 0x81, 0x02,
576 0x09, 0x31,
577 0x27, UCLOGIC_PH(Y_LM),
578 0x47, UCLOGIC_PH(Y_PM),
579 0x81, 0x02,
580 0xB4,
581 0x09, 0x30,
582 0x27,
583 UCLOGIC_PH(PRESSURE_LM),
584 0x81, 0x02,
585 0xC0,
586 0xC0
587};
588
589
590static const __u8 uclogic_buttonpad_rdesc[] = {
591 0x05, 0x01,
592 0x09, 0x07,
593 0xA1, 0x01,
594 0x85, 0xF7,
595 0x05, 0x0D,
596 0x09, 0x39,
597 0xA0,
598 0x05, 0x09,
599 0x75, 0x01,
600 0x95, 0x18,
601 0x81, 0x03,
602 0x19, 0x01,
603 0x29, 0x08,
604 0x95, 0x08,
605 0x81, 0x02,
606 0xC0,
607 0xC0
608};
609
610
611enum uclogic_prm {
612 UCLOGIC_PRM_X_LM = 1,
613 UCLOGIC_PRM_Y_LM = 2,
614 UCLOGIC_PRM_PRESSURE_LM = 4,
615 UCLOGIC_PRM_RESOLUTION = 5,
616 UCLOGIC_PRM_NUM
617};
618
619
620struct uclogic_drvdata {
621 __u8 *rdesc;
622 unsigned int rsize;
623 bool invert_pen_inrange;
624 bool ignore_pen_usage;
625 bool has_virtual_pad_interface;
626};
627
628static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
629 unsigned int *rsize)
630{
631 struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
632 __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
633 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
634
635 if (drvdata->rdesc != NULL) {
636 rdesc = drvdata->rdesc;
637 *rsize = drvdata->rsize;
638 return rdesc;
639 }
640
641 switch (hdev->product) {
642 case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
643 if (*rsize == PF1209_RDESC_ORIG_SIZE) {
644 rdesc = pf1209_rdesc_fixed;
645 *rsize = sizeof(pf1209_rdesc_fixed);
646 }
647 break;
648 case USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U:
649 if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
650 rdesc = wp4030u_rdesc_fixed;
651 *rsize = sizeof(wp4030u_rdesc_fixed);
652 }
653 break;
654 case USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U:
655 if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
656 rdesc = wp5540u_rdesc_fixed;
657 *rsize = sizeof(wp5540u_rdesc_fixed);
658 }
659 break;
660 case USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U:
661 if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
662 rdesc = wp8060u_rdesc_fixed;
663 *rsize = sizeof(wp8060u_rdesc_fixed);
664 }
665 break;
666 case USB_DEVICE_ID_UCLOGIC_TABLET_WP1062:
667 if (*rsize == WP1062_RDESC_ORIG_SIZE) {
668 rdesc = wp1062_rdesc_fixed;
669 *rsize = sizeof(wp1062_rdesc_fixed);
670 }
671 break;
672 case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850:
673 switch (iface_num) {
674 case 0:
675 if (*rsize == TWHL850_RDESC_ORIG_SIZE0) {
676 rdesc = twhl850_rdesc_fixed0;
677 *rsize = sizeof(twhl850_rdesc_fixed0);
678 }
679 break;
680 case 1:
681 if (*rsize == TWHL850_RDESC_ORIG_SIZE1) {
682 rdesc = twhl850_rdesc_fixed1;
683 *rsize = sizeof(twhl850_rdesc_fixed1);
684 }
685 break;
686 case 2:
687 if (*rsize == TWHL850_RDESC_ORIG_SIZE2) {
688 rdesc = twhl850_rdesc_fixed2;
689 *rsize = sizeof(twhl850_rdesc_fixed2);
690 }
691 break;
692 }
693 break;
694 case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60:
695 switch (iface_num) {
696 case 0:
697 if (*rsize == TWHA60_RDESC_ORIG_SIZE0) {
698 rdesc = twha60_rdesc_fixed0;
699 *rsize = sizeof(twha60_rdesc_fixed0);
700 }
701 break;
702 case 1:
703 if (*rsize == TWHA60_RDESC_ORIG_SIZE1) {
704 rdesc = twha60_rdesc_fixed1;
705 *rsize = sizeof(twha60_rdesc_fixed1);
706 }
707 break;
708 }
709 break;
710 }
711
712 return rdesc;
713}
714
715static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi,
716 struct hid_field *field, struct hid_usage *usage,
717 unsigned long **bit, int *max)
718{
719 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
720
721
722 if ((drvdata->ignore_pen_usage) &&
723 (field->application == HID_DG_PEN))
724 return -1;
725
726
727 return 0;
728}
729
730static int uclogic_input_configured(struct hid_device *hdev,
731 struct hid_input *hi)
732{
733 char *name;
734 const char *suffix = NULL;
735 struct hid_field *field;
736 size_t len;
737
738
739 if (!hi->report)
740 return 0;
741
742 field = hi->report->field[0];
743
744 switch (field->application) {
745 case HID_GD_KEYBOARD:
746 suffix = "Keyboard";
747 break;
748 case HID_GD_MOUSE:
749 suffix = "Mouse";
750 break;
751 case HID_GD_KEYPAD:
752 suffix = "Pad";
753 break;
754 case HID_DG_PEN:
755 suffix = "Pen";
756 break;
757 case HID_CP_CONSUMER_CONTROL:
758 suffix = "Consumer Control";
759 break;
760 case HID_GD_SYSTEM_CONTROL:
761 suffix = "System Control";
762 break;
763 }
764
765 if (suffix) {
766 len = strlen(hdev->name) + 2 + strlen(suffix);
767 name = devm_kzalloc(&hi->input->dev, len, GFP_KERNEL);
768 if (name) {
769 snprintf(name, len, "%s %s", hdev->name, suffix);
770 hi->input->name = name;
771 }
772 }
773
774 return 0;
775}
776
777
778
779
780
781
782static int uclogic_tablet_enable(struct hid_device *hdev)
783{
784 int rc;
785 struct usb_device *usb_dev = hid_to_usb_dev(hdev);
786 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
787 __le16 *buf = NULL;
788 size_t len;
789 s32 params[UCLOGIC_PH_ID_NUM];
790 s32 resolution;
791 __u8 *p;
792 s32 v;
793
794
795
796
797
798
799
800 len = UCLOGIC_PRM_NUM * sizeof(*buf);
801 buf = kmalloc(len, GFP_KERNEL);
802 if (buf == NULL) {
803 rc = -ENOMEM;
804 goto cleanup;
805 }
806 rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
807 USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
808 (USB_DT_STRING << 8) + 0x64,
809 0x0409, buf, len,
810 USB_CTRL_GET_TIMEOUT);
811 if (rc == -EPIPE) {
812 hid_err(hdev, "device parameters not found\n");
813 rc = -ENODEV;
814 goto cleanup;
815 } else if (rc < 0) {
816 hid_err(hdev, "failed to get device parameters: %d\n", rc);
817 rc = -ENODEV;
818 goto cleanup;
819 } else if (rc != len) {
820 hid_err(hdev, "invalid device parameters\n");
821 rc = -ENODEV;
822 goto cleanup;
823 }
824
825
826 params[UCLOGIC_PH_ID_X_LM] = le16_to_cpu(buf[UCLOGIC_PRM_X_LM]);
827 params[UCLOGIC_PH_ID_Y_LM] = le16_to_cpu(buf[UCLOGIC_PRM_Y_LM]);
828 params[UCLOGIC_PH_ID_PRESSURE_LM] =
829 le16_to_cpu(buf[UCLOGIC_PRM_PRESSURE_LM]);
830 resolution = le16_to_cpu(buf[UCLOGIC_PRM_RESOLUTION]);
831 if (resolution == 0) {
832 params[UCLOGIC_PH_ID_X_PM] = 0;
833 params[UCLOGIC_PH_ID_Y_PM] = 0;
834 } else {
835 params[UCLOGIC_PH_ID_X_PM] = params[UCLOGIC_PH_ID_X_LM] *
836 1000 / resolution;
837 params[UCLOGIC_PH_ID_Y_PM] = params[UCLOGIC_PH_ID_Y_LM] *
838 1000 / resolution;
839 }
840
841
842 drvdata->rdesc = devm_kzalloc(&hdev->dev,
843 sizeof(uclogic_tablet_rdesc_template),
844 GFP_KERNEL);
845 if (drvdata->rdesc == NULL) {
846 rc = -ENOMEM;
847 goto cleanup;
848 }
849 drvdata->rsize = sizeof(uclogic_tablet_rdesc_template);
850
851
852 memcpy(drvdata->rdesc, uclogic_tablet_rdesc_template,
853 drvdata->rsize);
854 for (p = drvdata->rdesc;
855 p <= drvdata->rdesc + drvdata->rsize - 4;) {
856 if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
857 p[3] < ARRAY_SIZE(params)) {
858 v = params[p[3]];
859 put_unaligned(cpu_to_le32(v), (s32 *)p);
860 p += 4;
861 } else {
862 p++;
863 }
864 }
865
866 rc = 0;
867
868cleanup:
869 kfree(buf);
870 return rc;
871}
872
873
874
875
876
877
878static int uclogic_button_enable(struct hid_device *hdev)
879{
880 int rc;
881 struct usb_device *usb_dev = hid_to_usb_dev(hdev);
882 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
883 char *str_buf;
884 size_t str_len = 16;
885 unsigned char *rdesc;
886 size_t rdesc_len;
887
888 str_buf = kzalloc(str_len, GFP_KERNEL);
889 if (str_buf == NULL) {
890 rc = -ENOMEM;
891 goto cleanup;
892 }
893
894
895 rc = usb_string(usb_dev, 0x7b, str_buf, str_len);
896 if (rc == -EPIPE) {
897 hid_info(hdev, "button mode setting not found\n");
898 rc = 0;
899 goto cleanup;
900 } else if (rc < 0) {
901 hid_err(hdev, "failed to enable abstract keyboard\n");
902 goto cleanup;
903 } else if (strncmp(str_buf, "HK On", rc)) {
904 hid_info(hdev, "invalid answer when requesting buttons: '%s'\n",
905 str_buf);
906 rc = -EINVAL;
907 goto cleanup;
908 }
909
910
911 rdesc_len = drvdata->rsize + sizeof(uclogic_buttonpad_rdesc);
912 rdesc = devm_kzalloc(&hdev->dev, rdesc_len, GFP_KERNEL);
913 if (!rdesc) {
914 rc = -ENOMEM;
915 goto cleanup;
916 }
917
918 memcpy(rdesc, drvdata->rdesc, drvdata->rsize);
919
920
921 memcpy(rdesc + drvdata->rsize, uclogic_buttonpad_rdesc,
922 sizeof(uclogic_buttonpad_rdesc));
923
924
925 drvdata->rsize = rdesc_len;
926 devm_kfree(&hdev->dev, drvdata->rdesc);
927 drvdata->rdesc = rdesc;
928
929 rc = 0;
930
931cleanup:
932 kfree(str_buf);
933 return rc;
934}
935
936static int uclogic_probe(struct hid_device *hdev,
937 const struct hid_device_id *id)
938{
939 int rc;
940 struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
941 struct usb_device *udev = hid_to_usb_dev(hdev);
942 struct uclogic_drvdata *drvdata;
943
944
945
946
947
948 hdev->quirks |= HID_QUIRK_MULTI_INPUT;
949
950
951 drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
952 if (drvdata == NULL)
953 return -ENOMEM;
954
955 hid_set_drvdata(hdev, drvdata);
956
957 switch (id->product) {
958 case USB_DEVICE_ID_HUION_TABLET:
959 case USB_DEVICE_ID_YIYNOVA_TABLET:
960 case USB_DEVICE_ID_UGEE_TABLET_81:
961 case USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3:
962 case USB_DEVICE_ID_UGEE_TABLET_45:
963
964 if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
965 rc = uclogic_tablet_enable(hdev);
966 if (rc) {
967 hid_err(hdev, "tablet enabling failed\n");
968 return rc;
969 }
970 drvdata->invert_pen_inrange = true;
971
972 rc = uclogic_button_enable(hdev);
973 drvdata->has_virtual_pad_interface = !rc;
974 } else {
975 drvdata->ignore_pen_usage = true;
976 }
977 break;
978 case USB_DEVICE_ID_UGTIZER_TABLET_GP0610:
979 case USB_DEVICE_ID_UGEE_TABLET_EX07S:
980
981 if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
982 rc = uclogic_tablet_enable(hdev);
983 if (rc) {
984 hid_err(hdev, "tablet enabling failed\n");
985 return rc;
986 }
987 drvdata->invert_pen_inrange = true;
988 } else {
989 drvdata->ignore_pen_usage = true;
990 }
991 break;
992 case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60:
993
994
995
996
997 if (udev->config->desc.bNumInterfaces == 3) {
998
999 if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
1000 rc = uclogic_tablet_enable(hdev);
1001 if (rc) {
1002 hid_err(hdev, "tablet enabling failed\n");
1003 return rc;
1004 }
1005 drvdata->invert_pen_inrange = true;
1006
1007 rc = uclogic_button_enable(hdev);
1008 drvdata->has_virtual_pad_interface = !rc;
1009 } else {
1010 drvdata->ignore_pen_usage = true;
1011 }
1012 }
1013 break;
1014 }
1015
1016 rc = hid_parse(hdev);
1017 if (rc) {
1018 hid_err(hdev, "parse failed\n");
1019 return rc;
1020 }
1021
1022 rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
1023 if (rc) {
1024 hid_err(hdev, "hw start failed\n");
1025 return rc;
1026 }
1027
1028 return 0;
1029}
1030
1031static int uclogic_raw_event(struct hid_device *hdev, struct hid_report *report,
1032 u8 *data, int size)
1033{
1034 struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
1035
1036 if ((report->type == HID_INPUT_REPORT) &&
1037 (report->id == UCLOGIC_PEN_REPORT_ID) &&
1038 (size >= 2)) {
1039 if (drvdata->has_virtual_pad_interface && (data[1] & 0x20))
1040
1041 data[0] = 0xf7;
1042 else if (drvdata->invert_pen_inrange)
1043
1044 data[1] ^= 0x40;
1045 }
1046
1047 return 0;
1048}
1049
1050static const struct hid_device_id uclogic_devices[] = {
1051 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1052 USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
1053 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1054 USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
1055 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1056 USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
1057 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1058 USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
1059 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1060 USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
1061 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1062 USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
1063 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1064 USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
1065 { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
1066 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) },
1067 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET) },
1068 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_81) },
1069 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_45) },
1070 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) },
1071 { HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
1072 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_EX07S) },
1073 { }
1074};
1075MODULE_DEVICE_TABLE(hid, uclogic_devices);
1076
1077static struct hid_driver uclogic_driver = {
1078 .name = "uclogic",
1079 .id_table = uclogic_devices,
1080 .probe = uclogic_probe,
1081 .report_fixup = uclogic_report_fixup,
1082 .raw_event = uclogic_raw_event,
1083 .input_mapping = uclogic_input_mapping,
1084 .input_configured = uclogic_input_configured,
1085};
1086module_hid_driver(uclogic_driver);
1087
1088MODULE_AUTHOR("Martin Rusko");
1089MODULE_AUTHOR("Nikolai Kondrashov");
1090MODULE_LICENSE("GPL");
1091