linux/drivers/hid/hid-uclogic.c
<<
>>
Prefs
   1/*
   2 *  HID driver for UC-Logic devices not fully compliant with HID standard
   3 *
   4 *  Copyright (c) 2010-2014 Nikolai Kondrashov
   5 *  Copyright (c) 2013 Martin Rusko
   6 */
   7
   8/*
   9 * This program is free software; you can redistribute it and/or modify it
  10 * under the terms of the GNU General Public License as published by the Free
  11 * Software Foundation; either version 2 of the License, or (at your option)
  12 * any later version.
  13 */
  14
  15#include <linux/device.h>
  16#include <linux/hid.h>
  17#include <linux/module.h>
  18#include <linux/usb.h>
  19#include <asm/unaligned.h>
  20#include "usbhid/usbhid.h"
  21
  22#include "hid-ids.h"
  23
  24/*
  25 * See WPXXXXU model descriptions, device and HID report descriptors at
  26 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP4030U
  27 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP5540U
  28 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP8060U
  29 */
  30
  31/* Size of the original descriptor of WPXXXXU tablets */
  32#define WPXXXXU_RDESC_ORIG_SIZE 212
  33
  34/* Fixed WP4030U report descriptor */
  35static __u8 wp4030u_rdesc_fixed[] = {
  36        0x05, 0x0D,         /*  Usage Page (Digitizer),             */
  37        0x09, 0x02,         /*  Usage (Pen),                        */
  38        0xA1, 0x01,         /*  Collection (Application),           */
  39        0x85, 0x09,         /*      Report ID (9),                  */
  40        0x09, 0x20,         /*      Usage (Stylus),                 */
  41        0xA0,               /*      Collection (Physical),          */
  42        0x75, 0x01,         /*          Report Size (1),            */
  43        0x09, 0x42,         /*          Usage (Tip Switch),         */
  44        0x09, 0x44,         /*          Usage (Barrel Switch),      */
  45        0x09, 0x46,         /*          Usage (Tablet Pick),        */
  46        0x14,               /*          Logical Minimum (0),        */
  47        0x25, 0x01,         /*          Logical Maximum (1),        */
  48        0x95, 0x03,         /*          Report Count (3),           */
  49        0x81, 0x02,         /*          Input (Variable),           */
  50        0x95, 0x05,         /*          Report Count (5),           */
  51        0x81, 0x01,         /*          Input (Constant),           */
  52        0x75, 0x10,         /*          Report Size (16),           */
  53        0x95, 0x01,         /*          Report Count (1),           */
  54        0x14,               /*          Logical Minimum (0),        */
  55        0xA4,               /*          Push,                       */
  56        0x05, 0x01,         /*          Usage Page (Desktop),       */
  57        0x55, 0xFD,         /*          Unit Exponent (-3),         */
  58        0x65, 0x13,         /*          Unit (Inch),                */
  59        0x34,               /*          Physical Minimum (0),       */
  60        0x09, 0x30,         /*          Usage (X),                  */
  61        0x46, 0xA0, 0x0F,   /*          Physical Maximum (4000),    */
  62        0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
  63        0x81, 0x02,         /*          Input (Variable),           */
  64        0x09, 0x31,         /*          Usage (Y),                  */
  65        0x46, 0xB8, 0x0B,   /*          Physical Maximum (3000),    */
  66        0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
  67        0x81, 0x02,         /*          Input (Variable),           */
  68        0xB4,               /*          Pop,                        */
  69        0x09, 0x30,         /*          Usage (Tip Pressure),       */
  70        0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
  71        0x81, 0x02,         /*          Input (Variable),           */
  72        0xC0,               /*      End Collection,                 */
  73        0xC0                /*  End Collection                      */
  74};
  75
  76/* Fixed WP5540U report descriptor */
  77static __u8 wp5540u_rdesc_fixed[] = {
  78        0x05, 0x0D,         /*  Usage Page (Digitizer),             */
  79        0x09, 0x02,         /*  Usage (Pen),                        */
  80        0xA1, 0x01,         /*  Collection (Application),           */
  81        0x85, 0x09,         /*      Report ID (9),                  */
  82        0x09, 0x20,         /*      Usage (Stylus),                 */
  83        0xA0,               /*      Collection (Physical),          */
  84        0x75, 0x01,         /*          Report Size (1),            */
  85        0x09, 0x42,         /*          Usage (Tip Switch),         */
  86        0x09, 0x44,         /*          Usage (Barrel Switch),      */
  87        0x09, 0x46,         /*          Usage (Tablet Pick),        */
  88        0x14,               /*          Logical Minimum (0),        */
  89        0x25, 0x01,         /*          Logical Maximum (1),        */
  90        0x95, 0x03,         /*          Report Count (3),           */
  91        0x81, 0x02,         /*          Input (Variable),           */
  92        0x95, 0x05,         /*          Report Count (5),           */
  93        0x81, 0x01,         /*          Input (Constant),           */
  94        0x75, 0x10,         /*          Report Size (16),           */
  95        0x95, 0x01,         /*          Report Count (1),           */
  96        0x14,               /*          Logical Minimum (0),        */
  97        0xA4,               /*          Push,                       */
  98        0x05, 0x01,         /*          Usage Page (Desktop),       */
  99        0x55, 0xFD,         /*          Unit Exponent (-3),         */
 100        0x65, 0x13,         /*          Unit (Inch),                */
 101        0x34,               /*          Physical Minimum (0),       */
 102        0x09, 0x30,         /*          Usage (X),                  */
 103        0x46, 0x7C, 0x15,   /*          Physical Maximum (5500),    */
 104        0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
 105        0x81, 0x02,         /*          Input (Variable),           */
 106        0x09, 0x31,         /*          Usage (Y),                  */
 107        0x46, 0xA0, 0x0F,   /*          Physical Maximum (4000),    */
 108        0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
 109        0x81, 0x02,         /*          Input (Variable),           */
 110        0xB4,               /*          Pop,                        */
 111        0x09, 0x30,         /*          Usage (Tip Pressure),       */
 112        0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
 113        0x81, 0x02,         /*          Input (Variable),           */
 114        0xC0,               /*      End Collection,                 */
 115        0xC0,               /*  End Collection,                     */
 116        0x05, 0x01,         /*  Usage Page (Desktop),               */
 117        0x09, 0x02,         /*  Usage (Mouse),                      */
 118        0xA1, 0x01,         /*  Collection (Application),           */
 119        0x85, 0x08,         /*      Report ID (8),                  */
 120        0x09, 0x01,         /*      Usage (Pointer),                */
 121        0xA0,               /*      Collection (Physical),          */
 122        0x75, 0x01,         /*          Report Size (1),            */
 123        0x05, 0x09,         /*          Usage Page (Button),        */
 124        0x19, 0x01,         /*          Usage Minimum (01h),        */
 125        0x29, 0x03,         /*          Usage Maximum (03h),        */
 126        0x14,               /*          Logical Minimum (0),        */
 127        0x25, 0x01,         /*          Logical Maximum (1),        */
 128        0x95, 0x03,         /*          Report Count (3),           */
 129        0x81, 0x02,         /*          Input (Variable),           */
 130        0x95, 0x05,         /*          Report Count (5),           */
 131        0x81, 0x01,         /*          Input (Constant),           */
 132        0x05, 0x01,         /*          Usage Page (Desktop),       */
 133        0x75, 0x08,         /*          Report Size (8),            */
 134        0x09, 0x30,         /*          Usage (X),                  */
 135        0x09, 0x31,         /*          Usage (Y),                  */
 136        0x15, 0x81,         /*          Logical Minimum (-127),     */
 137        0x25, 0x7F,         /*          Logical Maximum (127),      */
 138        0x95, 0x02,         /*          Report Count (2),           */
 139        0x81, 0x06,         /*          Input (Variable, Relative), */
 140        0x09, 0x38,         /*          Usage (Wheel),              */
 141        0x15, 0xFF,         /*          Logical Minimum (-1),       */
 142        0x25, 0x01,         /*          Logical Maximum (1),        */
 143        0x95, 0x01,         /*          Report Count (1),           */
 144        0x81, 0x06,         /*          Input (Variable, Relative), */
 145        0x81, 0x01,         /*          Input (Constant),           */
 146        0xC0,               /*      End Collection,                 */
 147        0xC0                /*  End Collection                      */
 148};
 149
 150/* Fixed WP8060U report descriptor */
 151static __u8 wp8060u_rdesc_fixed[] = {
 152        0x05, 0x0D,         /*  Usage Page (Digitizer),             */
 153        0x09, 0x02,         /*  Usage (Pen),                        */
 154        0xA1, 0x01,         /*  Collection (Application),           */
 155        0x85, 0x09,         /*      Report ID (9),                  */
 156        0x09, 0x20,         /*      Usage (Stylus),                 */
 157        0xA0,               /*      Collection (Physical),          */
 158        0x75, 0x01,         /*          Report Size (1),            */
 159        0x09, 0x42,         /*          Usage (Tip Switch),         */
 160        0x09, 0x44,         /*          Usage (Barrel Switch),      */
 161        0x09, 0x46,         /*          Usage (Tablet Pick),        */
 162        0x14,               /*          Logical Minimum (0),        */
 163        0x25, 0x01,         /*          Logical Maximum (1),        */
 164        0x95, 0x03,         /*          Report Count (3),           */
 165        0x81, 0x02,         /*          Input (Variable),           */
 166        0x95, 0x05,         /*          Report Count (5),           */
 167        0x81, 0x01,         /*          Input (Constant),           */
 168        0x75, 0x10,         /*          Report Size (16),           */
 169        0x95, 0x01,         /*          Report Count (1),           */
 170        0x14,               /*          Logical Minimum (0),        */
 171        0xA4,               /*          Push,                       */
 172        0x05, 0x01,         /*          Usage Page (Desktop),       */
 173        0x55, 0xFD,         /*          Unit Exponent (-3),         */
 174        0x65, 0x13,         /*          Unit (Inch),                */
 175        0x34,               /*          Physical Minimum (0),       */
 176        0x09, 0x30,         /*          Usage (X),                  */
 177        0x46, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
 178        0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
 179        0x81, 0x02,         /*          Input (Variable),           */
 180        0x09, 0x31,         /*          Usage (Y),                  */
 181        0x46, 0x70, 0x17,   /*          Physical Maximum (6000),    */
 182        0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
 183        0x81, 0x02,         /*          Input (Variable),           */
 184        0xB4,               /*          Pop,                        */
 185        0x09, 0x30,         /*          Usage (Tip Pressure),       */
 186        0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
 187        0x81, 0x02,         /*          Input (Variable),           */
 188        0xC0,               /*      End Collection,                 */
 189        0xC0,               /*  End Collection,                     */
 190        0x05, 0x01,         /*  Usage Page (Desktop),               */
 191        0x09, 0x02,         /*  Usage (Mouse),                      */
 192        0xA1, 0x01,         /*  Collection (Application),           */
 193        0x85, 0x08,         /*      Report ID (8),                  */
 194        0x09, 0x01,         /*      Usage (Pointer),                */
 195        0xA0,               /*      Collection (Physical),          */
 196        0x75, 0x01,         /*          Report Size (1),            */
 197        0x05, 0x09,         /*          Usage Page (Button),        */
 198        0x19, 0x01,         /*          Usage Minimum (01h),        */
 199        0x29, 0x03,         /*          Usage Maximum (03h),        */
 200        0x14,               /*          Logical Minimum (0),        */
 201        0x25, 0x01,         /*          Logical Maximum (1),        */
 202        0x95, 0x03,         /*          Report Count (3),           */
 203        0x81, 0x02,         /*          Input (Variable),           */
 204        0x95, 0x05,         /*          Report Count (5),           */
 205        0x81, 0x01,         /*          Input (Constant),           */
 206        0x05, 0x01,         /*          Usage Page (Desktop),       */
 207        0x75, 0x08,         /*          Report Size (8),            */
 208        0x09, 0x30,         /*          Usage (X),                  */
 209        0x09, 0x31,         /*          Usage (Y),                  */
 210        0x15, 0x81,         /*          Logical Minimum (-127),     */
 211        0x25, 0x7F,         /*          Logical Maximum (127),      */
 212        0x95, 0x02,         /*          Report Count (2),           */
 213        0x81, 0x06,         /*          Input (Variable, Relative), */
 214        0x09, 0x38,         /*          Usage (Wheel),              */
 215        0x15, 0xFF,         /*          Logical Minimum (-1),       */
 216        0x25, 0x01,         /*          Logical Maximum (1),        */
 217        0x95, 0x01,         /*          Report Count (1),           */
 218        0x81, 0x06,         /*          Input (Variable, Relative), */
 219        0x81, 0x01,         /*          Input (Constant),           */
 220        0xC0,               /*      End Collection,                 */
 221        0xC0                /*  End Collection                      */
 222};
 223
 224/*
 225 * See WP1062 description, device and HID report descriptors at
 226 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_WP1062
 227 */
 228
 229/* Size of the original descriptor of WP1062 tablet */
 230#define WP1062_RDESC_ORIG_SIZE  254
 231
 232/* Fixed WP1062 report descriptor */
 233static __u8 wp1062_rdesc_fixed[] = {
 234        0x05, 0x0D,         /*  Usage Page (Digitizer),             */
 235        0x09, 0x02,         /*  Usage (Pen),                        */
 236        0xA1, 0x01,         /*  Collection (Application),           */
 237        0x85, 0x09,         /*      Report ID (9),                  */
 238        0x09, 0x20,         /*      Usage (Stylus),                 */
 239        0xA0,               /*      Collection (Physical),          */
 240        0x75, 0x01,         /*          Report Size (1),            */
 241        0x09, 0x42,         /*          Usage (Tip Switch),         */
 242        0x09, 0x44,         /*          Usage (Barrel Switch),      */
 243        0x09, 0x46,         /*          Usage (Tablet Pick),        */
 244        0x14,               /*          Logical Minimum (0),        */
 245        0x25, 0x01,         /*          Logical Maximum (1),        */
 246        0x95, 0x03,         /*          Report Count (3),           */
 247        0x81, 0x02,         /*          Input (Variable),           */
 248        0x95, 0x04,         /*          Report Count (4),           */
 249        0x81, 0x01,         /*          Input (Constant),           */
 250        0x09, 0x32,         /*          Usage (In Range),           */
 251        0x95, 0x01,         /*          Report Count (1),           */
 252        0x81, 0x02,         /*          Input (Variable),           */
 253        0x75, 0x10,         /*          Report Size (16),           */
 254        0x95, 0x01,         /*          Report Count (1),           */
 255        0x14,               /*          Logical Minimum (0),        */
 256        0xA4,               /*          Push,                       */
 257        0x05, 0x01,         /*          Usage Page (Desktop),       */
 258        0x55, 0xFD,         /*          Unit Exponent (-3),         */
 259        0x65, 0x13,         /*          Unit (Inch),                */
 260        0x34,               /*          Physical Minimum (0),       */
 261        0x09, 0x30,         /*          Usage (X),                  */
 262        0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
 263        0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
 264        0x81, 0x02,         /*          Input (Variable),           */
 265        0x09, 0x31,         /*          Usage (Y),                  */
 266        0x46, 0xB7, 0x19,   /*          Physical Maximum (6583),    */
 267        0x26, 0x6E, 0x33,   /*          Logical Maximum (13166),    */
 268        0x81, 0x02,         /*          Input (Variable),           */
 269        0xB4,               /*          Pop,                        */
 270        0x09, 0x30,         /*          Usage (Tip Pressure),       */
 271        0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
 272        0x81, 0x02,         /*          Input (Variable),           */
 273        0xC0,               /*      End Collection,                 */
 274        0xC0                /*  End Collection                      */
 275};
 276
 277/*
 278 * See PF1209 description, device and HID report descriptors at
 279 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_PF1209
 280 */
 281
 282/* Size of the original descriptor of PF1209 tablet */
 283#define PF1209_RDESC_ORIG_SIZE  234
 284
 285/* Fixed PF1209 report descriptor */
 286static __u8 pf1209_rdesc_fixed[] = {
 287        0x05, 0x0D,         /*  Usage Page (Digitizer),             */
 288        0x09, 0x02,         /*  Usage (Pen),                        */
 289        0xA1, 0x01,         /*  Collection (Application),           */
 290        0x85, 0x09,         /*      Report ID (9),                  */
 291        0x09, 0x20,         /*      Usage (Stylus),                 */
 292        0xA0,               /*      Collection (Physical),          */
 293        0x75, 0x01,         /*          Report Size (1),            */
 294        0x09, 0x42,         /*          Usage (Tip Switch),         */
 295        0x09, 0x44,         /*          Usage (Barrel Switch),      */
 296        0x09, 0x46,         /*          Usage (Tablet Pick),        */
 297        0x14,               /*          Logical Minimum (0),        */
 298        0x25, 0x01,         /*          Logical Maximum (1),        */
 299        0x95, 0x03,         /*          Report Count (3),           */
 300        0x81, 0x02,         /*          Input (Variable),           */
 301        0x95, 0x05,         /*          Report Count (5),           */
 302        0x81, 0x01,         /*          Input (Constant),           */
 303        0x75, 0x10,         /*          Report Size (16),           */
 304        0x95, 0x01,         /*          Report Count (1),           */
 305        0x14,               /*          Logical Minimum (0),        */
 306        0xA4,               /*          Push,                       */
 307        0x05, 0x01,         /*          Usage Page (Desktop),       */
 308        0x55, 0xFD,         /*          Unit Exponent (-3),         */
 309        0x65, 0x13,         /*          Unit (Inch),                */
 310        0x34,               /*          Physical Minimum (0),       */
 311        0x09, 0x30,         /*          Usage (X),                  */
 312        0x46, 0xE0, 0x2E,   /*          Physical Maximum (12000),   */
 313        0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
 314        0x81, 0x02,         /*          Input (Variable),           */
 315        0x09, 0x31,         /*          Usage (Y),                  */
 316        0x46, 0x28, 0x23,   /*          Physical Maximum (9000),    */
 317        0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
 318        0x81, 0x02,         /*          Input (Variable),           */
 319        0xB4,               /*          Pop,                        */
 320        0x09, 0x30,         /*          Usage (Tip Pressure),       */
 321        0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
 322        0x81, 0x02,         /*          Input (Variable),           */
 323        0xC0,               /*      End Collection,                 */
 324        0xC0,               /*  End Collection,                     */
 325        0x05, 0x01,         /*  Usage Page (Desktop),               */
 326        0x09, 0x02,         /*  Usage (Mouse),                      */
 327        0xA1, 0x01,         /*  Collection (Application),           */
 328        0x85, 0x08,         /*      Report ID (8),                  */
 329        0x09, 0x01,         /*      Usage (Pointer),                */
 330        0xA0,               /*      Collection (Physical),          */
 331        0x75, 0x01,         /*          Report Size (1),            */
 332        0x05, 0x09,         /*          Usage Page (Button),        */
 333        0x19, 0x01,         /*          Usage Minimum (01h),        */
 334        0x29, 0x03,         /*          Usage Maximum (03h),        */
 335        0x14,               /*          Logical Minimum (0),        */
 336        0x25, 0x01,         /*          Logical Maximum (1),        */
 337        0x95, 0x03,         /*          Report Count (3),           */
 338        0x81, 0x02,         /*          Input (Variable),           */
 339        0x95, 0x05,         /*          Report Count (5),           */
 340        0x81, 0x01,         /*          Input (Constant),           */
 341        0x05, 0x01,         /*          Usage Page (Desktop),       */
 342        0x75, 0x08,         /*          Report Size (8),            */
 343        0x09, 0x30,         /*          Usage (X),                  */
 344        0x09, 0x31,         /*          Usage (Y),                  */
 345        0x15, 0x81,         /*          Logical Minimum (-127),     */
 346        0x25, 0x7F,         /*          Logical Maximum (127),      */
 347        0x95, 0x02,         /*          Report Count (2),           */
 348        0x81, 0x06,         /*          Input (Variable, Relative), */
 349        0x09, 0x38,         /*          Usage (Wheel),              */
 350        0x15, 0xFF,         /*          Logical Minimum (-1),       */
 351        0x25, 0x01,         /*          Logical Maximum (1),        */
 352        0x95, 0x01,         /*          Report Count (1),           */
 353        0x81, 0x06,         /*          Input (Variable, Relative), */
 354        0x81, 0x01,         /*          Input (Constant),           */
 355        0xC0,               /*      End Collection,                 */
 356        0xC0                /*  End Collection                      */
 357};
 358
 359/*
 360 * See TWHL850 description, device and HID report descriptors at
 361 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Wireless_Tablet_TWHL850
 362 */
 363
 364/* Size of the original descriptors of TWHL850 tablet */
 365#define TWHL850_RDESC_ORIG_SIZE0        182
 366#define TWHL850_RDESC_ORIG_SIZE1        161
 367#define TWHL850_RDESC_ORIG_SIZE2        92
 368
 369/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
 370static __u8 twhl850_rdesc_fixed0[] = {
 371        0x05, 0x0D,         /*  Usage Page (Digitizer),             */
 372        0x09, 0x02,         /*  Usage (Pen),                        */
 373        0xA1, 0x01,         /*  Collection (Application),           */
 374        0x85, 0x09,         /*      Report ID (9),                  */
 375        0x09, 0x20,         /*      Usage (Stylus),                 */
 376        0xA0,               /*      Collection (Physical),          */
 377        0x14,               /*          Logical Minimum (0),        */
 378        0x25, 0x01,         /*          Logical Maximum (1),        */
 379        0x75, 0x01,         /*          Report Size (1),            */
 380        0x95, 0x03,         /*          Report Count (3),           */
 381        0x09, 0x42,         /*          Usage (Tip Switch),         */
 382        0x09, 0x44,         /*          Usage (Barrel Switch),      */
 383        0x09, 0x46,         /*          Usage (Tablet Pick),        */
 384        0x81, 0x02,         /*          Input (Variable),           */
 385        0x81, 0x03,         /*          Input (Constant, Variable), */
 386        0x95, 0x01,         /*          Report Count (1),           */
 387        0x09, 0x32,         /*          Usage (In Range),           */
 388        0x81, 0x02,         /*          Input (Variable),           */
 389        0x81, 0x03,         /*          Input (Constant, Variable), */
 390        0x75, 0x10,         /*          Report Size (16),           */
 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, 0x40, 0x1F,   /*          Physical Maximum (8000),    */
 398        0x26, 0x00, 0x7D,   /*          Logical Maximum (32000),    */
 399        0x81, 0x02,         /*          Input (Variable),           */
 400        0x09, 0x31,         /*          Usage (Y),                  */
 401        0x46, 0x88, 0x13,   /*          Physical Maximum (5000),    */
 402        0x26, 0x20, 0x4E,   /*          Logical Maximum (20000),    */
 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};
 411
 412/* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
 413static __u8 twhl850_rdesc_fixed1[] = {
 414        0x05, 0x01,         /*  Usage Page (Desktop),               */
 415        0x09, 0x02,         /*  Usage (Mouse),                      */
 416        0xA1, 0x01,         /*  Collection (Application),           */
 417        0x85, 0x01,         /*      Report ID (1),                  */
 418        0x09, 0x01,         /*      Usage (Pointer),                */
 419        0xA0,               /*      Collection (Physical),          */
 420        0x05, 0x09,         /*          Usage Page (Button),        */
 421        0x75, 0x01,         /*          Report Size (1),            */
 422        0x95, 0x03,         /*          Report Count (3),           */
 423        0x19, 0x01,         /*          Usage Minimum (01h),        */
 424        0x29, 0x03,         /*          Usage Maximum (03h),        */
 425        0x14,               /*          Logical Minimum (0),        */
 426        0x25, 0x01,         /*          Logical Maximum (1),        */
 427        0x81, 0x02,         /*          Input (Variable),           */
 428        0x95, 0x05,         /*          Report Count (5),           */
 429        0x81, 0x03,         /*          Input (Constant, Variable), */
 430        0x05, 0x01,         /*          Usage Page (Desktop),       */
 431        0x09, 0x30,         /*          Usage (X),                  */
 432        0x09, 0x31,         /*          Usage (Y),                  */
 433        0x16, 0x00, 0x80,   /*          Logical Minimum (-32768),   */
 434        0x26, 0xFF, 0x7F,   /*          Logical Maximum (32767),    */
 435        0x75, 0x10,         /*          Report Size (16),           */
 436        0x95, 0x02,         /*          Report Count (2),           */
 437        0x81, 0x06,         /*          Input (Variable, Relative), */
 438        0x09, 0x38,         /*          Usage (Wheel),              */
 439        0x15, 0xFF,         /*          Logical Minimum (-1),       */
 440        0x25, 0x01,         /*          Logical Maximum (1),        */
 441        0x95, 0x01,         /*          Report Count (1),           */
 442        0x75, 0x08,         /*          Report Size (8),            */
 443        0x81, 0x06,         /*          Input (Variable, Relative), */
 444        0x81, 0x03,         /*          Input (Constant, Variable), */
 445        0xC0,               /*      End Collection,                 */
 446        0xC0                /*  End Collection                      */
 447};
 448
 449/* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
 450static __u8 twhl850_rdesc_fixed2[] = {
 451        0x05, 0x01,         /*  Usage Page (Desktop),               */
 452        0x09, 0x06,         /*  Usage (Keyboard),                   */
 453        0xA1, 0x01,         /*  Collection (Application),           */
 454        0x85, 0x03,         /*      Report ID (3),                  */
 455        0x05, 0x07,         /*      Usage Page (Keyboard),          */
 456        0x14,               /*      Logical Minimum (0),            */
 457        0x19, 0xE0,         /*      Usage Minimum (KB Leftcontrol), */
 458        0x29, 0xE7,         /*      Usage Maximum (KB Right GUI),   */
 459        0x25, 0x01,         /*      Logical Maximum (1),            */
 460        0x75, 0x01,         /*      Report Size (1),                */
 461        0x95, 0x08,         /*      Report Count (8),               */
 462        0x81, 0x02,         /*      Input (Variable),               */
 463        0x18,               /*      Usage Minimum (None),           */
 464        0x29, 0xFF,         /*      Usage Maximum (FFh),            */
 465        0x26, 0xFF, 0x00,   /*      Logical Maximum (255),          */
 466        0x75, 0x08,         /*      Report Size (8),                */
 467        0x95, 0x06,         /*      Report Count (6),               */
 468        0x80,               /*      Input,                          */
 469        0xC0                /*  End Collection                      */
 470};
 471
 472/*
 473 * See TWHA60 description, device and HID report descriptors at
 474 * http://sf.net/apps/mediawiki/digimend/?title=UC-Logic_Tablet_TWHA60
 475 */
 476
 477/* Size of the original descriptors of TWHA60 tablet */
 478#define TWHA60_RDESC_ORIG_SIZE0 254
 479#define TWHA60_RDESC_ORIG_SIZE1 139
 480
 481/* Fixed TWHA60 report descriptor, interface 0 (stylus) */
 482static __u8 twha60_rdesc_fixed0[] = {
 483        0x05, 0x0D,         /*  Usage Page (Digitizer),             */
 484        0x09, 0x02,         /*  Usage (Pen),                        */
 485        0xA1, 0x01,         /*  Collection (Application),           */
 486        0x85, 0x09,         /*      Report ID (9),                  */
 487        0x09, 0x20,         /*      Usage (Stylus),                 */
 488        0xA0,               /*      Collection (Physical),          */
 489        0x75, 0x01,         /*          Report Size (1),            */
 490        0x09, 0x42,         /*          Usage (Tip Switch),         */
 491        0x09, 0x44,         /*          Usage (Barrel Switch),      */
 492        0x09, 0x46,         /*          Usage (Tablet Pick),        */
 493        0x14,               /*          Logical Minimum (0),        */
 494        0x25, 0x01,         /*          Logical Maximum (1),        */
 495        0x95, 0x03,         /*          Report Count (3),           */
 496        0x81, 0x02,         /*          Input (Variable),           */
 497        0x95, 0x04,         /*          Report Count (4),           */
 498        0x81, 0x01,         /*          Input (Constant),           */
 499        0x09, 0x32,         /*          Usage (In Range),           */
 500        0x95, 0x01,         /*          Report Count (1),           */
 501        0x81, 0x02,         /*          Input (Variable),           */
 502        0x75, 0x10,         /*          Report Size (16),           */
 503        0x95, 0x01,         /*          Report Count (1),           */
 504        0x14,               /*          Logical Minimum (0),        */
 505        0xA4,               /*          Push,                       */
 506        0x05, 0x01,         /*          Usage Page (Desktop),       */
 507        0x55, 0xFD,         /*          Unit Exponent (-3),         */
 508        0x65, 0x13,         /*          Unit (Inch),                */
 509        0x34,               /*          Physical Minimum (0),       */
 510        0x09, 0x30,         /*          Usage (X),                  */
 511        0x46, 0x10, 0x27,   /*          Physical Maximum (10000),   */
 512        0x27, 0x3F, 0x9C,
 513                0x00, 0x00, /*          Logical Maximum (39999),    */
 514        0x81, 0x02,         /*          Input (Variable),           */
 515        0x09, 0x31,         /*          Usage (Y),                  */
 516        0x46, 0x6A, 0x18,   /*          Physical Maximum (6250),    */
 517        0x26, 0xA7, 0x61,   /*          Logical Maximum (24999),    */
 518        0x81, 0x02,         /*          Input (Variable),           */
 519        0xB4,               /*          Pop,                        */
 520        0x09, 0x30,         /*          Usage (Tip Pressure),       */
 521        0x26, 0xFF, 0x03,   /*          Logical Maximum (1023),     */
 522        0x81, 0x02,         /*          Input (Variable),           */
 523        0xC0,               /*      End Collection,                 */
 524        0xC0                /*  End Collection                      */
 525};
 526
 527/* Fixed TWHA60 report descriptor, interface 1 (frame buttons) */
 528static __u8 twha60_rdesc_fixed1[] = {
 529        0x05, 0x01, /*  Usage Page (Desktop),       */
 530        0x09, 0x06, /*  Usage (Keyboard),           */
 531        0xA1, 0x01, /*  Collection (Application),   */
 532        0x85, 0x05, /*      Report ID (5),          */
 533        0x05, 0x07, /*      Usage Page (Keyboard),  */
 534        0x14,       /*      Logical Minimum (0),    */
 535        0x25, 0x01, /*      Logical Maximum (1),    */
 536        0x75, 0x01, /*      Report Size (1),        */
 537        0x95, 0x08, /*      Report Count (8),       */
 538        0x81, 0x01, /*      Input (Constant),       */
 539        0x95, 0x0C, /*      Report Count (12),      */
 540        0x19, 0x3A, /*      Usage Minimum (KB F1),  */
 541        0x29, 0x45, /*      Usage Maximum (KB F12), */
 542        0x81, 0x02, /*      Input (Variable),       */
 543        0x95, 0x0C, /*      Report Count (12),      */
 544        0x19, 0x68, /*      Usage Minimum (KB F13), */
 545        0x29, 0x73, /*      Usage Maximum (KB F24), */
 546        0x81, 0x02, /*      Input (Variable),       */
 547        0x95, 0x08, /*      Report Count (8),       */
 548        0x81, 0x01, /*      Input (Constant),       */
 549        0xC0        /*  End Collection              */
 550};
 551
 552/* Report descriptor template placeholder head */
 553#define UCLOGIC_PH_HEAD 0xFE, 0xED, 0x1D
 554
 555/* Report descriptor template placeholder IDs */
 556enum uclogic_ph_id {
 557        UCLOGIC_PH_ID_X_LM,
 558        UCLOGIC_PH_ID_X_PM,
 559        UCLOGIC_PH_ID_Y_LM,
 560        UCLOGIC_PH_ID_Y_PM,
 561        UCLOGIC_PH_ID_PRESSURE_LM,
 562        UCLOGIC_PH_ID_NUM
 563};
 564
 565/* Report descriptor template placeholder */
 566#define UCLOGIC_PH(_ID) UCLOGIC_PH_HEAD, UCLOGIC_PH_ID_##_ID
 567#define UCLOGIC_PEN_REPORT_ID   0x07
 568
 569/* Fixed report descriptor template */
 570static const __u8 uclogic_tablet_rdesc_template[] = {
 571        0x05, 0x0D,             /*  Usage Page (Digitizer),                 */
 572        0x09, 0x02,             /*  Usage (Pen),                            */
 573        0xA1, 0x01,             /*  Collection (Application),               */
 574        0x85, 0x07,             /*      Report ID (7),                      */
 575        0x09, 0x20,             /*      Usage (Stylus),                     */
 576        0xA0,                   /*      Collection (Physical),              */
 577        0x14,                   /*          Logical Minimum (0),            */
 578        0x25, 0x01,             /*          Logical Maximum (1),            */
 579        0x75, 0x01,             /*          Report Size (1),                */
 580        0x09, 0x42,             /*          Usage (Tip Switch),             */
 581        0x09, 0x44,             /*          Usage (Barrel Switch),          */
 582        0x09, 0x46,             /*          Usage (Tablet Pick),            */
 583        0x95, 0x03,             /*          Report Count (3),               */
 584        0x81, 0x02,             /*          Input (Variable),               */
 585        0x95, 0x03,             /*          Report Count (3),               */
 586        0x81, 0x03,             /*          Input (Constant, Variable),     */
 587        0x09, 0x32,             /*          Usage (In Range),               */
 588        0x95, 0x01,             /*          Report Count (1),               */
 589        0x81, 0x02,             /*          Input (Variable),               */
 590        0x95, 0x01,             /*          Report Count (1),               */
 591        0x81, 0x03,             /*          Input (Constant, Variable),     */
 592        0x75, 0x10,             /*          Report Size (16),               */
 593        0x95, 0x01,             /*          Report Count (1),               */
 594        0xA4,                   /*          Push,                           */
 595        0x05, 0x01,             /*          Usage Page (Desktop),           */
 596        0x65, 0x13,             /*          Unit (Inch),                    */
 597        0x55, 0xFD,             /*          Unit Exponent (-3),             */
 598        0x34,                   /*          Physical Minimum (0),           */
 599        0x09, 0x30,             /*          Usage (X),                      */
 600        0x27, UCLOGIC_PH(X_LM), /*          Logical Maximum (PLACEHOLDER),  */
 601        0x47, UCLOGIC_PH(X_PM), /*          Physical Maximum (PLACEHOLDER), */
 602        0x81, 0x02,             /*          Input (Variable),               */
 603        0x09, 0x31,             /*          Usage (Y),                      */
 604        0x27, UCLOGIC_PH(Y_LM), /*          Logical Maximum (PLACEHOLDER),  */
 605        0x47, UCLOGIC_PH(Y_PM), /*          Physical Maximum (PLACEHOLDER), */
 606        0x81, 0x02,             /*          Input (Variable),               */
 607        0xB4,                   /*          Pop,                            */
 608        0x09, 0x30,             /*          Usage (Tip Pressure),           */
 609        0x27,
 610        UCLOGIC_PH(PRESSURE_LM),/*          Logical Maximum (PLACEHOLDER),  */
 611        0x81, 0x02,             /*          Input (Variable),               */
 612        0xC0,                   /*      End Collection,                     */
 613        0xC0                    /*  End Collection                          */
 614};
 615
 616/* Parameter indices */
 617enum uclogic_prm {
 618        UCLOGIC_PRM_X_LM        = 1,
 619        UCLOGIC_PRM_Y_LM        = 2,
 620        UCLOGIC_PRM_PRESSURE_LM = 4,
 621        UCLOGIC_PRM_RESOLUTION  = 5,
 622        UCLOGIC_PRM_NUM
 623};
 624
 625/* Driver data */
 626struct uclogic_drvdata {
 627        __u8 *rdesc;
 628        unsigned int rsize;
 629        bool invert_pen_inrange;
 630        bool ignore_pen_usage;
 631};
 632
 633static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
 634                                        unsigned int *rsize)
 635{
 636        struct usb_interface *iface = to_usb_interface(hdev->dev.parent);
 637        __u8 iface_num = iface->cur_altsetting->desc.bInterfaceNumber;
 638        struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
 639
 640        switch (hdev->product) {
 641        case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209:
 642                if (*rsize == PF1209_RDESC_ORIG_SIZE) {
 643                        rdesc = pf1209_rdesc_fixed;
 644                        *rsize = sizeof(pf1209_rdesc_fixed);
 645                }
 646                break;
 647        case USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U:
 648                if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
 649                        rdesc = wp4030u_rdesc_fixed;
 650                        *rsize = sizeof(wp4030u_rdesc_fixed);
 651                }
 652                break;
 653        case USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U:
 654                if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
 655                        rdesc = wp5540u_rdesc_fixed;
 656                        *rsize = sizeof(wp5540u_rdesc_fixed);
 657                }
 658                break;
 659        case USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U:
 660                if (*rsize == WPXXXXU_RDESC_ORIG_SIZE) {
 661                        rdesc = wp8060u_rdesc_fixed;
 662                        *rsize = sizeof(wp8060u_rdesc_fixed);
 663                }
 664                break;
 665        case USB_DEVICE_ID_UCLOGIC_TABLET_WP1062:
 666                if (*rsize == WP1062_RDESC_ORIG_SIZE) {
 667                        rdesc = wp1062_rdesc_fixed;
 668                        *rsize = sizeof(wp1062_rdesc_fixed);
 669                }
 670                break;
 671        case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850:
 672                switch (iface_num) {
 673                case 0:
 674                        if (*rsize == TWHL850_RDESC_ORIG_SIZE0) {
 675                                rdesc = twhl850_rdesc_fixed0;
 676                                *rsize = sizeof(twhl850_rdesc_fixed0);
 677                        }
 678                        break;
 679                case 1:
 680                        if (*rsize == TWHL850_RDESC_ORIG_SIZE1) {
 681                                rdesc = twhl850_rdesc_fixed1;
 682                                *rsize = sizeof(twhl850_rdesc_fixed1);
 683                        }
 684                        break;
 685                case 2:
 686                        if (*rsize == TWHL850_RDESC_ORIG_SIZE2) {
 687                                rdesc = twhl850_rdesc_fixed2;
 688                                *rsize = sizeof(twhl850_rdesc_fixed2);
 689                        }
 690                        break;
 691                }
 692                break;
 693        case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60:
 694                switch (iface_num) {
 695                case 0:
 696                        if (*rsize == TWHA60_RDESC_ORIG_SIZE0) {
 697                                rdesc = twha60_rdesc_fixed0;
 698                                *rsize = sizeof(twha60_rdesc_fixed0);
 699                        }
 700                        break;
 701                case 1:
 702                        if (*rsize == TWHA60_RDESC_ORIG_SIZE1) {
 703                                rdesc = twha60_rdesc_fixed1;
 704                                *rsize = sizeof(twha60_rdesc_fixed1);
 705                        }
 706                        break;
 707                }
 708                break;
 709        default:
 710                if (drvdata->rdesc != NULL) {
 711                        rdesc = drvdata->rdesc;
 712                        *rsize = drvdata->rsize;
 713                }
 714        }
 715
 716        return rdesc;
 717}
 718
 719static int uclogic_input_mapping(struct hid_device *hdev, struct hid_input *hi,
 720                struct hid_field *field, struct hid_usage *usage,
 721                unsigned long **bit, int *max)
 722{
 723        struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
 724
 725        /* discard the unused pen interface */
 726        if ((drvdata->ignore_pen_usage) &&
 727            (field->application == HID_DG_PEN))
 728                return -1;
 729
 730        /* let hid-core decide what to do */
 731        return 0;
 732}
 733
 734static int uclogic_input_configured(struct hid_device *hdev,
 735                struct hid_input *hi)
 736{
 737        char *name;
 738        const char *suffix = NULL;
 739        struct hid_field *field;
 740        size_t len;
 741
 742        /* no report associated (HID_QUIRK_MULTI_INPUT not set) */
 743        if (!hi->report)
 744                return 0;
 745
 746        field = hi->report->field[0];
 747
 748        switch (field->application) {
 749        case HID_GD_KEYBOARD:
 750                suffix = "Keyboard";
 751                break;
 752        case HID_GD_MOUSE:
 753                suffix = "Mouse";
 754                break;
 755        case HID_GD_KEYPAD:
 756                suffix = "Pad";
 757                break;
 758        case HID_DG_PEN:
 759                suffix = "Pen";
 760                break;
 761        case HID_CP_CONSUMER_CONTROL:
 762                suffix = "Consumer Control";
 763                break;
 764        case HID_GD_SYSTEM_CONTROL:
 765                suffix = "System Control";
 766                break;
 767        }
 768
 769        if (suffix) {
 770                len = strlen(hdev->name) + 2 + strlen(suffix);
 771                name = devm_kzalloc(&hi->input->dev, len, GFP_KERNEL);
 772                if (name) {
 773                        snprintf(name, len, "%s %s", hdev->name, suffix);
 774                        hi->input->name = name;
 775                }
 776        }
 777
 778        return 0;
 779}
 780
 781/**
 782 * Enable fully-functional tablet mode and determine device parameters.
 783 *
 784 * @hdev:       HID device
 785 */
 786static int uclogic_tablet_enable(struct hid_device *hdev)
 787{
 788        int rc;
 789        struct usb_device *usb_dev = hid_to_usb_dev(hdev);
 790        struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
 791        __le16 *buf = NULL;
 792        size_t len;
 793        s32 params[UCLOGIC_PH_ID_NUM];
 794        s32 resolution;
 795        __u8 *p;
 796        s32 v;
 797
 798        /*
 799         * Read string descriptor containing tablet parameters. The specific
 800         * string descriptor and data were discovered by sniffing the Windows
 801         * driver traffic.
 802         * NOTE: This enables fully-functional tablet mode.
 803         */
 804        len = UCLOGIC_PRM_NUM * sizeof(*buf);
 805        buf = kmalloc(len, GFP_KERNEL);
 806        if (buf == NULL) {
 807                hid_err(hdev, "failed to allocate parameter buffer\n");
 808                rc = -ENOMEM;
 809                goto cleanup;
 810        }
 811        rc = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
 812                                USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
 813                                (USB_DT_STRING << 8) + 0x64,
 814                                0x0409, buf, len,
 815                                USB_CTRL_GET_TIMEOUT);
 816        if (rc == -EPIPE) {
 817                hid_err(hdev, "device parameters not found\n");
 818                rc = -ENODEV;
 819                goto cleanup;
 820        } else if (rc < 0) {
 821                hid_err(hdev, "failed to get device parameters: %d\n", rc);
 822                rc = -ENODEV;
 823                goto cleanup;
 824        } else if (rc != len) {
 825                hid_err(hdev, "invalid device parameters\n");
 826                rc = -ENODEV;
 827                goto cleanup;
 828        }
 829
 830        /* Extract device parameters */
 831        params[UCLOGIC_PH_ID_X_LM] = le16_to_cpu(buf[UCLOGIC_PRM_X_LM]);
 832        params[UCLOGIC_PH_ID_Y_LM] = le16_to_cpu(buf[UCLOGIC_PRM_Y_LM]);
 833        params[UCLOGIC_PH_ID_PRESSURE_LM] =
 834                le16_to_cpu(buf[UCLOGIC_PRM_PRESSURE_LM]);
 835        resolution = le16_to_cpu(buf[UCLOGIC_PRM_RESOLUTION]);
 836        if (resolution == 0) {
 837                params[UCLOGIC_PH_ID_X_PM] = 0;
 838                params[UCLOGIC_PH_ID_Y_PM] = 0;
 839        } else {
 840                params[UCLOGIC_PH_ID_X_PM] = params[UCLOGIC_PH_ID_X_LM] *
 841                                                1000 / resolution;
 842                params[UCLOGIC_PH_ID_Y_PM] = params[UCLOGIC_PH_ID_Y_LM] *
 843                                                1000 / resolution;
 844        }
 845
 846        /* Allocate fixed report descriptor */
 847        drvdata->rdesc = devm_kzalloc(&hdev->dev,
 848                                sizeof(uclogic_tablet_rdesc_template),
 849                                GFP_KERNEL);
 850        if (drvdata->rdesc == NULL) {
 851                hid_err(hdev, "failed to allocate fixed rdesc\n");
 852                rc = -ENOMEM;
 853                goto cleanup;
 854        }
 855        drvdata->rsize = sizeof(uclogic_tablet_rdesc_template);
 856
 857        /* Format fixed report descriptor */
 858        memcpy(drvdata->rdesc, uclogic_tablet_rdesc_template,
 859                drvdata->rsize);
 860        for (p = drvdata->rdesc;
 861             p <= drvdata->rdesc + drvdata->rsize - 4;) {
 862                if (p[0] == 0xFE && p[1] == 0xED && p[2] == 0x1D &&
 863                    p[3] < ARRAY_SIZE(params)) {
 864                        v = params[p[3]];
 865                        put_unaligned(cpu_to_le32(v), (s32 *)p);
 866                        p += 4;
 867                } else {
 868                        p++;
 869                }
 870        }
 871
 872        rc = 0;
 873
 874cleanup:
 875        kfree(buf);
 876        return rc;
 877}
 878
 879static int uclogic_probe(struct hid_device *hdev,
 880                const struct hid_device_id *id)
 881{
 882        int rc;
 883        struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
 884        struct uclogic_drvdata *drvdata;
 885
 886        /*
 887         * libinput requires the pad interface to be on a different node
 888         * than the pen, so use QUIRK_MULTI_INPUT for all tablets.
 889         */
 890        hdev->quirks |= HID_QUIRK_MULTI_INPUT;
 891        hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT;
 892
 893        /* Allocate and assign driver data */
 894        drvdata = devm_kzalloc(&hdev->dev, sizeof(*drvdata), GFP_KERNEL);
 895        if (drvdata == NULL)
 896                return -ENOMEM;
 897
 898        hid_set_drvdata(hdev, drvdata);
 899
 900        switch (id->product) {
 901        case USB_DEVICE_ID_HUION_TABLET:
 902                /* If this is the pen interface */
 903                if (intf->cur_altsetting->desc.bInterfaceNumber == 0) {
 904                        rc = uclogic_tablet_enable(hdev);
 905                        if (rc) {
 906                                hid_err(hdev, "tablet enabling failed\n");
 907                                return rc;
 908                        }
 909                        drvdata->invert_pen_inrange = true;
 910                } else {
 911                        drvdata->ignore_pen_usage = true;
 912                }
 913                break;
 914        }
 915
 916        rc = hid_parse(hdev);
 917        if (rc) {
 918                hid_err(hdev, "parse failed\n");
 919                return rc;
 920        }
 921
 922        rc = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
 923        if (rc) {
 924                hid_err(hdev, "hw start failed\n");
 925                return rc;
 926        }
 927
 928        return 0;
 929}
 930
 931static int uclogic_raw_event(struct hid_device *hdev, struct hid_report *report,
 932                        u8 *data, int size)
 933{
 934        struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
 935
 936        if ((drvdata->invert_pen_inrange) &&
 937            (report->type == HID_INPUT_REPORT) &&
 938            (report->id == UCLOGIC_PEN_REPORT_ID) &&
 939            (size >= 2))
 940                /* Invert the in-range bit */
 941                data[1] ^= 0x40;
 942
 943        return 0;
 944}
 945
 946static const struct hid_device_id uclogic_devices[] = {
 947        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 948                                USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
 949        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 950                                USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
 951        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 952                                USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
 953        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 954                                USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U) },
 955        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 956                                USB_DEVICE_ID_UCLOGIC_TABLET_WP1062) },
 957        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 958                                USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850) },
 959        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
 960                                USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60) },
 961        { HID_USB_DEVICE(USB_VENDOR_ID_HUION, USB_DEVICE_ID_HUION_TABLET) },
 962        { HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_HUION_TABLET) },
 963        { }
 964};
 965MODULE_DEVICE_TABLE(hid, uclogic_devices);
 966
 967static struct hid_driver uclogic_driver = {
 968        .name = "uclogic",
 969        .id_table = uclogic_devices,
 970        .probe = uclogic_probe,
 971        .report_fixup = uclogic_report_fixup,
 972        .raw_event = uclogic_raw_event,
 973        .input_mapping = uclogic_input_mapping,
 974        .input_configured = uclogic_input_configured,
 975};
 976module_hid_driver(uclogic_driver);
 977
 978MODULE_AUTHOR("Martin Rusko");
 979MODULE_AUTHOR("Nikolai Kondrashov");
 980MODULE_LICENSE("GPL");
 981
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.