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 | |