• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 /*
25  * See WPXXXXU model descriptions, device and HID report descriptors at
26  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP4030U
27  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP5540U
28  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP8060U
29  */
30 
31 /* Size of the original descriptor of WPXXXXU tablets */
32 #define WPXXXXU_RDESC_ORIG_SIZE	212
33 
34 /* Fixed WP4030U report descriptor */
35 static __u8 wp4030u_rdesc_fixed[] = {
36 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
37 	0x09, 0x02,         /*  Usage (Pen),                        */
38 	0xA1, 0x01,         /*  Collection (Application),           */
39 	0x85, 0x09,         /*      Report ID (9),                  */
40 	0x09, 0x20,         /*      Usage (Stylus),                 */
41 	0xA0,               /*      Collection (Physical),          */
42 	0x75, 0x01,         /*          Report Size (1),            */
43 	0x09, 0x42,         /*          Usage (Tip Switch),         */
44 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
45 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
46 	0x14,               /*          Logical Minimum (0),        */
47 	0x25, 0x01,         /*          Logical Maximum (1),        */
48 	0x95, 0x03,         /*          Report Count (3),           */
49 	0x81, 0x02,         /*          Input (Variable),           */
50 	0x95, 0x05,         /*          Report Count (5),           */
51 	0x81, 0x01,         /*          Input (Constant),           */
52 	0x75, 0x10,         /*          Report Size (16),           */
53 	0x95, 0x01,         /*          Report Count (1),           */
54 	0x14,               /*          Logical Minimum (0),        */
55 	0xA4,               /*          Push,                       */
56 	0x05, 0x01,         /*          Usage Page (Desktop),       */
57 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
58 	0x65, 0x13,         /*          Unit (Inch),                */
59 	0x34,               /*          Physical Minimum (0),       */
60 	0x09, 0x30,         /*          Usage (X),                  */
61 	0x46, 0xA0, 0x0F,   /*          Physical Maximum (4000),    */
62 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
63 	0x81, 0x02,         /*          Input (Variable),           */
64 	0x09, 0x31,         /*          Usage (Y),                  */
65 	0x46, 0xB8, 0x0B,   /*          Physical Maximum (3000),    */
66 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
67 	0x81, 0x02,         /*          Input (Variable),           */
68 	0xB4,               /*          Pop,                        */
69 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
70 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
71 	0x81, 0x02,         /*          Input (Variable),           */
72 	0xC0,               /*      End Collection,                 */
73 	0xC0                /*  End Collection                      */
74 };
75 
76 /* Fixed WP5540U report descriptor */
77 static __u8 wp5540u_rdesc_fixed[] = {
78 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
79 	0x09, 0x02,         /*  Usage (Pen),                        */
80 	0xA1, 0x01,         /*  Collection (Application),           */
81 	0x85, 0x09,         /*      Report ID (9),                  */
82 	0x09, 0x20,         /*      Usage (Stylus),                 */
83 	0xA0,               /*      Collection (Physical),          */
84 	0x75, 0x01,         /*          Report Size (1),            */
85 	0x09, 0x42,         /*          Usage (Tip Switch),         */
86 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
87 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
88 	0x14,               /*          Logical Minimum (0),        */
89 	0x25, 0x01,         /*          Logical Maximum (1),        */
90 	0x95, 0x03,         /*          Report Count (3),           */
91 	0x81, 0x02,         /*          Input (Variable),           */
92 	0x95, 0x05,         /*          Report Count (5),           */
93 	0x81, 0x01,         /*          Input (Constant),           */
94 	0x75, 0x10,         /*          Report Size (16),           */
95 	0x95, 0x01,         /*          Report Count (1),           */
96 	0x14,               /*          Logical Minimum (0),        */
97 	0xA4,               /*          Push,                       */
98 	0x05, 0x01,         /*          Usage Page (Desktop),       */
99 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
100 	0x65, 0x13,         /*          Unit (Inch),                */
101 	0x34,               /*          Physical Minimum (0),       */
102 	0x09, 0x30,         /*          Usage (X),                  */
103 	0x46, 0x7C, 0x15,   /*          Physical Maximum (5500),    */
104 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
105 	0x81, 0x02,         /*          Input (Variable),           */
106 	0x09, 0x31,         /*          Usage (Y),                  */
107 	0x46, 0xA0, 0x0F,   /*          Physical Maximum (4000),    */
108 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
109 	0x81, 0x02,         /*          Input (Variable),           */
110 	0xB4,               /*          Pop,                        */
111 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
112 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
113 	0x81, 0x02,         /*          Input (Variable),           */
114 	0xC0,               /*      End Collection,                 */
115 	0xC0,               /*  End Collection,                     */
116 	0x05, 0x01,         /*  Usage Page (Desktop),               */
117 	0x09, 0x02,         /*  Usage (Mouse),                      */
118 	0xA1, 0x01,         /*  Collection (Application),           */
119 	0x85, 0x08,         /*      Report ID (8),                  */
120 	0x09, 0x01,         /*      Usage (Pointer),                */
121 	0xA0,               /*      Collection (Physical),          */
122 	0x75, 0x01,         /*          Report Size (1),            */
123 	0x05, 0x09,         /*          Usage Page (Button),        */
124 	0x19, 0x01,         /*          Usage Minimum (01h),        */
125 	0x29, 0x03,         /*          Usage Maximum (03h),        */
126 	0x14,               /*          Logical Minimum (0),        */
127 	0x25, 0x01,         /*          Logical Maximum (1),        */
128 	0x95, 0x03,         /*          Report Count (3),           */
129 	0x81, 0x02,         /*          Input (Variable),           */
130 	0x95, 0x05,         /*          Report Count (5),           */
131 	0x81, 0x01,         /*          Input (Constant),           */
132 	0x05, 0x01,         /*          Usage Page (Desktop),       */
133 	0x75, 0x08,         /*          Report Size (8),            */
134 	0x09, 0x30,         /*          Usage (X),                  */
135 	0x09, 0x31,         /*          Usage (Y),                  */
136 	0x15, 0x81,         /*          Logical Minimum (-127),     */
137 	0x25, 0x7F,         /*          Logical Maximum (127),      */
138 	0x95, 0x02,         /*          Report Count (2),           */
139 	0x81, 0x06,         /*          Input (Variable, Relative), */
140 	0x09, 0x38,         /*          Usage (Wheel),              */
141 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
142 	0x25, 0x01,         /*          Logical Maximum (1),        */
143 	0x95, 0x01,         /*          Report Count (1),           */
144 	0x81, 0x06,         /*          Input (Variable, Relative), */
145 	0x81, 0x01,         /*          Input (Constant),           */
146 	0xC0,               /*      End Collection,                 */
147 	0xC0                /*  End Collection                      */
148 };
149 
150 /* Fixed WP8060U report descriptor */
151 static __u8 wp8060u_rdesc_fixed[] = {
152 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
153 	0x09, 0x02,         /*  Usage (Pen),                        */
154 	0xA1, 0x01,         /*  Collection (Application),           */
155 	0x85, 0x09,         /*      Report ID (9),                  */
156 	0x09, 0x20,         /*      Usage (Stylus),                 */
157 	0xA0,               /*      Collection (Physical),          */
158 	0x75, 0x01,         /*          Report Size (1),            */
159 	0x09, 0x42,         /*          Usage (Tip Switch),         */
160 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
161 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
162 	0x14,               /*          Logical Minimum (0),        */
163 	0x25, 0x01,         /*          Logical Maximum (1),        */
164 	0x95, 0x03,         /*          Report Count (3),           */
165 	0x81, 0x02,         /*          Input (Variable),           */
166 	0x95, 0x05,         /*          Report Count (5),           */
167 	0x81, 0x01,         /*          Input (Constant),           */
168 	0x75, 0x10,         /*          Report Size (16),           */
169 	0x95, 0x01,         /*          Report Count (1),           */
170 	0x14,               /*          Logical Minimum (0),        */
171 	0xA4,               /*          Push,                       */
172 	0x05, 0x01,         /*          Usage Page (Desktop),       */
173 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
174 	0x65, 0x13,         /*          Unit (Inch),                */
175 	0x34,               /*          Physical Minimum (0),       */
176 	0x09, 0x30,         /*          Usage (X),                  */
177 	0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
178 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
179 	0x81, 0x02,         /*          Input (Variable),           */
180 	0x09, 0x31,         /*          Usage (Y),                  */
181 	0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
182 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
183 	0x81, 0x02,         /*          Input (Variable),           */
184 	0xB4,               /*          Pop,                        */
185 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
186 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
187 	0x81, 0x02,         /*          Input (Variable),           */
188 	0xC0,               /*      End Collection,                 */
189 	0xC0,               /*  End Collection,                     */
190 	0x05, 0x01,         /*  Usage Page (Desktop),               */
191 	0x09, 0x02,         /*  Usage (Mouse),                      */
192 	0xA1, 0x01,         /*  Collection (Application),           */
193 	0x85, 0x08,         /*      Report ID (8),                  */
194 	0x09, 0x01,         /*      Usage (Pointer),                */
195 	0xA0,               /*      Collection (Physical),          */
196 	0x75, 0x01,         /*          Report Size (1),            */
197 	0x05, 0x09,         /*          Usage Page (Button),        */
198 	0x19, 0x01,         /*          Usage Minimum (01h),        */
199 	0x29, 0x03,         /*          Usage Maximum (03h),        */
200 	0x14,               /*          Logical Minimum (0),        */
201 	0x25, 0x01,         /*          Logical Maximum (1),        */
202 	0x95, 0x03,         /*          Report Count (3),           */
203 	0x81, 0x02,         /*          Input (Variable),           */
204 	0x95, 0x05,         /*          Report Count (5),           */
205 	0x81, 0x01,         /*          Input (Constant),           */
206 	0x05, 0x01,         /*          Usage Page (Desktop),       */
207 	0x75, 0x08,         /*          Report Size (8),            */
208 	0x09, 0x30,         /*          Usage (X),                  */
209 	0x09, 0x31,         /*          Usage (Y),                  */
210 	0x15, 0x81,         /*          Logical Minimum (-127),     */
211 	0x25, 0x7F,         /*          Logical Maximum (127),      */
212 	0x95, 0x02,         /*          Report Count (2),           */
213 	0x81, 0x06,         /*          Input (Variable, Relative), */
214 	0x09, 0x38,         /*          Usage (Wheel),              */
215 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
216 	0x25, 0x01,         /*          Logical Maximum (1),        */
217 	0x95, 0x01,         /*          Report Count (1),           */
218 	0x81, 0x06,         /*          Input (Variable, Relative), */
219 	0x81, 0x01,         /*          Input (Constant),           */
220 	0xC0,               /*      End Collection,                 */
221 	0xC0                /*  End Collection                      */
222 };
223 
224 /*
225  * See WP1062 description, device and HID report descriptors at
226  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP1062
227  */
228 
229 /* Size of the original descriptor of WP1062 tablet */
230 #define WP1062_RDESC_ORIG_SIZE	254
231 
232 /* Fixed WP1062 report descriptor */
233 static __u8 wp1062_rdesc_fixed[] = {
234 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
235 	0x09, 0x02,         /*  Usage (Pen),                        */
236 	0xA1, 0x01,         /*  Collection (Application),           */
237 	0x85, 0x09,         /*      Report ID (9),                  */
238 	0x09, 0x20,         /*      Usage (Stylus),                 */
239 	0xA0,               /*      Collection (Physical),          */
240 	0x75, 0x01,         /*          Report Size (1),            */
241 	0x09, 0x42,         /*          Usage (Tip Switch),         */
242 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
243 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
244 	0x14,               /*          Logical Minimum (0),        */
245 	0x25, 0x01,         /*          Logical Maximum (1),        */
246 	0x95, 0x03,         /*          Report Count (3),           */
247 	0x81, 0x02,         /*          Input (Variable),           */
248 	0x95, 0x04,         /*          Report Count (4),           */
249 	0x81, 0x01,         /*          Input (Constant),           */
250 	0x09, 0x32,         /*          Usage (In Range),           */
251 	0x95, 0x01,         /*          Report Count (1),           */
252 	0x81, 0x02,         /*          Input (Variable),           */
253 	0x75, 0x10,         /*          Report Size (16),           */
254 	0x95, 0x01,         /*          Report Count (1),           */
255 	0x14,               /*          Logical Minimum (0),        */
256 	0xA4,               /*          Push,                       */
257 	0x05, 0x01,         /*          Usage Page (Desktop),       */
258 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
259 	0x65, 0x13,         /*          Unit (Inch),                */
260 	0x34,               /*          Physical Minimum (0),       */
261 	0x09, 0x30,         /*          Usage (X),                  */
262 	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
263 	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
264 	0x81, 0x02,         /*          Input (Variable),           */
265 	0x09, 0x31,         /*          Usage (Y),                  */
266 	0x46, 0xB7, 0x19,   /*          Physical Maximum (6583),    */
267 	0x26, 0x6E, 0x33,   /*          Logical Maximum (13166),    */
268 	0x81, 0x02,         /*          Input (Variable),           */
269 	0xB4,               /*          Pop,                        */
270 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
271 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
272 	0x81, 0x02,         /*          Input (Variable),           */
273 	0xC0,               /*      End Collection,                 */
274 	0xC0                /*  End Collection                      */
275 };
276 
277 /*
278  * See PF1209 description, device and HID report descriptors at
279  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_PF1209
280  */
281 
282 /* Size of the original descriptor of PF1209 tablet */
283 #define PF1209_RDESC_ORIG_SIZE	234
284 
285 /* Fixed PF1209 report descriptor */
286 static __u8 pf1209_rdesc_fixed[] = {
287 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
288 	0x09, 0x02,         /*  Usage (Pen),                        */
289 	0xA1, 0x01,         /*  Collection (Application),           */
290 	0x85, 0x09,         /*      Report ID (9),                  */
291 	0x09, 0x20,         /*      Usage (Stylus),                 */
292 	0xA0,               /*      Collection (Physical),          */
293 	0x75, 0x01,         /*          Report Size (1),            */
294 	0x09, 0x42,         /*          Usage (Tip Switch),         */
295 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
296 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
297 	0x14,               /*          Logical Minimum (0),        */
298 	0x25, 0x01,         /*          Logical Maximum (1),        */
299 	0x95, 0x03,         /*          Report Count (3),           */
300 	0x81, 0x02,         /*          Input (Variable),           */
301 	0x95, 0x05,         /*          Report Count (5),           */
302 	0x81, 0x01,         /*          Input (Constant),           */
303 	0x75, 0x10,         /*          Report Size (16),           */
304 	0x95, 0x01,         /*          Report Count (1),           */
305 	0x14,               /*          Logical Minimum (0),        */
306 	0xA4,               /*          Push,                       */
307 	0x05, 0x01,         /*          Usage Page (Desktop),       */
308 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
309 	0x65, 0x13,         /*          Unit (Inch),                */
310 	0x34,               /*          Physical Minimum (0),       */
311 	0x09, 0x30,         /*          Usage (X),                  */
312 	0x46, 0xE0, 0x2E,   /*          Physical Maximum (12000),   */
313 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
314 	0x81, 0x02,         /*          Input (Variable),           */
315 	0x09, 0x31,         /*          Usage (Y),                  */
316 	0x46, 0x28, 0x23,   /*          Physical Maximum (9000),    */
317 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
318 	0x81, 0x02,         /*          Input (Variable),           */
319 	0xB4,               /*          Pop,                        */
320 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
321 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
322 	0x81, 0x02,         /*          Input (Variable),           */
323 	0xC0,               /*      End Collection,                 */
324 	0xC0,               /*  End Collection,                     */
325 	0x05, 0x01,         /*  Usage Page (Desktop),               */
326 	0x09, 0x02,         /*  Usage (Mouse),                      */
327 	0xA1, 0x01,         /*  Collection (Application),           */
328 	0x85, 0x08,         /*      Report ID (8),                  */
329 	0x09, 0x01,         /*      Usage (Pointer),                */
330 	0xA0,               /*      Collection (Physical),          */
331 	0x75, 0x01,         /*          Report Size (1),            */
332 	0x05, 0x09,         /*          Usage Page (Button),        */
333 	0x19, 0x01,         /*          Usage Minimum (01h),        */
334 	0x29, 0x03,         /*          Usage Maximum (03h),        */
335 	0x14,               /*          Logical Minimum (0),        */
336 	0x25, 0x01,         /*          Logical Maximum (1),        */
337 	0x95, 0x03,         /*          Report Count (3),           */
338 	0x81, 0x02,         /*          Input (Variable),           */
339 	0x95, 0x05,         /*          Report Count (5),           */
340 	0x81, 0x01,         /*          Input (Constant),           */
341 	0x05, 0x01,         /*          Usage Page (Desktop),       */
342 	0x75, 0x08,         /*          Report Size (8),            */
343 	0x09, 0x30,         /*          Usage (X),                  */
344 	0x09, 0x31,         /*          Usage (Y),                  */
345 	0x15, 0x81,         /*          Logical Minimum (-127),     */
346 	0x25, 0x7F,         /*          Logical Maximum (127),      */
347 	0x95, 0x02,         /*          Report Count (2),           */
348 	0x81, 0x06,         /*          Input (Variable, Relative), */
349 	0x09, 0x38,         /*          Usage (Wheel),              */
350 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
351 	0x25, 0x01,         /*          Logical Maximum (1),        */
352 	0x95, 0x01,         /*          Report Count (1),           */
353 	0x81, 0x06,         /*          Input (Variable, Relative), */
354 	0x81, 0x01,         /*          Input (Constant),           */
355 	0xC0,               /*      End Collection,                 */
356 	0xC0                /*  End Collection                      */
357 };
358 
359 /*
360  * See TWHL850 description, device and HID report descriptors at
361  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Wireless_Tablet_TWHL850
362  */
363 
364 /* Size of the original descriptors of TWHL850 tablet */
365 #define TWHL850_RDESC_ORIG_SIZE0	182
366 #define TWHL850_RDESC_ORIG_SIZE1	161
367 #define TWHL850_RDESC_ORIG_SIZE2	92
368 
369 /* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
370 static __u8 twhl850_rdesc_fixed0[] = {
371 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
372 	0x09, 0x02,         /*  Usage (Pen),                        */
373 	0xA1, 0x01,         /*  Collection (Application),           */
374 	0x85, 0x09,         /*      Report ID (9),                  */
375 	0x09, 0x20,         /*      Usage (Stylus),                 */
376 	0xA0,               /*      Collection (Physical),          */
377 	0x14,               /*          Logical Minimum (0),        */
378 	0x25, 0x01,         /*          Logical Maximum (1),        */
379 	0x75, 0x01,         /*          Report Size (1),            */
380 	0x95, 0x03,         /*          Report Count (3),           */
381 	0x09, 0x42,         /*          Usage (Tip Switch),         */
382 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
383 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
384 	0x81, 0x02,         /*          Input (Variable),           */
385 	0x81, 0x03,         /*          Input (Constant, Variable), */
386 	0x95, 0x01,         /*          Report Count (1),           */
387 	0x09, 0x32,         /*          Usage (In Range),           */
388 	0x81, 0x02,         /*          Input (Variable),           */
389 	0x81, 0x03,         /*          Input (Constant, Variable), */
390 	0x75, 0x10,         /*          Report Size (16),           */
391 	0xA4,               /*          Push,                       */
392 	0x05, 0x01,         /*          Usage Page (Desktop),       */
393 	0x65, 0x13,         /*          Unit (Inch),                */
394 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
395 	0x34,               /*          Physical Minimum (0),       */
396 	0x09, 0x30,         /*          Usage (X),                  */
397 	0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
398 	0x26, 0x00, 0x7D,   /*          Logical Maximum (32000),    */
399 	0x81, 0x02,         /*          Input (Variable),           */
400 	0x09, 0x31,         /*          Usage (Y),                  */
401 	0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */
402 	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
403 	0x81, 0x02,         /*          Input (Variable),           */
404 	0xB4,               /*          Pop,                        */
405 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
406 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
407 	0x81, 0x02,         /*          Input (Variable),           */
408 	0xC0,               /*      End Collection,                 */
409 	0xC0                /*  End Collection                      */
410 };
411 
412 /* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
413 static __u8 twhl850_rdesc_fixed1[] = {
414 	0x05, 0x01,         /*  Usage Page (Desktop),               */
415 	0x09, 0x02,         /*  Usage (Mouse),                      */
416 	0xA1, 0x01,         /*  Collection (Application),           */
417 	0x85, 0x01,         /*      Report ID (1),                  */
418 	0x09, 0x01,         /*      Usage (Pointer),                */
419 	0xA0,               /*      Collection (Physical),          */
420 	0x05, 0x09,         /*          Usage Page (Button),        */
421 	0x75, 0x01,         /*          Report Size (1),            */
422 	0x95, 0x03,         /*          Report Count (3),           */
423 	0x19, 0x01,         /*          Usage Minimum (01h),        */
424 	0x29, 0x03,         /*          Usage Maximum (03h),        */
425 	0x14,               /*          Logical Minimum (0),        */
426 	0x25, 0x01,         /*          Logical Maximum (1),        */
427 	0x81, 0x02,         /*          Input (Variable),           */
428 	0x95, 0x05,         /*          Report Count (5),           */
429 	0x81, 0x03,         /*          Input (Constant, Variable), */
430 	0x05, 0x01,         /*          Usage Page (Desktop),       */
431 	0x09, 0x30,         /*          Usage (X),                  */
432 	0x09, 0x31,         /*          Usage (Y),                  */
433 	0x16, 0x00, 0x80,   /*          Logical Minimum (-32768),   */
434 	0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
435 	0x75, 0x10,         /*          Report Size (16),           */
436 	0x95, 0x02,         /*          Report Count (2),           */
437 	0x81, 0x06,         /*          Input (Variable, Relative), */
438 	0x09, 0x38,         /*          Usage (Wheel),              */
439 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
440 	0x25, 0x01,         /*          Logical Maximum (1),        */
441 	0x95, 0x01,         /*          Report Count (1),           */
442 	0x75, 0x08,         /*          Report Size (8),            */
443 	0x81, 0x06,         /*          Input (Variable, Relative), */
444 	0x81, 0x03,         /*          Input (Constant, Variable), */
445 	0xC0,               /*      End Collection,                 */
446 	0xC0                /*  End Collection                      */
447 };
448 
449 /* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
450 static __u8 twhl850_rdesc_fixed2[] = {
451 	0x05, 0x01,         /*  Usage Page (Desktop),               */
452 	0x09, 0x06,         /*  Usage (Keyboard),                   */
453 	0xA1, 0x01,         /*  Collection (Application),           */
454 	0x85, 0x03,         /*      Report ID (3),                  */
455 	0x05, 0x07,         /*      Usage Page (Keyboard),          */
456 	0x14,               /*      Logical Minimum (0),            */
457 	0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */
458 	0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */
459 	0x25, 0x01,         /*      Logical Maximum (1),            */
460 	0x75, 0x01,         /*      Report Size (1),                */
461 	0x95, 0x08,         /*      Report Count (8),               */
462 	0x81, 0x02,         /*      Input (Variable),               */
463 	0x18,               /*      Usage Minimum (None),           */
464 	0x29, 0xFF,         /*      Usage Maximum (FFh),            */
465 	0x26, 0xFF, 0x00,   /*      Logical Maximum (255),          */
466 	0x75, 0x08,         /*      Report Size (8),                */
467 	0x95, 0x06,         /*      Report Count (6),               */
468 	0x80,               /*      Input,                          */
469 	0xC0                /*  End Collection                      */
470 };
471 
472 /*
473  * See TWHA60 description, device and HID report descriptors at
474  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_TWHA60
475  */
476 
477 /* Size of the original descriptors of TWHA60 tablet */
478 #define TWHA60_RDESC_ORIG_SIZE0 254
479 #define TWHA60_RDESC_ORIG_SIZE1 139
480 
481 /* Fixed TWHA60 report descriptor, interface 0 (stylus) */
482 static __u8 twha60_rdesc_fixed0[] = {
483 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
484 	0x09, 0x02,         /*  Usage (Pen),                        */
485 	0xA1, 0x01,         /*  Collection (Application),           */
486 	0x85, 0x09,         /*      Report ID (9),                  */
487 	0x09, 0x20,         /*      Usage (Stylus),                 */
488 	0xA0,               /*      Collection (Physical),          */
489 	0x75, 0x01,         /*          Report Size (1),            */
490 	0x09, 0x42,         /*          Usage (Tip Switch),         */
491 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
492 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
493 	0x14,               /*          Logical Minimum (0),        */
494 	0x25, 0x01,         /*          Logical Maximum (1),        */
495 	0x95, 0x03,         /*          Report Count (3),           */
496 	0x81, 0x02,         /*          Input (Variable),           */
497 	0x95, 0x04,         /*          Report Count (4),           */
498 	0x81, 0x01,         /*          Input (Constant),           */
499 	0x09, 0x32,         /*          Usage (In Range),           */
500 	0x95, 0x01,         /*          Report Count (1),           */
501 	0x81, 0x02,         /*          Input (Variable),           */
502 	0x75, 0x10,         /*          Report Size (16),           */
503 	0x95, 0x01,         /*          Report Count (1),           */
504 	0x14,               /*          Logical Minimum (0),        */
505 	0xA4,               /*          Push,                       */
506 	0x05, 0x01,         /*          Usage Page (Desktop),       */
507 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
508 	0x65, 0x13,         /*          Unit (Inch),                */
509 	0x34,               /*          Physical Minimum (0),       */
510 	0x09, 0x30,         /*          Usage (X),                  */
511 	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
512 	0x27, 0x3F, 0x9C,
513 		0x00, 0x00, /*          Logical Maximum (39999),    */
514 	0x81, 0x02,         /*          Input (Variable),           */
515 	0x09, 0x31,         /*          Usage (Y),                  */
516 	0x46, 0x6A, 0x18,   /*          Physical Maximum (6250),    */
517 	0x26, 0xA7, 0x61,   /*          Logical Maximum (24999),    */
518 	0x81, 0x02,         /*          Input (Variable),           */
519 	0xB4,               /*          Pop,                        */
520 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
521 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
522 	0x81, 0x02,         /*          Input (Variable),           */
523 	0xC0,               /*      End Collection,                 */
524 	0xC0                /*  End Collection                      */
525 };
526 
527 /* Fixed TWHA60 report descriptor, interface 1 (frame buttons) */
528 static __u8 twha60_rdesc_fixed1[] = {
529 	0x05, 0x01, /*  Usage Page (Desktop),       */
530 	0x09, 0x06, /*  Usage (Keyboard),           */
531 	0xA1, 0x01, /*  Collection (Application),   */
532 	0x85, 0x05, /*      Report ID (5),          */
533 	0x05, 0x07, /*      Usage Page (Keyboard),  */
534 	0x14,       /*      Logical Minimum (0),    */
535 	0x25, 0x01, /*      Logical Maximum (1),    */
536 	0x75, 0x01, /*      Report Size (1),        */
537 	0x95, 0x08, /*      Report Count (8),       */
538 	0x81, 0x01, /*      Input (Constant),       */
539 	0x95, 0x0C, /*      Report Count (12),      */
540 	0x19, 0x3A, /*      Usage Minimum (KB F1),  */
541 	0x29, 0x45, /*      Usage Maximum (KB F12), */
542 	0x81, 0x02, /*      Input (Variable),       */
543 	0x95, 0x0C, /*      Report Count (12),      */
544 	0x19, 0x68, /*      Usage Minimum (KB F13), */
545 	0x29, 0x73, /*      Usage Maximum (KB F24), */
546 	0x81, 0x02, /*      Input (Variable),       */
547 	0x95, 0x08, /*      Report Count (8),       */
548 	0x81, 0x01, /*      Input (Constant),       */
549 	0xC0        /*  End Collection              */
550 };
551 
552 /* Report descriptor template placeholder head */
553 #define UCLOGIC_PH_HEAD	0xFE, 0xED, 0x1D
554 
555 /* Report descriptor template placeholder IDs */
556 enum uclogic_ph_id {
557 	UCLOGIC_PH_ID_X_LM,
558 	UCLOGIC_PH_ID_X_PM,
559 	UCLOGIC_PH_ID_Y_LM,
560 	UCLOGIC_PH_ID_Y_PM,
561 	UCLOGIC_PH_ID_PRESSURE_LM,
562 	UCLOGIC_PH_ID_NUM
563 };
564 
565 /* Report descriptor template placeholder */
566 #define UCLOGIC_PH(_ID) UCLOGIC_PH_HEAD, UCLOGIC_PH_ID_##_ID
567 #define UCLOGIC_PEN_REPORT_ID	0x07
568 
569 /* Fixed report descriptor template */
570 static const __u8 uclogic_tablet_rdesc_template[] = {
571 	0x05, 0x0D,             /*  Usage Page (Digitizer),                 */
572 	0x09, 0x02,             /*  Usage (Pen),                            */
573 	0xA1, 0x01,             /*  Collection (Application),               */
574 	0x85, 0x07,             /*      Report ID (7),                      */
575 	0x09, 0x20,             /*      Usage (Stylus),                     */
576 	0xA0,                   /*      Collection (Physical),              */
577 	0x14,                   /*          Logical Minimum (0),            */
578 	0x25, 0x01,             /*          Logical Maximum (1),            */
579 	0x75, 0x01,             /*          Report Size (1),                */
580 	0x09, 0x42,             /*          Usage (Tip Switch),             */
581 	0x09, 0x44,             /*          Usage (Barrel Switch),          */
582 	0x09, 0x46,             /*          Usage (Tablet Pick),            */
583 	0x95, 0x03,             /*          Report Count (3),               */
584 	0x81, 0x02,             /*          Input (Variable),               */
585 	0x95, 0x03,             /*          Report Count (3),               */
586 	0x81, 0x03,             /*          Input (Constant, Variable),     */
587 	0x09, 0x32,             /*          Usage (In Range),               */
588 	0x95, 0x01,             /*          Report Count (1),               */
589 	0x81, 0x02,             /*          Input (Variable),               */
590 	0x95, 0x01,             /*          Report Count (1),               */
591 	0x81, 0x03,             /*          Input (Constant, Variable),     */
592 	0x75, 0x10,             /*          Report Size (16),               */
593 	0x95, 0x01,             /*          Report Count (1),               */
594 	0xA4,                   /*          Push,                           */
595 	0x05, 0x01,             /*          Usage Page (Desktop),           */
596 	0x65, 0x13,             /*          Unit (Inch),                    */
597 	0x55, 0xFD,             /*          Unit Exponent (-3),             */
598 	0x34,                   /*          Physical Minimum (0),           */
599 	0x09, 0x30,             /*          Usage (X),                      */
600 	0x27, UCLOGIC_PH(X_LM), /*          Logical Maximum (PLACEHOLDER),  */
601 	0x47, UCLOGIC_PH(X_PM), /*          Physical Maximum (PLACEHOLDER), */
602 	0x81, 0x02,             /*          Input (Variable),               */
603 	0x09, 0x31,             /*          Usage (Y),                      */
604 	0x27, UCLOGIC_PH(Y_LM), /*          Logical Maximum (PLACEHOLDER),  */
605 	0x47, UCLOGIC_PH(Y_PM), /*          Physical Maximum (PLACEHOLDER), */
606 	0x81, 0x02,             /*          Input (Variable),               */
607 	0xB4,                   /*          Pop,                            */
608 	0x09, 0x30,             /*          Usage (Tip Pressure),           */
609 	0x27,
610 	UCLOGIC_PH(PRESSURE_LM),/*          Logical Maximum (PLACEHOLDER),  */
611 	0x81, 0x02,             /*          Input (Variable),               */
612 	0xC0,                   /*      End Collection,                     */
613 	0xC0                    /*  End Collection                          */
614 };
615 
616 /* Parameter indices */
617 enum uclogic_prm {
618 	UCLOGIC_PRM_X_LM	= 1,
619 	UCLOGIC_PRM_Y_LM	= 2,
620 	UCLOGIC_PRM_PRESSURE_LM	= 4,
621 	UCLOGIC_PRM_RESOLUTION	= 5,
622 	UCLOGIC_PRM_NUM
623 };
624 
625 /* Driver data */
626 struct uclogic_drvdata {
627 	__u8 *rdesc;
628 	unsigned int rsize;
629 	bool invert_pen_inrange;
630 	bool ignore_pen_usage;
631 };
632 
uclogic_report_fixup(struct hid_device * hdev,__u8 * rdesc,unsigned int * rsize)633 static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
634 					unsigned int *rsize)
635 {
636 	struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
637 	__u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
638 	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
639 
640 	switch (hdev->product) {
641 	case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
642 		if (*rsize == PF1209_RDESC_ORIG_SIZE) {
643 			rdesc = pf1209_rdesc_fixed;
644 			*rsize = sizeof(pf1209_rdesc_fixed);
645 		}
646 		break;
647 	case USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U:
648 		if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
649 			rdesc = wp4030u_rdesc_fixed;
650 			*rsize = sizeof(wp4030u_rdesc_fixed);
651 		}
652 		break;
653 	case USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U:
654 		if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
655 			rdesc = wp5540u_rdesc_fixed;
656 			*rsize = sizeof(wp5540u_rdesc_fixed);
657 		}
658 		break;
659 	case USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U:
660 		if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
661 			rdesc = wp8060u_rdesc_fixed;
662 			*rsize = sizeof(wp8060u_rdesc_fixed);
663 		}
664 		break;
665 	case USB_DEVICE_ID_UCLOGIC_TABLET_WP1062:
666 		if (*rsize == WP1062_RDESC_ORIG_SIZE) {
667 			rdesc = wp1062_rdesc_fixed;
668 			*rsize = sizeof(wp1062_rdesc_fixed);
669 		}
670 		break;
671 	case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850:
672 		switch (iface_num) {
673 		case 0:
674 			if (*rsize == TWHL850_RDESC_ORIG_SIZE0) {
675 				rdesc = twhl850_rdesc_fixed0;
676 				*rsize = sizeof(twhl850_rdesc_fixed0);
677 			}
678 			break;
679 		case 1:
680 			if (*rsize == TWHL850_RDESC_ORIG_SIZE1) {
681 				rdesc = twhl850_rdesc_fixed1;
682 				*rsize = sizeof(twhl850_rdesc_fixed1);
683 			}
684 			break;
685 		case 2:
686 			if (*rsize == TWHL850_RDESC_ORIG_SIZE2) {
687 				rdesc = twhl850_rdesc_fixed2;
688 				*rsize = sizeof(twhl850_rdesc_fixed2);
689 			}
690 			break;
691 		}
692 		break;
693 	case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60:
694 		switch (iface_num) {
695 		case 0:
696 			if (*rsize == TWHA60_RDESC_ORIG_SIZE0) {
697 				rdesc = twha60_rdesc_fixed0;
698 				*rsize = sizeof(twha60_rdesc_fixed0);
699 			}
700 			break;
701 		case 1:
702 			if (*rsize == TWHA60_RDESC_ORIG_SIZE1) {
703 				rdesc = twha60_rdesc_fixed1;
704 				*rsize = sizeof(twha60_rdesc_fixed1);
705 			}
706 			break;
707 		}
708 		break;
709 	default:
710 		if (drvdata->rdesc != NULL) {
711 			rdesc = drvdata->rdesc;
712 			*rsize = drvdata->rsize;
713 		}
714 	}
715 
716 	return rdesc;
717 }
718 
uclogic_input_mapping(struct hid_device * hdev,struct hid_input * hi,struct hid_field * field,struct hid_usage * usage,unsigned long ** bit,int * max)719 static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi,
720 		struct hid_field *field, struct hid_usage *usage,
721 		unsigned long **bit, int *max)
722 {
723 	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
724 
725 	/* discard the unused pen interface */
726 	if ((drvdata->ignore_pen_usage) &&
727 	    (field->application == HID_DG_PEN))
728 		return -1;
729 
730 	/* let hid-core decide what to do */
731 	return 0;
732 }
733 
uclogic_input_configured(struct hid_device * hdev,struct hid_input * hi)734 static int uclogic_input_configured(struct hid_device *hdev,
735 		struct hid_input *hi)
736 {
737 	char *name;
738 	const char *suffix = NULL;
739 	struct hid_field *field;
740 	size_t len;
741 
742 	/* no report associated (HID_QUIRK_MULTI_INPUT not set) */
743 	if (!hi->report)
744 		return 0;
745 
746 	field = hi->report->field[0];
747 
748 	switch (field->application) {
749 	case HID_GD_KEYBOARD:
750 		suffix = "Keyboard";
751 		break;
752 	case HID_GD_MOUSE:
753 		suffix = "Mouse";
754 		break;
755 	case HID_GD_KEYPAD:
756 		suffix = "Pad";
757 		break;
758 	case HID_DG_PEN:
759 		suffix = "Pen";
760 		break;
761 	case HID_CP_CONSUMER_CONTROL:
762 		suffix = "Consumer Control";
763 		break;
764 	case HID_GD_SYSTEM_CONTROL:
765 		suffix = "System Control";
766 		break;
767 	}
768 
769 	if (suffix) {
770 		len = strlen(hdev->name) + 2 + strlen(suffix);
771 		name = devm_kzalloc(&hi->input->dev, len, GFP_KERNEL);
772 		if (name) {
773 			snprintf(name, len, "%s %s", hdev->name, suffix);
774 			hi->input->name = name;
775 		}
776 	}
777 
778 	return 0;
779 }
780 
781 /**
782  * Enable fully-functional tablet mode and determine device parameters.
783  *
784  * @hdev:	HID device
785  */
uclogic_tablet_enable(struct hid_device * hdev)786 static int uclogic_tablet_enable(struct hid_device *hdev)
787 {
788 	int rc;
789 	struct usb_device *usb_dev = hid_to_usb_dev(hdev);
790 	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
791 	__le16 *buf = NULL;
792 	size_t len;
793 	s32 params[UCLOGIC_PH_ID_NUM];
794 	s32 resolution;
795 	__u8 *p;
796 	s32 v;
797 
798 	if (!hid_is_usb(hdev))
799 		return -EINVAL;
800 
801 	/*
802 	 * Read string descriptor containing tablet parameters. The specific
803 	 * string descriptor and data were discovered by sniffing the Windows
804 	 * driver traffic.
805 	 * NOTE: This enables fully-functional tablet mode.
806 	 */
807 	len = UCLOGIC_PRM_NUM * sizeof(*buf);
808 	buf = kmalloc(len, GFP_KERNEL);
809 	if (buf == NULL) {
810 		hid_err(hdev, "failed to allocate parameter buffer\n");
811 		rc = -ENOMEM;
812 		goto cleanup;
813 	}
814 	rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
815 				USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
816 				(USB_DT_STRING << 8) + 0x64,
817 				0x0409, buf, len,
818 				USB_CTRL_GET_TIMEOUT);
819 	if (rc == -EPIPE) {
820 		hid_err(hdev, "device parameters not found\n");
821 		rc = -ENODEV;
822 		goto cleanup;
823 	} else if (rc < 0) {
824 		hid_err(hdev, "failed to get device parameters: %d\n", rc);
825 		rc = -ENODEV;
826 		goto cleanup;
827 	} else if (rc != len) {
828 		hid_err(hdev, "invalid device parameters\n");
829 		rc = -ENODEV;
830 		goto cleanup;
831 	}
832 
833 	/* Extract device parameters */
834 	params[UCLOGIC_PH_ID_X_LM] = le16_to_cpu(buf[UCLOGIC_PRM_X_LM]);
835 	params[UCLOGIC_PH_ID_Y_LM] = le16_to_cpu(buf[UCLOGIC_PRM_Y_LM]);
836 	params[UCLOGIC_PH_ID_PRESSURE_LM] =
837 		le16_to_cpu(buf[UCLOGIC_PRM_PRESSURE_LM]);
838 	resolution = le16_to_cpu(buf[UCLOGIC_PRM_RESOLUTION]);
839 	if (resolution == 0) {
840 		params[UCLOGIC_PH_ID_X_PM] = 0;
841 		params[UCLOGIC_PH_ID_Y_PM] = 0;
842 	} else {
843 		params[UCLOGIC_PH_ID_X_PM] = params[UCLOGIC_PH_ID_X_LM] *
844 						1000 / resolution;
845 		params[UCLOGIC_PH_ID_Y_PM] = params[UCLOGIC_PH_ID_Y_LM] *
846 						1000 / resolution;
847 	}
848 
849 	/* Allocate fixed report descriptor */
850 	drvdata->rdesc = devm_kzalloc(&hdev->dev,
851 				sizeof(uclogic_tablet_rdesc_template),
852 				GFP_KERNEL);
853 	if (drvdata->rdesc == NULL) {
854 		hid_err(hdev, "failed to allocate fixed rdesc\n");
855 		rc = -ENOMEM;
856 		goto cleanup;
857 	}
858 	drvdata->rsize = sizeof(uclogic_tablet_rdesc_template);
859 
860 	/* Format fixed report descriptor */
861 	memcpy(drvdata->rdesc, uclogic_tablet_rdesc_template,
862 		drvdata->rsize);
863 	for (p = drvdata->rdesc;
864 	     p <= drvdata->rdesc + drvdata->rsize - 4;) {
865 		if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
866 		    p[3] < ARRAY_SIZE(params)) {
867 			v = params[p[3]];
868 			put_unaligned(cpu_to_le32(v), (s32 *)p);
869 			p += 4;
870 		} else {
871 			p++;
872 		}
873 	}
874 
875 	rc = 0;
876 
877 cleanup:
878 	kfree(buf);
879 	return rc;
880 }
881 
uclogic_probe(struct hid_device * hdev,const struct hid_device_id * id)882 static int uclogic_probe(struct hid_device *hdev,
883 		const struct hid_device_id *id)
884 {
885 	int rc;
886 	struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
887 	struct uclogic_drvdata *drvdata;
888 
889 	/*
890 	 * libinput requires the pad interface to be on a different node
891 	 * than the pen, so use QUIRK_MULTI_INPUT for all tablets.
892 	 */
893 	hdev->quirks |= HID_QUIRK_MULTI_INPUT;
894 	hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT;
895 
896 	/* Allocate and assign driver data */
897 	drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
898 	if (drvdata == NULL)
899 		return -ENOMEM;
900 
901 	hid_set_drvdata(hdev, drvdata);
902 
903 	switch (id->product) {
904 	case USB_DEVICE_ID_HUION_TABLET:
905 		/* If this is the pen interface */
906 		if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
907 			rc = uclogic_tablet_enable(hdev);
908 			if (rc) {
909 				hid_err(hdev, "tablet enabling failed\n");
910 				return rc;
911 			}
912 			drvdata->invert_pen_inrange = true;
913 		} else {
914 			drvdata->ignore_pen_usage = true;
915 		}
916 		break;
917 	}
918 
919 	rc = hid_parse(hdev);
920 	if (rc) {
921 		hid_err(hdev, "parse failed\n");
922 		return rc;
923 	}
924 
925 	rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
926 	if (rc) {
927 		hid_err(hdev, "hw start failed\n");
928 		return rc;
929 	}
930 
931 	return 0;
932 }
933 
uclogic_raw_event(struct hid_device * hdev,struct hid_report * report,u8 * data,int size)934 static int uclogic_raw_event(struct hid_device *hdev, struct hid_report *report,
935 			u8 *data, int size)
936 {
937 	struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
938 
939 	if ((drvdata->invert_pen_inrange) &&
940 	    (report->type == HID_INPUT_REPORT) &&
941 	    (report->id == UCLOGIC_PEN_REPORT_ID) &&
942 	    (size >= 2))
943 		/* Invert the in-range bit */
944 		data[1] ^= 0x40;
945 
946 	return 0;
947 }
948 
949 static const struct hid_device_id uclogic_devices[] = {
950 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
951 				USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
952 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
953 				USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
954 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
955 				USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
956 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
957 				USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
958 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
959 				USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
960 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
961 				USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
962 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
963 				USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
964 	{ HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
965 	{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) },
966 	{ }
967 };
968 MODULE_DEVICE_TABLE(hid, uclogic_devices);
969 
970 static struct hid_driver uclogic_driver = {
971 	.name = "uclogic",
972 	.id_table = uclogic_devices,
973 	.probe = uclogic_probe,
974 	.report_fixup = uclogic_report_fixup,
975 	.raw_event = uclogic_raw_event,
976 	.input_mapping = uclogic_input_mapping,
977 	.input_configured = uclogic_input_configured,
978 };
979 module_hid_driver(uclogic_driver);
980 
981 MODULE_AUTHOR("Martin Rusko");
982 MODULE_AUTHOR("Nikolai Kondrashov");
983 MODULE_LICENSE("GPL");
984