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