2010-08-09 20:44:17 +04:00
/*
* HID driver for UC - Logic devices not fully compliant with HID standard
*
2015-03-03 20:44:01 +03:00
* Copyright ( c ) 2010 - 2014 Nikolai Kondrashov
* Copyright ( c ) 2013 Martin Rusko
2010-08-09 20:44:17 +04:00
*/
/*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation ; either version 2 of the License , or ( at your option )
* any later version .
*/
# include <linux/device.h>
# include <linux/hid.h>
# include <linux/module.h>
2012-05-14 21:30:38 +04:00
# include <linux/usb.h>
2015-03-03 20:44:01 +03:00
# include <asm/unaligned.h>
# include "usbhid/usbhid.h"
2010-08-09 20:44:17 +04:00
# include "hid-ids.h"
/* Size of the original descriptor of WPXXXXU tablets */
# define WPXXXXU_RDESC_ORIG_SIZE 212
2012-03-06 11:54:22 +04:00
/* Fixed WP4030U report descriptor */
2010-08-09 20:44:17 +04:00
static __u8 wp4030u_rdesc_fixed [ ] = {
0x05 , 0x0D , /* Usage Page (Digitizer), */
0x09 , 0x02 , /* Usage (Pen), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x09 , /* Report ID (9), */
0x09 , 0x20 , /* Usage (Stylus), */
0xA0 , /* Collection (Physical), */
0x75 , 0x01 , /* Report Size (1), */
0x09 , 0x42 , /* Usage (Tip Switch), */
0x09 , 0x44 , /* Usage (Barrel Switch), */
0x09 , 0x46 , /* Usage (Tablet Pick), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x03 , /* Report Count (3), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x05 , /* Report Count (5), */
0x81 , 0x01 , /* Input (Constant), */
0x75 , 0x10 , /* Report Size (16), */
0x95 , 0x01 , /* Report Count (1), */
0x14 , /* Logical Minimum (0), */
0xA4 , /* Push, */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x55 , 0xFD , /* Unit Exponent (-3), */
0x65 , 0x13 , /* Unit (Inch), */
0x34 , /* Physical Minimum (0), */
0x09 , 0x30 , /* Usage (X), */
0x46 , 0xA0 , 0x0F , /* Physical Maximum (4000), */
0x26 , 0xFF , 0x7F , /* Logical Maximum (32767), */
0x81 , 0x02 , /* Input (Variable), */
0x09 , 0x31 , /* Usage (Y), */
0x46 , 0xB8 , 0x0B , /* Physical Maximum (3000), */
0x26 , 0xFF , 0x7F , /* Logical Maximum (32767), */
0x81 , 0x02 , /* Input (Variable), */
0xB4 , /* Pop, */
0x09 , 0x30 , /* Usage (Tip Pressure), */
0x26 , 0xFF , 0x03 , /* Logical Maximum (1023), */
0x81 , 0x02 , /* Input (Variable), */
0xC0 , /* End Collection, */
0xC0 /* End Collection */
} ;
/* Fixed WP5540U report descriptor */
static __u8 wp5540u_rdesc_fixed [ ] = {
0x05 , 0x0D , /* Usage Page (Digitizer), */
0x09 , 0x02 , /* Usage (Pen), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x09 , /* Report ID (9), */
0x09 , 0x20 , /* Usage (Stylus), */
0xA0 , /* Collection (Physical), */
0x75 , 0x01 , /* Report Size (1), */
0x09 , 0x42 , /* Usage (Tip Switch), */
0x09 , 0x44 , /* Usage (Barrel Switch), */
0x09 , 0x46 , /* Usage (Tablet Pick), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x03 , /* Report Count (3), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x05 , /* Report Count (5), */
0x81 , 0x01 , /* Input (Constant), */
0x75 , 0x10 , /* Report Size (16), */
0x95 , 0x01 , /* Report Count (1), */
0x14 , /* Logical Minimum (0), */
0xA4 , /* Push, */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x55 , 0xFD , /* Unit Exponent (-3), */
0x65 , 0x13 , /* Unit (Inch), */
0x34 , /* Physical Minimum (0), */
0x09 , 0x30 , /* Usage (X), */
0x46 , 0x7C , 0x15 , /* Physical Maximum (5500), */
0x26 , 0xFF , 0x7F , /* Logical Maximum (32767), */
0x81 , 0x02 , /* Input (Variable), */
0x09 , 0x31 , /* Usage (Y), */
0x46 , 0xA0 , 0x0F , /* Physical Maximum (4000), */
0x26 , 0xFF , 0x7F , /* Logical Maximum (32767), */
0x81 , 0x02 , /* Input (Variable), */
0xB4 , /* Pop, */
0x09 , 0x30 , /* Usage (Tip Pressure), */
0x26 , 0xFF , 0x03 , /* Logical Maximum (1023), */
0x81 , 0x02 , /* Input (Variable), */
0xC0 , /* End Collection, */
0xC0 , /* End Collection, */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x09 , 0x02 , /* Usage (Mouse), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x08 , /* Report ID (8), */
0x09 , 0x01 , /* Usage (Pointer), */
0xA0 , /* Collection (Physical), */
0x75 , 0x01 , /* Report Size (1), */
0x05 , 0x09 , /* Usage Page (Button), */
0x19 , 0x01 , /* Usage Minimum (01h), */
0x29 , 0x03 , /* Usage Maximum (03h), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x03 , /* Report Count (3), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x05 , /* Report Count (5), */
0x81 , 0x01 , /* Input (Constant), */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x75 , 0x08 , /* Report Size (8), */
0x09 , 0x30 , /* Usage (X), */
0x09 , 0x31 , /* Usage (Y), */
0x15 , 0x81 , /* Logical Minimum (-127), */
0x25 , 0x7F , /* Logical Maximum (127), */
0x95 , 0x02 , /* Report Count (2), */
0x81 , 0x06 , /* Input (Variable, Relative), */
0x09 , 0x38 , /* Usage (Wheel), */
0x15 , 0xFF , /* Logical Minimum (-1), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x01 , /* Report Count (1), */
0x81 , 0x06 , /* Input (Variable, Relative), */
0x81 , 0x01 , /* Input (Constant), */
0xC0 , /* End Collection, */
0xC0 /* End Collection */
} ;
/* Fixed WP8060U report descriptor */
static __u8 wp8060u_rdesc_fixed [ ] = {
0x05 , 0x0D , /* Usage Page (Digitizer), */
0x09 , 0x02 , /* Usage (Pen), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x09 , /* Report ID (9), */
0x09 , 0x20 , /* Usage (Stylus), */
0xA0 , /* Collection (Physical), */
0x75 , 0x01 , /* Report Size (1), */
0x09 , 0x42 , /* Usage (Tip Switch), */
0x09 , 0x44 , /* Usage (Barrel Switch), */
0x09 , 0x46 , /* Usage (Tablet Pick), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x03 , /* Report Count (3), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x05 , /* Report Count (5), */
0x81 , 0x01 , /* Input (Constant), */
0x75 , 0x10 , /* Report Size (16), */
0x95 , 0x01 , /* Report Count (1), */
0x14 , /* Logical Minimum (0), */
0xA4 , /* Push, */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x55 , 0xFD , /* Unit Exponent (-3), */
0x65 , 0x13 , /* Unit (Inch), */
0x34 , /* Physical Minimum (0), */
0x09 , 0x30 , /* Usage (X), */
0x46 , 0x40 , 0x1F , /* Physical Maximum (8000), */
0x26 , 0xFF , 0x7F , /* Logical Maximum (32767), */
0x81 , 0x02 , /* Input (Variable), */
0x09 , 0x31 , /* Usage (Y), */
0x46 , 0x70 , 0x17 , /* Physical Maximum (6000), */
0x26 , 0xFF , 0x7F , /* Logical Maximum (32767), */
0x81 , 0x02 , /* Input (Variable), */
0xB4 , /* Pop, */
0x09 , 0x30 , /* Usage (Tip Pressure), */
0x26 , 0xFF , 0x03 , /* Logical Maximum (1023), */
0x81 , 0x02 , /* Input (Variable), */
0xC0 , /* End Collection, */
0xC0 , /* End Collection, */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x09 , 0x02 , /* Usage (Mouse), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x08 , /* Report ID (8), */
0x09 , 0x01 , /* Usage (Pointer), */
0xA0 , /* Collection (Physical), */
0x75 , 0x01 , /* Report Size (1), */
0x05 , 0x09 , /* Usage Page (Button), */
0x19 , 0x01 , /* Usage Minimum (01h), */
0x29 , 0x03 , /* Usage Maximum (03h), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x03 , /* Report Count (3), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x05 , /* Report Count (5), */
0x81 , 0x01 , /* Input (Constant), */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x75 , 0x08 , /* Report Size (8), */
0x09 , 0x30 , /* Usage (X), */
0x09 , 0x31 , /* Usage (Y), */
0x15 , 0x81 , /* Logical Minimum (-127), */
0x25 , 0x7F , /* Logical Maximum (127), */
0x95 , 0x02 , /* Report Count (2), */
0x81 , 0x06 , /* Input (Variable, Relative), */
0x09 , 0x38 , /* Usage (Wheel), */
0x15 , 0xFF , /* Logical Minimum (-1), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x01 , /* Report Count (1), */
0x81 , 0x06 , /* Input (Variable, Relative), */
0x81 , 0x01 , /* Input (Constant), */
0xC0 , /* End Collection, */
0xC0 /* End Collection */
} ;
2011-07-06 10:23:41 +04:00
/* Size of the original descriptor of WP1062 tablet */
# define WP1062_RDESC_ORIG_SIZE 254
2012-03-06 11:54:22 +04:00
/* Fixed WP1062 report descriptor */
2011-07-06 10:23:41 +04:00
static __u8 wp1062_rdesc_fixed [ ] = {
0x05 , 0x0D , /* Usage Page (Digitizer), */
0x09 , 0x02 , /* Usage (Pen), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x09 , /* Report ID (9), */
0x09 , 0x20 , /* Usage (Stylus), */
0xA0 , /* Collection (Physical), */
0x75 , 0x01 , /* Report Size (1), */
0x09 , 0x42 , /* Usage (Tip Switch), */
0x09 , 0x44 , /* Usage (Barrel Switch), */
0x09 , 0x46 , /* Usage (Tablet Pick), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x03 , /* Report Count (3), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x04 , /* Report Count (4), */
0x81 , 0x01 , /* Input (Constant), */
0x09 , 0x32 , /* Usage (In Range), */
0x95 , 0x01 , /* Report Count (1), */
0x81 , 0x02 , /* Input (Variable), */
0x75 , 0x10 , /* Report Size (16), */
0x95 , 0x01 , /* Report Count (1), */
0x14 , /* Logical Minimum (0), */
0xA4 , /* Push, */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x55 , 0xFD , /* Unit Exponent (-3), */
0x65 , 0x13 , /* Unit (Inch), */
0x34 , /* Physical Minimum (0), */
0x09 , 0x30 , /* Usage (X), */
0x46 , 0x10 , 0x27 , /* Physical Maximum (10000), */
0x26 , 0x20 , 0x4E , /* Logical Maximum (20000), */
0x81 , 0x02 , /* Input (Variable), */
0x09 , 0x31 , /* Usage (Y), */
0x46 , 0xB7 , 0x19 , /* Physical Maximum (6583), */
0x26 , 0x6E , 0x33 , /* Logical Maximum (13166), */
0x81 , 0x02 , /* Input (Variable), */
0xB4 , /* Pop, */
0x09 , 0x30 , /* Usage (Tip Pressure), */
0x26 , 0xFF , 0x03 , /* Logical Maximum (1023), */
0x81 , 0x02 , /* Input (Variable), */
0xC0 , /* End Collection, */
0xC0 /* End Collection */
} ;
2010-08-23 15:09:01 +04:00
/* Size of the original descriptor of PF1209 tablet */
# define PF1209_RDESC_ORIG_SIZE 234
2012-03-06 11:54:22 +04:00
/* Fixed PF1209 report descriptor */
2010-08-23 15:09:01 +04:00
static __u8 pf1209_rdesc_fixed [ ] = {
0x05 , 0x0D , /* Usage Page (Digitizer), */
0x09 , 0x02 , /* Usage (Pen), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x09 , /* Report ID (9), */
0x09 , 0x20 , /* Usage (Stylus), */
0xA0 , /* Collection (Physical), */
0x75 , 0x01 , /* Report Size (1), */
0x09 , 0x42 , /* Usage (Tip Switch), */
0x09 , 0x44 , /* Usage (Barrel Switch), */
0x09 , 0x46 , /* Usage (Tablet Pick), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x03 , /* Report Count (3), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x05 , /* Report Count (5), */
0x81 , 0x01 , /* Input (Constant), */
0x75 , 0x10 , /* Report Size (16), */
0x95 , 0x01 , /* Report Count (1), */
0x14 , /* Logical Minimum (0), */
0xA4 , /* Push, */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x55 , 0xFD , /* Unit Exponent (-3), */
0x65 , 0x13 , /* Unit (Inch), */
0x34 , /* Physical Minimum (0), */
0x09 , 0x30 , /* Usage (X), */
0x46 , 0xE0 , 0x2E , /* Physical Maximum (12000), */
0x26 , 0xFF , 0x7F , /* Logical Maximum (32767), */
0x81 , 0x02 , /* Input (Variable), */
0x09 , 0x31 , /* Usage (Y), */
0x46 , 0x28 , 0x23 , /* Physical Maximum (9000), */
0x26 , 0xFF , 0x7F , /* Logical Maximum (32767), */
0x81 , 0x02 , /* Input (Variable), */
0xB4 , /* Pop, */
0x09 , 0x30 , /* Usage (Tip Pressure), */
0x26 , 0xFF , 0x03 , /* Logical Maximum (1023), */
0x81 , 0x02 , /* Input (Variable), */
0xC0 , /* End Collection, */
0xC0 , /* End Collection, */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x09 , 0x02 , /* Usage (Mouse), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x08 , /* Report ID (8), */
0x09 , 0x01 , /* Usage (Pointer), */
0xA0 , /* Collection (Physical), */
0x75 , 0x01 , /* Report Size (1), */
0x05 , 0x09 , /* Usage Page (Button), */
0x19 , 0x01 , /* Usage Minimum (01h), */
0x29 , 0x03 , /* Usage Maximum (03h), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x03 , /* Report Count (3), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x05 , /* Report Count (5), */
0x81 , 0x01 , /* Input (Constant), */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x75 , 0x08 , /* Report Size (8), */
0x09 , 0x30 , /* Usage (X), */
0x09 , 0x31 , /* Usage (Y), */
0x15 , 0x81 , /* Logical Minimum (-127), */
0x25 , 0x7F , /* Logical Maximum (127), */
0x95 , 0x02 , /* Report Count (2), */
0x81 , 0x06 , /* Input (Variable, Relative), */
0x09 , 0x38 , /* Usage (Wheel), */
0x15 , 0xFF , /* Logical Minimum (-1), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x01 , /* Report Count (1), */
0x81 , 0x06 , /* Input (Variable, Relative), */
0x81 , 0x01 , /* Input (Constant), */
0xC0 , /* End Collection, */
0xC0 /* End Collection */
} ;
2012-05-14 21:30:38 +04:00
/* Size of the original descriptors of TWHL850 tablet */
# define TWHL850_RDESC_ORIG_SIZE0 182
# define TWHL850_RDESC_ORIG_SIZE1 161
# define TWHL850_RDESC_ORIG_SIZE2 92
/* Fixed PID 0522 tablet report descriptor, interface 0 (stylus) */
static __u8 twhl850_rdesc_fixed0 [ ] = {
0x05 , 0x0D , /* Usage Page (Digitizer), */
0x09 , 0x02 , /* Usage (Pen), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x09 , /* Report ID (9), */
0x09 , 0x20 , /* Usage (Stylus), */
0xA0 , /* Collection (Physical), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x75 , 0x01 , /* Report Size (1), */
0x95 , 0x03 , /* Report Count (3), */
0x09 , 0x42 , /* Usage (Tip Switch), */
0x09 , 0x44 , /* Usage (Barrel Switch), */
0x09 , 0x46 , /* Usage (Tablet Pick), */
0x81 , 0x02 , /* Input (Variable), */
0x81 , 0x03 , /* Input (Constant, Variable), */
0x95 , 0x01 , /* Report Count (1), */
0x09 , 0x32 , /* Usage (In Range), */
0x81 , 0x02 , /* Input (Variable), */
0x81 , 0x03 , /* Input (Constant, Variable), */
0x75 , 0x10 , /* Report Size (16), */
0xA4 , /* Push, */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x65 , 0x13 , /* Unit (Inch), */
0x55 , 0xFD , /* Unit Exponent (-3), */
0x34 , /* Physical Minimum (0), */
0x09 , 0x30 , /* Usage (X), */
0x46 , 0x40 , 0x1F , /* Physical Maximum (8000), */
0x26 , 0x00 , 0x7D , /* Logical Maximum (32000), */
0x81 , 0x02 , /* Input (Variable), */
0x09 , 0x31 , /* Usage (Y), */
0x46 , 0x88 , 0x13 , /* Physical Maximum (5000), */
0x26 , 0x20 , 0x4E , /* Logical Maximum (20000), */
0x81 , 0x02 , /* Input (Variable), */
0xB4 , /* Pop, */
0x09 , 0x30 , /* Usage (Tip Pressure), */
0x26 , 0xFF , 0x03 , /* Logical Maximum (1023), */
0x81 , 0x02 , /* Input (Variable), */
0xC0 , /* End Collection, */
0xC0 /* End Collection */
} ;
/* Fixed PID 0522 tablet report descriptor, interface 1 (mouse) */
static __u8 twhl850_rdesc_fixed1 [ ] = {
0x05 , 0x01 , /* Usage Page (Desktop), */
0x09 , 0x02 , /* Usage (Mouse), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x01 , /* Report ID (1), */
0x09 , 0x01 , /* Usage (Pointer), */
0xA0 , /* Collection (Physical), */
0x05 , 0x09 , /* Usage Page (Button), */
0x75 , 0x01 , /* Report Size (1), */
0x95 , 0x03 , /* Report Count (3), */
0x19 , 0x01 , /* Usage Minimum (01h), */
0x29 , 0x03 , /* Usage Maximum (03h), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x05 , /* Report Count (5), */
0x81 , 0x03 , /* Input (Constant, Variable), */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x09 , 0x30 , /* Usage (X), */
0x09 , 0x31 , /* Usage (Y), */
0x16 , 0x00 , 0x80 , /* Logical Minimum (-32768), */
0x26 , 0xFF , 0x7F , /* Logical Maximum (32767), */
0x75 , 0x10 , /* Report Size (16), */
0x95 , 0x02 , /* Report Count (2), */
0x81 , 0x06 , /* Input (Variable, Relative), */
0x09 , 0x38 , /* Usage (Wheel), */
0x15 , 0xFF , /* Logical Minimum (-1), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x01 , /* Report Count (1), */
0x75 , 0x08 , /* Report Size (8), */
0x81 , 0x06 , /* Input (Variable, Relative), */
0x81 , 0x03 , /* Input (Constant, Variable), */
0xC0 , /* End Collection, */
0xC0 /* End Collection */
} ;
/* Fixed PID 0522 tablet report descriptor, interface 2 (frame buttons) */
static __u8 twhl850_rdesc_fixed2 [ ] = {
0x05 , 0x01 , /* Usage Page (Desktop), */
0x09 , 0x06 , /* Usage (Keyboard), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x03 , /* Report ID (3), */
0x05 , 0x07 , /* Usage Page (Keyboard), */
0x14 , /* Logical Minimum (0), */
0x19 , 0xE0 , /* Usage Minimum (KB Leftcontrol), */
0x29 , 0xE7 , /* Usage Maximum (KB Right GUI), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x75 , 0x01 , /* Report Size (1), */
0x95 , 0x08 , /* Report Count (8), */
0x81 , 0x02 , /* Input (Variable), */
0x18 , /* Usage Minimum (None), */
0x29 , 0xFF , /* Usage Maximum (FFh), */
0x26 , 0xFF , 0x00 , /* Logical Maximum (255), */
0x75 , 0x08 , /* Report Size (8), */
0x95 , 0x06 , /* Report Count (6), */
0x80 , /* Input, */
0xC0 /* End Collection */
} ;
2012-08-26 21:55:08 +04:00
/* Size of the original descriptors of TWHA60 tablet */
# define TWHA60_RDESC_ORIG_SIZE0 254
# define TWHA60_RDESC_ORIG_SIZE1 139
/* Fixed TWHA60 report descriptor, interface 0 (stylus) */
static __u8 twha60_rdesc_fixed0 [ ] = {
0x05 , 0x0D , /* Usage Page (Digitizer), */
0x09 , 0x02 , /* Usage (Pen), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x09 , /* Report ID (9), */
0x09 , 0x20 , /* Usage (Stylus), */
0xA0 , /* Collection (Physical), */
0x75 , 0x01 , /* Report Size (1), */
0x09 , 0x42 , /* Usage (Tip Switch), */
0x09 , 0x44 , /* Usage (Barrel Switch), */
0x09 , 0x46 , /* Usage (Tablet Pick), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x95 , 0x03 , /* Report Count (3), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x04 , /* Report Count (4), */
0x81 , 0x01 , /* Input (Constant), */
0x09 , 0x32 , /* Usage (In Range), */
0x95 , 0x01 , /* Report Count (1), */
0x81 , 0x02 , /* Input (Variable), */
0x75 , 0x10 , /* Report Size (16), */
0x95 , 0x01 , /* Report Count (1), */
0x14 , /* Logical Minimum (0), */
0xA4 , /* Push, */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x55 , 0xFD , /* Unit Exponent (-3), */
0x65 , 0x13 , /* Unit (Inch), */
0x34 , /* Physical Minimum (0), */
0x09 , 0x30 , /* Usage (X), */
0x46 , 0x10 , 0x27 , /* Physical Maximum (10000), */
0x27 , 0x3F , 0x9C ,
0x00 , 0x00 , /* Logical Maximum (39999), */
0x81 , 0x02 , /* Input (Variable), */
0x09 , 0x31 , /* Usage (Y), */
0x46 , 0x6A , 0x18 , /* Physical Maximum (6250), */
0x26 , 0xA7 , 0x61 , /* Logical Maximum (24999), */
0x81 , 0x02 , /* Input (Variable), */
0xB4 , /* Pop, */
0x09 , 0x30 , /* Usage (Tip Pressure), */
0x26 , 0xFF , 0x03 , /* Logical Maximum (1023), */
0x81 , 0x02 , /* Input (Variable), */
0xC0 , /* End Collection, */
0xC0 /* End Collection */
} ;
/* Fixed TWHA60 report descriptor, interface 1 (frame buttons) */
static __u8 twha60_rdesc_fixed1 [ ] = {
0x05 , 0x01 , /* Usage Page (Desktop), */
0x09 , 0x06 , /* Usage (Keyboard), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x05 , /* Report ID (5), */
0x05 , 0x07 , /* Usage Page (Keyboard), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x75 , 0x01 , /* Report Size (1), */
0x95 , 0x08 , /* Report Count (8), */
0x81 , 0x01 , /* Input (Constant), */
0x95 , 0x0C , /* Report Count (12), */
0x19 , 0x3A , /* Usage Minimum (KB F1), */
0x29 , 0x45 , /* Usage Maximum (KB F12), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x0C , /* Report Count (12), */
0x19 , 0x68 , /* Usage Minimum (KB F13), */
0x29 , 0x73 , /* Usage Maximum (KB F24), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x08 , /* Report Count (8), */
0x81 , 0x01 , /* Input (Constant), */
0xC0 /* End Collection */
} ;
2015-03-03 20:44:01 +03:00
/* Report descriptor template placeholder head */
# define UCLOGIC_PH_HEAD 0xFE, 0xED, 0x1D
/* Report descriptor template placeholder IDs */
enum uclogic_ph_id {
UCLOGIC_PH_ID_X_LM ,
UCLOGIC_PH_ID_X_PM ,
UCLOGIC_PH_ID_Y_LM ,
UCLOGIC_PH_ID_Y_PM ,
UCLOGIC_PH_ID_PRESSURE_LM ,
UCLOGIC_PH_ID_NUM
} ;
/* Report descriptor template placeholder */
# define UCLOGIC_PH(_ID) UCLOGIC_PH_HEAD, UCLOGIC_PH_ID_##_ID
2015-03-03 20:44:05 +03:00
# define UCLOGIC_PEN_REPORT_ID 0x07
2015-03-03 20:44:01 +03:00
/* Fixed report descriptor template */
static const __u8 uclogic_tablet_rdesc_template [ ] = {
0x05 , 0x0D , /* Usage Page (Digitizer), */
0x09 , 0x02 , /* Usage (Pen), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0x07 , /* Report ID (7), */
0x09 , 0x20 , /* Usage (Stylus), */
0xA0 , /* Collection (Physical), */
0x14 , /* Logical Minimum (0), */
0x25 , 0x01 , /* Logical Maximum (1), */
0x75 , 0x01 , /* Report Size (1), */
0x09 , 0x42 , /* Usage (Tip Switch), */
0x09 , 0x44 , /* Usage (Barrel Switch), */
0x09 , 0x46 , /* Usage (Tablet Pick), */
0x95 , 0x03 , /* Report Count (3), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x03 , /* Report Count (3), */
0x81 , 0x03 , /* Input (Constant, Variable), */
0x09 , 0x32 , /* Usage (In Range), */
0x95 , 0x01 , /* Report Count (1), */
0x81 , 0x02 , /* Input (Variable), */
0x95 , 0x01 , /* Report Count (1), */
0x81 , 0x03 , /* Input (Constant, Variable), */
0x75 , 0x10 , /* Report Size (16), */
0x95 , 0x01 , /* Report Count (1), */
0xA4 , /* Push, */
0x05 , 0x01 , /* Usage Page (Desktop), */
0x65 , 0x13 , /* Unit (Inch), */
0x55 , 0xFD , /* Unit Exponent (-3), */
0x34 , /* Physical Minimum (0), */
0x09 , 0x30 , /* Usage (X), */
0x27 , UCLOGIC_PH ( X_LM ) , /* Logical Maximum (PLACEHOLDER), */
0x47 , UCLOGIC_PH ( X_PM ) , /* Physical Maximum (PLACEHOLDER), */
0x81 , 0x02 , /* Input (Variable), */
0x09 , 0x31 , /* Usage (Y), */
0x27 , UCLOGIC_PH ( Y_LM ) , /* Logical Maximum (PLACEHOLDER), */
0x47 , UCLOGIC_PH ( Y_PM ) , /* Physical Maximum (PLACEHOLDER), */
0x81 , 0x02 , /* Input (Variable), */
0xB4 , /* Pop, */
0x09 , 0x30 , /* Usage (Tip Pressure), */
0x27 ,
UCLOGIC_PH ( PRESSURE_LM ) , /* Logical Maximum (PLACEHOLDER), */
0x81 , 0x02 , /* Input (Variable), */
0xC0 , /* End Collection, */
0xC0 /* End Collection */
} ;
2016-09-14 21:38:16 +03:00
/* Fixed virtual pad report descriptor */
static const __u8 uclogic_buttonpad_rdesc [ ] = {
0x05 , 0x01 , /* Usage Page (Desktop), */
0x09 , 0x07 , /* Usage (Keypad), */
0xA1 , 0x01 , /* Collection (Application), */
0x85 , 0xF7 , /* Report ID (247), */
0x05 , 0x0D , /* Usage Page (Digitizers), */
0x09 , 0x39 , /* Usage (Tablet Function Keys), */
0xA0 , /* Collection (Physical), */
0x05 , 0x09 , /* Usage Page (Button), */
0x75 , 0x01 , /* Report Size (1), */
0x95 , 0x18 , /* Report Count (24), */
0x81 , 0x03 , /* Input (Constant, Variable), */
0x19 , 0x01 , /* Usage Minimum (01h), */
0x29 , 0x08 , /* Usage Maximum (08h), */
0x95 , 0x08 , /* Report Count (8), */
0x81 , 0x02 , /* Input (Variable), */
0xC0 , /* End Collection */
0xC0 /* End Collection */
} ;
2015-03-03 20:44:01 +03:00
/* Parameter indices */
enum uclogic_prm {
UCLOGIC_PRM_X_LM = 1 ,
UCLOGIC_PRM_Y_LM = 2 ,
UCLOGIC_PRM_PRESSURE_LM = 4 ,
UCLOGIC_PRM_RESOLUTION = 5 ,
UCLOGIC_PRM_NUM
} ;
/* Driver data */
struct uclogic_drvdata {
__u8 * rdesc ;
unsigned int rsize ;
2015-03-03 20:44:05 +03:00
bool invert_pen_inrange ;
2015-03-15 21:26:27 +03:00
bool ignore_pen_usage ;
2016-09-14 21:38:16 +03:00
bool has_virtual_pad_interface ;
2015-03-03 20:44:01 +03:00
} ;
2010-08-09 20:44:17 +04:00
static __u8 * uclogic_report_fixup ( struct hid_device * hdev , __u8 * rdesc ,
2010-08-23 15:09:00 +04:00
unsigned int * rsize )
2010-08-09 20:44:17 +04:00
{
2012-05-14 21:30:38 +04:00
struct usb_interface * iface = to_usb_interface ( hdev - > dev . parent ) ;
__u8 iface_num = iface - > cur_altsetting - > desc . bInterfaceNumber ;
2015-03-03 20:44:01 +03:00
struct uclogic_drvdata * drvdata = hid_get_drvdata ( hdev ) ;
2012-05-14 21:30:38 +04:00
2016-09-14 21:38:19 +03:00
if ( drvdata - > rdesc ! = NULL ) {
rdesc = drvdata - > rdesc ;
* rsize = drvdata - > rsize ;
return rdesc ;
}
2010-08-09 20:44:17 +04:00
switch ( hdev - > product ) {
2010-08-23 15:09:01 +04:00
case USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 :
if ( * rsize = = PF1209_RDESC_ORIG_SIZE ) {
rdesc = pf1209_rdesc_fixed ;
* rsize = sizeof ( pf1209_rdesc_fixed ) ;
}
break ;
2010-08-09 20:44:17 +04:00
case USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U :
2010-08-23 15:09:00 +04:00
if ( * rsize = = WPXXXXU_RDESC_ORIG_SIZE ) {
2010-08-09 20:44:17 +04:00
rdesc = wp4030u_rdesc_fixed ;
* rsize = sizeof ( wp4030u_rdesc_fixed ) ;
}
break ;
case USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U :
2010-08-23 15:09:00 +04:00
if ( * rsize = = WPXXXXU_RDESC_ORIG_SIZE ) {
2010-08-09 20:44:17 +04:00
rdesc = wp5540u_rdesc_fixed ;
* rsize = sizeof ( wp5540u_rdesc_fixed ) ;
}
break ;
case USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U :
2010-08-23 15:09:00 +04:00
if ( * rsize = = WPXXXXU_RDESC_ORIG_SIZE ) {
2010-08-09 20:44:17 +04:00
rdesc = wp8060u_rdesc_fixed ;
* rsize = sizeof ( wp8060u_rdesc_fixed ) ;
}
break ;
2011-07-06 10:23:41 +04:00
case USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 :
if ( * rsize = = WP1062_RDESC_ORIG_SIZE ) {
rdesc = wp1062_rdesc_fixed ;
* rsize = sizeof ( wp1062_rdesc_fixed ) ;
}
break ;
2012-05-14 21:30:38 +04:00
case USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 :
switch ( iface_num ) {
case 0 :
if ( * rsize = = TWHL850_RDESC_ORIG_SIZE0 ) {
rdesc = twhl850_rdesc_fixed0 ;
* rsize = sizeof ( twhl850_rdesc_fixed0 ) ;
}
break ;
case 1 :
if ( * rsize = = TWHL850_RDESC_ORIG_SIZE1 ) {
rdesc = twhl850_rdesc_fixed1 ;
* rsize = sizeof ( twhl850_rdesc_fixed1 ) ;
}
break ;
case 2 :
if ( * rsize = = TWHL850_RDESC_ORIG_SIZE2 ) {
rdesc = twhl850_rdesc_fixed2 ;
* rsize = sizeof ( twhl850_rdesc_fixed2 ) ;
}
break ;
}
break ;
2012-08-26 21:55:08 +04:00
case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 :
switch ( iface_num ) {
case 0 :
if ( * rsize = = TWHA60_RDESC_ORIG_SIZE0 ) {
rdesc = twha60_rdesc_fixed0 ;
* rsize = sizeof ( twha60_rdesc_fixed0 ) ;
}
break ;
case 1 :
if ( * rsize = = TWHA60_RDESC_ORIG_SIZE1 ) {
rdesc = twha60_rdesc_fixed1 ;
* rsize = sizeof ( twha60_rdesc_fixed1 ) ;
}
break ;
}
break ;
2010-08-09 20:44:17 +04:00
}
return rdesc ;
}
2015-03-03 20:44:04 +03:00
static int uclogic_input_mapping ( struct hid_device * hdev , struct hid_input * hi ,
struct hid_field * field , struct hid_usage * usage ,
unsigned long * * bit , int * max )
{
2015-03-15 21:26:27 +03:00
struct uclogic_drvdata * drvdata = hid_get_drvdata ( hdev ) ;
2015-03-03 20:44:04 +03:00
2015-03-15 21:26:27 +03:00
/* discard the unused pen interface */
if ( ( drvdata - > ignore_pen_usage ) & &
( field - > application = = HID_DG_PEN ) )
return - 1 ;
2015-03-03 20:44:04 +03:00
/* let hid-core decide what to do */
return 0 ;
}
2015-09-30 01:52:59 +03:00
static int uclogic_input_configured ( struct hid_device * hdev ,
2015-03-03 20:44:02 +03:00
struct hid_input * hi )
{
char * name ;
const char * suffix = NULL ;
struct hid_field * field ;
size_t len ;
/* no report associated (HID_QUIRK_MULTI_INPUT not set) */
if ( ! hi - > report )
2015-09-30 01:52:59 +03:00
return 0 ;
2015-03-03 20:44:02 +03:00
field = hi - > report - > field [ 0 ] ;
switch ( field - > application ) {
case HID_GD_KEYBOARD :
suffix = " Keyboard " ;
break ;
case HID_GD_MOUSE :
suffix = " Mouse " ;
break ;
case HID_GD_KEYPAD :
suffix = " Pad " ;
break ;
case HID_DG_PEN :
suffix = " Pen " ;
break ;
case HID_CP_CONSUMER_CONTROL :
suffix = " Consumer Control " ;
break ;
case HID_GD_SYSTEM_CONTROL :
suffix = " System Control " ;
break ;
}
if ( suffix ) {
len = strlen ( hdev - > name ) + 2 + strlen ( suffix ) ;
name = devm_kzalloc ( & hi - > input - > dev , len , GFP_KERNEL ) ;
if ( name ) {
snprintf ( name , len , " %s %s " , hdev - > name , suffix ) ;
hi - > input - > name = name ;
}
}
2015-09-30 01:52:59 +03:00
return 0 ;
2015-03-03 20:44:02 +03:00
}
2015-03-03 20:44:01 +03:00
/**
* Enable fully - functional tablet mode and determine device parameters .
*
* @ hdev : HID device
*/
static int uclogic_tablet_enable ( struct hid_device * hdev )
{
int rc ;
struct usb_device * usb_dev = hid_to_usb_dev ( hdev ) ;
struct uclogic_drvdata * drvdata = hid_get_drvdata ( hdev ) ;
__le16 * buf = NULL ;
size_t len ;
s32 params [ UCLOGIC_PH_ID_NUM ] ;
s32 resolution ;
__u8 * p ;
s32 v ;
/*
* Read string descriptor containing tablet parameters . The specific
* string descriptor and data were discovered by sniffing the Windows
* driver traffic .
* NOTE : This enables fully - functional tablet mode .
*/
len = UCLOGIC_PRM_NUM * sizeof ( * buf ) ;
buf = kmalloc ( len , GFP_KERNEL ) ;
if ( buf = = NULL ) {
rc = - ENOMEM ;
goto cleanup ;
}
rc = usb_control_msg ( usb_dev , usb_rcvctrlpipe ( usb_dev , 0 ) ,
USB_REQ_GET_DESCRIPTOR , USB_DIR_IN ,
( USB_DT_STRING < < 8 ) + 0x64 ,
0x0409 , buf , len ,
USB_CTRL_GET_TIMEOUT ) ;
if ( rc = = - EPIPE ) {
hid_err ( hdev , " device parameters not found \n " ) ;
rc = - ENODEV ;
goto cleanup ;
} else if ( rc < 0 ) {
hid_err ( hdev , " failed to get device parameters: %d \n " , rc ) ;
rc = - ENODEV ;
goto cleanup ;
} else if ( rc ! = len ) {
hid_err ( hdev , " invalid device parameters \n " ) ;
rc = - ENODEV ;
goto cleanup ;
}
/* Extract device parameters */
params [ UCLOGIC_PH_ID_X_LM ] = le16_to_cpu ( buf [ UCLOGIC_PRM_X_LM ] ) ;
params [ UCLOGIC_PH_ID_Y_LM ] = le16_to_cpu ( buf [ UCLOGIC_PRM_Y_LM ] ) ;
params [ UCLOGIC_PH_ID_PRESSURE_LM ] =
le16_to_cpu ( buf [ UCLOGIC_PRM_PRESSURE_LM ] ) ;
resolution = le16_to_cpu ( buf [ UCLOGIC_PRM_RESOLUTION ] ) ;
if ( resolution = = 0 ) {
params [ UCLOGIC_PH_ID_X_PM ] = 0 ;
params [ UCLOGIC_PH_ID_Y_PM ] = 0 ;
} else {
params [ UCLOGIC_PH_ID_X_PM ] = params [ UCLOGIC_PH_ID_X_LM ] *
1000 / resolution ;
params [ UCLOGIC_PH_ID_Y_PM ] = params [ UCLOGIC_PH_ID_Y_LM ] *
1000 / resolution ;
}
/* Allocate fixed report descriptor */
drvdata - > rdesc = devm_kzalloc ( & hdev - > dev ,
sizeof ( uclogic_tablet_rdesc_template ) ,
GFP_KERNEL ) ;
if ( drvdata - > rdesc = = NULL ) {
rc = - ENOMEM ;
goto cleanup ;
}
drvdata - > rsize = sizeof ( uclogic_tablet_rdesc_template ) ;
/* Format fixed report descriptor */
memcpy ( drvdata - > rdesc , uclogic_tablet_rdesc_template ,
drvdata - > rsize ) ;
for ( p = drvdata - > rdesc ;
p < = drvdata - > rdesc + drvdata - > rsize - 4 ; ) {
if ( p [ 0 ] = = 0xFE & & p [ 1 ] = = 0xED & & p [ 2 ] = = 0x1D & &
2015-07-29 13:16:06 +03:00
p [ 3 ] < ARRAY_SIZE ( params ) ) {
2015-03-03 20:44:01 +03:00
v = params [ p [ 3 ] ] ;
put_unaligned ( cpu_to_le32 ( v ) , ( s32 * ) p ) ;
p + = 4 ;
} else {
p + + ;
}
}
rc = 0 ;
cleanup :
kfree ( buf ) ;
return rc ;
}
2016-09-14 21:38:16 +03:00
/**
* Enable actual button mode .
*
* @ hdev : HID device
*/
static int uclogic_button_enable ( struct hid_device * hdev )
{
int rc ;
struct usb_device * usb_dev = hid_to_usb_dev ( hdev ) ;
struct uclogic_drvdata * drvdata = hid_get_drvdata ( hdev ) ;
char * str_buf ;
size_t str_len = 16 ;
unsigned char * rdesc ;
size_t rdesc_len ;
str_buf = kzalloc ( str_len , GFP_KERNEL ) ;
if ( str_buf = = NULL ) {
rc = - ENOMEM ;
goto cleanup ;
}
/* Enable abstract keyboard mode */
rc = usb_string ( usb_dev , 0x7b , str_buf , str_len ) ;
if ( rc = = - EPIPE ) {
hid_info ( hdev , " button mode setting not found \n " ) ;
rc = 0 ;
goto cleanup ;
} else if ( rc < 0 ) {
hid_err ( hdev , " failed to enable abstract keyboard \n " ) ;
goto cleanup ;
} else if ( strncmp ( str_buf , " HK On " , rc ) ) {
hid_info ( hdev , " invalid answer when requesting buttons: '%s' \n " ,
str_buf ) ;
rc = - EINVAL ;
goto cleanup ;
}
/* Re-allocate fixed report descriptor */
rdesc_len = drvdata - > rsize + sizeof ( uclogic_buttonpad_rdesc ) ;
rdesc = devm_kzalloc ( & hdev - > dev , rdesc_len , GFP_KERNEL ) ;
if ( ! rdesc ) {
rc = - ENOMEM ;
goto cleanup ;
}
memcpy ( rdesc , drvdata - > rdesc , drvdata - > rsize ) ;
/* Append the buttonpad descriptor */
memcpy ( rdesc + drvdata - > rsize , uclogic_buttonpad_rdesc ,
sizeof ( uclogic_buttonpad_rdesc ) ) ;
/* clean up old rdesc and use the new one */
drvdata - > rsize = rdesc_len ;
devm_kfree ( & hdev - > dev , drvdata - > rdesc ) ;
drvdata - > rdesc = rdesc ;
rc = 0 ;
cleanup :
kfree ( str_buf ) ;
return rc ;
}
2015-03-03 20:44:00 +03:00
static int uclogic_probe ( struct hid_device * hdev ,
const struct hid_device_id * id )
{
int rc ;
2015-03-03 20:44:01 +03:00
struct usb_interface * intf = to_usb_interface ( hdev - > dev . parent ) ;
2016-09-14 21:38:20 +03:00
struct usb_device * udev = hid_to_usb_dev ( hdev ) ;
2015-03-03 20:44:01 +03:00
struct uclogic_drvdata * drvdata ;
2015-03-03 20:44:00 +03:00
/*
* libinput requires the pad interface to be on a different node
* than the pen , so use QUIRK_MULTI_INPUT for all tablets .
*/
hdev - > quirks | = HID_QUIRK_MULTI_INPUT ;
2015-03-03 20:44:03 +03:00
hdev - > quirks | = HID_QUIRK_NO_EMPTY_INPUT ;
2015-03-03 20:44:00 +03:00
2015-03-03 20:44:01 +03:00
/* Allocate and assign driver data */
drvdata = devm_kzalloc ( & hdev - > dev , sizeof ( * drvdata ) , GFP_KERNEL ) ;
if ( drvdata = = NULL )
return - ENOMEM ;
hid_set_drvdata ( hdev , drvdata ) ;
switch ( id - > product ) {
case USB_DEVICE_ID_HUION_TABLET :
2016-09-14 21:38:17 +03:00
case USB_DEVICE_ID_YIYNOVA_TABLET :
case USB_DEVICE_ID_UGEE_TABLET_81 :
case USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3 :
case USB_DEVICE_ID_UGEE_TABLET_45 :
2015-03-03 20:44:01 +03:00
/* If this is the pen interface */
if ( intf - > cur_altsetting - > desc . bInterfaceNumber = = 0 ) {
rc = uclogic_tablet_enable ( hdev ) ;
if ( rc ) {
hid_err ( hdev , " tablet enabling failed \n " ) ;
return rc ;
}
2015-03-03 20:44:05 +03:00
drvdata - > invert_pen_inrange = true ;
2016-09-14 21:38:16 +03:00
rc = uclogic_button_enable ( hdev ) ;
drvdata - > has_virtual_pad_interface = ! rc ;
2015-03-15 21:26:27 +03:00
} else {
drvdata - > ignore_pen_usage = true ;
2015-03-03 20:44:01 +03:00
}
break ;
2016-09-14 21:38:18 +03:00
case USB_DEVICE_ID_UGTIZER_TABLET_GP0610 :
2017-03-30 14:43:09 +03:00
case USB_DEVICE_ID_UGEE_TABLET_EX07S :
2016-09-14 21:38:18 +03:00
/* If this is the pen interface */
if ( intf - > cur_altsetting - > desc . bInterfaceNumber = = 1 ) {
rc = uclogic_tablet_enable ( hdev ) ;
if ( rc ) {
hid_err ( hdev , " tablet enabling failed \n " ) ;
return rc ;
}
drvdata - > invert_pen_inrange = true ;
} else {
drvdata - > ignore_pen_usage = true ;
}
break ;
2016-09-14 21:38:20 +03:00
case USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 :
/*
* If it is the three - interface version , which is known to
* respond to initialization .
*/
if ( udev - > config - > desc . bNumInterfaces = = 3 ) {
/* If it is the pen interface */
if ( intf - > cur_altsetting - > desc . bInterfaceNumber = = 0 ) {
rc = uclogic_tablet_enable ( hdev ) ;
if ( rc ) {
hid_err ( hdev , " tablet enabling failed \n " ) ;
return rc ;
}
drvdata - > invert_pen_inrange = true ;
rc = uclogic_button_enable ( hdev ) ;
drvdata - > has_virtual_pad_interface = ! rc ;
} else {
drvdata - > ignore_pen_usage = true ;
}
}
break ;
2015-03-03 20:44:01 +03:00
}
2015-03-03 20:44:00 +03:00
rc = hid_parse ( hdev ) ;
if ( rc ) {
hid_err ( hdev , " parse failed \n " ) ;
return rc ;
}
rc = hid_hw_start ( hdev , HID_CONNECT_DEFAULT ) ;
if ( rc ) {
hid_err ( hdev , " hw start failed \n " ) ;
return rc ;
}
return 0 ;
}
2015-03-03 20:44:01 +03:00
static int uclogic_raw_event ( struct hid_device * hdev , struct hid_report * report ,
u8 * data , int size )
{
2015-03-03 20:44:05 +03:00
struct uclogic_drvdata * drvdata = hid_get_drvdata ( hdev ) ;
2015-03-03 20:44:01 +03:00
2016-09-14 21:38:16 +03:00
if ( ( report - > type = = HID_INPUT_REPORT ) & &
2015-03-03 20:44:05 +03:00
( report - > id = = UCLOGIC_PEN_REPORT_ID ) & &
2016-09-14 21:38:16 +03:00
( size > = 2 ) ) {
if ( drvdata - > has_virtual_pad_interface & & ( data [ 1 ] & 0x20 ) )
/* Change to virtual frame button report ID */
data [ 0 ] = 0xf7 ;
else if ( drvdata - > invert_pen_inrange )
/* Invert the in-range bit */
data [ 1 ] ^ = 0x40 ;
}
2015-03-03 20:44:01 +03:00
return 0 ;
}
2010-08-09 20:44:17 +04:00
static const struct hid_device_id uclogic_devices [ ] = {
2010-08-23 15:09:01 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_UCLOGIC ,
USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 ) } ,
2010-08-09 20:44:17 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_UCLOGIC ,
USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U ) } ,
{ HID_USB_DEVICE ( USB_VENDOR_ID_UCLOGIC ,
USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U ) } ,
{ HID_USB_DEVICE ( USB_VENDOR_ID_UCLOGIC ,
USB_DEVICE_ID_UCLOGIC_TABLET_WP8060U ) } ,
2011-07-06 10:23:41 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_UCLOGIC ,
USB_DEVICE_ID_UCLOGIC_TABLET_WP1062 ) } ,
2012-05-14 21:30:38 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_UCLOGIC ,
USB_DEVICE_ID_UCLOGIC_WIRELESS_TABLET_TWHL850 ) } ,
2012-08-26 21:55:08 +04:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_UCLOGIC ,
USB_DEVICE_ID_UCLOGIC_TABLET_TWHA60 ) } ,
2015-03-03 20:44:01 +03:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_HUION , USB_DEVICE_ID_HUION_TABLET ) } ,
{ HID_USB_DEVICE ( USB_VENDOR_ID_UCLOGIC , USB_DEVICE_ID_HUION_TABLET ) } ,
2016-09-14 21:38:17 +03:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_UCLOGIC , USB_DEVICE_ID_YIYNOVA_TABLET ) } ,
{ HID_USB_DEVICE ( USB_VENDOR_ID_UCLOGIC , USB_DEVICE_ID_UGEE_TABLET_81 ) } ,
{ HID_USB_DEVICE ( USB_VENDOR_ID_UCLOGIC , USB_DEVICE_ID_UGEE_TABLET_45 ) } ,
{ HID_USB_DEVICE ( USB_VENDOR_ID_UCLOGIC , USB_DEVICE_ID_UCLOGIC_DRAWIMAGE_G3 ) } ,
2016-09-14 21:38:18 +03:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_UGTIZER , USB_DEVICE_ID_UGTIZER_TABLET_GP0610 ) } ,
2017-03-30 14:43:09 +03:00
{ HID_USB_DEVICE ( USB_VENDOR_ID_UGEE , USB_DEVICE_ID_UGEE_TABLET_EX07S ) } ,
2010-08-09 20:44:17 +04:00
{ }
} ;
MODULE_DEVICE_TABLE ( hid , uclogic_devices ) ;
static struct hid_driver uclogic_driver = {
. name = " uclogic " ,
. id_table = uclogic_devices ,
2015-03-03 20:44:00 +03:00
. probe = uclogic_probe ,
2010-08-09 20:44:17 +04:00
. report_fixup = uclogic_report_fixup ,
2015-03-03 20:44:01 +03:00
. raw_event = uclogic_raw_event ,
2015-03-03 20:44:04 +03:00
. input_mapping = uclogic_input_mapping ,
2015-03-03 20:44:02 +03:00
. input_configured = uclogic_input_configured ,
2010-08-09 20:44:17 +04:00
} ;
2012-12-18 02:28:26 +04:00
module_hid_driver ( uclogic_driver ) ;
2010-08-09 20:44:17 +04:00
2015-03-03 20:44:01 +03:00
MODULE_AUTHOR ( " Martin Rusko " ) ;
MODULE_AUTHOR ( " Nikolai Kondrashov " ) ;
2010-08-09 20:44:17 +04:00
MODULE_LICENSE ( " GPL " ) ;