xref: /openbmc/linux/drivers/hid/hid-waltop.c (revision dea54fba)
1 /*
2  *  HID driver for Waltop devices not fully compliant with HID standard
3  *
4  *  Copyright (c) 2010 Nikolai Kondrashov
5  */
6 
7 /*
8  * This program is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by the Free
10  * Software Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  */
13 
14 #include <linux/device.h>
15 #include <linux/hid.h>
16 #include <linux/module.h>
17 
18 #include "hid-ids.h"
19 
20 /*
21  * There exists an official driver on the manufacturer's website, which
22  * wasn't submitted to the kernel, for some reason. The official driver
23  * doesn't seem to support extra features of some tablets, like wheels.
24  *
25  * It shows that the feature report ID 2 could be used to control any waltop
26  * tablet input mode, switching it between "default", "tablet" and "ink".
27  *
28  * This driver only uses "default" mode for all the supported tablets. This
29  * mode tries to be HID-compatible (not very successfully), but cripples the
30  * resolution of some tablets.
31  *
32  * The "tablet" mode uses some proprietary, yet decipherable protocol, which
33  * represents the correct resolution, but is possibly HID-incompatible (i.e.
34  * indescribable by a report descriptor).
35  *
36  * The purpose of the "ink" mode is unknown.
37  *
38  * The feature reports needed for switching to each mode are these:
39  *
40  * 02 16 00     default
41  * 02 16 01     tablet
42  * 02 16 02     ink
43  */
44 
45 /* Size of the original report descriptor of Slim Tablet 5.8 inch */
46 #define SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE	222
47 
48 /* Fixed Slim Tablet 5.8 inch descriptor */
49 static __u8 slim_tablet_5_8_inch_rdesc_fixed[] = {
50 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
51 	0x09, 0x02,         /*  Usage (Pen),                        */
52 	0xA1, 0x01,         /*  Collection (Application),           */
53 	0x85, 0x10,         /*      Report ID (16),                 */
54 	0x09, 0x20,         /*      Usage (Stylus),                 */
55 	0xA0,               /*      Collection (Physical),          */
56 	0x09, 0x42,         /*          Usage (Tip Switch),         */
57 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
58 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
59 	0x15, 0x01,         /*          Logical Minimum (1),        */
60 	0x25, 0x03,         /*          Logical Maximum (3),        */
61 	0x75, 0x04,         /*          Report Size (4),            */
62 	0x95, 0x01,         /*          Report Count (1),           */
63 	0x80,               /*          Input,                      */
64 	0x09, 0x32,         /*          Usage (In Range),           */
65 	0x14,               /*          Logical Minimum (0),        */
66 	0x25, 0x01,         /*          Logical Maximum (1),        */
67 	0x75, 0x01,         /*          Report Size (1),            */
68 	0x95, 0x01,         /*          Report Count (1),           */
69 	0x81, 0x02,         /*          Input (Variable),           */
70 	0x95, 0x03,         /*          Report Count (3),           */
71 	0x81, 0x03,         /*          Input (Constant, Variable), */
72 	0x75, 0x10,         /*          Report Size (16),           */
73 	0x95, 0x01,         /*          Report Count (1),           */
74 	0x14,               /*          Logical Minimum (0),        */
75 	0xA4,               /*          Push,                       */
76 	0x05, 0x01,         /*          Usage Page (Desktop),       */
77 	0x65, 0x13,         /*          Unit (Inch),                */
78 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
79 	0x34,               /*          Physical Minimum (0),       */
80 	0x09, 0x30,         /*          Usage (X),                  */
81 	0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */
82 	0x26, 0x10, 0x27,   /*          Logical Maximum (10000),    */
83 	0x81, 0x02,         /*          Input (Variable),           */
84 	0x09, 0x31,         /*          Usage (Y),                  */
85 	0x46, 0xB8, 0x0B,   /*          Physical Maximum (3000),    */
86 	0x26, 0x70, 0x17,   /*          Logical Maximum (6000),     */
87 	0x81, 0x02,         /*          Input (Variable),           */
88 	0xB4,               /*          Pop,                        */
89 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
90 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
91 	0x81, 0x02,         /*          Input (Variable),           */
92 	0xC0,               /*      End Collection,                 */
93 	0xC0                /*  End Collection                      */
94 };
95 
96 /* Size of the original report descriptor of Slim Tablet 12.1 inch */
97 #define SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE	269
98 
99 /* Fixed Slim Tablet 12.1 inch descriptor */
100 static __u8 slim_tablet_12_1_inch_rdesc_fixed[] = {
101 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
102 	0x09, 0x02,         /*  Usage (Pen),                        */
103 	0xA1, 0x01,         /*  Collection (Application),           */
104 	0x85, 0x10,         /*      Report ID (16),                 */
105 	0x09, 0x20,         /*      Usage (Stylus),                 */
106 	0xA0,               /*      Collection (Physical),          */
107 	0x09, 0x42,         /*          Usage (Tip Switch),         */
108 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
109 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
110 	0x15, 0x01,         /*          Logical Minimum (1),        */
111 	0x25, 0x03,         /*          Logical Maximum (3),        */
112 	0x75, 0x04,         /*          Report Size (4),            */
113 	0x95, 0x01,         /*          Report Count (1),           */
114 	0x80,               /*          Input,                      */
115 	0x09, 0x32,         /*          Usage (In Range),           */
116 	0x14,               /*          Logical Minimum (0),        */
117 	0x25, 0x01,         /*          Logical Maximum (1),        */
118 	0x75, 0x01,         /*          Report Size (1),            */
119 	0x95, 0x01,         /*          Report Count (1),           */
120 	0x81, 0x02,         /*          Input (Variable),           */
121 	0x95, 0x03,         /*          Report Count (3),           */
122 	0x81, 0x03,         /*          Input (Constant, Variable), */
123 	0x75, 0x10,         /*          Report Size (16),           */
124 	0x95, 0x01,         /*          Report Count (1),           */
125 	0x14,               /*          Logical Minimum (0),        */
126 	0xA4,               /*          Push,                       */
127 	0x05, 0x01,         /*          Usage Page (Desktop),       */
128 	0x65, 0x13,         /*          Unit (Inch),                */
129 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
130 	0x34,               /*          Physical Minimum (0),       */
131 	0x09, 0x30,         /*          Usage (X),                  */
132 	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
133 	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
134 	0x81, 0x02,         /*          Input (Variable),           */
135 	0x09, 0x31,         /*          Usage (Y),                  */
136 	0x46, 0x6A, 0x18,   /*          Physical Maximum (6250),    */
137 	0x26, 0xD4, 0x30,   /*          Logical Maximum (12500),    */
138 	0x81, 0x02,         /*          Input (Variable),           */
139 	0xB4,               /*          Pop,                        */
140 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
141 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
142 	0x81, 0x02,         /*          Input (Variable),           */
143 	0xC0,               /*      End Collection,                 */
144 	0xC0                /*  End Collection                      */
145 };
146 
147 /* Size of the original report descriptor of Q Pad */
148 #define Q_PAD_RDESC_ORIG_SIZE	241
149 
150 /* Fixed Q Pad descriptor */
151 static __u8 q_pad_rdesc_fixed[] = {
152 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
153 	0x09, 0x02,         /*  Usage (Pen),                        */
154 	0xA1, 0x01,         /*  Collection (Application),           */
155 	0x85, 0x10,         /*      Report ID (16),                 */
156 	0x09, 0x20,         /*      Usage (Stylus),                 */
157 	0xA0,               /*      Collection (Physical),          */
158 	0x09, 0x42,         /*          Usage (Tip Switch),         */
159 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
160 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
161 	0x15, 0x01,         /*          Logical Minimum (1),        */
162 	0x25, 0x03,         /*          Logical Maximum (3),        */
163 	0x75, 0x04,         /*          Report Size (4),            */
164 	0x95, 0x01,         /*          Report Count (1),           */
165 	0x80,               /*          Input,                      */
166 	0x09, 0x32,         /*          Usage (In Range),           */
167 	0x14,               /*          Logical Minimum (0),        */
168 	0x25, 0x01,         /*          Logical Maximum (1),        */
169 	0x75, 0x01,         /*          Report Size (1),            */
170 	0x95, 0x01,         /*          Report Count (1),           */
171 	0x81, 0x02,         /*          Input (Variable),           */
172 	0x95, 0x03,         /*          Report Count (3),           */
173 	0x81, 0x03,         /*          Input (Constant, Variable), */
174 	0x75, 0x10,         /*          Report Size (16),           */
175 	0x95, 0x01,         /*          Report Count (1),           */
176 	0x14,               /*          Logical Minimum (0),        */
177 	0xA4,               /*          Push,                       */
178 	0x05, 0x01,         /*          Usage Page (Desktop),       */
179 	0x65, 0x13,         /*          Unit (Inch),                */
180 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
181 	0x34,               /*          Physical Minimum (0),       */
182 	0x09, 0x30,         /*          Usage (X),                  */
183 	0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
184 	0x26, 0x00, 0x30,   /*          Logical Maximum (12288),    */
185 	0x81, 0x02,         /*          Input (Variable),           */
186 	0x09, 0x31,         /*          Usage (Y),                  */
187 	0x46, 0x94, 0x11,   /*          Physical Maximum (4500),    */
188 	0x26, 0x00, 0x24,   /*          Logical Maximum (9216),     */
189 	0x81, 0x02,         /*          Input (Variable),           */
190 	0xB4,               /*          Pop,                        */
191 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
192 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
193 	0x81, 0x02,         /*          Input (Variable),           */
194 	0xC0,               /*      End Collection,                 */
195 	0xC0                /*  End Collection                      */
196 };
197 
198 /* Size of the original report descriptor of tablet with PID 0038 */
199 #define PID_0038_RDESC_ORIG_SIZE	241
200 
201 /*
202  * Fixed report descriptor for tablet with PID 0038.
203  */
204 static __u8 pid_0038_rdesc_fixed[] = {
205 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
206 	0x09, 0x02,         /*  Usage (Pen),                        */
207 	0xA1, 0x01,         /*  Collection (Application),           */
208 	0x85, 0x10,         /*      Report ID (16),                 */
209 	0x09, 0x20,         /*      Usage (Stylus),                 */
210 	0xA0,               /*      Collection (Physical),          */
211 	0x09, 0x42,         /*          Usage (Tip Switch),         */
212 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
213 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
214 	0x15, 0x01,         /*          Logical Minimum (1),        */
215 	0x25, 0x03,         /*          Logical Maximum (3),        */
216 	0x75, 0x04,         /*          Report Size (4),            */
217 	0x95, 0x01,         /*          Report Count (1),           */
218 	0x80,               /*          Input,                      */
219 	0x09, 0x32,         /*          Usage (In Range),           */
220 	0x14,               /*          Logical Minimum (0),        */
221 	0x25, 0x01,         /*          Logical Maximum (1),        */
222 	0x75, 0x01,         /*          Report Size (1),            */
223 	0x95, 0x01,         /*          Report Count (1),           */
224 	0x81, 0x02,         /*          Input (Variable),           */
225 	0x95, 0x03,         /*          Report Count (3),           */
226 	0x81, 0x03,         /*          Input (Constant, Variable), */
227 	0x75, 0x10,         /*          Report Size (16),           */
228 	0x95, 0x01,         /*          Report Count (1),           */
229 	0x14,               /*          Logical Minimum (0),        */
230 	0xA4,               /*          Push,                       */
231 	0x05, 0x01,         /*          Usage Page (Desktop),       */
232 	0x65, 0x13,         /*          Unit (Inch),                */
233 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
234 	0x34,               /*          Physical Minimum (0),       */
235 	0x09, 0x30,         /*          Usage (X),                  */
236 	0x46, 0x2E, 0x22,   /*          Physical Maximum (8750),    */
237 	0x26, 0x00, 0x46,   /*          Logical Maximum (17920),    */
238 	0x81, 0x02,         /*          Input (Variable),           */
239 	0x09, 0x31,         /*          Usage (Y),                  */
240 	0x46, 0x82, 0x14,   /*          Physical Maximum (5250),    */
241 	0x26, 0x00, 0x2A,   /*          Logical Maximum (10752),    */
242 	0x81, 0x02,         /*          Input (Variable),           */
243 	0xB4,               /*          Pop,                        */
244 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
245 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
246 	0x81, 0x02,         /*          Input (Variable),           */
247 	0xC0,               /*      End Collection,                 */
248 	0xC0                /*  End Collection                      */
249 };
250 
251 /* Size of the original report descriptor of Media Tablet 10.6 inch */
252 #define MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE	300
253 
254 /* Fixed Media Tablet 10.6 inch descriptor */
255 static __u8 media_tablet_10_6_inch_rdesc_fixed[] = {
256 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
257 	0x09, 0x02,         /*  Usage (Pen),                        */
258 	0xA1, 0x01,         /*  Collection (Application),           */
259 	0x85, 0x10,         /*      Report ID (16),                 */
260 	0x09, 0x20,         /*      Usage (Stylus),                 */
261 	0xA0,               /*      Collection (Physical),          */
262 	0x09, 0x42,         /*          Usage (Tip Switch),         */
263 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
264 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
265 	0x15, 0x01,         /*          Logical Minimum (1),        */
266 	0x25, 0x03,         /*          Logical Maximum (3),        */
267 	0x75, 0x04,         /*          Report Size (4),            */
268 	0x95, 0x01,         /*          Report Count (1),           */
269 	0x80,               /*          Input,                      */
270 	0x75, 0x01,         /*          Report Size (1),            */
271 	0x09, 0x32,         /*          Usage (In Range),           */
272 	0x14,               /*          Logical Minimum (0),        */
273 	0x25, 0x01,         /*          Logical Maximum (1),        */
274 	0x95, 0x01,         /*          Report Count (1),           */
275 	0x81, 0x02,         /*          Input (Variable),           */
276 	0x95, 0x03,         /*          Report Count (3),           */
277 	0x81, 0x03,         /*          Input (Constant, Variable), */
278 	0x75, 0x10,         /*          Report Size (16),           */
279 	0x95, 0x01,         /*          Report Count (1),           */
280 	0x14,               /*          Logical Minimum (0),        */
281 	0xA4,               /*          Push,                       */
282 	0x05, 0x01,         /*          Usage Page (Desktop),       */
283 	0x65, 0x13,         /*          Unit (Inch),                */
284 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
285 	0x34,               /*          Physical Minimum (0),       */
286 	0x09, 0x30,         /*          Usage (X),                  */
287 	0x46, 0x28, 0x23,   /*          Physical Maximum (9000),    */
288 	0x26, 0x50, 0x46,   /*          Logical Maximum (18000),    */
289 	0x81, 0x02,         /*          Input (Variable),           */
290 	0x09, 0x31,         /*          Usage (Y),                  */
291 	0x46, 0x7C, 0x15,   /*          Physical Maximum (5500),    */
292 	0x26, 0xF8, 0x2A,   /*          Logical Maximum (11000),    */
293 	0x81, 0x02,         /*          Input (Variable),           */
294 	0xB4,               /*          Pop,                        */
295 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
296 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
297 	0x81, 0x02,         /*          Input (Variable),           */
298 	0xC0,               /*      End Collection,                 */
299 	0xC0,               /*  End Collection,                     */
300 	0x05, 0x01,         /*  Usage Page (Desktop),               */
301 	0x09, 0x02,         /*  Usage (Mouse),                      */
302 	0xA1, 0x01,         /*  Collection (Application),           */
303 	0x85, 0x01,         /*      Report ID (1),                  */
304 	0x09, 0x01,         /*      Usage (Pointer),                */
305 	0xA0,               /*      Collection (Physical),          */
306 	0x75, 0x08,         /*          Report Size (8),            */
307 	0x95, 0x03,         /*          Report Count (3),           */
308 	0x81, 0x03,         /*          Input (Constant, Variable), */
309 	0x95, 0x02,         /*          Report Count (2),           */
310 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
311 	0x25, 0x01,         /*          Logical Maximum (1),        */
312 	0x09, 0x38,         /*          Usage (Wheel),              */
313 	0x0B, 0x38, 0x02,   /*          Usage (Consumer AC Pan),    */
314 		0x0C, 0x00,
315 	0x81, 0x06,         /*          Input (Variable, Relative), */
316 	0x95, 0x02,         /*          Report Count (2),           */
317 	0x81, 0x03,         /*          Input (Constant, Variable), */
318 	0xC0,               /*      End Collection,                 */
319 	0xC0,               /*  End Collection,                     */
320 	0x05, 0x0C,         /*  Usage Page (Consumer),              */
321 	0x09, 0x01,         /*  Usage (Consumer Control),           */
322 	0xA1, 0x01,         /*  Collection (Application),           */
323 	0x85, 0x0D,         /*      Report ID (13),                 */
324 	0x95, 0x01,         /*      Report Count (1),               */
325 	0x75, 0x10,         /*      Report Size (16),               */
326 	0x81, 0x03,         /*      Input (Constant, Variable),     */
327 	0x0A, 0x2F, 0x02,   /*      Usage (AC Zoom),                */
328 	0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
329 	0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
330 	0x09, 0xB6,         /*      Usage (Scan Previous Track),    */
331 	0x09, 0xB5,         /*      Usage (Scan Next Track),        */
332 	0x08,               /*      Usage (00h),                    */
333 	0x08,               /*      Usage (00h),                    */
334 	0x08,               /*      Usage (00h),                    */
335 	0x08,               /*      Usage (00h),                    */
336 	0x08,               /*      Usage (00h),                    */
337 	0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
338 	0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
339 	0x15, 0x0C,         /*      Logical Minimum (12),           */
340 	0x25, 0x17,         /*      Logical Maximum (23),           */
341 	0x75, 0x05,         /*      Report Size (5),                */
342 	0x80,               /*      Input,                          */
343 	0x75, 0x03,         /*      Report Size (3),                */
344 	0x81, 0x03,         /*      Input (Constant, Variable),     */
345 	0x75, 0x20,         /*      Report Size (32),               */
346 	0x81, 0x03,         /*      Input (Constant, Variable),     */
347 	0xC0,               /*  End Collection,                     */
348 	0x09, 0x01,         /*  Usage (Consumer Control),           */
349 	0xA1, 0x01,         /*  Collection (Application),           */
350 	0x85, 0x0C,         /*      Report ID (12),                 */
351 	0x75, 0x01,         /*      Report Size (1),                */
352 	0x09, 0xE9,         /*      Usage (Volume Inc),             */
353 	0x09, 0xEA,         /*      Usage (Volume Dec),             */
354 	0x09, 0xE2,         /*      Usage (Mute),                   */
355 	0x14,               /*      Logical Minimum (0),            */
356 	0x25, 0x01,         /*      Logical Maximum (1),            */
357 	0x95, 0x03,         /*      Report Count (3),               */
358 	0x81, 0x06,         /*      Input (Variable, Relative),     */
359 	0x95, 0x35,         /*      Report Count (53),              */
360 	0x81, 0x03,         /*      Input (Constant, Variable),     */
361 	0xC0                /*  End Collection                      */
362 };
363 
364 /* Size of the original report descriptor of Media Tablet 14.1 inch */
365 #define MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE	309
366 
367 /* Fixed Media Tablet 14.1 inch descriptor */
368 static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {
369 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
370 	0x09, 0x02,         /*  Usage (Pen),                        */
371 	0xA1, 0x01,         /*  Collection (Application),           */
372 	0x85, 0x10,         /*      Report ID (16),                 */
373 	0x09, 0x20,         /*      Usage (Stylus),                 */
374 	0xA0,               /*      Collection (Physical),          */
375 	0x09, 0x42,         /*          Usage (Tip Switch),         */
376 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
377 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
378 	0x15, 0x01,         /*          Logical Minimum (1),        */
379 	0x25, 0x03,         /*          Logical Maximum (3),        */
380 	0x75, 0x04,         /*          Report Size (4),            */
381 	0x95, 0x01,         /*          Report Count (1),           */
382 	0x80,               /*          Input,                      */
383 	0x75, 0x01,         /*          Report Size (1),            */
384 	0x09, 0x32,         /*          Usage (In Range),           */
385 	0x14,               /*          Logical Minimum (0),        */
386 	0x25, 0x01,         /*          Logical Maximum (1),        */
387 	0x95, 0x01,         /*          Report Count (1),           */
388 	0x81, 0x02,         /*          Input (Variable),           */
389 	0x95, 0x03,         /*          Report Count (3),           */
390 	0x81, 0x03,         /*          Input (Constant, Variable), */
391 	0x75, 0x10,         /*          Report Size (16),           */
392 	0x95, 0x01,         /*          Report Count (1),           */
393 	0x14,               /*          Logical Minimum (0),        */
394 	0xA4,               /*          Push,                       */
395 	0x05, 0x01,         /*          Usage Page (Desktop),       */
396 	0x65, 0x13,         /*          Unit (Inch),                */
397 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
398 	0x34,               /*          Physical Minimum (0),       */
399 	0x09, 0x30,         /*          Usage (X),                  */
400 	0x46, 0xE0, 0x2E,   /*          Physical Maximum (12000),   */
401 	0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),    */
402 	0x81, 0x02,         /*          Input (Variable),           */
403 	0x09, 0x31,         /*          Usage (Y),                  */
404 	0x46, 0x52, 0x1C,   /*          Physical Maximum (7250),    */
405 	0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),    */
406 	0x81, 0x02,         /*          Input (Variable),           */
407 	0xB4,               /*          Pop,                        */
408 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
409 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
410 	0x81, 0x02,         /*          Input (Variable),           */
411 	0xC0,               /*      End Collection,                 */
412 	0xC0,               /*  End Collection,                     */
413 	0x05, 0x01,         /*  Usage Page (Desktop),               */
414 	0x09, 0x02,         /*  Usage (Mouse),                      */
415 	0xA1, 0x01,         /*  Collection (Application),           */
416 	0x85, 0x01,         /*      Report ID (1),                  */
417 	0x09, 0x01,         /*      Usage (Pointer),                */
418 	0xA0,               /*      Collection (Physical),          */
419 	0x75, 0x08,         /*          Report Size (8),            */
420 	0x95, 0x03,         /*          Report Count (3),           */
421 	0x81, 0x03,         /*          Input (Constant, Variable), */
422 	0x95, 0x02,         /*          Report Count (2),           */
423 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
424 	0x25, 0x01,         /*          Logical Maximum (1),        */
425 	0x09, 0x38,         /*          Usage (Wheel),              */
426 	0x0B, 0x38, 0x02,   /*          Usage (Consumer AC Pan),    */
427 		0x0C, 0x00,
428 	0x81, 0x06,         /*          Input (Variable, Relative), */
429 	0xC0,               /*      End Collection,                 */
430 	0xC0,               /*  End Collection,                     */
431 	0x05, 0x0C,         /*  Usage Page (Consumer),              */
432 	0x09, 0x01,         /*  Usage (Consumer Control),           */
433 	0xA1, 0x01,         /*  Collection (Application),           */
434 	0x85, 0x0D,         /*      Report ID (13),                 */
435 	0x95, 0x01,         /*      Report Count (1),               */
436 	0x75, 0x10,         /*      Report Size (16),               */
437 	0x81, 0x03,         /*      Input (Constant, Variable),     */
438 	0x0A, 0x2F, 0x02,   /*      Usage (AC Zoom),                */
439 	0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
440 	0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
441 	0x09, 0xB6,         /*      Usage (Scan Previous Track),    */
442 	0x09, 0xB5,         /*      Usage (Scan Next Track),        */
443 	0x08,               /*      Usage (00h),                    */
444 	0x08,               /*      Usage (00h),                    */
445 	0x08,               /*      Usage (00h),                    */
446 	0x08,               /*      Usage (00h),                    */
447 	0x08,               /*      Usage (00h),                    */
448 	0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
449 	0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
450 	0x15, 0x0C,         /*      Logical Minimum (12),           */
451 	0x25, 0x17,         /*      Logical Maximum (23),           */
452 	0x75, 0x05,         /*      Report Size (5),                */
453 	0x80,               /*      Input,                          */
454 	0x75, 0x03,         /*      Report Size (3),                */
455 	0x81, 0x03,         /*      Input (Constant, Variable),     */
456 	0x75, 0x20,         /*      Report Size (32),               */
457 	0x81, 0x03,         /*      Input (Constant, Variable),     */
458 	0xC0,               /*  End Collection,                     */
459 	0x09, 0x01,         /*  Usage (Consumer Control),           */
460 	0xA1, 0x01,         /*  Collection (Application),           */
461 	0x85, 0x0C,         /*      Report ID (12),                 */
462 	0x75, 0x01,         /*      Report Size (1),                */
463 	0x09, 0xE9,         /*      Usage (Volume Inc),             */
464 	0x09, 0xEA,         /*      Usage (Volume Dec),             */
465 	0x09, 0xE2,         /*      Usage (Mute),                   */
466 	0x14,               /*      Logical Minimum (0),            */
467 	0x25, 0x01,         /*      Logical Maximum (1),            */
468 	0x95, 0x03,         /*      Report Count (3),               */
469 	0x81, 0x06,         /*      Input (Variable, Relative),     */
470 	0x75, 0x05,         /*      Report Size (5),                */
471 	0x81, 0x03,         /*      Input (Constant, Variable),     */
472 	0xC0                /*  End Collection                      */
473 };
474 
475 /* Size of the original report descriptor of Sirius Battery Free Tablet */
476 #define SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE	335
477 
478 /* Fixed Sirius Battery Free Tablet descriptor */
479 static __u8 sirius_battery_free_tablet_rdesc_fixed[] = {
480 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
481 	0x09, 0x02,         /*  Usage (Pen),                        */
482 	0xA1, 0x01,         /*  Collection (Application),           */
483 	0x85, 0x10,         /*      Report ID (16),                 */
484 	0x09, 0x20,         /*      Usage (Stylus),                 */
485 	0xA0,               /*      Collection (Physical),          */
486 	0x95, 0x01,         /*          Report Count (1),           */
487 	0x15, 0x01,         /*          Logical Minimum (1),        */
488 	0x25, 0x03,         /*          Logical Maximum (3),        */
489 	0x75, 0x02,         /*          Report Size (2),            */
490 	0x09, 0x42,         /*          Usage (Tip Switch),         */
491 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
492 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
493 	0x80,               /*          Input,                      */
494 	0x14,               /*          Logical Minimum (0),        */
495 	0x25, 0x01,         /*          Logical Maximum (1),        */
496 	0x75, 0x01,         /*          Report Size (1),            */
497 	0x09, 0x3C,         /*          Usage (Invert),             */
498 	0x81, 0x02,         /*          Input (Variable),           */
499 	0x81, 0x03,         /*          Input (Constant, Variable), */
500 	0x09, 0x32,         /*          Usage (In Range),           */
501 	0x81, 0x02,         /*          Input (Variable),           */
502 	0x95, 0x03,         /*          Report Count (3),           */
503 	0x81, 0x03,         /*          Input (Constant, Variable), */
504 	0xA4,               /*          Push,                       */
505 	0x05, 0x01,         /*          Usage Page (Desktop),       */
506 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
507 	0x65, 0x13,         /*          Unit (Inch),                */
508 	0x34,               /*          Physical Minimum (0),       */
509 	0x14,               /*          Logical Minimum (0),        */
510 	0x75, 0x10,         /*          Report Size (16),           */
511 	0x95, 0x01,         /*          Report Count (1),           */
512 	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
513 	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
514 	0x09, 0x30,         /*          Usage (X),                  */
515 	0x81, 0x02,         /*          Input (Variable),           */
516 	0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
517 	0x26, 0xE0, 0x2E,   /*          Logical Maximum (12000),    */
518 	0x09, 0x31,         /*          Usage (Y),                  */
519 	0x81, 0x02,         /*          Input (Variable),           */
520 	0xB4,               /*          Pop,                        */
521 	0x75, 0x10,         /*          Report Size (16),           */
522 	0x95, 0x01,         /*          Report Count (1),           */
523 	0x14,               /*          Logical Minimum (0),        */
524 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
525 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
526 	0x81, 0x02,         /*          Input (Variable),           */
527 	0xA4,               /*          Push,                       */
528 	0x55, 0xFE,         /*          Unit Exponent (-2),         */
529 	0x65, 0x12,         /*          Unit (Radians),             */
530 	0x35, 0x97,         /*          Physical Minimum (-105),    */
531 	0x45, 0x69,         /*          Physical Maximum (105),     */
532 	0x15, 0x97,         /*          Logical Minimum (-105),     */
533 	0x25, 0x69,         /*          Logical Maximum (105),      */
534 	0x75, 0x08,         /*          Report Size (8),            */
535 	0x95, 0x02,         /*          Report Count (2),           */
536 	0x09, 0x3D,         /*          Usage (X Tilt),             */
537 	0x09, 0x3E,         /*          Usage (Y Tilt),             */
538 	0x81, 0x02,         /*          Input (Variable),           */
539 	0xB4,               /*          Pop,                        */
540 	0xC0,               /*      End Collection,                 */
541 	0xC0,               /*  End Collection,                     */
542 	0x05, 0x01,         /*  Usage Page (Desktop),               */
543 	0x09, 0x02,         /*  Usage (Mouse),                      */
544 	0xA1, 0x01,         /*  Collection (Application),           */
545 	0x85, 0x01,         /*      Report ID (1),                  */
546 	0x09, 0x01,         /*      Usage (Pointer),                */
547 	0xA0,               /*      Collection (Physical),          */
548 	0x75, 0x08,         /*          Report Size (8),            */
549 	0x95, 0x03,         /*          Report Count (3),           */
550 	0x81, 0x03,         /*          Input (Constant, Variable), */
551 	0x09, 0x38,         /*          Usage (Wheel),              */
552 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
553 	0x25, 0x01,         /*          Logical Maximum (1),        */
554 	0x75, 0x08,         /*          Report Size (8),            */
555 	0x95, 0x01,         /*          Report Count (1),           */
556 	0x81, 0x06,         /*          Input (Variable, Relative), */
557 	0x75, 0x08,         /*          Report Size (8),            */
558 	0x95, 0x03,         /*          Report Count (3),           */
559 	0x81, 0x03,         /*          Input (Constant, Variable), */
560 	0xC0,               /*      End Collection,                 */
561 	0xC0,               /*  End Collection,                     */
562 	0x05, 0x01,         /*  Usage Page (Desktop),               */
563 	0x09, 0x06,         /*  Usage (Keyboard),                   */
564 	0xA1, 0x01,         /*  Collection (Application),           */
565 	0x85, 0x0D,         /*      Report ID (13),                 */
566 	0x05, 0x07,         /*      Usage Page (Keyboard),          */
567 	0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */
568 	0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */
569 	0x14,               /*      Logical Minimum (0),            */
570 	0x25, 0x01,         /*      Logical Maximum (1),            */
571 	0x75, 0x01,         /*      Report Size (1),                */
572 	0x95, 0x08,         /*      Report Count (8),               */
573 	0x81, 0x02,         /*      Input (Variable),               */
574 	0x75, 0x08,         /*      Report Size (8),                */
575 	0x95, 0x01,         /*      Report Count (1),               */
576 	0x81, 0x01,         /*      Input (Constant),               */
577 	0x18,               /*      Usage Minimum (None),           */
578 	0x29, 0x65,         /*      Usage Maximum (KB Application), */
579 	0x14,               /*      Logical Minimum (0),            */
580 	0x25, 0x65,         /*      Logical Maximum (101),          */
581 	0x75, 0x08,         /*      Report Size (8),                */
582 	0x95, 0x05,         /*      Report Count (5),               */
583 	0x80,               /*      Input,                          */
584 	0xC0,               /*  End Collection,                     */
585 	0x05, 0x0C,         /*  Usage Page (Consumer),              */
586 	0x09, 0x01,         /*  Usage (Consumer Control),           */
587 	0xA1, 0x01,         /*  Collection (Application),           */
588 	0x85, 0x0C,         /*      Report ID (12),                 */
589 	0x09, 0xE9,         /*      Usage (Volume Inc),             */
590 	0x09, 0xEA,         /*      Usage (Volume Dec),             */
591 	0x14,               /*      Logical Minimum (0),            */
592 	0x25, 0x01,         /*      Logical Maximum (1),            */
593 	0x75, 0x01,         /*      Report Size (1),                */
594 	0x95, 0x02,         /*      Report Count (2),               */
595 	0x81, 0x02,         /*      Input (Variable),               */
596 	0x75, 0x06,         /*      Report Size (6),                */
597 	0x95, 0x01,         /*      Report Count (1),               */
598 	0x81, 0x03,         /*      Input (Constant, Variable),     */
599 	0x75, 0x10,         /*      Report Size (16),               */
600 	0x95, 0x03,         /*      Report Count (3),               */
601 	0x81, 0x03,         /*      Input (Constant, Variable),     */
602 	0xC0                /*  End Collection                      */
603 };
604 
605 static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
606 		unsigned int *rsize)
607 {
608 	switch (hdev->product) {
609 	case USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH:
610 		if (*rsize == SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE) {
611 			rdesc = slim_tablet_5_8_inch_rdesc_fixed;
612 			*rsize = sizeof(slim_tablet_5_8_inch_rdesc_fixed);
613 		}
614 		break;
615 	case USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH:
616 		if (*rsize == SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE) {
617 			rdesc = slim_tablet_12_1_inch_rdesc_fixed;
618 			*rsize = sizeof(slim_tablet_12_1_inch_rdesc_fixed);
619 		}
620 		break;
621 	case USB_DEVICE_ID_WALTOP_Q_PAD:
622 		if (*rsize == Q_PAD_RDESC_ORIG_SIZE) {
623 			rdesc = q_pad_rdesc_fixed;
624 			*rsize = sizeof(q_pad_rdesc_fixed);
625 		}
626 		break;
627 	case USB_DEVICE_ID_WALTOP_PID_0038:
628 		if (*rsize == PID_0038_RDESC_ORIG_SIZE) {
629 			rdesc = pid_0038_rdesc_fixed;
630 			*rsize = sizeof(pid_0038_rdesc_fixed);
631 		}
632 		break;
633 	case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH:
634 		if (*rsize == MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE) {
635 			rdesc = media_tablet_10_6_inch_rdesc_fixed;
636 			*rsize = sizeof(media_tablet_10_6_inch_rdesc_fixed);
637 		}
638 		break;
639 	case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH:
640 		if (*rsize == MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE) {
641 			rdesc = media_tablet_14_1_inch_rdesc_fixed;
642 			*rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed);
643 		}
644 		break;
645 	case USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET:
646 		if (*rsize == SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE) {
647 			rdesc = sirius_battery_free_tablet_rdesc_fixed;
648 			*rsize = sizeof(sirius_battery_free_tablet_rdesc_fixed);
649 		}
650 		break;
651 	}
652 	return rdesc;
653 }
654 
655 static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report,
656 		     u8 *data, int size)
657 {
658 	/* If this is a pen input report */
659 	if (report->type == HID_INPUT_REPORT && report->id == 16 && size >= 8) {
660 		/*
661 		 * Ignore reported pressure when a barrel button is pressed,
662 		 * because it is rarely correct.
663 		 */
664 
665 		/* If a barrel button is pressed */
666 		if ((data[1] & 0xF) > 1) {
667 			/* Report zero pressure */
668 			data[6] = 0;
669 			data[7] = 0;
670 		}
671 	}
672 
673 	/* If this is a pen input report of Sirius Battery Free Tablet */
674 	if (hdev->product == USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET &&
675 	    report->type == HID_INPUT_REPORT &&
676 	    report->id == 16 &&
677 	    size == 10) {
678 		/*
679 		 * The tablet reports tilt as roughly sin(a)*21 (18 means 60
680 		 * degrees).
681 		 *
682 		 * This array stores angles as radians * 100, corresponding to
683 		 * reported values up to 60 degrees, as expected by userspace.
684 		 */
685 		static const s8 tilt_to_radians[] = {
686 			0, 5, 10, 14, 19, 24, 29, 34, 40, 45,
687 			50, 56, 62, 68, 74, 81, 88, 96, 105
688 		};
689 
690 		s8 tilt_x = (s8)data[8];
691 		s8 tilt_y = (s8)data[9];
692 		s8 sign_x = tilt_x >= 0 ? 1 : -1;
693 		s8 sign_y = tilt_y >= 0 ? 1 : -1;
694 
695 		tilt_x *= sign_x;
696 		tilt_y *= sign_y;
697 
698 		/*
699 		 * Reverse the Y Tilt direction to match the HID standard and
700 		 * userspace expectations. See HID Usage Tables v1.12 16.3.2
701 		 * Tilt Orientation.
702 		 */
703 		sign_y *= -1;
704 
705 		/*
706 		 * This effectively clamps reported tilt to 60 degrees - the
707 		 * range expected by userspace
708 		 */
709 		if (tilt_x > ARRAY_SIZE(tilt_to_radians) - 1)
710 			tilt_x = ARRAY_SIZE(tilt_to_radians) - 1;
711 		if (tilt_y > ARRAY_SIZE(tilt_to_radians) - 1)
712 			tilt_y = ARRAY_SIZE(tilt_to_radians) - 1;
713 
714 		data[8] = tilt_to_radians[tilt_x] * sign_x;
715 		data[9] = tilt_to_radians[tilt_y] * sign_y;
716 	}
717 
718 	return 0;
719 }
720 
721 static const struct hid_device_id waltop_devices[] = {
722 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
723 				USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
724 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
725 				USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
726 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
727 				USB_DEVICE_ID_WALTOP_Q_PAD) },
728 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
729 				USB_DEVICE_ID_WALTOP_PID_0038) },
730 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
731 				USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
732 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
733 				USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
734 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
735 			 USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
736 	{ }
737 };
738 MODULE_DEVICE_TABLE(hid, waltop_devices);
739 
740 static struct hid_driver waltop_driver = {
741 	.name = "waltop",
742 	.id_table = waltop_devices,
743 	.report_fixup = waltop_report_fixup,
744 	.raw_event = waltop_raw_event,
745 };
746 module_hid_driver(waltop_driver);
747 
748 MODULE_LICENSE("GPL");
749