Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hid-waltop.c
Go to the documentation of this file.
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 __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
642  unsigned int *rsize)
643 {
644  switch (hdev->product) {
646  if (*rsize == SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE) {
647  rdesc = slim_tablet_5_8_inch_rdesc_fixed;
648  *rsize = sizeof(slim_tablet_5_8_inch_rdesc_fixed);
649  }
650  break;
653  rdesc = slim_tablet_12_1_inch_rdesc_fixed;
654  *rsize = sizeof(slim_tablet_12_1_inch_rdesc_fixed);
655  }
656  break;
658  if (*rsize == Q_PAD_RDESC_ORIG_SIZE) {
659  rdesc = q_pad_rdesc_fixed;
660  *rsize = sizeof(q_pad_rdesc_fixed);
661  }
662  break;
664  if (*rsize == PID_0038_RDESC_ORIG_SIZE) {
665  rdesc = pid_0038_rdesc_fixed;
666  *rsize = sizeof(pid_0038_rdesc_fixed);
667  }
668  break;
671  rdesc = media_tablet_10_6_inch_rdesc_fixed;
672  *rsize = sizeof(media_tablet_10_6_inch_rdesc_fixed);
673  }
674  break;
677  rdesc = media_tablet_14_1_inch_rdesc_fixed;
678  *rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed);
679  }
680  break;
683  rdesc = sirius_battery_free_tablet_rdesc_fixed;
684  *rsize = sizeof(sirius_battery_free_tablet_rdesc_fixed);
685  }
686  break;
687  }
688  return rdesc;
689 }
690 
691 static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report,
692  u8 *data, int size)
693 {
694  /* If this is a pen input report */
695  if (report->type == HID_INPUT_REPORT && report->id == 16 && size >= 8) {
696  /*
697  * Ignore reported pressure when a barrel button is pressed,
698  * because it is rarely correct.
699  */
700 
701  /* If a barrel button is pressed */
702  if ((data[1] & 0xF) > 1) {
703  /* Report zero pressure */
704  data[6] = 0;
705  data[7] = 0;
706  }
707  }
708 
709  /* If this is a pen input report of Sirius Battery Free Tablet */
711  report->type == HID_INPUT_REPORT &&
712  report->id == 16 &&
713  size == 10) {
714  /*
715  * The tablet reports tilt as roughly sin(a)*21 (18 means 60
716  * degrees).
717  *
718  * This array stores angles as radians * 100, corresponding to
719  * reported values up to 60 degrees, as expected by userspace.
720  */
721  static const s8 tilt_to_radians[] = {
722  0, 5, 10, 14, 19, 24, 29, 34, 40, 45,
723  50, 56, 62, 68, 74, 81, 88, 96, 105
724  };
725 
726  s8 tilt_x = (s8)data[8];
727  s8 tilt_y = (s8)data[9];
728  s8 sign_x = tilt_x >= 0 ? 1 : -1;
729  s8 sign_y = tilt_y >= 0 ? 1 : -1;
730 
731  tilt_x *= sign_x;
732  tilt_y *= sign_y;
733 
734  /*
735  * Reverse the Y Tilt direction to match the HID standard and
736  * userspace expectations. See HID Usage Tables v1.12 16.3.2
737  * Tilt Orientation.
738  */
739  sign_y *= -1;
740 
741  /*
742  * This effectively clamps reported tilt to 60 degrees - the
743  * range expected by userspace
744  */
745  if (tilt_x > ARRAY_SIZE(tilt_to_radians) - 1)
746  tilt_x = ARRAY_SIZE(tilt_to_radians) - 1;
747  if (tilt_y > ARRAY_SIZE(tilt_to_radians) - 1)
748  tilt_y = ARRAY_SIZE(tilt_to_radians) - 1;
749 
750  data[8] = tilt_to_radians[tilt_x] * sign_x;
751  data[9] = tilt_to_radians[tilt_y] * sign_y;
752  }
753 
754  return 0;
755 }
756 
757 static const struct hid_device_id waltop_devices[] = {
772  { }
773 };
774 MODULE_DEVICE_TABLE(hid, waltop_devices);
775 
776 static struct hid_driver waltop_driver = {
777  .name = "waltop",
778  .id_table = waltop_devices,
779  .report_fixup = waltop_report_fixup,
780  .raw_event = waltop_raw_event,
781 };
782 
783 static int __init waltop_init(void)
784 {
785  return hid_register_driver(&waltop_driver);
786 }
787 
788 static void __exit waltop_exit(void)
789 {
790  hid_unregister_driver(&waltop_driver);
791 }
792 
793 module_init(waltop_init);
794 module_exit(waltop_exit);
795 MODULE_LICENSE("GPL");