Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  *  HID driver for Waltop devices not fully compliant with HID standard
0004  *
0005  *  Copyright (c) 2010 Nikolai Kondrashov
0006  */
0007 
0008 /*
0009  */
0010 
0011 #include <linux/device.h>
0012 #include <linux/hid.h>
0013 #include <linux/module.h>
0014 
0015 #include "hid-ids.h"
0016 
0017 /*
0018  * There exists an official driver on the manufacturer's website, which
0019  * wasn't submitted to the kernel, for some reason. The official driver
0020  * doesn't seem to support extra features of some tablets, like wheels.
0021  *
0022  * It shows that the feature report ID 2 could be used to control any waltop
0023  * tablet input mode, switching it between "default", "tablet" and "ink".
0024  *
0025  * This driver only uses "default" mode for all the supported tablets. This
0026  * mode tries to be HID-compatible (not very successfully), but cripples the
0027  * resolution of some tablets.
0028  *
0029  * The "tablet" mode uses some proprietary, yet decipherable protocol, which
0030  * represents the correct resolution, but is possibly HID-incompatible (i.e.
0031  * indescribable by a report descriptor).
0032  *
0033  * The purpose of the "ink" mode is unknown.
0034  *
0035  * The feature reports needed for switching to each mode are these:
0036  *
0037  * 02 16 00     default
0038  * 02 16 01     tablet
0039  * 02 16 02     ink
0040  */
0041 
0042 /* Size of the original report descriptor of Slim Tablet 5.8 inch */
0043 #define SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE    222
0044 
0045 /* Fixed Slim Tablet 5.8 inch descriptor */
0046 static __u8 slim_tablet_5_8_inch_rdesc_fixed[] = {
0047     0x05, 0x0D,         /*  Usage Page (Digitizer),             */
0048     0x09, 0x02,         /*  Usage (Pen),                        */
0049     0xA1, 0x01,         /*  Collection (Application),           */
0050     0x85, 0x10,         /*      Report ID (16),                 */
0051     0x09, 0x20,         /*      Usage (Stylus),                 */
0052     0xA0,               /*      Collection (Physical),          */
0053     0x09, 0x42,         /*          Usage (Tip Switch),         */
0054     0x09, 0x44,         /*          Usage (Barrel Switch),      */
0055     0x09, 0x46,         /*          Usage (Tablet Pick),        */
0056     0x15, 0x01,         /*          Logical Minimum (1),        */
0057     0x25, 0x03,         /*          Logical Maximum (3),        */
0058     0x75, 0x04,         /*          Report Size (4),            */
0059     0x95, 0x01,         /*          Report Count (1),           */
0060     0x80,               /*          Input,                      */
0061     0x09, 0x32,         /*          Usage (In Range),           */
0062     0x14,               /*          Logical Minimum (0),        */
0063     0x25, 0x01,         /*          Logical Maximum (1),        */
0064     0x75, 0x01,         /*          Report Size (1),            */
0065     0x95, 0x01,         /*          Report Count (1),           */
0066     0x81, 0x02,         /*          Input (Variable),           */
0067     0x95, 0x03,         /*          Report Count (3),           */
0068     0x81, 0x03,         /*          Input (Constant, Variable), */
0069     0x75, 0x10,         /*          Report Size (16),           */
0070     0x95, 0x01,         /*          Report Count (1),           */
0071     0x14,               /*          Logical Minimum (0),        */
0072     0xA4,               /*          Push,                       */
0073     0x05, 0x01,         /*          Usage Page (Desktop),       */
0074     0x65, 0x13,         /*          Unit (Inch),                */
0075     0x55, 0xFD,         /*          Unit Exponent (-3),         */
0076     0x34,               /*          Physical Minimum (0),       */
0077     0x09, 0x30,         /*          Usage (X),                  */
0078     0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */
0079     0x26, 0x10, 0x27,   /*          Logical Maximum (10000),    */
0080     0x81, 0x02,         /*          Input (Variable),           */
0081     0x09, 0x31,         /*          Usage (Y),                  */
0082     0x46, 0xB8, 0x0B,   /*          Physical Maximum (3000),    */
0083     0x26, 0x70, 0x17,   /*          Logical Maximum (6000),     */
0084     0x81, 0x02,         /*          Input (Variable),           */
0085     0xB4,               /*          Pop,                        */
0086     0x09, 0x30,         /*          Usage (Tip Pressure),       */
0087     0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
0088     0x81, 0x02,         /*          Input (Variable),           */
0089     0xC0,               /*      End Collection,                 */
0090     0xC0                /*  End Collection                      */
0091 };
0092 
0093 /* Size of the original report descriptor of Slim Tablet 12.1 inch */
0094 #define SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE   269
0095 
0096 /* Fixed Slim Tablet 12.1 inch descriptor */
0097 static __u8 slim_tablet_12_1_inch_rdesc_fixed[] = {
0098     0x05, 0x0D,         /*  Usage Page (Digitizer),             */
0099     0x09, 0x02,         /*  Usage (Pen),                        */
0100     0xA1, 0x01,         /*  Collection (Application),           */
0101     0x85, 0x10,         /*      Report ID (16),                 */
0102     0x09, 0x20,         /*      Usage (Stylus),                 */
0103     0xA0,               /*      Collection (Physical),          */
0104     0x09, 0x42,         /*          Usage (Tip Switch),         */
0105     0x09, 0x44,         /*          Usage (Barrel Switch),      */
0106     0x09, 0x46,         /*          Usage (Tablet Pick),        */
0107     0x15, 0x01,         /*          Logical Minimum (1),        */
0108     0x25, 0x03,         /*          Logical Maximum (3),        */
0109     0x75, 0x04,         /*          Report Size (4),            */
0110     0x95, 0x01,         /*          Report Count (1),           */
0111     0x80,               /*          Input,                      */
0112     0x09, 0x32,         /*          Usage (In Range),           */
0113     0x14,               /*          Logical Minimum (0),        */
0114     0x25, 0x01,         /*          Logical Maximum (1),        */
0115     0x75, 0x01,         /*          Report Size (1),            */
0116     0x95, 0x01,         /*          Report Count (1),           */
0117     0x81, 0x02,         /*          Input (Variable),           */
0118     0x95, 0x03,         /*          Report Count (3),           */
0119     0x81, 0x03,         /*          Input (Constant, Variable), */
0120     0x75, 0x10,         /*          Report Size (16),           */
0121     0x95, 0x01,         /*          Report Count (1),           */
0122     0x14,               /*          Logical Minimum (0),        */
0123     0xA4,               /*          Push,                       */
0124     0x05, 0x01,         /*          Usage Page (Desktop),       */
0125     0x65, 0x13,         /*          Unit (Inch),                */
0126     0x55, 0xFD,         /*          Unit Exponent (-3),         */
0127     0x34,               /*          Physical Minimum (0),       */
0128     0x09, 0x30,         /*          Usage (X),                  */
0129     0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
0130     0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
0131     0x81, 0x02,         /*          Input (Variable),           */
0132     0x09, 0x31,         /*          Usage (Y),                  */
0133     0x46, 0x6A, 0x18,   /*          Physical Maximum (6250),    */
0134     0x26, 0xD4, 0x30,   /*          Logical Maximum (12500),    */
0135     0x81, 0x02,         /*          Input (Variable),           */
0136     0xB4,               /*          Pop,                        */
0137     0x09, 0x30,         /*          Usage (Tip Pressure),       */
0138     0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
0139     0x81, 0x02,         /*          Input (Variable),           */
0140     0xC0,               /*      End Collection,                 */
0141     0xC0                /*  End Collection                      */
0142 };
0143 
0144 /* Size of the original report descriptor of Q Pad */
0145 #define Q_PAD_RDESC_ORIG_SIZE   241
0146 
0147 /* Fixed Q Pad descriptor */
0148 static __u8 q_pad_rdesc_fixed[] = {
0149     0x05, 0x0D,         /*  Usage Page (Digitizer),             */
0150     0x09, 0x02,         /*  Usage (Pen),                        */
0151     0xA1, 0x01,         /*  Collection (Application),           */
0152     0x85, 0x10,         /*      Report ID (16),                 */
0153     0x09, 0x20,         /*      Usage (Stylus),                 */
0154     0xA0,               /*      Collection (Physical),          */
0155     0x09, 0x42,         /*          Usage (Tip Switch),         */
0156     0x09, 0x44,         /*          Usage (Barrel Switch),      */
0157     0x09, 0x46,         /*          Usage (Tablet Pick),        */
0158     0x15, 0x01,         /*          Logical Minimum (1),        */
0159     0x25, 0x03,         /*          Logical Maximum (3),        */
0160     0x75, 0x04,         /*          Report Size (4),            */
0161     0x95, 0x01,         /*          Report Count (1),           */
0162     0x80,               /*          Input,                      */
0163     0x09, 0x32,         /*          Usage (In Range),           */
0164     0x14,               /*          Logical Minimum (0),        */
0165     0x25, 0x01,         /*          Logical Maximum (1),        */
0166     0x75, 0x01,         /*          Report Size (1),            */
0167     0x95, 0x01,         /*          Report Count (1),           */
0168     0x81, 0x02,         /*          Input (Variable),           */
0169     0x95, 0x03,         /*          Report Count (3),           */
0170     0x81, 0x03,         /*          Input (Constant, Variable), */
0171     0x75, 0x10,         /*          Report Size (16),           */
0172     0x95, 0x01,         /*          Report Count (1),           */
0173     0x14,               /*          Logical Minimum (0),        */
0174     0xA4,               /*          Push,                       */
0175     0x05, 0x01,         /*          Usage Page (Desktop),       */
0176     0x65, 0x13,         /*          Unit (Inch),                */
0177     0x55, 0xFD,         /*          Unit Exponent (-3),         */
0178     0x34,               /*          Physical Minimum (0),       */
0179     0x09, 0x30,         /*          Usage (X),                  */
0180     0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
0181     0x26, 0x00, 0x30,   /*          Logical Maximum (12288),    */
0182     0x81, 0x02,         /*          Input (Variable),           */
0183     0x09, 0x31,         /*          Usage (Y),                  */
0184     0x46, 0x94, 0x11,   /*          Physical Maximum (4500),    */
0185     0x26, 0x00, 0x24,   /*          Logical Maximum (9216),     */
0186     0x81, 0x02,         /*          Input (Variable),           */
0187     0xB4,               /*          Pop,                        */
0188     0x09, 0x30,         /*          Usage (Tip Pressure),       */
0189     0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
0190     0x81, 0x02,         /*          Input (Variable),           */
0191     0xC0,               /*      End Collection,                 */
0192     0xC0                /*  End Collection                      */
0193 };
0194 
0195 /* Size of the original report descriptor of tablet with PID 0038 */
0196 #define PID_0038_RDESC_ORIG_SIZE    241
0197 
0198 /*
0199  * Fixed report descriptor for tablet with PID 0038.
0200  */
0201 static __u8 pid_0038_rdesc_fixed[] = {
0202     0x05, 0x0D,         /*  Usage Page (Digitizer),             */
0203     0x09, 0x02,         /*  Usage (Pen),                        */
0204     0xA1, 0x01,         /*  Collection (Application),           */
0205     0x85, 0x10,         /*      Report ID (16),                 */
0206     0x09, 0x20,         /*      Usage (Stylus),                 */
0207     0xA0,               /*      Collection (Physical),          */
0208     0x09, 0x42,         /*          Usage (Tip Switch),         */
0209     0x09, 0x44,         /*          Usage (Barrel Switch),      */
0210     0x09, 0x46,         /*          Usage (Tablet Pick),        */
0211     0x15, 0x01,         /*          Logical Minimum (1),        */
0212     0x25, 0x03,         /*          Logical Maximum (3),        */
0213     0x75, 0x04,         /*          Report Size (4),            */
0214     0x95, 0x01,         /*          Report Count (1),           */
0215     0x80,               /*          Input,                      */
0216     0x09, 0x32,         /*          Usage (In Range),           */
0217     0x14,               /*          Logical Minimum (0),        */
0218     0x25, 0x01,         /*          Logical Maximum (1),        */
0219     0x75, 0x01,         /*          Report Size (1),            */
0220     0x95, 0x01,         /*          Report Count (1),           */
0221     0x81, 0x02,         /*          Input (Variable),           */
0222     0x95, 0x03,         /*          Report Count (3),           */
0223     0x81, 0x03,         /*          Input (Constant, Variable), */
0224     0x75, 0x10,         /*          Report Size (16),           */
0225     0x95, 0x01,         /*          Report Count (1),           */
0226     0x14,               /*          Logical Minimum (0),        */
0227     0xA4,               /*          Push,                       */
0228     0x05, 0x01,         /*          Usage Page (Desktop),       */
0229     0x65, 0x13,         /*          Unit (Inch),                */
0230     0x55, 0xFD,         /*          Unit Exponent (-3),         */
0231     0x34,               /*          Physical Minimum (0),       */
0232     0x09, 0x30,         /*          Usage (X),                  */
0233     0x46, 0x2E, 0x22,   /*          Physical Maximum (8750),    */
0234     0x26, 0x00, 0x46,   /*          Logical Maximum (17920),    */
0235     0x81, 0x02,         /*          Input (Variable),           */
0236     0x09, 0x31,         /*          Usage (Y),                  */
0237     0x46, 0x82, 0x14,   /*          Physical Maximum (5250),    */
0238     0x26, 0x00, 0x2A,   /*          Logical Maximum (10752),    */
0239     0x81, 0x02,         /*          Input (Variable),           */
0240     0xB4,               /*          Pop,                        */
0241     0x09, 0x30,         /*          Usage (Tip Pressure),       */
0242     0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
0243     0x81, 0x02,         /*          Input (Variable),           */
0244     0xC0,               /*      End Collection,                 */
0245     0xC0                /*  End Collection                      */
0246 };
0247 
0248 /* Size of the original report descriptor of Media Tablet 10.6 inch */
0249 #define MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE  300
0250 
0251 /* Fixed Media Tablet 10.6 inch descriptor */
0252 static __u8 media_tablet_10_6_inch_rdesc_fixed[] = {
0253     0x05, 0x0D,         /*  Usage Page (Digitizer),             */
0254     0x09, 0x02,         /*  Usage (Pen),                        */
0255     0xA1, 0x01,         /*  Collection (Application),           */
0256     0x85, 0x10,         /*      Report ID (16),                 */
0257     0x09, 0x20,         /*      Usage (Stylus),                 */
0258     0xA0,               /*      Collection (Physical),          */
0259     0x09, 0x42,         /*          Usage (Tip Switch),         */
0260     0x09, 0x44,         /*          Usage (Barrel Switch),      */
0261     0x09, 0x46,         /*          Usage (Tablet Pick),        */
0262     0x15, 0x01,         /*          Logical Minimum (1),        */
0263     0x25, 0x03,         /*          Logical Maximum (3),        */
0264     0x75, 0x04,         /*          Report Size (4),            */
0265     0x95, 0x01,         /*          Report Count (1),           */
0266     0x80,               /*          Input,                      */
0267     0x75, 0x01,         /*          Report Size (1),            */
0268     0x09, 0x32,         /*          Usage (In Range),           */
0269     0x14,               /*          Logical Minimum (0),        */
0270     0x25, 0x01,         /*          Logical Maximum (1),        */
0271     0x95, 0x01,         /*          Report Count (1),           */
0272     0x81, 0x02,         /*          Input (Variable),           */
0273     0x95, 0x03,         /*          Report Count (3),           */
0274     0x81, 0x03,         /*          Input (Constant, Variable), */
0275     0x75, 0x10,         /*          Report Size (16),           */
0276     0x95, 0x01,         /*          Report Count (1),           */
0277     0x14,               /*          Logical Minimum (0),        */
0278     0xA4,               /*          Push,                       */
0279     0x05, 0x01,         /*          Usage Page (Desktop),       */
0280     0x65, 0x13,         /*          Unit (Inch),                */
0281     0x55, 0xFD,         /*          Unit Exponent (-3),         */
0282     0x34,               /*          Physical Minimum (0),       */
0283     0x09, 0x30,         /*          Usage (X),                  */
0284     0x46, 0x28, 0x23,   /*          Physical Maximum (9000),    */
0285     0x26, 0x50, 0x46,   /*          Logical Maximum (18000),    */
0286     0x81, 0x02,         /*          Input (Variable),           */
0287     0x09, 0x31,         /*          Usage (Y),                  */
0288     0x46, 0x7C, 0x15,   /*          Physical Maximum (5500),    */
0289     0x26, 0xF8, 0x2A,   /*          Logical Maximum (11000),    */
0290     0x81, 0x02,         /*          Input (Variable),           */
0291     0xB4,               /*          Pop,                        */
0292     0x09, 0x30,         /*          Usage (Tip Pressure),       */
0293     0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
0294     0x81, 0x02,         /*          Input (Variable),           */
0295     0xC0,               /*      End Collection,                 */
0296     0xC0,               /*  End Collection,                     */
0297     0x05, 0x01,         /*  Usage Page (Desktop),               */
0298     0x09, 0x02,         /*  Usage (Mouse),                      */
0299     0xA1, 0x01,         /*  Collection (Application),           */
0300     0x85, 0x01,         /*      Report ID (1),                  */
0301     0x09, 0x01,         /*      Usage (Pointer),                */
0302     0xA0,               /*      Collection (Physical),          */
0303     0x75, 0x08,         /*          Report Size (8),            */
0304     0x95, 0x03,         /*          Report Count (3),           */
0305     0x81, 0x03,         /*          Input (Constant, Variable), */
0306     0x95, 0x02,         /*          Report Count (2),           */
0307     0x15, 0xFF,         /*          Logical Minimum (-1),       */
0308     0x25, 0x01,         /*          Logical Maximum (1),        */
0309     0x09, 0x38,         /*          Usage (Wheel),              */
0310     0x0B, 0x38, 0x02,   /*          Usage (Consumer AC Pan),    */
0311         0x0C, 0x00,
0312     0x81, 0x06,         /*          Input (Variable, Relative), */
0313     0x95, 0x02,         /*          Report Count (2),           */
0314     0x81, 0x03,         /*          Input (Constant, Variable), */
0315     0xC0,               /*      End Collection,                 */
0316     0xC0,               /*  End Collection,                     */
0317     0x05, 0x0C,         /*  Usage Page (Consumer),              */
0318     0x09, 0x01,         /*  Usage (Consumer Control),           */
0319     0xA1, 0x01,         /*  Collection (Application),           */
0320     0x85, 0x0D,         /*      Report ID (13),                 */
0321     0x95, 0x01,         /*      Report Count (1),               */
0322     0x75, 0x10,         /*      Report Size (16),               */
0323     0x81, 0x03,         /*      Input (Constant, Variable),     */
0324     0x0A, 0x2F, 0x02,   /*      Usage (AC Zoom),                */
0325     0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
0326     0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
0327     0x09, 0xB6,         /*      Usage (Scan Previous Track),    */
0328     0x09, 0xB5,         /*      Usage (Scan Next Track),        */
0329     0x08,               /*      Usage (00h),                    */
0330     0x08,               /*      Usage (00h),                    */
0331     0x08,               /*      Usage (00h),                    */
0332     0x08,               /*      Usage (00h),                    */
0333     0x08,               /*      Usage (00h),                    */
0334     0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
0335     0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
0336     0x15, 0x0C,         /*      Logical Minimum (12),           */
0337     0x25, 0x17,         /*      Logical Maximum (23),           */
0338     0x75, 0x05,         /*      Report Size (5),                */
0339     0x80,               /*      Input,                          */
0340     0x75, 0x03,         /*      Report Size (3),                */
0341     0x81, 0x03,         /*      Input (Constant, Variable),     */
0342     0x75, 0x20,         /*      Report Size (32),               */
0343     0x81, 0x03,         /*      Input (Constant, Variable),     */
0344     0xC0,               /*  End Collection,                     */
0345     0x09, 0x01,         /*  Usage (Consumer Control),           */
0346     0xA1, 0x01,         /*  Collection (Application),           */
0347     0x85, 0x0C,         /*      Report ID (12),                 */
0348     0x75, 0x01,         /*      Report Size (1),                */
0349     0x09, 0xE9,         /*      Usage (Volume Inc),             */
0350     0x09, 0xEA,         /*      Usage (Volume Dec),             */
0351     0x09, 0xE2,         /*      Usage (Mute),                   */
0352     0x14,               /*      Logical Minimum (0),            */
0353     0x25, 0x01,         /*      Logical Maximum (1),            */
0354     0x95, 0x03,         /*      Report Count (3),               */
0355     0x81, 0x06,         /*      Input (Variable, Relative),     */
0356     0x95, 0x35,         /*      Report Count (53),              */
0357     0x81, 0x03,         /*      Input (Constant, Variable),     */
0358     0xC0                /*  End Collection                      */
0359 };
0360 
0361 /* Size of the original report descriptor of Media Tablet 14.1 inch */
0362 #define MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE  309
0363 
0364 /* Fixed Media Tablet 14.1 inch descriptor */
0365 static __u8 media_tablet_14_1_inch_rdesc_fixed[] = {
0366     0x05, 0x0D,         /*  Usage Page (Digitizer),             */
0367     0x09, 0x02,         /*  Usage (Pen),                        */
0368     0xA1, 0x01,         /*  Collection (Application),           */
0369     0x85, 0x10,         /*      Report ID (16),                 */
0370     0x09, 0x20,         /*      Usage (Stylus),                 */
0371     0xA0,               /*      Collection (Physical),          */
0372     0x09, 0x42,         /*          Usage (Tip Switch),         */
0373     0x09, 0x44,         /*          Usage (Barrel Switch),      */
0374     0x09, 0x46,         /*          Usage (Tablet Pick),        */
0375     0x15, 0x01,         /*          Logical Minimum (1),        */
0376     0x25, 0x03,         /*          Logical Maximum (3),        */
0377     0x75, 0x04,         /*          Report Size (4),            */
0378     0x95, 0x01,         /*          Report Count (1),           */
0379     0x80,               /*          Input,                      */
0380     0x75, 0x01,         /*          Report Size (1),            */
0381     0x09, 0x32,         /*          Usage (In Range),           */
0382     0x14,               /*          Logical Minimum (0),        */
0383     0x25, 0x01,         /*          Logical Maximum (1),        */
0384     0x95, 0x01,         /*          Report Count (1),           */
0385     0x81, 0x02,         /*          Input (Variable),           */
0386     0x95, 0x03,         /*          Report Count (3),           */
0387     0x81, 0x03,         /*          Input (Constant, Variable), */
0388     0x75, 0x10,         /*          Report Size (16),           */
0389     0x95, 0x01,         /*          Report Count (1),           */
0390     0x14,               /*          Logical Minimum (0),        */
0391     0xA4,               /*          Push,                       */
0392     0x05, 0x01,         /*          Usage Page (Desktop),       */
0393     0x65, 0x13,         /*          Unit (Inch),                */
0394     0x55, 0xFD,         /*          Unit Exponent (-3),         */
0395     0x34,               /*          Physical Minimum (0),       */
0396     0x09, 0x30,         /*          Usage (X),                  */
0397     0x46, 0xE0, 0x2E,   /*          Physical Maximum (12000),   */
0398     0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),    */
0399     0x81, 0x02,         /*          Input (Variable),           */
0400     0x09, 0x31,         /*          Usage (Y),                  */
0401     0x46, 0x52, 0x1C,   /*          Physical Maximum (7250),    */
0402     0x26, 0xFF, 0x3F,   /*          Logical Maximum (16383),    */
0403     0x81, 0x02,         /*          Input (Variable),           */
0404     0xB4,               /*          Pop,                        */
0405     0x09, 0x30,         /*          Usage (Tip Pressure),       */
0406     0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
0407     0x81, 0x02,         /*          Input (Variable),           */
0408     0xC0,               /*      End Collection,                 */
0409     0xC0,               /*  End Collection,                     */
0410     0x05, 0x01,         /*  Usage Page (Desktop),               */
0411     0x09, 0x02,         /*  Usage (Mouse),                      */
0412     0xA1, 0x01,         /*  Collection (Application),           */
0413     0x85, 0x01,         /*      Report ID (1),                  */
0414     0x09, 0x01,         /*      Usage (Pointer),                */
0415     0xA0,               /*      Collection (Physical),          */
0416     0x75, 0x08,         /*          Report Size (8),            */
0417     0x95, 0x03,         /*          Report Count (3),           */
0418     0x81, 0x03,         /*          Input (Constant, Variable), */
0419     0x95, 0x02,         /*          Report Count (2),           */
0420     0x15, 0xFF,         /*          Logical Minimum (-1),       */
0421     0x25, 0x01,         /*          Logical Maximum (1),        */
0422     0x09, 0x38,         /*          Usage (Wheel),              */
0423     0x0B, 0x38, 0x02,   /*          Usage (Consumer AC Pan),    */
0424         0x0C, 0x00,
0425     0x81, 0x06,         /*          Input (Variable, Relative), */
0426     0xC0,               /*      End Collection,                 */
0427     0xC0,               /*  End Collection,                     */
0428     0x05, 0x0C,         /*  Usage Page (Consumer),              */
0429     0x09, 0x01,         /*  Usage (Consumer Control),           */
0430     0xA1, 0x01,         /*  Collection (Application),           */
0431     0x85, 0x0D,         /*      Report ID (13),                 */
0432     0x95, 0x01,         /*      Report Count (1),               */
0433     0x75, 0x10,         /*      Report Size (16),               */
0434     0x81, 0x03,         /*      Input (Constant, Variable),     */
0435     0x0A, 0x2F, 0x02,   /*      Usage (AC Zoom),                */
0436     0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
0437     0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
0438     0x09, 0xB6,         /*      Usage (Scan Previous Track),    */
0439     0x09, 0xB5,         /*      Usage (Scan Next Track),        */
0440     0x08,               /*      Usage (00h),                    */
0441     0x08,               /*      Usage (00h),                    */
0442     0x08,               /*      Usage (00h),                    */
0443     0x08,               /*      Usage (00h),                    */
0444     0x08,               /*      Usage (00h),                    */
0445     0x0A, 0x2E, 0x02,   /*      Usage (AC Zoom Out),            */
0446     0x0A, 0x2D, 0x02,   /*      Usage (AC Zoom In),             */
0447     0x15, 0x0C,         /*      Logical Minimum (12),           */
0448     0x25, 0x17,         /*      Logical Maximum (23),           */
0449     0x75, 0x05,         /*      Report Size (5),                */
0450     0x80,               /*      Input,                          */
0451     0x75, 0x03,         /*      Report Size (3),                */
0452     0x81, 0x03,         /*      Input (Constant, Variable),     */
0453     0x75, 0x20,         /*      Report Size (32),               */
0454     0x81, 0x03,         /*      Input (Constant, Variable),     */
0455     0xC0,               /*  End Collection,                     */
0456     0x09, 0x01,         /*  Usage (Consumer Control),           */
0457     0xA1, 0x01,         /*  Collection (Application),           */
0458     0x85, 0x0C,         /*      Report ID (12),                 */
0459     0x75, 0x01,         /*      Report Size (1),                */
0460     0x09, 0xE9,         /*      Usage (Volume Inc),             */
0461     0x09, 0xEA,         /*      Usage (Volume Dec),             */
0462     0x09, 0xE2,         /*      Usage (Mute),                   */
0463     0x14,               /*      Logical Minimum (0),            */
0464     0x25, 0x01,         /*      Logical Maximum (1),            */
0465     0x95, 0x03,         /*      Report Count (3),               */
0466     0x81, 0x06,         /*      Input (Variable, Relative),     */
0467     0x75, 0x05,         /*      Report Size (5),                */
0468     0x81, 0x03,         /*      Input (Constant, Variable),     */
0469     0xC0                /*  End Collection                      */
0470 };
0471 
0472 /* Size of the original report descriptor of Sirius Battery Free Tablet */
0473 #define SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE  335
0474 
0475 /* Fixed Sirius Battery Free Tablet descriptor */
0476 static __u8 sirius_battery_free_tablet_rdesc_fixed[] = {
0477     0x05, 0x0D,         /*  Usage Page (Digitizer),             */
0478     0x09, 0x02,         /*  Usage (Pen),                        */
0479     0xA1, 0x01,         /*  Collection (Application),           */
0480     0x85, 0x10,         /*      Report ID (16),                 */
0481     0x09, 0x20,         /*      Usage (Stylus),                 */
0482     0xA0,               /*      Collection (Physical),          */
0483     0x95, 0x01,         /*          Report Count (1),           */
0484     0x15, 0x01,         /*          Logical Minimum (1),        */
0485     0x25, 0x03,         /*          Logical Maximum (3),        */
0486     0x75, 0x02,         /*          Report Size (2),            */
0487     0x09, 0x42,         /*          Usage (Tip Switch),         */
0488     0x09, 0x44,         /*          Usage (Barrel Switch),      */
0489     0x09, 0x46,         /*          Usage (Tablet Pick),        */
0490     0x80,               /*          Input,                      */
0491     0x14,               /*          Logical Minimum (0),        */
0492     0x25, 0x01,         /*          Logical Maximum (1),        */
0493     0x75, 0x01,         /*          Report Size (1),            */
0494     0x09, 0x3C,         /*          Usage (Invert),             */
0495     0x81, 0x02,         /*          Input (Variable),           */
0496     0x81, 0x03,         /*          Input (Constant, Variable), */
0497     0x09, 0x32,         /*          Usage (In Range),           */
0498     0x81, 0x02,         /*          Input (Variable),           */
0499     0x95, 0x03,         /*          Report Count (3),           */
0500     0x81, 0x03,         /*          Input (Constant, Variable), */
0501     0xA4,               /*          Push,                       */
0502     0x05, 0x01,         /*          Usage Page (Desktop),       */
0503     0x55, 0xFD,         /*          Unit Exponent (-3),         */
0504     0x65, 0x13,         /*          Unit (Inch),                */
0505     0x34,               /*          Physical Minimum (0),       */
0506     0x14,               /*          Logical Minimum (0),        */
0507     0x75, 0x10,         /*          Report Size (16),           */
0508     0x95, 0x01,         /*          Report Count (1),           */
0509     0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
0510     0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
0511     0x09, 0x30,         /*          Usage (X),                  */
0512     0x81, 0x02,         /*          Input (Variable),           */
0513     0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
0514     0x26, 0xE0, 0x2E,   /*          Logical Maximum (12000),    */
0515     0x09, 0x31,         /*          Usage (Y),                  */
0516     0x81, 0x02,         /*          Input (Variable),           */
0517     0xB4,               /*          Pop,                        */
0518     0x75, 0x10,         /*          Report Size (16),           */
0519     0x95, 0x01,         /*          Report Count (1),           */
0520     0x14,               /*          Logical Minimum (0),        */
0521     0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
0522     0x09, 0x30,         /*          Usage (Tip Pressure),       */
0523     0x81, 0x02,         /*          Input (Variable),           */
0524     0xA4,               /*          Push,                       */
0525     0x55, 0xFE,         /*          Unit Exponent (-2),         */
0526     0x65, 0x12,         /*          Unit (Radians),             */
0527     0x35, 0x97,         /*          Physical Minimum (-105),    */
0528     0x45, 0x69,         /*          Physical Maximum (105),     */
0529     0x15, 0x97,         /*          Logical Minimum (-105),     */
0530     0x25, 0x69,         /*          Logical Maximum (105),      */
0531     0x75, 0x08,         /*          Report Size (8),            */
0532     0x95, 0x02,         /*          Report Count (2),           */
0533     0x09, 0x3D,         /*          Usage (X Tilt),             */
0534     0x09, 0x3E,         /*          Usage (Y Tilt),             */
0535     0x81, 0x02,         /*          Input (Variable),           */
0536     0xB4,               /*          Pop,                        */
0537     0xC0,               /*      End Collection,                 */
0538     0xC0,               /*  End Collection,                     */
0539     0x05, 0x01,         /*  Usage Page (Desktop),               */
0540     0x09, 0x02,         /*  Usage (Mouse),                      */
0541     0xA1, 0x01,         /*  Collection (Application),           */
0542     0x85, 0x01,         /*      Report ID (1),                  */
0543     0x09, 0x01,         /*      Usage (Pointer),                */
0544     0xA0,               /*      Collection (Physical),          */
0545     0x75, 0x08,         /*          Report Size (8),            */
0546     0x95, 0x03,         /*          Report Count (3),           */
0547     0x81, 0x03,         /*          Input (Constant, Variable), */
0548     0x09, 0x38,         /*          Usage (Wheel),              */
0549     0x15, 0xFF,         /*          Logical Minimum (-1),       */
0550     0x25, 0x01,         /*          Logical Maximum (1),        */
0551     0x75, 0x08,         /*          Report Size (8),            */
0552     0x95, 0x01,         /*          Report Count (1),           */
0553     0x81, 0x06,         /*          Input (Variable, Relative), */
0554     0x75, 0x08,         /*          Report Size (8),            */
0555     0x95, 0x03,         /*          Report Count (3),           */
0556     0x81, 0x03,         /*          Input (Constant, Variable), */
0557     0xC0,               /*      End Collection,                 */
0558     0xC0,               /*  End Collection,                     */
0559     0x05, 0x01,         /*  Usage Page (Desktop),               */
0560     0x09, 0x06,         /*  Usage (Keyboard),                   */
0561     0xA1, 0x01,         /*  Collection (Application),           */
0562     0x85, 0x0D,         /*      Report ID (13),                 */
0563     0x05, 0x07,         /*      Usage Page (Keyboard),          */
0564     0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */
0565     0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */
0566     0x14,               /*      Logical Minimum (0),            */
0567     0x25, 0x01,         /*      Logical Maximum (1),            */
0568     0x75, 0x01,         /*      Report Size (1),                */
0569     0x95, 0x08,         /*      Report Count (8),               */
0570     0x81, 0x02,         /*      Input (Variable),               */
0571     0x75, 0x08,         /*      Report Size (8),                */
0572     0x95, 0x01,         /*      Report Count (1),               */
0573     0x81, 0x01,         /*      Input (Constant),               */
0574     0x18,               /*      Usage Minimum (None),           */
0575     0x29, 0x65,         /*      Usage Maximum (KB Application), */
0576     0x14,               /*      Logical Minimum (0),            */
0577     0x25, 0x65,         /*      Logical Maximum (101),          */
0578     0x75, 0x08,         /*      Report Size (8),                */
0579     0x95, 0x05,         /*      Report Count (5),               */
0580     0x80,               /*      Input,                          */
0581     0xC0,               /*  End Collection,                     */
0582     0x05, 0x0C,         /*  Usage Page (Consumer),              */
0583     0x09, 0x01,         /*  Usage (Consumer Control),           */
0584     0xA1, 0x01,         /*  Collection (Application),           */
0585     0x85, 0x0C,         /*      Report ID (12),                 */
0586     0x09, 0xE9,         /*      Usage (Volume Inc),             */
0587     0x09, 0xEA,         /*      Usage (Volume Dec),             */
0588     0x14,               /*      Logical Minimum (0),            */
0589     0x25, 0x01,         /*      Logical Maximum (1),            */
0590     0x75, 0x01,         /*      Report Size (1),                */
0591     0x95, 0x02,         /*      Report Count (2),               */
0592     0x81, 0x02,         /*      Input (Variable),               */
0593     0x75, 0x06,         /*      Report Size (6),                */
0594     0x95, 0x01,         /*      Report Count (1),               */
0595     0x81, 0x03,         /*      Input (Constant, Variable),     */
0596     0x75, 0x10,         /*      Report Size (16),               */
0597     0x95, 0x03,         /*      Report Count (3),               */
0598     0x81, 0x03,         /*      Input (Constant, Variable),     */
0599     0xC0                /*  End Collection                      */
0600 };
0601 
0602 static __u8 *waltop_report_fixup(struct hid_device *hdev, __u8 *rdesc,
0603         unsigned int *rsize)
0604 {
0605     switch (hdev->product) {
0606     case USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH:
0607         if (*rsize == SLIM_TABLET_5_8_INCH_RDESC_ORIG_SIZE) {
0608             rdesc = slim_tablet_5_8_inch_rdesc_fixed;
0609             *rsize = sizeof(slim_tablet_5_8_inch_rdesc_fixed);
0610         }
0611         break;
0612     case USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH:
0613         if (*rsize == SLIM_TABLET_12_1_INCH_RDESC_ORIG_SIZE) {
0614             rdesc = slim_tablet_12_1_inch_rdesc_fixed;
0615             *rsize = sizeof(slim_tablet_12_1_inch_rdesc_fixed);
0616         }
0617         break;
0618     case USB_DEVICE_ID_WALTOP_Q_PAD:
0619         if (*rsize == Q_PAD_RDESC_ORIG_SIZE) {
0620             rdesc = q_pad_rdesc_fixed;
0621             *rsize = sizeof(q_pad_rdesc_fixed);
0622         }
0623         break;
0624     case USB_DEVICE_ID_WALTOP_PID_0038:
0625         if (*rsize == PID_0038_RDESC_ORIG_SIZE) {
0626             rdesc = pid_0038_rdesc_fixed;
0627             *rsize = sizeof(pid_0038_rdesc_fixed);
0628         }
0629         break;
0630     case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH:
0631         if (*rsize == MEDIA_TABLET_10_6_INCH_RDESC_ORIG_SIZE) {
0632             rdesc = media_tablet_10_6_inch_rdesc_fixed;
0633             *rsize = sizeof(media_tablet_10_6_inch_rdesc_fixed);
0634         }
0635         break;
0636     case USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH:
0637         if (*rsize == MEDIA_TABLET_14_1_INCH_RDESC_ORIG_SIZE) {
0638             rdesc = media_tablet_14_1_inch_rdesc_fixed;
0639             *rsize = sizeof(media_tablet_14_1_inch_rdesc_fixed);
0640         }
0641         break;
0642     case USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET:
0643         if (*rsize == SIRIUS_BATTERY_FREE_TABLET_RDESC_ORIG_SIZE) {
0644             rdesc = sirius_battery_free_tablet_rdesc_fixed;
0645             *rsize = sizeof(sirius_battery_free_tablet_rdesc_fixed);
0646         }
0647         break;
0648     }
0649     return rdesc;
0650 }
0651 
0652 static int waltop_raw_event(struct hid_device *hdev, struct hid_report *report,
0653              u8 *data, int size)
0654 {
0655     /* If this is a pen input report */
0656     if (report->type == HID_INPUT_REPORT && report->id == 16 && size >= 8) {
0657         /*
0658          * Ignore reported pressure when a barrel button is pressed,
0659          * because it is rarely correct.
0660          */
0661 
0662         /* If a barrel button is pressed */
0663         if ((data[1] & 0xF) > 1) {
0664             /* Report zero pressure */
0665             data[6] = 0;
0666             data[7] = 0;
0667         }
0668     }
0669 
0670     /* If this is a pen input report of Sirius Battery Free Tablet */
0671     if (hdev->product == USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET &&
0672         report->type == HID_INPUT_REPORT &&
0673         report->id == 16 &&
0674         size == 10) {
0675         /*
0676          * The tablet reports tilt as roughly sin(a)*21 (18 means 60
0677          * degrees).
0678          *
0679          * This array stores angles as radians * 100, corresponding to
0680          * reported values up to 60 degrees, as expected by userspace.
0681          */
0682         static const s8 tilt_to_radians[] = {
0683             0, 5, 10, 14, 19, 24, 29, 34, 40, 45,
0684             50, 56, 62, 68, 74, 81, 88, 96, 105
0685         };
0686 
0687         s8 tilt_x = (s8)data[8];
0688         s8 tilt_y = (s8)data[9];
0689         s8 sign_x = tilt_x >= 0 ? 1 : -1;
0690         s8 sign_y = tilt_y >= 0 ? 1 : -1;
0691 
0692         tilt_x *= sign_x;
0693         tilt_y *= sign_y;
0694 
0695         /*
0696          * Reverse the Y Tilt direction to match the HID standard and
0697          * userspace expectations. See HID Usage Tables v1.12 16.3.2
0698          * Tilt Orientation.
0699          */
0700         sign_y *= -1;
0701 
0702         /*
0703          * This effectively clamps reported tilt to 60 degrees - the
0704          * range expected by userspace
0705          */
0706         if (tilt_x > ARRAY_SIZE(tilt_to_radians) - 1)
0707             tilt_x = ARRAY_SIZE(tilt_to_radians) - 1;
0708         if (tilt_y > ARRAY_SIZE(tilt_to_radians) - 1)
0709             tilt_y = ARRAY_SIZE(tilt_to_radians) - 1;
0710 
0711         data[8] = tilt_to_radians[tilt_x] * sign_x;
0712         data[9] = tilt_to_radians[tilt_y] * sign_y;
0713     }
0714 
0715     return 0;
0716 }
0717 
0718 static const struct hid_device_id waltop_devices[] = {
0719     { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
0720                 USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH) },
0721     { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
0722                 USB_DEVICE_ID_WALTOP_SLIM_TABLET_12_1_INCH) },
0723     { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
0724                 USB_DEVICE_ID_WALTOP_Q_PAD) },
0725     { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
0726                 USB_DEVICE_ID_WALTOP_PID_0038) },
0727     { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
0728                 USB_DEVICE_ID_WALTOP_MEDIA_TABLET_10_6_INCH) },
0729     { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
0730                 USB_DEVICE_ID_WALTOP_MEDIA_TABLET_14_1_INCH) },
0731     { HID_USB_DEVICE(USB_VENDOR_ID_WALTOP,
0732              USB_DEVICE_ID_WALTOP_SIRIUS_BATTERY_FREE_TABLET) },
0733     { }
0734 };
0735 MODULE_DEVICE_TABLE(hid, waltop_devices);
0736 
0737 static struct hid_driver waltop_driver = {
0738     .name = "waltop",
0739     .id_table = waltop_devices,
0740     .report_fixup = waltop_report_fixup,
0741     .raw_event = waltop_raw_event,
0742 };
0743 module_hid_driver(waltop_driver);
0744 
0745 MODULE_LICENSE("GPL");