blob: 1f1128910337a5e004c60e4896c843d70b88b56c [file] [log] [blame]
Nikolai Kondrashovf8a489c2010-08-09 20:44:17 +04001/*
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
18#include "hid-ids.h"
19
20/*
Nikolai Kondrashov51153a72012-03-06 09:54:22 +020021 * See WPXXXXU model descriptions, device and HID report descriptors at
22 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP4030U
23 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP5540U
24 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP8060U
Nikolai Kondrashovf8a489c2010-08-09 20:44:17 +040025 */
26
27/* Size of the original descriptor of WPXXXXU tablets */
28#define WPXXXXU_RDESC_ORIG_SIZE 212
29
Nikolai Kondrashov51153a72012-03-06 09:54:22 +020030/* Fixed WP4030U report descriptor */
Nikolai Kondrashovf8a489c2010-08-09 20:44:17 +040031static __u8 wp4030u_rdesc_fixed[] = {
32 0x05, 0x0D, /* Usage Page (Digitizer), */
33 0x09, 0x02, /* Usage (Pen), */
34 0xA1, 0x01, /* Collection (Application), */
35 0x85, 0x09, /* Report ID (9), */
36 0x09, 0x20, /* Usage (Stylus), */
37 0xA0, /* Collection (Physical), */
38 0x75, 0x01, /* Report Size (1), */
39 0x09, 0x42, /* Usage (Tip Switch), */
40 0x09, 0x44, /* Usage (Barrel Switch), */
41 0x09, 0x46, /* Usage (Tablet Pick), */
42 0x14, /* Logical Minimum (0), */
43 0x25, 0x01, /* Logical Maximum (1), */
44 0x95, 0x03, /* Report Count (3), */
45 0x81, 0x02, /* Input (Variable), */
46 0x95, 0x05, /* Report Count (5), */
47 0x81, 0x01, /* Input (Constant), */
48 0x75, 0x10, /* Report Size (16), */
49 0x95, 0x01, /* Report Count (1), */
50 0x14, /* Logical Minimum (0), */
51 0xA4, /* Push, */
52 0x05, 0x01, /* Usage Page (Desktop), */
53 0x55, 0xFD, /* Unit Exponent (-3), */
54 0x65, 0x13, /* Unit (Inch), */
55 0x34, /* Physical Minimum (0), */
56 0x09, 0x30, /* Usage (X), */
57 0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */
58 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
59 0x81, 0x02, /* Input (Variable), */
60 0x09, 0x31, /* Usage (Y), */
61 0x46, 0xB8, 0x0B, /* Physical Maximum (3000), */
62 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
63 0x81, 0x02, /* Input (Variable), */
64 0xB4, /* Pop, */
65 0x09, 0x30, /* Usage (Tip Pressure), */
66 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
67 0x81, 0x02, /* Input (Variable), */
68 0xC0, /* End Collection, */
69 0xC0 /* End Collection */
70};
71
72/* Fixed WP5540U report descriptor */
73static __u8 wp5540u_rdesc_fixed[] = {
74 0x05, 0x0D, /* Usage Page (Digitizer), */
75 0x09, 0x02, /* Usage (Pen), */
76 0xA1, 0x01, /* Collection (Application), */
77 0x85, 0x09, /* Report ID (9), */
78 0x09, 0x20, /* Usage (Stylus), */
79 0xA0, /* Collection (Physical), */
80 0x75, 0x01, /* Report Size (1), */
81 0x09, 0x42, /* Usage (Tip Switch), */
82 0x09, 0x44, /* Usage (Barrel Switch), */
83 0x09, 0x46, /* Usage (Tablet Pick), */
84 0x14, /* Logical Minimum (0), */
85 0x25, 0x01, /* Logical Maximum (1), */
86 0x95, 0x03, /* Report Count (3), */
87 0x81, 0x02, /* Input (Variable), */
88 0x95, 0x05, /* Report Count (5), */
89 0x81, 0x01, /* Input (Constant), */
90 0x75, 0x10, /* Report Size (16), */
91 0x95, 0x01, /* Report Count (1), */
92 0x14, /* Logical Minimum (0), */
93 0xA4, /* Push, */
94 0x05, 0x01, /* Usage Page (Desktop), */
95 0x55, 0xFD, /* Unit Exponent (-3), */
96 0x65, 0x13, /* Unit (Inch), */
97 0x34, /* Physical Minimum (0), */
98 0x09, 0x30, /* Usage (X), */
99 0x46, 0x7C, 0x15, /* Physical Maximum (5500), */
100 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
101 0x81, 0x02, /* Input (Variable), */
102 0x09, 0x31, /* Usage (Y), */
103 0x46, 0xA0, 0x0F, /* Physical Maximum (4000), */
104 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
105 0x81, 0x02, /* Input (Variable), */
106 0xB4, /* Pop, */
107 0x09, 0x30, /* Usage (Tip Pressure), */
108 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
109 0x81, 0x02, /* Input (Variable), */
110 0xC0, /* End Collection, */
111 0xC0, /* End Collection, */
112 0x05, 0x01, /* Usage Page (Desktop), */
113 0x09, 0x02, /* Usage (Mouse), */
114 0xA1, 0x01, /* Collection (Application), */
115 0x85, 0x08, /* Report ID (8), */
116 0x09, 0x01, /* Usage (Pointer), */
117 0xA0, /* Collection (Physical), */
118 0x75, 0x01, /* Report Size (1), */
119 0x05, 0x09, /* Usage Page (Button), */
120 0x19, 0x01, /* Usage Minimum (01h), */
121 0x29, 0x03, /* Usage Maximum (03h), */
122 0x14, /* Logical Minimum (0), */
123 0x25, 0x01, /* Logical Maximum (1), */
124 0x95, 0x03, /* Report Count (3), */
125 0x81, 0x02, /* Input (Variable), */
126 0x95, 0x05, /* Report Count (5), */
127 0x81, 0x01, /* Input (Constant), */
128 0x05, 0x01, /* Usage Page (Desktop), */
129 0x75, 0x08, /* Report Size (8), */
130 0x09, 0x30, /* Usage (X), */
131 0x09, 0x31, /* Usage (Y), */
132 0x15, 0x81, /* Logical Minimum (-127), */
133 0x25, 0x7F, /* Logical Maximum (127), */
134 0x95, 0x02, /* Report Count (2), */
135 0x81, 0x06, /* Input (Variable, Relative), */
136 0x09, 0x38, /* Usage (Wheel), */
137 0x15, 0xFF, /* Logical Minimum (-1), */
138 0x25, 0x01, /* Logical Maximum (1), */
139 0x95, 0x01, /* Report Count (1), */
140 0x81, 0x06, /* Input (Variable, Relative), */
141 0x81, 0x01, /* Input (Constant), */
142 0xC0, /* End Collection, */
143 0xC0 /* End Collection */
144};
145
146/* Fixed WP8060U report descriptor */
147static __u8 wp8060u_rdesc_fixed[] = {
148 0x05, 0x0D, /* Usage Page (Digitizer), */
149 0x09, 0x02, /* Usage (Pen), */
150 0xA1, 0x01, /* Collection (Application), */
151 0x85, 0x09, /* Report ID (9), */
152 0x09, 0x20, /* Usage (Stylus), */
153 0xA0, /* Collection (Physical), */
154 0x75, 0x01, /* Report Size (1), */
155 0x09, 0x42, /* Usage (Tip Switch), */
156 0x09, 0x44, /* Usage (Barrel Switch), */
157 0x09, 0x46, /* Usage (Tablet Pick), */
158 0x14, /* Logical Minimum (0), */
159 0x25, 0x01, /* Logical Maximum (1), */
160 0x95, 0x03, /* Report Count (3), */
161 0x81, 0x02, /* Input (Variable), */
162 0x95, 0x05, /* Report Count (5), */
163 0x81, 0x01, /* Input (Constant), */
164 0x75, 0x10, /* Report Size (16), */
165 0x95, 0x01, /* Report Count (1), */
166 0x14, /* Logical Minimum (0), */
167 0xA4, /* Push, */
168 0x05, 0x01, /* Usage Page (Desktop), */
169 0x55, 0xFD, /* Unit Exponent (-3), */
170 0x65, 0x13, /* Unit (Inch), */
171 0x34, /* Physical Minimum (0), */
172 0x09, 0x30, /* Usage (X), */
173 0x46, 0x40, 0x1F, /* Physical Maximum (8000), */
174 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
175 0x81, 0x02, /* Input (Variable), */
176 0x09, 0x31, /* Usage (Y), */
177 0x46, 0x70, 0x17, /* Physical Maximum (6000), */
178 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
179 0x81, 0x02, /* Input (Variable), */
180 0xB4, /* Pop, */
181 0x09, 0x30, /* Usage (Tip Pressure), */
182 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
183 0x81, 0x02, /* Input (Variable), */
184 0xC0, /* End Collection, */
185 0xC0, /* End Collection, */
186 0x05, 0x01, /* Usage Page (Desktop), */
187 0x09, 0x02, /* Usage (Mouse), */
188 0xA1, 0x01, /* Collection (Application), */
189 0x85, 0x08, /* Report ID (8), */
190 0x09, 0x01, /* Usage (Pointer), */
191 0xA0, /* Collection (Physical), */
192 0x75, 0x01, /* Report Size (1), */
193 0x05, 0x09, /* Usage Page (Button), */
194 0x19, 0x01, /* Usage Minimum (01h), */
195 0x29, 0x03, /* Usage Maximum (03h), */
196 0x14, /* Logical Minimum (0), */
197 0x25, 0x01, /* Logical Maximum (1), */
198 0x95, 0x03, /* Report Count (3), */
199 0x81, 0x02, /* Input (Variable), */
200 0x95, 0x05, /* Report Count (5), */
201 0x81, 0x01, /* Input (Constant), */
202 0x05, 0x01, /* Usage Page (Desktop), */
203 0x75, 0x08, /* Report Size (8), */
204 0x09, 0x30, /* Usage (X), */
205 0x09, 0x31, /* Usage (Y), */
206 0x15, 0x81, /* Logical Minimum (-127), */
207 0x25, 0x7F, /* Logical Maximum (127), */
208 0x95, 0x02, /* Report Count (2), */
209 0x81, 0x06, /* Input (Variable, Relative), */
210 0x09, 0x38, /* Usage (Wheel), */
211 0x15, 0xFF, /* Logical Minimum (-1), */
212 0x25, 0x01, /* Logical Maximum (1), */
213 0x95, 0x01, /* Report Count (1), */
214 0x81, 0x06, /* Input (Variable, Relative), */
215 0x81, 0x01, /* Input (Constant), */
216 0xC0, /* End Collection, */
217 0xC0 /* End Collection */
218};
219
Nikolai Kondrashov41fa9232010-08-23 15:09:01 +0400220/*
Nikolai Kondrashov51153a72012-03-06 09:54:22 +0200221 * See WP1062 description, device and HID report descriptors at
222 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP1062
Nikolai Kondrashov6be914f2011-07-06 09:23:41 +0300223 */
224
225/* Size of the original descriptor of WP1062 tablet */
226#define WP1062_RDESC_ORIG_SIZE 254
227
Nikolai Kondrashov51153a72012-03-06 09:54:22 +0200228/* Fixed WP1062 report descriptor */
Nikolai Kondrashov6be914f2011-07-06 09:23:41 +0300229static __u8 wp1062_rdesc_fixed[] = {
230 0x05, 0x0D, /* Usage Page (Digitizer), */
231 0x09, 0x02, /* Usage (Pen), */
232 0xA1, 0x01, /* Collection (Application), */
233 0x85, 0x09, /* Report ID (9), */
234 0x09, 0x20, /* Usage (Stylus), */
235 0xA0, /* Collection (Physical), */
236 0x75, 0x01, /* Report Size (1), */
237 0x09, 0x42, /* Usage (Tip Switch), */
238 0x09, 0x44, /* Usage (Barrel Switch), */
239 0x09, 0x46, /* Usage (Tablet Pick), */
240 0x14, /* Logical Minimum (0), */
241 0x25, 0x01, /* Logical Maximum (1), */
242 0x95, 0x03, /* Report Count (3), */
243 0x81, 0x02, /* Input (Variable), */
244 0x95, 0x04, /* Report Count (4), */
245 0x81, 0x01, /* Input (Constant), */
246 0x09, 0x32, /* Usage (In Range), */
247 0x95, 0x01, /* Report Count (1), */
248 0x81, 0x02, /* Input (Variable), */
249 0x75, 0x10, /* Report Size (16), */
250 0x95, 0x01, /* Report Count (1), */
251 0x14, /* Logical Minimum (0), */
252 0xA4, /* Push, */
253 0x05, 0x01, /* Usage Page (Desktop), */
254 0x55, 0xFD, /* Unit Exponent (-3), */
255 0x65, 0x13, /* Unit (Inch), */
256 0x34, /* Physical Minimum (0), */
257 0x09, 0x30, /* Usage (X), */
258 0x46, 0x10, 0x27, /* Physical Maximum (10000), */
259 0x26, 0x20, 0x4E, /* Logical Maximum (20000), */
260 0x81, 0x02, /* Input (Variable), */
261 0x09, 0x31, /* Usage (Y), */
262 0x46, 0xB7, 0x19, /* Physical Maximum (6583), */
263 0x26, 0x6E, 0x33, /* Logical Maximum (13166), */
264 0x81, 0x02, /* Input (Variable), */
265 0xB4, /* Pop, */
266 0x09, 0x30, /* Usage (Tip Pressure), */
267 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
268 0x81, 0x02, /* Input (Variable), */
269 0xC0, /* End Collection, */
270 0xC0 /* End Collection */
271};
272
273/*
Nikolai Kondrashov51153a72012-03-06 09:54:22 +0200274 * See PF1209 description, device and HID report descriptors at
275 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_PF1209
Nikolai Kondrashov41fa9232010-08-23 15:09:01 +0400276 */
277
278/* Size of the original descriptor of PF1209 tablet */
279#define PF1209_RDESC_ORIG_SIZE 234
280
Nikolai Kondrashov51153a72012-03-06 09:54:22 +0200281/* Fixed PF1209 report descriptor */
Nikolai Kondrashov41fa9232010-08-23 15:09:01 +0400282static __u8 pf1209_rdesc_fixed[] = {
283 0x05, 0x0D, /* Usage Page (Digitizer), */
284 0x09, 0x02, /* Usage (Pen), */
285 0xA1, 0x01, /* Collection (Application), */
286 0x85, 0x09, /* Report ID (9), */
287 0x09, 0x20, /* Usage (Stylus), */
288 0xA0, /* Collection (Physical), */
289 0x75, 0x01, /* Report Size (1), */
290 0x09, 0x42, /* Usage (Tip Switch), */
291 0x09, 0x44, /* Usage (Barrel Switch), */
292 0x09, 0x46, /* Usage (Tablet Pick), */
293 0x14, /* Logical Minimum (0), */
294 0x25, 0x01, /* Logical Maximum (1), */
295 0x95, 0x03, /* Report Count (3), */
296 0x81, 0x02, /* Input (Variable), */
297 0x95, 0x05, /* Report Count (5), */
298 0x81, 0x01, /* Input (Constant), */
299 0x75, 0x10, /* Report Size (16), */
300 0x95, 0x01, /* Report Count (1), */
301 0x14, /* Logical Minimum (0), */
302 0xA4, /* Push, */
303 0x05, 0x01, /* Usage Page (Desktop), */
304 0x55, 0xFD, /* Unit Exponent (-3), */
305 0x65, 0x13, /* Unit (Inch), */
306 0x34, /* Physical Minimum (0), */
307 0x09, 0x30, /* Usage (X), */
308 0x46, 0xE0, 0x2E, /* Physical Maximum (12000), */
309 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
310 0x81, 0x02, /* Input (Variable), */
311 0x09, 0x31, /* Usage (Y), */
312 0x46, 0x28, 0x23, /* Physical Maximum (9000), */
313 0x26, 0xFF, 0x7F, /* Logical Maximum (32767), */
314 0x81, 0x02, /* Input (Variable), */
315 0xB4, /* Pop, */
316 0x09, 0x30, /* Usage (Tip Pressure), */
317 0x26, 0xFF, 0x03, /* Logical Maximum (1023), */
318 0x81, 0x02, /* Input (Variable), */
319 0xC0, /* End Collection, */
320 0xC0, /* End Collection, */
321 0x05, 0x01, /* Usage Page (Desktop), */
322 0x09, 0x02, /* Usage (Mouse), */
323 0xA1, 0x01, /* Collection (Application), */
324 0x85, 0x08, /* Report ID (8), */
325 0x09, 0x01, /* Usage (Pointer), */
326 0xA0, /* Collection (Physical), */
327 0x75, 0x01, /* Report Size (1), */
328 0x05, 0x09, /* Usage Page (Button), */
329 0x19, 0x01, /* Usage Minimum (01h), */
330 0x29, 0x03, /* Usage Maximum (03h), */
331 0x14, /* Logical Minimum (0), */
332 0x25, 0x01, /* Logical Maximum (1), */
333 0x95, 0x03, /* Report Count (3), */
334 0x81, 0x02, /* Input (Variable), */
335 0x95, 0x05, /* Report Count (5), */
336 0x81, 0x01, /* Input (Constant), */
337 0x05, 0x01, /* Usage Page (Desktop), */
338 0x75, 0x08, /* Report Size (8), */
339 0x09, 0x30, /* Usage (X), */
340 0x09, 0x31, /* Usage (Y), */
341 0x15, 0x81, /* Logical Minimum (-127), */
342 0x25, 0x7F, /* Logical Maximum (127), */
343 0x95, 0x02, /* Report Count (2), */
344 0x81, 0x06, /* Input (Variable, Relative), */
345 0x09, 0x38, /* Usage (Wheel), */
346 0x15, 0xFF, /* Logical Minimum (-1), */
347 0x25, 0x01, /* Logical Maximum (1), */
348 0x95, 0x01, /* Report Count (1), */
349 0x81, 0x06, /* Input (Variable, Relative), */
350 0x81, 0x01, /* Input (Constant), */
351 0xC0, /* End Collection, */
352 0xC0 /* End Collection */
353};
354
Nikolai Kondrashovf8a489c2010-08-09 20:44:17 +0400355static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
Nikolai Kondrashovbd9033e2010-08-23 15:09:00 +0400356 unsigned int *rsize)
Nikolai Kondrashovf8a489c2010-08-09 20:44:17 +0400357{
358 switch (hdev->product) {
Nikolai Kondrashov41fa9232010-08-23 15:09:01 +0400359 case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
360 if (*rsize == PF1209_RDESC_ORIG_SIZE) {
361 rdesc = pf1209_rdesc_fixed;
362 *rsize = sizeof(pf1209_rdesc_fixed);
363 }
364 break;
Nikolai Kondrashovf8a489c2010-08-09 20:44:17 +0400365 case USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U:
Nikolai Kondrashovbd9033e2010-08-23 15:09:00 +0400366 if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
Nikolai Kondrashovf8a489c2010-08-09 20:44:17 +0400367 rdesc = wp4030u_rdesc_fixed;
368 *rsize = sizeof(wp4030u_rdesc_fixed);
369 }
370 break;
371 case USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U:
Nikolai Kondrashovbd9033e2010-08-23 15:09:00 +0400372 if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
Nikolai Kondrashovf8a489c2010-08-09 20:44:17 +0400373 rdesc = wp5540u_rdesc_fixed;
374 *rsize = sizeof(wp5540u_rdesc_fixed);
375 }
376 break;
377 case USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U:
Nikolai Kondrashovbd9033e2010-08-23 15:09:00 +0400378 if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
Nikolai Kondrashovf8a489c2010-08-09 20:44:17 +0400379 rdesc = wp8060u_rdesc_fixed;
380 *rsize = sizeof(wp8060u_rdesc_fixed);
381 }
382 break;
Nikolai Kondrashov6be914f2011-07-06 09:23:41 +0300383 case USB_DEVICE_ID_UCLOGIC_TABLET_WP1062:
384 if (*rsize == WP1062_RDESC_ORIG_SIZE) {
385 rdesc = wp1062_rdesc_fixed;
386 *rsize = sizeof(wp1062_rdesc_fixed);
387 }
388 break;
Nikolai Kondrashovf8a489c2010-08-09 20:44:17 +0400389 }
390
391 return rdesc;
392}
393
394static const struct hid_device_id uclogic_devices[] = {
395 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
Nikolai Kondrashov41fa9232010-08-23 15:09:01 +0400396 USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
397 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
Nikolai Kondrashovf8a489c2010-08-09 20:44:17 +0400398 USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
399 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
400 USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
401 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
402 USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
Nikolai Kondrashov6be914f2011-07-06 09:23:41 +0300403 { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
404 USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
Nikolai Kondrashovf8a489c2010-08-09 20:44:17 +0400405 { }
406};
407MODULE_DEVICE_TABLE(hid, uclogic_devices);
408
409static struct hid_driver uclogic_driver = {
410 .name = "uclogic",
411 .id_table = uclogic_devices,
412 .report_fixup = uclogic_report_fixup,
413};
414
415static int __init uclogic_init(void)
416{
417 return hid_register_driver(&uclogic_driver);
418}
419
420static void __exit uclogic_exit(void)
421{
422 hid_unregister_driver(&uclogic_driver);
423}
424
425module_init(uclogic_init);
426module_exit(uclogic_exit);
427MODULE_LICENSE("GPL");