xref: /openbmc/linux/drivers/hid/hid-waltop.c (revision 95e9fd10)
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 /*
46  * See Slim Tablet 5.8 inch description, device and HID report descriptors at
47  * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Slim_Tablet_5.8%22
48  */
49 
50 /* Size of the original report descriptor of Slim Tablet 5.8 inch */
51 #define SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE	222
52 
53 /* Fixed Slim Tablet 5.8 inch descriptor */
54 static __u8 slim_tablet_5_8_inch_rdesc_fixed[] = {
55 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
56 	0x09, 0x02,         /*  Usage (Pen),                        */
57 	0xA1, 0x01,         /*  Collection (Application),           */
58 	0x85, 0x10,         /*      Report ID (16),                 */
59 	0x09, 0x20,         /*      Usage (Stylus),                 */
60 	0xA0,               /*      Collection (Physical),          */
61 	0x09, 0x42,         /*          Usage (Tip Switch),         */
62 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
63 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
64 	0x15, 0x01,         /*          Logical Minimum (1),        */
65 	0x25, 0x03,         /*          Logical Maximum (3),        */
66 	0x75, 0x04,         /*          Report Size (4),            */
67 	0x95, 0x01,         /*          Report Count (1),           */
68 	0x80,               /*          Input,                      */
69 	0x09, 0x32,         /*          Usage (In Range),           */
70 	0x14,               /*          Logical Minimum (0),        */
71 	0x25, 0x01,         /*          Logical Maximum (1),        */
72 	0x75, 0x01,         /*          Report Size (1),            */
73 	0x95, 0x01,         /*          Report Count (1),           */
74 	0x81, 0x02,         /*          Input (Variable),           */
75 	0x95, 0x03,         /*          Report Count (3),           */
76 	0x81, 0x03,         /*          Input (Constant, Variable), */
77 	0x75, 0x10,         /*          Report Size (16),           */
78 	0x95, 0x01,         /*          Report Count (1),           */
79 	0x14,               /*          Logical Minimum (0),        */
80 	0xA4,               /*          Push,                       */
81 	0x05, 0x01,         /*          Usage Page (Desktop),       */
82 	0x65, 0x13,         /*          Unit (Inch),                */
83 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
84 	0x34,               /*          Physical Minimum (0),       */
85 	0x09, 0x30,         /*          Usage (X),                  */
86 	0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */
87 	0x26, 0x10, 0x27,   /*          Logical Maximum (10000),    */
88 	0x81, 0x02,         /*          Input (Variable),           */
89 	0x09, 0x31,         /*          Usage (Y),                  */
90 	0x46, 0xB8, 0x0B,   /*          Physical Maximum (3000),    */
91 	0x26, 0x70, 0x17,   /*          Logical Maximum (6000),     */
92 	0x81, 0x02,         /*          Input (Variable),           */
93 	0xB4,               /*          Pop,                        */
94 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
95 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
96 	0x81, 0x02,         /*          Input (Variable),           */
97 	0xC0,               /*      End Collection,                 */
98 	0xC0                /*  End Collection                      */
99 };
100 
101 /*
102  * See Slim Tablet 12.1 inch description, device and HID report descriptors at
103  * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Slim_Tablet_12.1%22
104  */
105 
106 /* Size of the original report descriptor of Slim Tablet 12.1 inch */
107 #define SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE	269
108 
109 /* Fixed Slim Tablet 12.1 inch descriptor */
110 static __u8 slim_tablet_12_1_inch_rdesc_fixed[] = {
111 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
112 	0x09, 0x02,         /*  Usage (Pen),                        */
113 	0xA1, 0x01,         /*  Collection (Application),           */
114 	0x85, 0x10,         /*      Report ID (16),                 */
115 	0x09, 0x20,         /*      Usage (Stylus),                 */
116 	0xA0,               /*      Collection (Physical),          */
117 	0x09, 0x42,         /*          Usage (Tip Switch),         */
118 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
119 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
120 	0x15, 0x01,         /*          Logical Minimum (1),        */
121 	0x25, 0x03,         /*          Logical Maximum (3),        */
122 	0x75, 0x04,         /*          Report Size (4),            */
123 	0x95, 0x01,         /*          Report Count (1),           */
124 	0x80,               /*          Input,                      */
125 	0x09, 0x32,         /*          Usage (In Range),           */
126 	0x14,               /*          Logical Minimum (0),        */
127 	0x25, 0x01,         /*          Logical Maximum (1),        */
128 	0x75, 0x01,         /*          Report Size (1),            */
129 	0x95, 0x01,         /*          Report Count (1),           */
130 	0x81, 0x02,         /*          Input (Variable),           */
131 	0x95, 0x03,         /*          Report Count (3),           */
132 	0x81, 0x03,         /*          Input (Constant, Variable), */
133 	0x75, 0x10,         /*          Report Size (16),           */
134 	0x95, 0x01,         /*          Report Count (1),           */
135 	0x14,               /*          Logical Minimum (0),        */
136 	0xA4,               /*          Push,                       */
137 	0x05, 0x01,         /*          Usage Page (Desktop),       */
138 	0x65, 0x13,         /*          Unit (Inch),                */
139 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
140 	0x34,               /*          Physical Minimum (0),       */
141 	0x09, 0x30,         /*          Usage (X),                  */
142 	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
143 	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
144 	0x81, 0x02,         /*          Input (Variable),           */
145 	0x09, 0x31,         /*          Usage (Y),                  */
146 	0x46, 0x6A, 0x18,   /*          Physical Maximum (6250),    */
147 	0x26, 0xD4, 0x30,   /*          Logical Maximum (12500),    */
148 	0x81, 0x02,         /*          Input (Variable),           */
149 	0xB4,               /*          Pop,                        */
150 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
151 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
152 	0x81, 0x02,         /*          Input (Variable),           */
153 	0xC0,               /*      End Collection,                 */
154 	0xC0                /*  End Collection                      */
155 };
156 
157 /*
158  * See Q Pad description, device and HID report descriptors at
159  * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Q_Pad
160  */
161 
162 /* Size of the original report descriptor of Q Pad */
163 #define Q_PAD_RDESC_ORIG_SIZE	241
164 
165 /* Fixed Q Pad descriptor */
166 static __u8 q_pad_rdesc_fixed[] = {
167 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
168 	0x09, 0x02,         /*  Usage (Pen),                        */
169 	0xA1, 0x01,         /*  Collection (Application),           */
170 	0x85, 0x10,         /*      Report ID (16),                 */
171 	0x09, 0x20,         /*      Usage (Stylus),                 */
172 	0xA0,               /*      Collection (Physical),          */
173 	0x09, 0x42,         /*          Usage (Tip Switch),         */
174 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
175 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
176 	0x15, 0x01,         /*          Logical Minimum (1),        */
177 	0x25, 0x03,         /*          Logical Maximum (3),        */
178 	0x75, 0x04,         /*          Report Size (4),            */
179 	0x95, 0x01,         /*          Report Count (1),           */
180 	0x80,               /*          Input,                      */
181 	0x09, 0x32,         /*          Usage (In Range),           */
182 	0x14,               /*          Logical Minimum (0),        */
183 	0x25, 0x01,         /*          Logical Maximum (1),        */
184 	0x75, 0x01,         /*          Report Size (1),            */
185 	0x95, 0x01,         /*          Report Count (1),           */
186 	0x81, 0x02,         /*          Input (Variable),           */
187 	0x95, 0x03,         /*          Report Count (3),           */
188 	0x81, 0x03,         /*          Input (Constant, Variable), */
189 	0x75, 0x10,         /*          Report Size (16),           */
190 	0x95, 0x01,         /*          Report Count (1),           */
191 	0x14,               /*          Logical Minimum (0),        */
192 	0xA4,               /*          Push,                       */
193 	0x05, 0x01,         /*          Usage Page (Desktop),       */
194 	0x65, 0x13,         /*          Unit (Inch),                */
195 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
196 	0x34,               /*          Physical Minimum (0),       */
197 	0x09, 0x30,         /*          Usage (X),                  */
198 	0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
199 	0x26, 0x00, 0x30,   /*          Logical Maximum (12288),    */
200 	0x81, 0x02,         /*          Input (Variable),           */
201 	0x09, 0x31,         /*          Usage (Y),                  */
202 	0x46, 0x94, 0x11,   /*          Physical Maximum (4500),    */
203 	0x26, 0x00, 0x24,   /*          Logical Maximum (9216),     */
204 	0x81, 0x02,         /*          Input (Variable),           */
205 	0xB4,               /*          Pop,                        */
206 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
207 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
208 	0x81, 0x02,         /*          Input (Variable),           */
209 	0xC0,               /*      End Collection,                 */
210 	0xC0                /*  End Collection                      */
211 };
212 
213 /*
214  * See description, device and HID report descriptors of tablet with PID 0038 at
215  * http://sf.net/apps/mediawiki/digimend/?title=Waltop_PID_0038
216  */
217 
218 /* Size of the original report descriptor of tablet with PID 0038 */
219 #define PID_0038_RDESC_ORIG_SIZE	241
220 
221 /*
222  * Fixed report descriptor for tablet with PID 0038.
223  */
224 static __u8 pid_0038_rdesc_fixed[] = {
225 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
226 	0x09, 0x02,         /*  Usage (Pen),                        */
227 	0xA1, 0x01,         /*  Collection (Application),           */
228 	0x85, 0x10,         /*      Report ID (16),                 */
229 	0x09, 0x20,         /*      Usage (Stylus),                 */
230 	0xA0,               /*      Collection (Physical),          */
231 	0x09, 0x42,         /*          Usage (Tip Switch),         */
232 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
233 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
234 	0x15, 0x01,         /*          Logical Minimum (1),        */
235 	0x25, 0x03,         /*          Logical Maximum (3),        */
236 	0x75, 0x04,         /*          Report Size (4),            */
237 	0x95, 0x01,         /*          Report Count (1),           */
238 	0x80,               /*          Input,                      */
239 	0x09, 0x32,         /*          Usage (In Range),           */
240 	0x14,               /*          Logical Minimum (0),        */
241 	0x25, 0x01,         /*          Logical Maximum (1),        */
242 	0x75, 0x01,         /*          Report Size (1),            */
243 	0x95, 0x01,         /*          Report Count (1),           */
244 	0x81, 0x02,         /*          Input (Variable),           */
245 	0x95, 0x03,         /*          Report Count (3),           */
246 	0x81, 0x03,         /*          Input (Constant, Variable), */
247 	0x75, 0x10,         /*          Report Size (16),           */
248 	0x95, 0x01,         /*          Report Count (1),           */
249 	0x14,               /*          Logical Minimum (0),        */
250 	0xA4,               /*          Push,                       */
251 	0x05, 0x01,         /*          Usage Page (Desktop),       */
252 	0x65, 0x13,         /*          Unit (Inch),                */
253 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
254 	0x34,               /*          Physical Minimum (0),       */
255 	0x09, 0x30,         /*          Usage (X),                  */
256 	0x46, 0x2E, 0x22,   /*          Physical Maximum (8750),    */
257 	0x26, 0x00, 0x46,   /*          Logical Maximum (17920),    */
258 	0x81, 0x02,         /*          Input (Variable),           */
259 	0x09, 0x31,         /*          Usage (Y),                  */
260 	0x46, 0x82, 0x14,   /*          Physical Maximum (5250),    */
261 	0x26, 0x00, 0x2A,   /*          Logical Maximum (10752),    */
262 	0x81, 0x02,         /*          Input (Variable),           */
263 	0xB4,               /*          Pop,                        */
264 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
265 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
266 	0x81, 0x02,         /*          Input (Variable),           */
267 	0xC0,               /*      End Collection,                 */
268 	0xC0                /*  End Collection                      */
269 };
270 
271 /*
272  * See Media Tablet 10.6 inch description, device and HID report descriptors at
273  * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Media_Tablet_10.6%22
274  */
275 
276 /* Size of the original report descriptor of Media Tablet 10.6 inch */
277 #define MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE	300
278 
279 /* Fixed Media Tablet 10.6 inch descriptor */
280 static __u8 media_tablet_10_6_inch_rdesc_fixed[] = {
281 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
282 	0x09, 0x02,         /*  Usage (Pen),                        */
283 	0xA1, 0x01,         /*  Collection (Application),           */
284 	0x85, 0x10,         /*      Report ID (16),                 */
285 	0x09, 0x20,         /*      Usage (Stylus),                 */
286 	0xA0,               /*      Collection (Physical),          */
287 	0x09, 0x42,         /*          Usage (Tip Switch),         */
288 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
289 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
290 	0x15, 0x01,         /*          Logical Minimum (1),        */
291 	0x25, 0x03,         /*          Logical Maximum (3),        */
292 	0x75, 0x04,         /*          Report Size (4),            */
293 	0x95, 0x01,         /*          Report Count (1),           */
294 	0x80,               /*          Input,                      */
295 	0x75, 0x01,         /*          Report Size (1),            */
296 	0x09, 0x32,         /*          Usage (In Range),           */
297 	0x14,               /*          Logical Minimum (0),        */
298 	0x25, 0x01,         /*          Logical Maximum (1),        */
299 	0x95, 0x01,         /*          Report Count (1),           */
300 	0x81, 0x02,         /*          Input (Variable),           */
301 	0x95, 0x03,         /*          Report Count (3),           */
302 	0x81, 0x03,         /*          Input (Constant, Variable), */
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 	0x65, 0x13,         /*          Unit (Inch),                */
309 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
310 	0x34,               /*          Physical Minimum (0),       */
311 	0x09, 0x30,         /*          Usage (X),                  */
312 	0x46, 0x28, 0x23,   /*          Physical Maximum (9000),    */
313 	0x26, 0x50, 0x46,   /*          Logical Maximum (18000),    */
314 	0x81, 0x02,         /*          Input (Variable),           */
315 	0x09, 0x31,         /*          Usage (Y),                  */
316 	0x46, 0x7C, 0x15,   /*          Physical Maximum (5500),    */
317 	0x26, 0xF8, 0x2A,   /*          Logical Maximum (11000),    */
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, 0x01,         /*      Report ID (1),                  */
329 	0x09, 0x01,         /*      Usage (Pointer),                */
330 	0xA0,               /*      Collection (Physical),          */
331 	0x75, 0x08,         /*          Report Size (8),            */
332 	0x95, 0x03,         /*          Report Count (3),           */
333 	0x81, 0x03,         /*          Input (Constant, Variable), */
334 	0x95, 0x02,         /*          Report Count (2),           */
335 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
336 	0x25, 0x01,         /*          Logical Maximum (1),        */
337 	0x09, 0x38,         /*          Usage (Wheel),              */
338 	0x0B, 0x38, 0x02,   /*          Usage (Consumer AC Pan),    */
339 		0x0C, 0x00,
340 	0x81, 0x06,         /*          Input (Variable, Relative), */
341 	0x95, 0x02,         /*          Report Count (2),           */
342 	0x81, 0x03,         /*          Input (Constant, Variable), */
343 	0xC0,               /*      End Collection,                 */
344 	0xC0,               /*  End Collection,                     */
345 	0x05, 0x0C,         /*  Usage Page (Consumer),              */
346 	0x09, 0x01,         /*  Usage (Consumer Control),           */
347 	0xA1, 0x01,         /*  Collection (Application),           */
348 	0x85, 0x0D,         /*      Report ID (13),                 */
349 	0x95, 0x01,         /*      Report Count (1),               */
350 	0x75, 0x10,         /*      Report Size (16),               */
351 	0x81, 0x03,         /*      Input (Constant, Variable),     */
352 	0x0A, 0x2F, 0x02,   /*      Usage (AC Zoom),                */
353 	0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
354 	0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
355 	0x09, 0xB6,         /*      Usage (Scan Previous Track),    */
356 	0x09, 0xB5,         /*      Usage (Scan Next Track),        */
357 	0x08,               /*      Usage (00h),                    */
358 	0x08,               /*      Usage (00h),                    */
359 	0x08,               /*      Usage (00h),                    */
360 	0x08,               /*      Usage (00h),                    */
361 	0x08,               /*      Usage (00h),                    */
362 	0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
363 	0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
364 	0x15, 0x0C,         /*      Logical Minimum (12),           */
365 	0x25, 0x17,         /*      Logical Maximum (23),           */
366 	0x75, 0x05,         /*      Report Size (5),                */
367 	0x80,               /*      Input,                          */
368 	0x75, 0x03,         /*      Report Size (3),                */
369 	0x81, 0x03,         /*      Input (Constant, Variable),     */
370 	0x75, 0x20,         /*      Report Size (32),               */
371 	0x81, 0x03,         /*      Input (Constant, Variable),     */
372 	0xC0,               /*  End Collection,                     */
373 	0x09, 0x01,         /*  Usage (Consumer Control),           */
374 	0xA1, 0x01,         /*  Collection (Application),           */
375 	0x85, 0x0C,         /*      Report ID (12),                 */
376 	0x75, 0x01,         /*      Report Size (1),                */
377 	0x09, 0xE9,         /*      Usage (Volume Inc),             */
378 	0x09, 0xEA,         /*      Usage (Volume Dec),             */
379 	0x09, 0xE2,         /*      Usage (Mute),                   */
380 	0x14,               /*      Logical Minimum (0),            */
381 	0x25, 0x01,         /*      Logical Maximum (1),            */
382 	0x95, 0x03,         /*      Report Count (3),               */
383 	0x81, 0x06,         /*      Input (Variable, Relative),     */
384 	0x95, 0x35,         /*      Report Count (53),              */
385 	0x81, 0x03,         /*      Input (Constant, Variable),     */
386 	0xC0                /*  End Collection                      */
387 };
388 
389 /*
390  * See Media Tablet 14.1 inch description, device and HID report descriptors at
391  * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Media_Tablet_14.1%22
392  */
393 
394 /* Size of the original report descriptor of Media Tablet 14.1 inch */
395 #define MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE	309
396 
397 /* Fixed Media Tablet 14.1 inch descriptor */
398 static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {
399 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
400 	0x09, 0x02,         /*  Usage (Pen),                        */
401 	0xA1, 0x01,         /*  Collection (Application),           */
402 	0x85, 0x10,         /*      Report ID (16),                 */
403 	0x09, 0x20,         /*      Usage (Stylus),                 */
404 	0xA0,               /*      Collection (Physical),          */
405 	0x09, 0x42,         /*          Usage (Tip Switch),         */
406 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
407 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
408 	0x15, 0x01,         /*          Logical Minimum (1),        */
409 	0x25, 0x03,         /*          Logical Maximum (3),        */
410 	0x75, 0x04,         /*          Report Size (4),            */
411 	0x95, 0x01,         /*          Report Count (1),           */
412 	0x80,               /*          Input,                      */
413 	0x75, 0x01,         /*          Report Size (1),            */
414 	0x09, 0x32,         /*          Usage (In Range),           */
415 	0x14,               /*          Logical Minimum (0),        */
416 	0x25, 0x01,         /*          Logical Maximum (1),        */
417 	0x95, 0x01,         /*          Report Count (1),           */
418 	0x81, 0x02,         /*          Input (Variable),           */
419 	0x95, 0x03,         /*          Report Count (3),           */
420 	0x81, 0x03,         /*          Input (Constant, Variable), */
421 	0x75, 0x10,         /*          Report Size (16),           */
422 	0x95, 0x01,         /*          Report Count (1),           */
423 	0x14,               /*          Logical Minimum (0),        */
424 	0xA4,               /*          Push,                       */
425 	0x05, 0x01,         /*          Usage Page (Desktop),       */
426 	0x65, 0x13,         /*          Unit (Inch),                */
427 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
428 	0x34,               /*          Physical Minimum (0),       */
429 	0x09, 0x30,         /*          Usage (X),                  */
430 	0x46, 0xE0, 0x2E,   /*          Physical Maximum (12000),   */
431 	0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),    */
432 	0x81, 0x02,         /*          Input (Variable),           */
433 	0x09, 0x31,         /*          Usage (Y),                  */
434 	0x46, 0x52, 0x1C,   /*          Physical Maximum (7250),    */
435 	0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),    */
436 	0x81, 0x02,         /*          Input (Variable),           */
437 	0xB4,               /*          Pop,                        */
438 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
439 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
440 	0x81, 0x02,         /*          Input (Variable),           */
441 	0xC0,               /*      End Collection,                 */
442 	0xC0,               /*  End Collection,                     */
443 	0x05, 0x01,         /*  Usage Page (Desktop),               */
444 	0x09, 0x02,         /*  Usage (Mouse),                      */
445 	0xA1, 0x01,         /*  Collection (Application),           */
446 	0x85, 0x01,         /*      Report ID (1),                  */
447 	0x09, 0x01,         /*      Usage (Pointer),                */
448 	0xA0,               /*      Collection (Physical),          */
449 	0x75, 0x08,         /*          Report Size (8),            */
450 	0x95, 0x03,         /*          Report Count (3),           */
451 	0x81, 0x03,         /*          Input (Constant, Variable), */
452 	0x95, 0x02,         /*          Report Count (2),           */
453 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
454 	0x25, 0x01,         /*          Logical Maximum (1),        */
455 	0x09, 0x38,         /*          Usage (Wheel),              */
456 	0x0B, 0x38, 0x02,   /*          Usage (Consumer AC Pan),    */
457 		0x0C, 0x00,
458 	0x81, 0x06,         /*          Input (Variable, Relative), */
459 	0xC0,               /*      End Collection,                 */
460 	0xC0,               /*  End Collection,                     */
461 	0x05, 0x0C,         /*  Usage Page (Consumer),              */
462 	0x09, 0x01,         /*  Usage (Consumer Control),           */
463 	0xA1, 0x01,         /*  Collection (Application),           */
464 	0x85, 0x0D,         /*      Report ID (13),                 */
465 	0x95, 0x01,         /*      Report Count (1),               */
466 	0x75, 0x10,         /*      Report Size (16),               */
467 	0x81, 0x03,         /*      Input (Constant, Variable),     */
468 	0x0A, 0x2F, 0x02,   /*      Usage (AC Zoom),                */
469 	0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
470 	0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
471 	0x09, 0xB6,         /*      Usage (Scan Previous Track),    */
472 	0x09, 0xB5,         /*      Usage (Scan Next Track),        */
473 	0x08,               /*      Usage (00h),                    */
474 	0x08,               /*      Usage (00h),                    */
475 	0x08,               /*      Usage (00h),                    */
476 	0x08,               /*      Usage (00h),                    */
477 	0x08,               /*      Usage (00h),                    */
478 	0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
479 	0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
480 	0x15, 0x0C,         /*      Logical Minimum (12),           */
481 	0x25, 0x17,         /*      Logical Maximum (23),           */
482 	0x75, 0x05,         /*      Report Size (5),                */
483 	0x80,               /*      Input,                          */
484 	0x75, 0x03,         /*      Report Size (3),                */
485 	0x81, 0x03,         /*      Input (Constant, Variable),     */
486 	0x75, 0x20,         /*      Report Size (32),               */
487 	0x81, 0x03,         /*      Input (Constant, Variable),     */
488 	0xC0,               /*  End Collection,                     */
489 	0x09, 0x01,         /*  Usage (Consumer Control),           */
490 	0xA1, 0x01,         /*  Collection (Application),           */
491 	0x85, 0x0C,         /*      Report ID (12),                 */
492 	0x75, 0x01,         /*      Report Size (1),                */
493 	0x09, 0xE9,         /*      Usage (Volume Inc),             */
494 	0x09, 0xEA,         /*      Usage (Volume Dec),             */
495 	0x09, 0xE2,         /*      Usage (Mute),                   */
496 	0x14,               /*      Logical Minimum (0),            */
497 	0x25, 0x01,         /*      Logical Maximum (1),            */
498 	0x95, 0x03,         /*      Report Count (3),               */
499 	0x81, 0x06,         /*      Input (Variable, Relative),     */
500 	0x75, 0x05,         /*      Report Size (5),                */
501 	0x81, 0x03,         /*      Input (Constant, Variable),     */
502 	0xC0                /*  End Collection                      */
503 };
504 
505 /*
506  * See Sirius Battery Free Tablet description, device and HID report descriptors
507  * at
508  * http://sf.net/apps/mediawiki/digimend/?title=Waltop_Sirius_Battery_Free_Tablet
509  */
510 
511 /* Size of the original report descriptor of Sirius Battery Free Tablet */
512 #define SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE	335
513 
514 /* Fixed Sirius Battery Free Tablet descriptor */
515 static __u8 sirius_battery_free_tablet_rdesc_fixed[] = {
516 	0x05, 0x0D,         /*  Usage Page (Digitizer),             */
517 	0x09, 0x02,         /*  Usage (Pen),                        */
518 	0xA1, 0x01,         /*  Collection (Application),           */
519 	0x85, 0x10,         /*      Report ID (16),                 */
520 	0x09, 0x20,         /*      Usage (Stylus),                 */
521 	0xA0,               /*      Collection (Physical),          */
522 	0x95, 0x01,         /*          Report Count (1),           */
523 	0x15, 0x01,         /*          Logical Minimum (1),        */
524 	0x25, 0x03,         /*          Logical Maximum (3),        */
525 	0x75, 0x02,         /*          Report Size (2),            */
526 	0x09, 0x42,         /*          Usage (Tip Switch),         */
527 	0x09, 0x44,         /*          Usage (Barrel Switch),      */
528 	0x09, 0x46,         /*          Usage (Tablet Pick),        */
529 	0x80,               /*          Input,                      */
530 	0x14,               /*          Logical Minimum (0),        */
531 	0x25, 0x01,         /*          Logical Maximum (1),        */
532 	0x75, 0x01,         /*          Report Size (1),            */
533 	0x09, 0x3C,         /*          Usage (Invert),             */
534 	0x81, 0x02,         /*          Input (Variable),           */
535 	0x81, 0x03,         /*          Input (Constant, Variable), */
536 	0x09, 0x32,         /*          Usage (In Range),           */
537 	0x81, 0x02,         /*          Input (Variable),           */
538 	0x95, 0x03,         /*          Report Count (3),           */
539 	0x81, 0x03,         /*          Input (Constant, Variable), */
540 	0xA4,               /*          Push,                       */
541 	0x05, 0x01,         /*          Usage Page (Desktop),       */
542 	0x55, 0xFD,         /*          Unit Exponent (-3),         */
543 	0x65, 0x13,         /*          Unit (Inch),                */
544 	0x34,               /*          Physical Minimum (0),       */
545 	0x14,               /*          Logical Minimum (0),        */
546 	0x75, 0x10,         /*          Report Size (16),           */
547 	0x95, 0x01,         /*          Report Count (1),           */
548 	0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
549 	0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
550 	0x09, 0x30,         /*          Usage (X),                  */
551 	0x81, 0x02,         /*          Input (Variable),           */
552 	0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
553 	0x26, 0xE0, 0x2E,   /*          Logical Maximum (12000),    */
554 	0x09, 0x31,         /*          Usage (Y),                  */
555 	0x81, 0x02,         /*          Input (Variable),           */
556 	0xB4,               /*          Pop,                        */
557 	0x75, 0x10,         /*          Report Size (16),           */
558 	0x95, 0x01,         /*          Report Count (1),           */
559 	0x14,               /*          Logical Minimum (0),        */
560 	0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
561 	0x09, 0x30,         /*          Usage (Tip Pressure),       */
562 	0x81, 0x02,         /*          Input (Variable),           */
563 	0xA4,               /*          Push,                       */
564 	0x55, 0xFE,         /*          Unit Exponent (-2),         */
565 	0x65, 0x12,         /*          Unit (Radians),             */
566 	0x35, 0x97,         /*          Physical Minimum (-105),    */
567 	0x45, 0x69,         /*          Physical Maximum (105),     */
568 	0x15, 0x97,         /*          Logical Minimum (-105),     */
569 	0x25, 0x69,         /*          Logical Maximum (105),      */
570 	0x75, 0x08,         /*          Report Size (8),            */
571 	0x95, 0x02,         /*          Report Count (2),           */
572 	0x09, 0x3D,         /*          Usage (X Tilt),             */
573 	0x09, 0x3E,         /*          Usage (Y Tilt),             */
574 	0x81, 0x02,         /*          Input (Variable),           */
575 	0xB4,               /*          Pop,                        */
576 	0xC0,               /*      End Collection,                 */
577 	0xC0,               /*  End Collection,                     */
578 	0x05, 0x01,         /*  Usage Page (Desktop),               */
579 	0x09, 0x02,         /*  Usage (Mouse),                      */
580 	0xA1, 0x01,         /*  Collection (Application),           */
581 	0x85, 0x01,         /*      Report ID (1),                  */
582 	0x09, 0x01,         /*      Usage (Pointer),                */
583 	0xA0,               /*      Collection (Physical),          */
584 	0x75, 0x08,         /*          Report Size (8),            */
585 	0x95, 0x03,         /*          Report Count (3),           */
586 	0x81, 0x03,         /*          Input (Constant, Variable), */
587 	0x09, 0x38,         /*          Usage (Wheel),              */
588 	0x15, 0xFF,         /*          Logical Minimum (-1),       */
589 	0x25, 0x01,         /*          Logical Maximum (1),        */
590 	0x75, 0x08,         /*          Report Size (8),            */
591 	0x95, 0x01,         /*          Report Count (1),           */
592 	0x81, 0x06,         /*          Input (Variable, Relative), */
593 	0x75, 0x08,         /*          Report Size (8),            */
594 	0x95, 0x03,         /*          Report Count (3),           */
595 	0x81, 0x03,         /*          Input (Constant, Variable), */
596 	0xC0,               /*      End Collection,                 */
597 	0xC0,               /*  End Collection,                     */
598 	0x05, 0x01,         /*  Usage Page (Desktop),               */
599 	0x09, 0x06,         /*  Usage (Keyboard),                   */
600 	0xA1, 0x01,         /*  Collection (Application),           */
601 	0x85, 0x0D,         /*      Report ID (13),                 */
602 	0x05, 0x07,         /*      Usage Page (Keyboard),          */
603 	0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */
604 	0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */
605 	0x14,               /*      Logical Minimum (0),            */
606 	0x25, 0x01,         /*      Logical Maximum (1),            */
607 	0x75, 0x01,         /*      Report Size (1),                */
608 	0x95, 0x08,         /*      Report Count (8),               */
609 	0x81, 0x02,         /*      Input (Variable),               */
610 	0x75, 0x08,         /*      Report Size (8),                */
611 	0x95, 0x01,         /*      Report Count (1),               */
612 	0x81, 0x01,         /*      Input (Constant),               */
613 	0x18,               /*      Usage Minimum (None),           */
614 	0x29, 0x65,         /*      Usage Maximum (KB Application), */
615 	0x14,               /*      Logical Minimum (0),            */
616 	0x25, 0x65,         /*      Logical Maximum (101),          */
617 	0x75, 0x08,         /*      Report Size (8),                */
618 	0x95, 0x05,         /*      Report Count (5),               */
619 	0x80,               /*      Input,                          */
620 	0xC0,               /*  End Collection,                     */
621 	0x05, 0x0C,         /*  Usage Page (Consumer),              */
622 	0x09, 0x01,         /*  Usage (Consumer Control),           */
623 	0xA1, 0x01,         /*  Collection (Application),           */
624 	0x85, 0x0C,         /*      Report ID (12),                 */
625 	0x09, 0xE9,         /*      Usage (Volume Inc),             */
626 	0x09, 0xEA,         /*      Usage (Volume Dec),             */
627 	0x14,               /*      Logical Minimum (0),            */
628 	0x25, 0x01,         /*      Logical Maximum (1),            */
629 	0x75, 0x01,         /*      Report Size (1),                */
630 	0x95, 0x02,         /*      Report Count (2),               */
631 	0x81, 0x02,         /*      Input (Variable),               */
632 	0x75, 0x06,         /*      Report Size (6),                */
633 	0x95, 0x01,         /*      Report Count (1),               */
634 	0x81, 0x03,         /*      Input (Constant, Variable),     */
635 	0x75, 0x10,         /*      Report Size (16),               */
636 	0x95, 0x03,         /*      Report Count (3),               */
637 	0x81, 0x03,         /*      Input (Constant, Variable),     */
638 	0xC0                /*  End Collection                      */
639 };
640 
641 static int waltop_probe(struct hid_device *hdev,
642 			const struct hid_device_id *id)
643 {
644 	int ret;
645 
646 	ret = hid_parse(hdev);
647 	if (ret) {
648 		hid_err(hdev, "parse failed\n");
649 		goto err;
650 	}
651 
652 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
653 	if (ret) {
654 		hid_err(hdev, "hw start failed\n");
655 		goto err;
656 	}
657 
658 	return 0;
659 err:
660 	return ret;
661 }
662 
663 static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
664 		unsigned int *rsize)
665 {
666 	switch (hdev->product) {
667 	case USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH:
668 		if (*rsize == SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE) {
669 			rdesc = slim_tablet_5_8_inch_rdesc_fixed;
670 			*rsize = sizeof(slim_tablet_5_8_inch_rdesc_fixed);
671 		}
672 		break;
673 	case USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH:
674 		if (*rsize == SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE) {
675 			rdesc = slim_tablet_12_1_inch_rdesc_fixed;
676 			*rsize = sizeof(slim_tablet_12_1_inch_rdesc_fixed);
677 		}
678 		break;
679 	case USB_DEVICE_ID_WALTOP_Q_PAD:
680 		if (*rsize == Q_PAD_RDESC_ORIG_SIZE) {
681 			rdesc = q_pad_rdesc_fixed;
682 			*rsize = sizeof(q_pad_rdesc_fixed);
683 		}
684 		break;
685 	case USB_DEVICE_ID_WALTOP_PID_0038:
686 		if (*rsize == PID_0038_RDESC_ORIG_SIZE) {
687 			rdesc = pid_0038_rdesc_fixed;
688 			*rsize = sizeof(pid_0038_rdesc_fixed);
689 		}
690 		break;
691 	case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH:
692 		if (*rsize == MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE) {
693 			rdesc = media_tablet_10_6_inch_rdesc_fixed;
694 			*rsize = sizeof(media_tablet_10_6_inch_rdesc_fixed);
695 		}
696 		break;
697 	case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH:
698 		if (*rsize == MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE) {
699 			rdesc = media_tablet_14_1_inch_rdesc_fixed;
700 			*rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed);
701 		}
702 		break;
703 	case USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET:
704 		if (*rsize == SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE) {
705 			rdesc = sirius_battery_free_tablet_rdesc_fixed;
706 			*rsize = sizeof(sirius_battery_free_tablet_rdesc_fixed);
707 		}
708 		break;
709 	}
710 	return rdesc;
711 }
712 
713 static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report,
714 		     u8 *data, int size)
715 {
716 	/* If this is a pen input report */
717 	if (report->type == HID_INPUT_REPORT && report->id == 16 && size >= 8) {
718 		/*
719 		 * Ignore reported pressure when a barrel button is pressed,
720 		 * because it is rarely correct.
721 		 */
722 
723 		/* If a barrel button is pressed */
724 		if ((data[1] & 0xF) > 1) {
725 			/* Report zero pressure */
726 			data[6] = 0;
727 			data[7] = 0;
728 		}
729 	}
730 
731 	/* If this is a pen input report of Sirius Battery Free Tablet */
732 	if (hdev->product == USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET &&
733 	    report->type == HID_INPUT_REPORT &&
734 	    report->id == 16 &&
735 	    size == 10) {
736 		/*
737 		 * The tablet reports tilt as roughly sin(a)*21 (18 means 60
738 		 * degrees).
739 		 *
740 		 * This array stores angles as radians * 100, corresponding to
741 		 * reported values up to 60 degrees, as expected by userspace.
742 		 */
743 		static const s8 tilt_to_radians[] = {
744 			0, 5, 10, 14, 19, 24, 29, 34, 40, 45,
745 			50, 56, 62, 68, 74, 81, 88, 96, 105
746 		};
747 
748 		s8 tilt_x = (s8)data[8];
749 		s8 tilt_y = (s8)data[9];
750 		s8 sign_x = tilt_x >= 0 ? 1 : -1;
751 		s8 sign_y = tilt_y >= 0 ? 1 : -1;
752 
753 		tilt_x *= sign_x;
754 		tilt_y *= sign_y;
755 
756 		/*
757 		 * Reverse the Y Tilt direction to match the HID standard and
758 		 * userspace expectations. See HID Usage Tables v1.12 16.3.2
759 		 * Tilt Orientation.
760 		 */
761 		sign_y *= -1;
762 
763 		/*
764 		 * This effectively clamps reported tilt to 60 degrees - the
765 		 * range expected by userspace
766 		 */
767 		if (tilt_x > ARRAY_SIZE(tilt_to_radians) - 1)
768 			tilt_x = ARRAY_SIZE(tilt_to_radians) - 1;
769 		if (tilt_y > ARRAY_SIZE(tilt_to_radians) - 1)
770 			tilt_y = ARRAY_SIZE(tilt_to_radians) - 1;
771 
772 		data[8] = tilt_to_radians[tilt_x] * sign_x;
773 		data[9] = tilt_to_radians[tilt_y] * sign_y;
774 	}
775 
776 	return 0;
777 }
778 
779 static void waltop_remove(struct hid_device *hdev)
780 {
781 	hid_hw_stop(hdev);
782 }
783 
784 static const struct hid_device_id waltop_devices[] = {
785 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
786 				USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
787 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
788 				USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
789 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
790 				USB_DEVICE_ID_WALTOP_Q_PAD) },
791 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
792 				USB_DEVICE_ID_WALTOP_PID_0038) },
793 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
794 				USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
795 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
796 				USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
797 	{ HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
798 			 USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
799 	{ }
800 };
801 MODULE_DEVICE_TABLE(hid, waltop_devices);
802 
803 static struct hid_driver waltop_driver = {
804 	.name = "waltop",
805 	.id_table = waltop_devices,
806 	.probe = waltop_probe,
807 	.report_fixup = waltop_report_fixup,
808 	.raw_event = waltop_raw_event,
809 	.remove = waltop_remove,
810 };
811 
812 static int __init waltop_init(void)
813 {
814 	return hid_register_driver(&waltop_driver);
815 }
816 
817 static void __exit waltop_exit(void)
818 {
819 	hid_unregister_driver(&waltop_driver);
820 }
821 
822 module_init(waltop_init);
823 module_exit(waltop_exit);
824 MODULE_LICENSE("GPL");
825