Linux Audio

Check our new training course

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