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