Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hid-uclogic.c
Go to the documentation of this file.
1 /*
2  * HID driver for UC-Logic 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 #include <linux/usb.h>
18 
19 #include "hid-ids.h"
20 
21 /*
22  * See WPXXXXU model descriptions, device and HID report descriptors at
23  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP4030U
24  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP5540U
25  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP8060U
26  */
27 
28 /* Size of the original descriptor of WPXXXXU tablets */
29 #define WPXXXXU_RDESC_ORIG_SIZE 212
30 
31 /* Fixed WP4030U report descriptor */
32 static __u8 wp4030u_rdesc_fixed[] = {
33  0x05, 0x0D, /* Usage Page (Digitizer), */
34  0x09, 0x02, /* Usage (Pen), */
35  0xA1, 0x01, /* Collection (Application), */
36  0x85, 0x09, /* Report ID (9), */
37  0x09, 0x20, /* Usage (Stylus), */
38  0xA0, /* Collection (Physical), */
39  0x75, 0x01, /* Report Size (1), */
40  0x09, 0x42, /* Usage (Tip Switch), */
41  0x09, 0x44, /* Usage (Barrel Switch), */
42  0x09, 0x46, /* Usage (Tablet Pick), */
43  0x14, /* Logical Minimum (0), */
44  0x25, 0x01, /* Logical Maximum (1), */
45  0x95, 0x03, /* Report Count (3), */
46  0x81, 0x02, /* Input (Variable), */
47  0x95, 0x05, /* Report Count (5), */
48  0x81, 0x01, /* Input (Constant), */
49  0x75, 0x10, /* Report Size (16), */
50  0x95, 0x01, /* Report Count (1), */
51  0x14, /* Logical Minimum (0), */
52  0xA4, /* Push, */
53  0x05, 0x01, /* Usage Page (Desktop), */
54  0x55, 0xFD, /* Unit Exponent (-3), */
55  0x65, 0x13, /* Unit (Inch), */
56  0x34, /* Physical Minimum (0), */
57  0x09, 0x30, /* Usage (X), */
58  0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */
59  0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
60  0x81, 0x02, /* Input (Variable), */
61  0x09, 0x31, /* Usage (Y), */
62  0x46, 0xB8, 0x0B, /* Physical Maximum (3000), */
63  0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
64  0x81, 0x02, /* Input (Variable), */
65  0xB4, /* Pop, */
66  0x09, 0x30, /* Usage (Tip Pressure), */
67  0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
68  0x81, 0x02, /* Input (Variable), */
69  0xC0, /* End Collection, */
70  0xC0 /* End Collection */
71 };
72 
73 /* Fixed WP5540U report descriptor */
74 static __u8 wp5540u_rdesc_fixed[] = {
75  0x05, 0x0D, /* Usage Page (Digitizer), */
76  0x09, 0x02, /* Usage (Pen), */
77  0xA1, 0x01, /* Collection (Application), */
78  0x85, 0x09, /* Report ID (9), */
79  0x09, 0x20, /* Usage (Stylus), */
80  0xA0, /* Collection (Physical), */
81  0x75, 0x01, /* Report Size (1), */
82  0x09, 0x42, /* Usage (Tip Switch), */
83  0x09, 0x44, /* Usage (Barrel Switch), */
84  0x09, 0x46, /* Usage (Tablet Pick), */
85  0x14, /* Logical Minimum (0), */
86  0x25, 0x01, /* Logical Maximum (1), */
87  0x95, 0x03, /* Report Count (3), */
88  0x81, 0x02, /* Input (Variable), */
89  0x95, 0x05, /* Report Count (5), */
90  0x81, 0x01, /* Input (Constant), */
91  0x75, 0x10, /* Report Size (16), */
92  0x95, 0x01, /* Report Count (1), */
93  0x14, /* Logical Minimum (0), */
94  0xA4, /* Push, */
95  0x05, 0x01, /* Usage Page (Desktop), */
96  0x55, 0xFD, /* Unit Exponent (-3), */
97  0x65, 0x13, /* Unit (Inch), */
98  0x34, /* Physical Minimum (0), */
99  0x09, 0x30, /* Usage (X), */
100  0x46, 0x7C, 0x15, /* Physical Maximum (5500), */
101  0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
102  0x81, 0x02, /* Input (Variable), */
103  0x09, 0x31, /* Usage (Y), */
104  0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */
105  0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
106  0x81, 0x02, /* Input (Variable), */
107  0xB4, /* Pop, */
108  0x09, 0x30, /* Usage (Tip Pressure), */
109  0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
110  0x81, 0x02, /* Input (Variable), */
111  0xC0, /* End Collection, */
112  0xC0, /* End Collection, */
113  0x05, 0x01, /* Usage Page (Desktop), */
114  0x09, 0x02, /* Usage (Mouse), */
115  0xA1, 0x01, /* Collection (Application), */
116  0x85, 0x08, /* Report ID (8), */
117  0x09, 0x01, /* Usage (Pointer), */
118  0xA0, /* Collection (Physical), */
119  0x75, 0x01, /* Report Size (1), */
120  0x05, 0x09, /* Usage Page (Button), */
121  0x19, 0x01, /* Usage Minimum (01h), */
122  0x29, 0x03, /* Usage Maximum (03h), */
123  0x14, /* Logical Minimum (0), */
124  0x25, 0x01, /* Logical Maximum (1), */
125  0x95, 0x03, /* Report Count (3), */
126  0x81, 0x02, /* Input (Variable), */
127  0x95, 0x05, /* Report Count (5), */
128  0x81, 0x01, /* Input (Constant), */
129  0x05, 0x01, /* Usage Page (Desktop), */
130  0x75, 0x08, /* Report Size (8), */
131  0x09, 0x30, /* Usage (X), */
132  0x09, 0x31, /* Usage (Y), */
133  0x15, 0x81, /* Logical Minimum (-127), */
134  0x25, 0x7F, /* Logical Maximum (127), */
135  0x95, 0x02, /* Report Count (2), */
136  0x81, 0x06, /* Input (Variable, Relative), */
137  0x09, 0x38, /* Usage (Wheel), */
138  0x15, 0xFF, /* Logical Minimum (-1), */
139  0x25, 0x01, /* Logical Maximum (1), */
140  0x95, 0x01, /* Report Count (1), */
141  0x81, 0x06, /* Input (Variable, Relative), */
142  0x81, 0x01, /* Input (Constant), */
143  0xC0, /* End Collection, */
144  0xC0 /* End Collection */
145 };
146 
147 /* Fixed WP8060U report descriptor */
148 static __u8 wp8060u_rdesc_fixed[] = {
149  0x05, 0x0D, /* Usage Page (Digitizer), */
150  0x09, 0x02, /* Usage (Pen), */
151  0xA1, 0x01, /* Collection (Application), */
152  0x85, 0x09, /* Report ID (9), */
153  0x09, 0x20, /* Usage (Stylus), */
154  0xA0, /* Collection (Physical), */
155  0x75, 0x01, /* Report Size (1), */
156  0x09, 0x42, /* Usage (Tip Switch), */
157  0x09, 0x44, /* Usage (Barrel Switch), */
158  0x09, 0x46, /* Usage (Tablet Pick), */
159  0x14, /* Logical Minimum (0), */
160  0x25, 0x01, /* Logical Maximum (1), */
161  0x95, 0x03, /* Report Count (3), */
162  0x81, 0x02, /* Input (Variable), */
163  0x95, 0x05, /* Report Count (5), */
164  0x81, 0x01, /* Input (Constant), */
165  0x75, 0x10, /* Report Size (16), */
166  0x95, 0x01, /* Report Count (1), */
167  0x14, /* Logical Minimum (0), */
168  0xA4, /* Push, */
169  0x05, 0x01, /* Usage Page (Desktop), */
170  0x55, 0xFD, /* Unit Exponent (-3), */
171  0x65, 0x13, /* Unit (Inch), */
172  0x34, /* Physical Minimum (0), */
173  0x09, 0x30, /* Usage (X), */
174  0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
175  0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
176  0x81, 0x02, /* Input (Variable), */
177  0x09, 0x31, /* Usage (Y), */
178  0x46, 0x70, 0x17, /* Physical Maximum (6000), */
179  0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
180  0x81, 0x02, /* Input (Variable), */
181  0xB4, /* Pop, */
182  0x09, 0x30, /* Usage (Tip Pressure), */
183  0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
184  0x81, 0x02, /* Input (Variable), */
185  0xC0, /* End Collection, */
186  0xC0, /* End Collection, */
187  0x05, 0x01, /* Usage Page (Desktop), */
188  0x09, 0x02, /* Usage (Mouse), */
189  0xA1, 0x01, /* Collection (Application), */
190  0x85, 0x08, /* Report ID (8), */
191  0x09, 0x01, /* Usage (Pointer), */
192  0xA0, /* Collection (Physical), */
193  0x75, 0x01, /* Report Size (1), */
194  0x05, 0x09, /* Usage Page (Button), */
195  0x19, 0x01, /* Usage Minimum (01h), */
196  0x29, 0x03, /* Usage Maximum (03h), */
197  0x14, /* Logical Minimum (0), */
198  0x25, 0x01, /* Logical Maximum (1), */
199  0x95, 0x03, /* Report Count (3), */
200  0x81, 0x02, /* Input (Variable), */
201  0x95, 0x05, /* Report Count (5), */
202  0x81, 0x01, /* Input (Constant), */
203  0x05, 0x01, /* Usage Page (Desktop), */
204  0x75, 0x08, /* Report Size (8), */
205  0x09, 0x30, /* Usage (X), */
206  0x09, 0x31, /* Usage (Y), */
207  0x15, 0x81, /* Logical Minimum (-127), */
208  0x25, 0x7F, /* Logical Maximum (127), */
209  0x95, 0x02, /* Report Count (2), */
210  0x81, 0x06, /* Input (Variable, Relative), */
211  0x09, 0x38, /* Usage (Wheel), */
212  0x15, 0xFF, /* Logical Minimum (-1), */
213  0x25, 0x01, /* Logical Maximum (1), */
214  0x95, 0x01, /* Report Count (1), */
215  0x81, 0x06, /* Input (Variable, Relative), */
216  0x81, 0x01, /* Input (Constant), */
217  0xC0, /* End Collection, */
218  0xC0 /* End Collection */
219 };
220 
221 /*
222  * See WP1062 description, device and HID report descriptors at
223  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP1062
224  */
225 
226 /* Size of the original descriptor of WP1062 tablet */
227 #define WP1062_RDESC_ORIG_SIZE 254
228 
229 /* Fixed WP1062 report descriptor */
230 static __u8 wp1062_rdesc_fixed[] = {
231  0x05, 0x0D, /* Usage Page (Digitizer), */
232  0x09, 0x02, /* Usage (Pen), */
233  0xA1, 0x01, /* Collection (Application), */
234  0x85, 0x09, /* Report ID (9), */
235  0x09, 0x20, /* Usage (Stylus), */
236  0xA0, /* Collection (Physical), */
237  0x75, 0x01, /* Report Size (1), */
238  0x09, 0x42, /* Usage (Tip Switch), */
239  0x09, 0x44, /* Usage (Barrel Switch), */
240  0x09, 0x46, /* Usage (Tablet Pick), */
241  0x14, /* Logical Minimum (0), */
242  0x25, 0x01, /* Logical Maximum (1), */
243  0x95, 0x03, /* Report Count (3), */
244  0x81, 0x02, /* Input (Variable), */
245  0x95, 0x04, /* Report Count (4), */
246  0x81, 0x01, /* Input (Constant), */
247  0x09, 0x32, /* Usage (In Range), */
248  0x95, 0x01, /* Report Count (1), */
249  0x81, 0x02, /* Input (Variable), */
250  0x75, 0x10, /* Report Size (16), */
251  0x95, 0x01, /* Report Count (1), */
252  0x14, /* Logical Minimum (0), */
253  0xA4, /* Push, */
254  0x05, 0x01, /* Usage Page (Desktop), */
255  0x55, 0xFD, /* Unit Exponent (-3), */
256  0x65, 0x13, /* Unit (Inch), */
257  0x34, /* Physical Minimum (0), */
258  0x09, 0x30, /* Usage (X), */
259  0x46, 0x10, 0x27, /* Physical Maximum (10000), */
260  0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
261  0x81, 0x02, /* Input (Variable), */
262  0x09, 0x31, /* Usage (Y), */
263  0x46, 0xB7, 0x19, /* Physical Maximum (6583), */
264  0x26, 0x6E, 0x33, /* Logical Maximum (13166), */
265  0x81, 0x02, /* Input (Variable), */
266  0xB4, /* Pop, */
267  0x09, 0x30, /* Usage (Tip Pressure), */
268  0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
269  0x81, 0x02, /* Input (Variable), */
270  0xC0, /* End Collection, */
271  0xC0 /* End Collection */
272 };
273 
274 /*
275  * See PF1209 description, device and HID report descriptors at
276  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_PF1209
277  */
278 
279 /* Size of the original descriptor of PF1209 tablet */
280 #define PF1209_RDESC_ORIG_SIZE 234
281 
282 /* Fixed PF1209 report descriptor */
283 static __u8 pf1209_rdesc_fixed[] = {
284  0x05, 0x0D, /* Usage Page (Digitizer), */
285  0x09, 0x02, /* Usage (Pen), */
286  0xA1, 0x01, /* Collection (Application), */
287  0x85, 0x09, /* Report ID (9), */
288  0x09, 0x20, /* Usage (Stylus), */
289  0xA0, /* Collection (Physical), */
290  0x75, 0x01, /* Report Size (1), */
291  0x09, 0x42, /* Usage (Tip Switch), */
292  0x09, 0x44, /* Usage (Barrel Switch), */
293  0x09, 0x46, /* Usage (Tablet Pick), */
294  0x14, /* Logical Minimum (0), */
295  0x25, 0x01, /* Logical Maximum (1), */
296  0x95, 0x03, /* Report Count (3), */
297  0x81, 0x02, /* Input (Variable), */
298  0x95, 0x05, /* Report Count (5), */
299  0x81, 0x01, /* Input (Constant), */
300  0x75, 0x10, /* Report Size (16), */
301  0x95, 0x01, /* Report Count (1), */
302  0x14, /* Logical Minimum (0), */
303  0xA4, /* Push, */
304  0x05, 0x01, /* Usage Page (Desktop), */
305  0x55, 0xFD, /* Unit Exponent (-3), */
306  0x65, 0x13, /* Unit (Inch), */
307  0x34, /* Physical Minimum (0), */
308  0x09, 0x30, /* Usage (X), */
309  0x46, 0xE0, 0x2E, /* Physical Maximum (12000), */
310  0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
311  0x81, 0x02, /* Input (Variable), */
312  0x09, 0x31, /* Usage (Y), */
313  0x46, 0x28, 0x23, /* Physical Maximum (9000), */
314  0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
315  0x81, 0x02, /* Input (Variable), */
316  0xB4, /* Pop, */
317  0x09, 0x30, /* Usage (Tip Pressure), */
318  0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
319  0x81, 0x02, /* Input (Variable), */
320  0xC0, /* End Collection, */
321  0xC0, /* End Collection, */
322  0x05, 0x01, /* Usage Page (Desktop), */
323  0x09, 0x02, /* Usage (Mouse), */
324  0xA1, 0x01, /* Collection (Application), */
325  0x85, 0x08, /* Report ID (8), */
326  0x09, 0x01, /* Usage (Pointer), */
327  0xA0, /* Collection (Physical), */
328  0x75, 0x01, /* Report Size (1), */
329  0x05, 0x09, /* Usage Page (Button), */
330  0x19, 0x01, /* Usage Minimum (01h), */
331  0x29, 0x03, /* Usage Maximum (03h), */
332  0x14, /* Logical Minimum (0), */
333  0x25, 0x01, /* Logical Maximum (1), */
334  0x95, 0x03, /* Report Count (3), */
335  0x81, 0x02, /* Input (Variable), */
336  0x95, 0x05, /* Report Count (5), */
337  0x81, 0x01, /* Input (Constant), */
338  0x05, 0x01, /* Usage Page (Desktop), */
339  0x75, 0x08, /* Report Size (8), */
340  0x09, 0x30, /* Usage (X), */
341  0x09, 0x31, /* Usage (Y), */
342  0x15, 0x81, /* Logical Minimum (-127), */
343  0x25, 0x7F, /* Logical Maximum (127), */
344  0x95, 0x02, /* Report Count (2), */
345  0x81, 0x06, /* Input (Variable, Relative), */
346  0x09, 0x38, /* Usage (Wheel), */
347  0x15, 0xFF, /* Logical Minimum (-1), */
348  0x25, 0x01, /* Logical Maximum (1), */
349  0x95, 0x01, /* Report Count (1), */
350  0x81, 0x06, /* Input (Variable, Relative), */
351  0x81, 0x01, /* Input (Constant), */
352  0xC0, /* End Collection, */
353  0xC0 /* End Collection */
354 };
355 
356 /*
357  * See TWHL850 description, device and HID report descriptors at
358  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Wireless_Tablet_TWHL850
359  */
360 
361 /* Size of the original descriptors of TWHL850 tablet */
362 #define TWHL850_RDESC_ORIG_SIZE0 182
363 #define TWHL850_RDESC_ORIG_SIZE1 161
364 #define TWHL850_RDESC_ORIG_SIZE2 92
365 
366 /* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
367 static __u8 twhl850_rdesc_fixed0[] = {
368  0x05, 0x0D, /* Usage Page (Digitizer), */
369  0x09, 0x02, /* Usage (Pen), */
370  0xA1, 0x01, /* Collection (Application), */
371  0x85, 0x09, /* Report ID (9), */
372  0x09, 0x20, /* Usage (Stylus), */
373  0xA0, /* Collection (Physical), */
374  0x14, /* Logical Minimum (0), */
375  0x25, 0x01, /* Logical Maximum (1), */
376  0x75, 0x01, /* Report Size (1), */
377  0x95, 0x03, /* Report Count (3), */
378  0x09, 0x42, /* Usage (Tip Switch), */
379  0x09, 0x44, /* Usage (Barrel Switch), */
380  0x09, 0x46, /* Usage (Tablet Pick), */
381  0x81, 0x02, /* Input (Variable), */
382  0x81, 0x03, /* Input (Constant, Variable), */
383  0x95, 0x01, /* Report Count (1), */
384  0x09, 0x32, /* Usage (In Range), */
385  0x81, 0x02, /* Input (Variable), */
386  0x81, 0x03, /* Input (Constant, Variable), */
387  0x75, 0x10, /* Report Size (16), */
388  0xA4, /* Push, */
389  0x05, 0x01, /* Usage Page (Desktop), */
390  0x65, 0x13, /* Unit (Inch), */
391  0x55, 0xFD, /* Unit Exponent (-3), */
392  0x34, /* Physical Minimum (0), */
393  0x09, 0x30, /* Usage (X), */
394  0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
395  0x26, 0x00, 0x7D, /* Logical Maximum (32000), */
396  0x81, 0x02, /* Input (Variable), */
397  0x09, 0x31, /* Usage (Y), */
398  0x46, 0x88, 0x13, /* Physical Maximum (5000), */
399  0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
400  0x81, 0x02, /* Input (Variable), */
401  0xB4, /* Pop, */
402  0x09, 0x30, /* Usage (Tip Pressure), */
403  0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
404  0x81, 0x02, /* Input (Variable), */
405  0xC0, /* End Collection, */
406  0xC0 /* End Collection */
407 };
408 
409 /* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
410 static __u8 twhl850_rdesc_fixed1[] = {
411  0x05, 0x01, /* Usage Page (Desktop), */
412  0x09, 0x02, /* Usage (Mouse), */
413  0xA1, 0x01, /* Collection (Application), */
414  0x85, 0x01, /* Report ID (1), */
415  0x09, 0x01, /* Usage (Pointer), */
416  0xA0, /* Collection (Physical), */
417  0x05, 0x09, /* Usage Page (Button), */
418  0x75, 0x01, /* Report Size (1), */
419  0x95, 0x03, /* Report Count (3), */
420  0x19, 0x01, /* Usage Minimum (01h), */
421  0x29, 0x03, /* Usage Maximum (03h), */
422  0x14, /* Logical Minimum (0), */
423  0x25, 0x01, /* Logical Maximum (1), */
424  0x81, 0x02, /* Input (Variable), */
425  0x95, 0x05, /* Report Count (5), */
426  0x81, 0x03, /* Input (Constant, Variable), */
427  0x05, 0x01, /* Usage Page (Desktop), */
428  0x09, 0x30, /* Usage (X), */
429  0x09, 0x31, /* Usage (Y), */
430  0x16, 0x00, 0x80, /* Logical Minimum (-32768), */
431  0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
432  0x75, 0x10, /* Report Size (16), */
433  0x95, 0x02, /* Report Count (2), */
434  0x81, 0x06, /* Input (Variable, Relative), */
435  0x09, 0x38, /* Usage (Wheel), */
436  0x15, 0xFF, /* Logical Minimum (-1), */
437  0x25, 0x01, /* Logical Maximum (1), */
438  0x95, 0x01, /* Report Count (1), */
439  0x75, 0x08, /* Report Size (8), */
440  0x81, 0x06, /* Input (Variable, Relative), */
441  0x81, 0x03, /* Input (Constant, Variable), */
442  0xC0, /* End Collection, */
443  0xC0 /* End Collection */
444 };
445 
446 /* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
447 static __u8 twhl850_rdesc_fixed2[] = {
448  0x05, 0x01, /* Usage Page (Desktop), */
449  0x09, 0x06, /* Usage (Keyboard), */
450  0xA1, 0x01, /* Collection (Application), */
451  0x85, 0x03, /* Report ID (3), */
452  0x05, 0x07, /* Usage Page (Keyboard), */
453  0x14, /* Logical Minimum (0), */
454  0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */
455  0x29, 0xE7, /* Usage Maximum (KB Right GUI), */
456  0x25, 0x01, /* Logical Maximum (1), */
457  0x75, 0x01, /* Report Size (1), */
458  0x95, 0x08, /* Report Count (8), */
459  0x81, 0x02, /* Input (Variable), */
460  0x18, /* Usage Minimum (None), */
461  0x29, 0xFF, /* Usage Maximum (FFh), */
462  0x26, 0xFF, 0x00, /* Logical Maximum (255), */
463  0x75, 0x08, /* Report Size (8), */
464  0x95, 0x06, /* Report Count (6), */
465  0x80, /* Input, */
466  0xC0 /* End Collection */
467 };
468 
469 /*
470  * See TWHA60 description, device and HID report descriptors at
471  * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_TWHA60
472  */
473 
474 /* Size of the original descriptors of TWHA60 tablet */
475 #define TWHA60_RDESC_ORIG_SIZE0 254
476 #define TWHA60_RDESC_ORIG_SIZE1 139
477 
478 /* Fixed TWHA60 report descriptor, interface 0 (stylus) */
479 static __u8 twha60_rdesc_fixed0[] = {
480  0x05, 0x0D, /* Usage Page (Digitizer), */
481  0x09, 0x02, /* Usage (Pen), */
482  0xA1, 0x01, /* Collection (Application), */
483  0x85, 0x09, /* Report ID (9), */
484  0x09, 0x20, /* Usage (Stylus), */
485  0xA0, /* Collection (Physical), */
486  0x75, 0x01, /* Report Size (1), */
487  0x09, 0x42, /* Usage (Tip Switch), */
488  0x09, 0x44, /* Usage (Barrel Switch), */
489  0x09, 0x46, /* Usage (Tablet Pick), */
490  0x14, /* Logical Minimum (0), */
491  0x25, 0x01, /* Logical Maximum (1), */
492  0x95, 0x03, /* Report Count (3), */
493  0x81, 0x02, /* Input (Variable), */
494  0x95, 0x04, /* Report Count (4), */
495  0x81, 0x01, /* Input (Constant), */
496  0x09, 0x32, /* Usage (In Range), */
497  0x95, 0x01, /* Report Count (1), */
498  0x81, 0x02, /* Input (Variable), */
499  0x75, 0x10, /* Report Size (16), */
500  0x95, 0x01, /* Report Count (1), */
501  0x14, /* Logical Minimum (0), */
502  0xA4, /* Push, */
503  0x05, 0x01, /* Usage Page (Desktop), */
504  0x55, 0xFD, /* Unit Exponent (-3), */
505  0x65, 0x13, /* Unit (Inch), */
506  0x34, /* Physical Minimum (0), */
507  0x09, 0x30, /* Usage (X), */
508  0x46, 0x10, 0x27, /* Physical Maximum (10000), */
509  0x27, 0x3F, 0x9C,
510  0x00, 0x00, /* Logical Maximum (39999), */
511  0x81, 0x02, /* Input (Variable), */
512  0x09, 0x31, /* Usage (Y), */
513  0x46, 0x6A, 0x18, /* Physical Maximum (6250), */
514  0x26, 0xA7, 0x61, /* Logical Maximum (24999), */
515  0x81, 0x02, /* Input (Variable), */
516  0xB4, /* Pop, */
517  0x09, 0x30, /* Usage (Tip Pressure), */
518  0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
519  0x81, 0x02, /* Input (Variable), */
520  0xC0, /* End Collection, */
521  0xC0 /* End Collection */
522 };
523 
524 /* Fixed TWHA60 report descriptor, interface 1 (frame buttons) */
525 static __u8 twha60_rdesc_fixed1[] = {
526  0x05, 0x01, /* Usage Page (Desktop), */
527  0x09, 0x06, /* Usage (Keyboard), */
528  0xA1, 0x01, /* Collection (Application), */
529  0x85, 0x05, /* Report ID (5), */
530  0x05, 0x07, /* Usage Page (Keyboard), */
531  0x14, /* Logical Minimum (0), */
532  0x25, 0x01, /* Logical Maximum (1), */
533  0x75, 0x01, /* Report Size (1), */
534  0x95, 0x08, /* Report Count (8), */
535  0x81, 0x01, /* Input (Constant), */
536  0x95, 0x0C, /* Report Count (12), */
537  0x19, 0x3A, /* Usage Minimum (KB F1), */
538  0x29, 0x45, /* Usage Maximum (KB F12), */
539  0x81, 0x02, /* Input (Variable), */
540  0x95, 0x0C, /* Report Count (12), */
541  0x19, 0x68, /* Usage Minimum (KB F13), */
542  0x29, 0x73, /* Usage Maximum (KB F24), */
543  0x81, 0x02, /* Input (Variable), */
544  0x95, 0x08, /* Report Count (8), */
545  0x81, 0x01, /* Input (Constant), */
546  0xC0 /* End Collection */
547 };
548 
549 static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
550  unsigned int *rsize)
551 {
552  struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
553  __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
554 
555  switch (hdev->product) {
557  if (*rsize == PF1209_RDESC_ORIG_SIZE) {
558  rdesc = pf1209_rdesc_fixed;
559  *rsize = sizeof(pf1209_rdesc_fixed);
560  }
561  break;
563  if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
564  rdesc = wp4030u_rdesc_fixed;
565  *rsize = sizeof(wp4030u_rdesc_fixed);
566  }
567  break;
569  if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
570  rdesc = wp5540u_rdesc_fixed;
571  *rsize = sizeof(wp5540u_rdesc_fixed);
572  }
573  break;
575  if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
576  rdesc = wp8060u_rdesc_fixed;
577  *rsize = sizeof(wp8060u_rdesc_fixed);
578  }
579  break;
581  if (*rsize == WP1062_RDESC_ORIG_SIZE) {
582  rdesc = wp1062_rdesc_fixed;
583  *rsize = sizeof(wp1062_rdesc_fixed);
584  }
585  break;
587  switch (iface_num) {
588  case 0:
589  if (*rsize == TWHL850_RDESC_ORIG_SIZE0) {
590  rdesc = twhl850_rdesc_fixed0;
591  *rsize = sizeof(twhl850_rdesc_fixed0);
592  }
593  break;
594  case 1:
595  if (*rsize == TWHL850_RDESC_ORIG_SIZE1) {
596  rdesc = twhl850_rdesc_fixed1;
597  *rsize = sizeof(twhl850_rdesc_fixed1);
598  }
599  break;
600  case 2:
601  if (*rsize == TWHL850_RDESC_ORIG_SIZE2) {
602  rdesc = twhl850_rdesc_fixed2;
603  *rsize = sizeof(twhl850_rdesc_fixed2);
604  }
605  break;
606  }
607  break;
609  switch (iface_num) {
610  case 0:
611  if (*rsize == TWHA60_RDESC_ORIG_SIZE0) {
612  rdesc = twha60_rdesc_fixed0;
613  *rsize = sizeof(twha60_rdesc_fixed0);
614  }
615  break;
616  case 1:
617  if (*rsize == TWHA60_RDESC_ORIG_SIZE1) {
618  rdesc = twha60_rdesc_fixed1;
619  *rsize = sizeof(twha60_rdesc_fixed1);
620  }
621  break;
622  }
623  break;
624  }
625 
626  return rdesc;
627 }
628 
629 static const struct hid_device_id uclogic_devices[] = {
644  { }
645 };
646 MODULE_DEVICE_TABLE(hid, uclogic_devices);
647 
648 static struct hid_driver uclogic_driver = {
649  .name = "uclogic",
650  .id_table = uclogic_devices,
651  .report_fixup = uclogic_report_fixup,
652 };
653 
654 static int __init uclogic_init(void)
655 {
656  return hid_register_driver(&uclogic_driver);
657 }
658 
659 static void __exit uclogic_exit(void)
660 {
661  hid_unregister_driver(&uclogic_driver);
662 }
663 
664 module_init(uclogic_init);
665 module_exit(uclogic_exit);
666 MODULE_LICENSE("GPL");