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