1 /*
2  *  HID driver for UC-Logic devices not fully compliant with HID standard
3  *
4  *  Copyright (c) 2010-2014 Nikolai Kondrashov
5  *  Copyright (c) 2013 Martin Rusko
6  */
7 
8 /*
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU General Public License as published by the Free
11  * Software Foundation; either version 2 of the License, or (at your option)
12  * any later version.
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 /* Size of the original descriptor of WPXXXXU tablets */
25 #define WPXXXXU_RDESC_ORIG_SIZE	212
26 
27 /* Fixed WP4030U report descriptor */
28 static __u8 wp4030u_rdesc_fixed[] = {
29 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
30 	0x09, 0x02,         /*  Usage (Pen),                        */
31 	0xA1, 0x01,         /*  Collection (Application),           */
32 	0x85, 0x09,         /*      Report ID (9),                  */
33 	0x09, 0x20,         /*      Usage (Stylus),                 */
34 	0xA0,               /*      Collection (Physical),          */
35 	0x75, 0x01,         /*          Report Size (1),            */
36 	0x09, 0x42,         /*          Usage (Tip Switch),         */
37 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
38 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
39 	0x14,               /*          Logical Minimum (0),        */
40 	0x25, 0x01,         /*          Logical Maximum (1),        */
41 	0x95, 0x03,         /*          Report Count (3),           */
42 	0x81, 0x02,         /*          Input (Variable),           */
43 	0x95, 0x05,         /*          Report Count (5),           */
44 	0x81, 0x01,         /*          Input (Constant),           */
45 	0x75, 0x10,         /*          Report Size (16),           */
46 	0x95, 0x01,         /*          Report Count (1),           */
47 	0x14,               /*          Logical Minimum (0),        */
48 	0xA4,               /*          Push,                       */
49 	0x05, 0x01,         /*          Usage Page (Desktop),       */
50 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
51 	0x65, 0x13,         /*          Unit (Inch),                */
52 	0x34,               /*          Physical Minimum (0),       */
53 	0x09, 0x30,         /*          Usage (X),                  */
54 	0x46, 0xA0, 0x0F,   /*          Physical Maximum (4000),    */
55 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
56 	0x81, 0x02,         /*          Input (Variable),           */
57 	0x09, 0x31,         /*          Usage (Y),                  */
58 	0x46, 0xB8, 0x0B,   /*          Physical Maximum (3000),    */
59 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
60 	0x81, 0x02,         /*          Input (Variable),           */
61 	0xB4,               /*          Pop,                        */
62 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
63 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
64 	0x81, 0x02,         /*          Input (Variable),           */
65 	0xC0,               /*      End Collection,                 */
66 	0xC0                /*  End Collection                      */
67 };
68 
69 /* Fixed WP5540U report descriptor */
70 static __u8 wp5540u_rdesc_fixed[] = {
71 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
72 	0x09, 0x02,         /*  Usage (Pen),                        */
73 	0xA1, 0x01,         /*  Collection (Application),           */
74 	0x85, 0x09,         /*      Report ID (9),                  */
75 	0x09, 0x20,         /*      Usage (Stylus),                 */
76 	0xA0,               /*      Collection (Physical),          */
77 	0x75, 0x01,         /*          Report Size (1),            */
78 	0x09, 0x42,         /*          Usage (Tip Switch),         */
79 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
80 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
81 	0x14,               /*          Logical Minimum (0),        */
82 	0x25, 0x01,         /*          Logical Maximum (1),        */
83 	0x95, 0x03,         /*          Report Count (3),           */
84 	0x81, 0x02,         /*          Input (Variable),           */
85 	0x95, 0x05,         /*          Report Count (5),           */
86 	0x81, 0x01,         /*          Input (Constant),           */
87 	0x75, 0x10,         /*          Report Size (16),           */
88 	0x95, 0x01,         /*          Report Count (1),           */
89 	0x14,               /*          Logical Minimum (0),        */
90 	0xA4,               /*          Push,                       */
91 	0x05, 0x01,         /*          Usage Page (Desktop),       */
92 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
93 	0x65, 0x13,         /*          Unit (Inch),                */
94 	0x34,               /*          Physical Minimum (0),       */
95 	0x09, 0x30,         /*          Usage (X),                  */
96 	0x46, 0x7C, 0x15,   /*          Physical Maximum (5500),    */
97 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
98 	0x81, 0x02,         /*          Input (Variable),           */
99 	0x09, 0x31,         /*          Usage (Y),                  */
100 	0x46, 0xA0, 0x0F,   /*          Physical Maximum (4000),    */
101 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
102 	0x81, 0x02,         /*          Input (Variable),           */
103 	0xB4,               /*          Pop,                        */
104 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
105 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
106 	0x81, 0x02,         /*          Input (Variable),           */
107 	0xC0,               /*      End Collection,                 */
108 	0xC0,               /*  End Collection,                     */
109 	0x05, 0x01,         /*  Usage Page (Desktop),               */
110 	0x09, 0x02,         /*  Usage (Mouse),                      */
111 	0xA1, 0x01,         /*  Collection (Application),           */
112 	0x85, 0x08,         /*      Report ID (8),                  */
113 	0x09, 0x01,         /*      Usage (Pointer),                */
114 	0xA0,               /*      Collection (Physical),          */
115 	0x75, 0x01,         /*          Report Size (1),            */
116 	0x05, 0x09,         /*          Usage Page (Button),        */
117 	0x19, 0x01,         /*          Usage Minimum (01h),        */
118 	0x29, 0x03,         /*          Usage Maximum (03h),        */
119 	0x14,               /*          Logical Minimum (0),        */
120 	0x25, 0x01,         /*          Logical Maximum (1),        */
121 	0x95, 0x03,         /*          Report Count (3),           */
122 	0x81, 0x02,         /*          Input (Variable),           */
123 	0x95, 0x05,         /*          Report Count (5),           */
124 	0x81, 0x01,         /*          Input (Constant),           */
125 	0x05, 0x01,         /*          Usage Page (Desktop),       */
126 	0x75, 0x08,         /*          Report Size (8),            */
127 	0x09, 0x30,         /*          Usage (X),                  */
128 	0x09, 0x31,         /*          Usage (Y),                  */
129 	0x15, 0x81,         /*          Logical Minimum (-127),     */
130 	0x25, 0x7F,         /*          Logical Maximum (127),      */
131 	0x95, 0x02,         /*          Report Count (2),           */
132 	0x81, 0x06,         /*          Input (Variable, Relative), */
133 	0x09, 0x38,         /*          Usage (Wheel),              */
134 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
135 	0x25, 0x01,         /*          Logical Maximum (1),        */
136 	0x95, 0x01,         /*          Report Count (1),           */
137 	0x81, 0x06,         /*          Input (Variable, Relative), */
138 	0x81, 0x01,         /*          Input (Constant),           */
139 	0xC0,               /*      End Collection,                 */
140 	0xC0                /*  End Collection                      */
141 };
142 
143 /* Fixed WP8060U report descriptor */
144 static __u8 wp8060u_rdesc_fixed[] = {
145 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
146 	0x09, 0x02,         /*  Usage (Pen),                        */
147 	0xA1, 0x01,         /*  Collection (Application),           */
148 	0x85, 0x09,         /*      Report ID (9),                  */
149 	0x09, 0x20,         /*      Usage (Stylus),                 */
150 	0xA0,               /*      Collection (Physical),          */
151 	0x75, 0x01,         /*          Report Size (1),            */
152 	0x09, 0x42,         /*          Usage (Tip Switch),         */
153 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
154 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
155 	0x14,               /*          Logical Minimum (0),        */
156 	0x25, 0x01,         /*          Logical Maximum (1),        */
157 	0x95, 0x03,         /*          Report Count (3),           */
158 	0x81, 0x02,         /*          Input (Variable),           */
159 	0x95, 0x05,         /*          Report Count (5),           */
160 	0x81, 0x01,         /*          Input (Constant),           */
161 	0x75, 0x10,         /*          Report Size (16),           */
162 	0x95, 0x01,         /*          Report Count (1),           */
163 	0x14,               /*          Logical Minimum (0),        */
164 	0xA4,               /*          Push,                       */
165 	0x05, 0x01,         /*          Usage Page (Desktop),       */
166 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
167 	0x65, 0x13,         /*          Unit (Inch),                */
168 	0x34,               /*          Physical Minimum (0),       */
169 	0x09, 0x30,         /*          Usage (X),                  */
170 	0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
171 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
172 	0x81, 0x02,         /*          Input (Variable),           */
173 	0x09, 0x31,         /*          Usage (Y),                  */
174 	0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
175 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
176 	0x81, 0x02,         /*          Input (Variable),           */
177 	0xB4,               /*          Pop,                        */
178 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
179 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
180 	0x81, 0x02,         /*          Input (Variable),           */
181 	0xC0,               /*      End Collection,                 */
182 	0xC0,               /*  End Collection,                     */
183 	0x05, 0x01,         /*  Usage Page (Desktop),               */
184 	0x09, 0x02,         /*  Usage (Mouse),                      */
185 	0xA1, 0x01,         /*  Collection (Application),           */
186 	0x85, 0x08,         /*      Report ID (8),                  */
187 	0x09, 0x01,         /*      Usage (Pointer),                */
188 	0xA0,               /*      Collection (Physical),          */
189 	0x75, 0x01,         /*          Report Size (1),            */
190 	0x05, 0x09,         /*          Usage Page (Button),        */
191 	0x19, 0x01,         /*          Usage Minimum (01h),        */
192 	0x29, 0x03,         /*          Usage Maximum (03h),        */
193 	0x14,               /*          Logical Minimum (0),        */
194 	0x25, 0x01,         /*          Logical Maximum (1),        */
195 	0x95, 0x03,         /*          Report Count (3),           */
196 	0x81, 0x02,         /*          Input (Variable),           */
197 	0x95, 0x05,         /*          Report Count (5),           */
198 	0x81, 0x01,         /*          Input (Constant),           */
199 	0x05, 0x01,         /*          Usage Page (Desktop),       */
200 	0x75, 0x08,         /*          Report Size (8),            */
201 	0x09, 0x30,         /*          Usage (X),                  */
202 	0x09, 0x31,         /*          Usage (Y),                  */
203 	0x15, 0x81,         /*          Logical Minimum (-127),     */
204 	0x25, 0x7F,         /*          Logical Maximum (127),      */
205 	0x95, 0x02,         /*          Report Count (2),           */
206 	0x81, 0x06,         /*          Input (Variable, Relative), */
207 	0x09, 0x38,         /*          Usage (Wheel),              */
208 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
209 	0x25, 0x01,         /*          Logical Maximum (1),        */
210 	0x95, 0x01,         /*          Report Count (1),           */
211 	0x81, 0x06,         /*          Input (Variable, Relative), */
212 	0x81, 0x01,         /*          Input (Constant),           */
213 	0xC0,               /*      End Collection,                 */
214 	0xC0                /*  End Collection                      */
215 };
216 
217 /* Size of the original descriptor of WP1062 tablet */
218 #define WP1062_RDESC_ORIG_SIZE	254
219 
220 /* Fixed WP1062 report descriptor */
221 static __u8 wp1062_rdesc_fixed[] = {
222 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
223 	0x09, 0x02,         /*  Usage (Pen),                        */
224 	0xA1, 0x01,         /*  Collection (Application),           */
225 	0x85, 0x09,         /*      Report ID (9),                  */
226 	0x09, 0x20,         /*      Usage (Stylus),                 */
227 	0xA0,               /*      Collection (Physical),          */
228 	0x75, 0x01,         /*          Report Size (1),            */
229 	0x09, 0x42,         /*          Usage (Tip Switch),         */
230 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
231 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
232 	0x14,               /*          Logical Minimum (0),        */
233 	0x25, 0x01,         /*          Logical Maximum (1),        */
234 	0x95, 0x03,         /*          Report Count (3),           */
235 	0x81, 0x02,         /*          Input (Variable),           */
236 	0x95, 0x04,         /*          Report Count (4),           */
237 	0x81, 0x01,         /*          Input (Constant),           */
238 	0x09, 0x32,         /*          Usage (In Range),           */
239 	0x95, 0x01,         /*          Report Count (1),           */
240 	0x81, 0x02,         /*          Input (Variable),           */
241 	0x75, 0x10,         /*          Report Size (16),           */
242 	0x95, 0x01,         /*          Report Count (1),           */
243 	0x14,               /*          Logical Minimum (0),        */
244 	0xA4,               /*          Push,                       */
245 	0x05, 0x01,         /*          Usage Page (Desktop),       */
246 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
247 	0x65, 0x13,         /*          Unit (Inch),                */
248 	0x34,               /*          Physical Minimum (0),       */
249 	0x09, 0x30,         /*          Usage (X),                  */
250 	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
251 	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
252 	0x81, 0x02,         /*          Input (Variable),           */
253 	0x09, 0x31,         /*          Usage (Y),                  */
254 	0x46, 0xB7, 0x19,   /*          Physical Maximum (6583),    */
255 	0x26, 0x6E, 0x33,   /*          Logical Maximum (13166),    */
256 	0x81, 0x02,         /*          Input (Variable),           */
257 	0xB4,               /*          Pop,                        */
258 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
259 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
260 	0x81, 0x02,         /*          Input (Variable),           */
261 	0xC0,               /*      End Collection,                 */
262 	0xC0                /*  End Collection                      */
263 };
264 
265 /* Size of the original descriptor of PF1209 tablet */
266 #define PF1209_RDESC_ORIG_SIZE	234
267 
268 /* Fixed PF1209 report descriptor */
269 static __u8 pf1209_rdesc_fixed[] = {
270 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
271 	0x09, 0x02,         /*  Usage (Pen),                        */
272 	0xA1, 0x01,         /*  Collection (Application),           */
273 	0x85, 0x09,         /*      Report ID (9),                  */
274 	0x09, 0x20,         /*      Usage (Stylus),                 */
275 	0xA0,               /*      Collection (Physical),          */
276 	0x75, 0x01,         /*          Report Size (1),            */
277 	0x09, 0x42,         /*          Usage (Tip Switch),         */
278 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
279 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
280 	0x14,               /*          Logical Minimum (0),        */
281 	0x25, 0x01,         /*          Logical Maximum (1),        */
282 	0x95, 0x03,         /*          Report Count (3),           */
283 	0x81, 0x02,         /*          Input (Variable),           */
284 	0x95, 0x05,         /*          Report Count (5),           */
285 	0x81, 0x01,         /*          Input (Constant),           */
286 	0x75, 0x10,         /*          Report Size (16),           */
287 	0x95, 0x01,         /*          Report Count (1),           */
288 	0x14,               /*          Logical Minimum (0),        */
289 	0xA4,               /*          Push,                       */
290 	0x05, 0x01,         /*          Usage Page (Desktop),       */
291 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
292 	0x65, 0x13,         /*          Unit (Inch),                */
293 	0x34,               /*          Physical Minimum (0),       */
294 	0x09, 0x30,         /*          Usage (X),                  */
295 	0x46, 0xE0, 0x2E,   /*          Physical Maximum (12000),   */
296 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
297 	0x81, 0x02,         /*          Input (Variable),           */
298 	0x09, 0x31,         /*          Usage (Y),                  */
299 	0x46, 0x28, 0x23,   /*          Physical Maximum (9000),    */
300 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
301 	0x81, 0x02,         /*          Input (Variable),           */
302 	0xB4,               /*          Pop,                        */
303 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
304 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
305 	0x81, 0x02,         /*          Input (Variable),           */
306 	0xC0,               /*      End Collection,                 */
307 	0xC0,               /*  End Collection,                     */
308 	0x05, 0x01,         /*  Usage Page (Desktop),               */
309 	0x09, 0x02,         /*  Usage (Mouse),                      */
310 	0xA1, 0x01,         /*  Collection (Application),           */
311 	0x85, 0x08,         /*      Report ID (8),                  */
312 	0x09, 0x01,         /*      Usage (Pointer),                */
313 	0xA0,               /*      Collection (Physical),          */
314 	0x75, 0x01,         /*          Report Size (1),            */
315 	0x05, 0x09,         /*          Usage Page (Button),        */
316 	0x19, 0x01,         /*          Usage Minimum (01h),        */
317 	0x29, 0x03,         /*          Usage Maximum (03h),        */
318 	0x14,               /*          Logical Minimum (0),        */
319 	0x25, 0x01,         /*          Logical Maximum (1),        */
320 	0x95, 0x03,         /*          Report Count (3),           */
321 	0x81, 0x02,         /*          Input (Variable),           */
322 	0x95, 0x05,         /*          Report Count (5),           */
323 	0x81, 0x01,         /*          Input (Constant),           */
324 	0x05, 0x01,         /*          Usage Page (Desktop),       */
325 	0x75, 0x08,         /*          Report Size (8),            */
326 	0x09, 0x30,         /*          Usage (X),                  */
327 	0x09, 0x31,         /*          Usage (Y),                  */
328 	0x15, 0x81,         /*          Logical Minimum (-127),     */
329 	0x25, 0x7F,         /*          Logical Maximum (127),      */
330 	0x95, 0x02,         /*          Report Count (2),           */
331 	0x81, 0x06,         /*          Input (Variable, Relative), */
332 	0x09, 0x38,         /*          Usage (Wheel),              */
333 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
334 	0x25, 0x01,         /*          Logical Maximum (1),        */
335 	0x95, 0x01,         /*          Report Count (1),           */
336 	0x81, 0x06,         /*          Input (Variable, Relative), */
337 	0x81, 0x01,         /*          Input (Constant),           */
338 	0xC0,               /*      End Collection,                 */
339 	0xC0                /*  End Collection                      */
340 };
341 
342 /* Size of the original descriptors of TWHL850 tablet */
343 #define TWHL850_RDESC_ORIG_SIZE0	182
344 #define TWHL850_RDESC_ORIG_SIZE1	161
345 #define TWHL850_RDESC_ORIG_SIZE2	92
346 
347 /* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
348 static __u8 twhl850_rdesc_fixed0[] = {
349 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
350 	0x09, 0x02,         /*  Usage (Pen),                        */
351 	0xA1, 0x01,         /*  Collection (Application),           */
352 	0x85, 0x09,         /*      Report ID (9),                  */
353 	0x09, 0x20,         /*      Usage (Stylus),                 */
354 	0xA0,               /*      Collection (Physical),          */
355 	0x14,               /*          Logical Minimum (0),        */
356 	0x25, 0x01,         /*          Logical Maximum (1),        */
357 	0x75, 0x01,         /*          Report Size (1),            */
358 	0x95, 0x03,         /*          Report Count (3),           */
359 	0x09, 0x42,         /*          Usage (Tip Switch),         */
360 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
361 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
362 	0x81, 0x02,         /*          Input (Variable),           */
363 	0x81, 0x03,         /*          Input (Constant, Variable), */
364 	0x95, 0x01,         /*          Report Count (1),           */
365 	0x09, 0x32,         /*          Usage (In Range),           */
366 	0x81, 0x02,         /*          Input (Variable),           */
367 	0x81, 0x03,         /*          Input (Constant, Variable), */
368 	0x75, 0x10,         /*          Report Size (16),           */
369 	0xA4,               /*          Push,                       */
370 	0x05, 0x01,         /*          Usage Page (Desktop),       */
371 	0x65, 0x13,         /*          Unit (Inch),                */
372 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
373 	0x34,               /*          Physical Minimum (0),       */
374 	0x09, 0x30,         /*          Usage (X),                  */
375 	0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
376 	0x26, 0x00, 0x7D,   /*          Logical Maximum (32000),    */
377 	0x81, 0x02,         /*          Input (Variable),           */
378 	0x09, 0x31,         /*          Usage (Y),                  */
379 	0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */
380 	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
381 	0x81, 0x02,         /*          Input (Variable),           */
382 	0xB4,               /*          Pop,                        */
383 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
384 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
385 	0x81, 0x02,         /*          Input (Variable),           */
386 	0xC0,               /*      End Collection,                 */
387 	0xC0                /*  End Collection                      */
388 };
389 
390 /* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
391 static __u8 twhl850_rdesc_fixed1[] = {
392 	0x05, 0x01,         /*  Usage Page (Desktop),               */
393 	0x09, 0x02,         /*  Usage (Mouse),                      */
394 	0xA1, 0x01,         /*  Collection (Application),           */
395 	0x85, 0x01,         /*      Report ID (1),                  */
396 	0x09, 0x01,         /*      Usage (Pointer),                */
397 	0xA0,               /*      Collection (Physical),          */
398 	0x05, 0x09,         /*          Usage Page (Button),        */
399 	0x75, 0x01,         /*          Report Size (1),            */
400 	0x95, 0x03,         /*          Report Count (3),           */
401 	0x19, 0x01,         /*          Usage Minimum (01h),        */
402 	0x29, 0x03,         /*          Usage Maximum (03h),        */
403 	0x14,               /*          Logical Minimum (0),        */
404 	0x25, 0x01,         /*          Logical Maximum (1),        */
405 	0x81, 0x02,         /*          Input (Variable),           */
406 	0x95, 0x05,         /*          Report Count (5),           */
407 	0x81, 0x03,         /*          Input (Constant, Variable), */
408 	0x05, 0x01,         /*          Usage Page (Desktop),       */
409 	0x09, 0x30,         /*          Usage (X),                  */
410 	0x09, 0x31,         /*          Usage (Y),                  */
411 	0x16, 0x00, 0x80,   /*          Logical Minimum (-32768),   */
412 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
413 	0x75, 0x10,         /*          Report Size (16),           */
414 	0x95, 0x02,         /*          Report Count (2),           */
415 	0x81, 0x06,         /*          Input (Variable, Relative), */
416 	0x09, 0x38,         /*          Usage (Wheel),              */
417 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
418 	0x25, 0x01,         /*          Logical Maximum (1),        */
419 	0x95, 0x01,         /*          Report Count (1),           */
420 	0x75, 0x08,         /*          Report Size (8),            */
421 	0x81, 0x06,         /*          Input (Variable, Relative), */
422 	0x81, 0x03,         /*          Input (Constant, Variable), */
423 	0xC0,               /*      End Collection,                 */
424 	0xC0                /*  End Collection                      */
425 };
426 
427 /* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
428 static __u8 twhl850_rdesc_fixed2[] = {
429 	0x05, 0x01,         /*  Usage Page (Desktop),               */
430 	0x09, 0x06,         /*  Usage (Keyboard),                   */
431 	0xA1, 0x01,         /*  Collection (Application),           */
432 	0x85, 0x03,         /*      Report ID (3),                  */
433 	0x05, 0x07,         /*      Usage Page (Keyboard),          */
434 	0x14,               /*      Logical Minimum (0),            */
435 	0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */
436 	0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */
437 	0x25, 0x01,         /*      Logical Maximum (1),            */
438 	0x75, 0x01,         /*      Report Size (1),                */
439 	0x95, 0x08,         /*      Report Count (8),               */
440 	0x81, 0x02,         /*      Input (Variable),               */
441 	0x18,               /*      Usage Minimum (None),           */
442 	0x29, 0xFF,         /*      Usage Maximum (FFh),            */
443 	0x26, 0xFF, 0x00,   /*      Logical Maximum (255),          */
444 	0x75, 0x08,         /*      Report Size (8),                */
445 	0x95, 0x06,         /*      Report Count (6),               */
446 	0x80,               /*      Input,                          */
447 	0xC0                /*  End Collection                      */
448 };
449 
450 /* Size of the original descriptors of TWHA60 tablet */
451 #define TWHA60_RDESC_ORIG_SIZE0 254
452 #define TWHA60_RDESC_ORIG_SIZE1 139
453 
454 /* Fixed TWHA60 report descriptor, interface 0 (stylus) */
455 static __u8 twha60_rdesc_fixed0[] = {
456 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
457 	0x09, 0x02,         /*  Usage (Pen),                        */
458 	0xA1, 0x01,         /*  Collection (Application),           */
459 	0x85, 0x09,         /*      Report ID (9),                  */
460 	0x09, 0x20,         /*      Usage (Stylus),                 */
461 	0xA0,               /*      Collection (Physical),          */
462 	0x75, 0x01,         /*          Report Size (1),            */
463 	0x09, 0x42,         /*          Usage (Tip Switch),         */
464 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
465 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
466 	0x14,               /*          Logical Minimum (0),        */
467 	0x25, 0x01,         /*          Logical Maximum (1),        */
468 	0x95, 0x03,         /*          Report Count (3),           */
469 	0x81, 0x02,         /*          Input (Variable),           */
470 	0x95, 0x04,         /*          Report Count (4),           */
471 	0x81, 0x01,         /*          Input (Constant),           */
472 	0x09, 0x32,         /*          Usage (In Range),           */
473 	0x95, 0x01,         /*          Report Count (1),           */
474 	0x81, 0x02,         /*          Input (Variable),           */
475 	0x75, 0x10,         /*          Report Size (16),           */
476 	0x95, 0x01,         /*          Report Count (1),           */
477 	0x14,               /*          Logical Minimum (0),        */
478 	0xA4,               /*          Push,                       */
479 	0x05, 0x01,         /*          Usage Page (Desktop),       */
480 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
481 	0x65, 0x13,         /*          Unit (Inch),                */
482 	0x34,               /*          Physical Minimum (0),       */
483 	0x09, 0x30,         /*          Usage (X),                  */
484 	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
485 	0x27, 0x3F, 0x9C,
486 		0x00, 0x00, /*          Logical Maximum (39999),    */
487 	0x81, 0x02,         /*          Input (Variable),           */
488 	0x09, 0x31,         /*          Usage (Y),                  */
489 	0x46, 0x6A, 0x18,   /*          Physical Maximum (6250),    */
490 	0x26, 0xA7, 0x61,   /*          Logical Maximum (24999),    */
491 	0x81, 0x02,         /*          Input (Variable),           */
492 	0xB4,               /*          Pop,                        */
493 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
494 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
495 	0x81, 0x02,         /*          Input (Variable),           */
496 	0xC0,               /*      End Collection,                 */
497 	0xC0                /*  End Collection                      */
498 };
499 
500 /* Fixed TWHA60 report descriptor, interface 1 (frame buttons) */
501 static __u8 twha60_rdesc_fixed1[] = {
502 	0x05, 0x01, /*  Usage Page (Desktop),       */
503 	0x09, 0x06, /*  Usage (Keyboard),           */
504 	0xA1, 0x01, /*  Collection (Application),   */
505 	0x85, 0x05, /*      Report ID (5),          */
506 	0x05, 0x07, /*      Usage Page (Keyboard),  */
507 	0x14,       /*      Logical Minimum (0),    */
508 	0x25, 0x01, /*      Logical Maximum (1),    */
509 	0x75, 0x01, /*      Report Size (1),        */
510 	0x95, 0x08, /*      Report Count (8),       */
511 	0x81, 0x01, /*      Input (Constant),       */
512 	0x95, 0x0C, /*      Report Count (12),      */
513 	0x19, 0x3A, /*      Usage Minimum (KB F1),  */
514 	0x29, 0x45, /*      Usage Maximum (KB F12), */
515 	0x81, 0x02, /*      Input (Variable),       */
516 	0x95, 0x0C, /*      Report Count (12),      */
517 	0x19, 0x68, /*      Usage Minimum (KB F13), */
518 	0x29, 0x73, /*      Usage Maximum (KB F24), */
519 	0x81, 0x02, /*      Input (Variable),       */
520 	0x95, 0x08, /*      Report Count (8),       */
521 	0x81, 0x01, /*      Input (Constant),       */
522 	0xC0        /*  End Collection              */
523 };
524 
525 /* Report descriptor template placeholder head */
526 #define UCLOGIC_PH_HEAD	0xFE, 0xED, 0x1D
527 
528 /* Report descriptor template placeholder IDs */
529 enum 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 /* Report descriptor template placeholder */
539 #define UCLOGIC_PH(_ID) UCLOGIC_PH_HEAD, UCLOGIC_PH_ID_##_ID
540 #define UCLOGIC_PEN_REPORT_ID	0x07
541 
542 /* Fixed report descriptor template */
543 static const __u8 uclogic_tablet_rdesc_template[] = {
544 	0x05, 0x0D,             /*  Usage Page (Digitizer),                 */
545 	0x09, 0x02,             /*  Usage (Pen),                            */
546 	0xA1, 0x01,             /*  Collection (Application),               */
547 	0x85, 0x07,             /*      Report ID (7),                      */
548 	0x09, 0x20,             /*      Usage (Stylus),                     */
549 	0xA0,                   /*      Collection (Physical),              */
550 	0x14,                   /*          Logical Minimum (0),            */
551 	0x25, 0x01,             /*          Logical Maximum (1),            */
552 	0x75, 0x01,             /*          Report Size (1),                */
553 	0x09, 0x42,             /*          Usage (Tip Switch),             */
554 	0x09, 0x44,             /*          Usage (Barrel Switch),          */
555 	0x09, 0x46,             /*          Usage (Tablet Pick),            */
556 	0x95, 0x03,             /*          Report Count (3),               */
557 	0x81, 0x02,             /*          Input (Variable),               */
558 	0x95, 0x03,             /*          Report Count (3),               */
559 	0x81, 0x03,             /*          Input (Constant, Variable),     */
560 	0x09, 0x32,             /*          Usage (In Range),               */
561 	0x95, 0x01,             /*          Report Count (1),               */
562 	0x81, 0x02,             /*          Input (Variable),               */
563 	0x95, 0x01,             /*          Report Count (1),               */
564 	0x81, 0x03,             /*          Input (Constant, Variable),     */
565 	0x75, 0x10,             /*          Report Size (16),               */
566 	0x95, 0x01,             /*          Report Count (1),               */
567 	0xA4,                   /*          Push,                           */
568 	0x05, 0x01,             /*          Usage Page (Desktop),           */
569 	0x65, 0x13,             /*          Unit (Inch),                    */
570 	0x55, 0xFD,             /*          Unit Exponent (-3),             */
571 	0x34,                   /*          Physical Minimum (0),           */
572 	0x09, 0x30,             /*          Usage (X),                      */
573 	0x27, UCLOGIC_PH(X_LM), /*          Logical Maximum (PLACEHOLDER),  */
574 	0x47, UCLOGIC_PH(X_PM), /*          Physical Maximum (PLACEHOLDER), */
575 	0x81, 0x02,             /*          Input (Variable),               */
576 	0x09, 0x31,             /*          Usage (Y),                      */
577 	0x27, UCLOGIC_PH(Y_LM), /*          Logical Maximum (PLACEHOLDER),  */
578 	0x47, UCLOGIC_PH(Y_PM), /*          Physical Maximum (PLACEHOLDER), */
579 	0x81, 0x02,             /*          Input (Variable),               */
580 	0xB4,                   /*          Pop,                            */
581 	0x09, 0x30,             /*          Usage (Tip Pressure),           */
582 	0x27,
583 	UCLOGIC_PH(PRESSURE_LM),/*          Logical Maximum (PLACEHOLDER),  */
584 	0x81, 0x02,             /*          Input (Variable),               */
585 	0xC0,                   /*      End Collection,                     */
586 	0xC0                    /*  End Collection                          */
587 };
588 
589 /* Fixed virtual pad report descriptor */
590 static const __u8 uclogic_buttonpad_rdesc[] = {
591 	0x05, 0x01,             /*  Usage Page (Desktop),                   */
592 	0x09, 0x07,             /*  Usage (Keypad),                         */
593 	0xA1, 0x01,             /*  Collection (Application),               */
594 	0x85, 0xF7,             /*      Report ID (247),                    */
595 	0x05, 0x0D,             /*      Usage Page (Digitizers),            */
596 	0x09, 0x39,             /*      Usage (Tablet Function Keys),       */
597 	0xA0,                   /*      Collection (Physical),              */
598 	0x05, 0x09,             /*          Usage Page (Button),            */
599 	0x75, 0x01,             /*          Report Size (1),                */
600 	0x95, 0x18,             /*          Report Count (24),              */
601 	0x81, 0x03,             /*          Input (Constant, Variable),     */
602 	0x19, 0x01,             /*          Usage Minimum (01h),            */
603 	0x29, 0x08,             /*          Usage Maximum (08h),            */
604 	0x95, 0x08,             /*          Report Count (8),               */
605 	0x81, 0x02,             /*          Input (Variable),               */
606 	0xC0,                   /*      End Collection                      */
607 	0xC0                    /*  End Collection                          */
608 };
609 
610 /* Parameter indices */
611 enum 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 /* Driver data */
620 struct 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 
uclogic_report_fixup(struct hid_device * hdev,__u8 * rdesc,unsigned int * rsize)628 static __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 
uclogic_input_mapping(struct hid_device * hdev,struct hid_input * hi,struct hid_field * field,struct hid_usage * usage,unsigned long ** bit,int * max)715 static 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 	/* discard the unused pen interface */
722 	if ((drvdata->ignore_pen_usage) &&
723 	    (field->application == HID_DG_PEN))
724 		return -1;
725 
726 	/* let hid-core decide what to do */
727 	return 0;
728 }
729 
uclogic_input_configured(struct hid_device * hdev,struct hid_input * hi)730 static 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 	/* no report associated (HID_QUIRK_MULTI_INPUT not set) */
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  * Enable fully-functional tablet mode and determine device parameters.
779  *
780  * @hdev:	HID device
781  */
uclogic_tablet_enable(struct hid_device * hdev)782 static 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 	if (!hid_is_usb(hdev))
795 		return -EINVAL;
796 
797 	/*
798 	 * Read string descriptor containing tablet parameters. The specific
799 	 * string descriptor and data were discovered by sniffing the Windows
800 	 * driver traffic.
801 	 * NOTE: This enables fully-functional tablet mode.
802 	 */
803 	len = UCLOGIC_PRM_NUM * sizeof(*buf);
804 	buf = kmalloc(len, GFP_KERNEL);
805 	if (buf == NULL) {
806 		rc = -ENOMEM;
807 		goto cleanup;
808 	}
809 	rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
810 				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
811 				(USB_DT_STRING << 8) + 0x64,
812 				0x0409, buf, len,
813 				USB_CTRL_GET_TIMEOUT);
814 	if (rc == -EPIPE) {
815 		hid_err(hdev, "device parameters not found\n");
816 		rc = -ENODEV;
817 		goto cleanup;
818 	} else if (rc < 0) {
819 		hid_err(hdev, "failed to get device parameters: %d\n", rc);
820 		rc = -ENODEV;
821 		goto cleanup;
822 	} else if (rc != len) {
823 		hid_err(hdev, "invalid device parameters\n");
824 		rc = -ENODEV;
825 		goto cleanup;
826 	}
827 
828 	/* Extract device parameters */
829 	params[UCLOGIC_PH_ID_X_LM] = le16_to_cpu(buf[UCLOGIC_PRM_X_LM]);
830 	params[UCLOGIC_PH_ID_Y_LM] = le16_to_cpu(buf[UCLOGIC_PRM_Y_LM]);
831 	params[UCLOGIC_PH_ID_PRESSURE_LM] =
832 		le16_to_cpu(buf[UCLOGIC_PRM_PRESSURE_LM]);
833 	resolution = le16_to_cpu(buf[UCLOGIC_PRM_RESOLUTION]);
834 	if (resolution == 0) {
835 		params[UCLOGIC_PH_ID_X_PM] = 0;
836 		params[UCLOGIC_PH_ID_Y_PM] = 0;
837 	} else {
838 		params[UCLOGIC_PH_ID_X_PM] = params[UCLOGIC_PH_ID_X_LM] *
839 						1000 / resolution;
840 		params[UCLOGIC_PH_ID_Y_PM] = params[UCLOGIC_PH_ID_Y_LM] *
841 						1000 / resolution;
842 	}
843 
844 	/* Allocate fixed report descriptor */
845 	drvdata->rdesc = devm_kzalloc(&hdev->dev,
846 				sizeof(uclogic_tablet_rdesc_template),
847 				GFP_KERNEL);
848 	if (drvdata->rdesc == NULL) {
849 		rc = -ENOMEM;
850 		goto cleanup;
851 	}
852 	drvdata->rsize = sizeof(uclogic_tablet_rdesc_template);
853 
854 	/* Format fixed report descriptor */
855 	memcpy(drvdata->rdesc, uclogic_tablet_rdesc_template,
856 		drvdata->rsize);
857 	for (p = drvdata->rdesc;
858 	     p <= drvdata->rdesc + drvdata->rsize - 4;) {
859 		if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
860 		    p[3] < ARRAY_SIZE(params)) {
861 			v = params[p[3]];
862 			put_unaligned(cpu_to_le32(v), (s32 *)p);
863 			p += 4;
864 		} else {
865 			p++;
866 		}
867 	}
868 
869 	rc = 0;
870 
871 cleanup:
872 	kfree(buf);
873 	return rc;
874 }
875 
876 /**
877  * Enable actual button mode.
878  *
879  * @hdev:	HID device
880  */
uclogic_button_enable(struct hid_device * hdev)881 static int uclogic_button_enable(struct hid_device *hdev)
882 {
883 	int rc;
884 	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
885 	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
886 	char *str_buf;
887 	size_t str_len = 16;
888 	unsigned char *rdesc;
889 	size_t rdesc_len;
890 
891 	str_buf = kzalloc(str_len, GFP_KERNEL);
892 	if (str_buf == NULL) {
893 		rc = -ENOMEM;
894 		goto cleanup;
895 	}
896 
897 	/* Enable abstract keyboard mode */
898 	rc = usb_string(usb_dev, 0x7b, str_buf, str_len);
899 	if (rc == -EPIPE) {
900 		hid_info(hdev, "button mode setting not found\n");
901 		rc = 0;
902 		goto cleanup;
903 	} else if (rc < 0) {
904 		hid_err(hdev, "failed to enable abstract keyboard\n");
905 		goto cleanup;
906 	} else if (strncmp(str_buf, "HK On", rc)) {
907 		hid_info(hdev, "invalid answer when requesting buttons: '%s'\n",
908 			str_buf);
909 		rc = -EINVAL;
910 		goto cleanup;
911 	}
912 
913 	/* Re-allocate fixed report descriptor */
914 	rdesc_len = drvdata->rsize + sizeof(uclogic_buttonpad_rdesc);
915 	rdesc = devm_kzalloc(&hdev->dev, rdesc_len, GFP_KERNEL);
916 	if (!rdesc) {
917 		rc = -ENOMEM;
918 		goto cleanup;
919 	}
920 
921 	memcpy(rdesc, drvdata->rdesc, drvdata->rsize);
922 
923 	/* Append the buttonpad descriptor */
924 	memcpy(rdesc + drvdata->rsize, uclogic_buttonpad_rdesc,
925 	       sizeof(uclogic_buttonpad_rdesc));
926 
927 	/* clean up old rdesc and use the new one */
928 	drvdata->rsize = rdesc_len;
929 	devm_kfree(&hdev->dev, drvdata->rdesc);
930 	drvdata->rdesc = rdesc;
931 
932 	rc = 0;
933 
934 cleanup:
935 	kfree(str_buf);
936 	return rc;
937 }
938 
uclogic_probe(struct hid_device * hdev,const struct hid_device_id * id)939 static int uclogic_probe(struct hid_device *hdev,
940 		const struct hid_device_id *id)
941 {
942 	int rc;
943 	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
944 	struct usb_device *udev = hid_to_usb_dev(hdev);
945 	struct uclogic_drvdata *drvdata;
946 
947 	/*
948 	 * libinput requires the pad interface to be on a different node
949 	 * than the pen, so use QUIRK_MULTI_INPUT for all tablets.
950 	 */
951 	hdev->quirks |= HID_QUIRK_MULTI_INPUT;
952 
953 	/* Allocate and assign driver data */
954 	drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
955 	if (drvdata == NULL)
956 		return -ENOMEM;
957 
958 	hid_set_drvdata(hdev, drvdata);
959 
960 	switch (id->product) {
961 	case USB_DEVICE_ID_HUION_TABLET:
962 	case USB_DEVICE_ID_YIYNOVA_TABLET:
963 	case USB_DEVICE_ID_UGEE_TABLET_81:
964 	case USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3:
965 	case USB_DEVICE_ID_UGEE_TABLET_45:
966 		/* If this is the pen interface */
967 		if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
968 			rc = uclogic_tablet_enable(hdev);
969 			if (rc) {
970 				hid_err(hdev, "tablet enabling failed\n");
971 				return rc;
972 			}
973 			drvdata->invert_pen_inrange = true;
974 
975 			rc = uclogic_button_enable(hdev);
976 			drvdata->has_virtual_pad_interface = !rc;
977 		} else {
978 			drvdata->ignore_pen_usage = true;
979 		}
980 		break;
981 	case USB_DEVICE_ID_UGTIZER_TABLET_GP0610:
982 	case USB_DEVICE_ID_UGEE_TABLET_EX07S:
983 		/* If this is the pen interface */
984 		if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
985 			rc = uclogic_tablet_enable(hdev);
986 			if (rc) {
987 				hid_err(hdev, "tablet enabling failed\n");
988 				return rc;
989 			}
990 			drvdata->invert_pen_inrange = true;
991 		} else {
992 			drvdata->ignore_pen_usage = true;
993 		}
994 		break;
995 	case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60:
996 		/*
997 		 * If it is the three-interface version, which is known to
998 		 * respond to initialization.
999 		 */
1000 		if (udev->config->desc.bNumInterfaces == 3) {
1001 			/* If it is the pen interface */
1002 			if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
1003 				rc = uclogic_tablet_enable(hdev);
1004 				if (rc) {
1005 					hid_err(hdev, "tablet enabling failed\n");
1006 					return rc;
1007 				}
1008 				drvdata->invert_pen_inrange = true;
1009 
1010 				rc = uclogic_button_enable(hdev);
1011 				drvdata->has_virtual_pad_interface = !rc;
1012 			} else {
1013 				drvdata->ignore_pen_usage = true;
1014 			}
1015 		}
1016 		break;
1017 	}
1018 
1019 	rc = hid_parse(hdev);
1020 	if (rc) {
1021 		hid_err(hdev, "parse failed\n");
1022 		return rc;
1023 	}
1024 
1025 	rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
1026 	if (rc) {
1027 		hid_err(hdev, "hw start failed\n");
1028 		return rc;
1029 	}
1030 
1031 	return 0;
1032 }
1033 
uclogic_raw_event(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)1034 static int uclogic_raw_event(struct hid_device *hdev, struct hid_report *report,
1035 			u8 *data, int size)
1036 {
1037 	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
1038 
1039 	if ((report->type == HID_INPUT_REPORT) &&
1040 	    (report->id == UCLOGIC_PEN_REPORT_ID) &&
1041 	    (size >= 2)) {
1042 		if (drvdata->has_virtual_pad_interface && (data[1] & 0x20))
1043 			/* Change to virtual frame button report ID */
1044 			data[0] = 0xf7;
1045 		else if (drvdata->invert_pen_inrange)
1046 			/* Invert the in-range bit */
1047 			data[1] ^= 0x40;
1048 	}
1049 
1050 	return 0;
1051 }
1052 
1053 static const struct hid_device_id uclogic_devices[] = {
1054 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1055 				USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
1056 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1057 				USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
1058 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1059 				USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
1060 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1061 				USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
1062 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1063 				USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
1064 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1065 				USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
1066 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
1067 				USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
1068 	{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
1069 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) },
1070 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_YIYNOVA_TABLET) },
1071 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_81) },
1072 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UGEE_TABLET_45) },
1073 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3) },
1074 	{ HID_USB_DEVICE(USB_VENDOR_ID_UGTIZER, USB_DEVICE_ID_UGTIZER_TABLET_GP0610) },
1075 	{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_TABLET_EX07S) },
1076 	{ }
1077 };
1078 MODULE_DEVICE_TABLE(hid, uclogic_devices);
1079 
1080 static struct hid_driver uclogic_driver = {
1081 	.name = "uclogic",
1082 	.id_table = uclogic_devices,
1083 	.probe = uclogic_probe,
1084 	.report_fixup = uclogic_report_fixup,
1085 	.raw_event = uclogic_raw_event,
1086 	.input_mapping = uclogic_input_mapping,
1087 	.input_configured = uclogic_input_configured,
1088 };
1089 module_hid_driver(uclogic_driver);
1090 
1091 MODULE_AUTHOR("Martin Rusko");
1092 MODULE_AUTHOR("Nikolai Kondrashov");
1093 MODULE_LICENSE("GPL");
1094