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