xref: /openbmc/linux/drivers/hid/hid-kye.c (revision 1ac731c529cd4d6adbce134754b51ff7d822b145)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
279422741SJiri Kosina /*
379422741SJiri Kosina  *  HID driver for Kye/Genius devices not fully compliant with HID standard
479422741SJiri Kosina  *
579422741SJiri Kosina  *  Copyright (c) 2009 Jiri Kosina
679422741SJiri Kosina  *  Copyright (c) 2009 Tomas Hanak
722ca20b2SNikolai Kondrashov  *  Copyright (c) 2012 Nikolai Kondrashov
8b8cd2d96SDavid Yang  *  Copyright (c) 2023 David Yang
979422741SJiri Kosina  */
1079422741SJiri Kosina 
11b8cd2d96SDavid Yang #include <asm-generic/unaligned.h>
1279422741SJiri Kosina #include <linux/device.h>
1379422741SJiri Kosina #include <linux/hid.h>
1479422741SJiri Kosina #include <linux/module.h>
1579422741SJiri Kosina 
1679422741SJiri Kosina #include "hid-ids.h"
1779422741SJiri Kosina 
182dd438cdSDavid Yang /* Data gathered from Database/VID0458_PID????/Vista/TBoard/default.xml in ioTablet driver
192dd438cdSDavid Yang  *
202dd438cdSDavid Yang  * TODO:
212dd438cdSDavid Yang  *   - Add battery and sleep support for EasyPen M406W and MousePen M508WX
222dd438cdSDavid Yang  *   - Investigate ScrollZ.MiceFMT buttons of EasyPen M406
232dd438cdSDavid Yang  */
242dd438cdSDavid Yang 
252dd438cdSDavid Yang static const __u8 easypen_m406_control_rdesc[] = {
262dd438cdSDavid Yang 	0x05, 0x0C,        /*  Usage Page (Consumer),    */
272dd438cdSDavid Yang 	0x09, 0x01,        /*  Usage (Consumer Control), */
282dd438cdSDavid Yang 	0xA1, 0x01,        /*  Collection (Application), */
292dd438cdSDavid Yang 	0x85, 0x12,        /*    Report ID (18),         */
302dd438cdSDavid Yang 	0x0A, 0x45, 0x02,  /*    Usage (AC Rotate),      */
312dd438cdSDavid Yang 	0x09, 0x40,        /*    Usage (Menu),           */
322dd438cdSDavid Yang 	0x0A, 0x2F, 0x02,  /*    Usage (AC Zoom),        */
332dd438cdSDavid Yang 	0x0A, 0x46, 0x02,  /*    Usage (AC Resize),      */
342dd438cdSDavid Yang 	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),        */
352dd438cdSDavid Yang 	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),      */
362dd438cdSDavid Yang 	0x0A, 0x24, 0x02,  /*    Usage (AC Back),        */
372dd438cdSDavid Yang 	0x0A, 0x25, 0x02,  /*    Usage (AC Forward),     */
382dd438cdSDavid Yang 	0x14,              /*    Logical Minimum (0),    */
392dd438cdSDavid Yang 	0x25, 0x01,        /*    Logical Maximum (1),    */
402dd438cdSDavid Yang 	0x75, 0x01,        /*    Report Size (1),        */
412dd438cdSDavid Yang 	0x95, 0x08,        /*    Report Count (8),       */
422dd438cdSDavid Yang 	0x81, 0x02,        /*    Input (Variable),       */
432dd438cdSDavid Yang 	0x95, 0x30,        /*    Report Count (48),      */
442dd438cdSDavid Yang 	0x81, 0x01,        /*    Input (Constant),       */
452dd438cdSDavid Yang 	0xC0               /*  End Collection            */
462dd438cdSDavid Yang };
472dd438cdSDavid Yang 
482dd438cdSDavid Yang static const __u8 easypen_m506_control_rdesc[] = {
492dd438cdSDavid Yang 	0x05, 0x0C,        /*  Usage Page (Consumer),    */
502dd438cdSDavid Yang 	0x09, 0x01,        /*  Usage (Consumer Control), */
512dd438cdSDavid Yang 	0xA1, 0x01,        /*  Collection (Application), */
522dd438cdSDavid Yang 	0x85, 0x12,        /*    Report ID (18),         */
532dd438cdSDavid Yang 	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),      */
542dd438cdSDavid Yang 	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),        */
552dd438cdSDavid Yang 	0x0A, 0x2D, 0x02,  /*    Usage (AC Zoom In),     */
562dd438cdSDavid Yang 	0x0A, 0x2E, 0x02,  /*    Usage (AC Zoom Out),    */
572dd438cdSDavid Yang 	0x14,              /*    Logical Minimum (0),    */
582dd438cdSDavid Yang 	0x25, 0x01,        /*    Logical Maximum (1),    */
592dd438cdSDavid Yang 	0x75, 0x01,        /*    Report Size (1),        */
602dd438cdSDavid Yang 	0x95, 0x04,        /*    Report Count (4),       */
612dd438cdSDavid Yang 	0x81, 0x02,        /*    Input (Variable),       */
622dd438cdSDavid Yang 	0x95, 0x34,        /*    Report Count (52),      */
632dd438cdSDavid Yang 	0x81, 0x01,        /*    Input (Constant),       */
642dd438cdSDavid Yang 	0xC0               /*  End Collection            */
652dd438cdSDavid Yang };
662dd438cdSDavid Yang 
672dd438cdSDavid Yang static const __u8 easypen_m406w_control_rdesc[] = {
682dd438cdSDavid Yang 	0x05, 0x0C,        /*  Usage Page (Consumer),    */
692dd438cdSDavid Yang 	0x09, 0x01,        /*  Usage (Consumer Control), */
702dd438cdSDavid Yang 	0xA1, 0x01,        /*  Collection (Application), */
712dd438cdSDavid Yang 	0x85, 0x12,        /*    Report ID (18),         */
722dd438cdSDavid Yang 	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),      */
732dd438cdSDavid Yang 	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),        */
742dd438cdSDavid Yang 	0x0A, 0x01, 0x02,  /*    Usage (AC New),         */
752dd438cdSDavid Yang 	0x09, 0x40,        /*    Usage (Menu),           */
762dd438cdSDavid Yang 	0x14,              /*    Logical Minimum (0),    */
772dd438cdSDavid Yang 	0x25, 0x01,        /*    Logical Maximum (1),    */
782dd438cdSDavid Yang 	0x75, 0x01,        /*    Report Size (1),        */
792dd438cdSDavid Yang 	0x95, 0x04,        /*    Report Count (4),       */
802dd438cdSDavid Yang 	0x81, 0x02,        /*    Input (Variable),       */
812dd438cdSDavid Yang 	0x95, 0x34,        /*    Report Count (52),      */
822dd438cdSDavid Yang 	0x81, 0x01,        /*    Input (Constant),       */
832dd438cdSDavid Yang 	0xC0               /*  End Collection            */
842dd438cdSDavid Yang };
852dd438cdSDavid Yang 
864782c0e0SDavid Yang static const __u8 easypen_m610x_control_rdesc[] = {
8722ca20b2SNikolai Kondrashov 	0x05, 0x0C,        /*  Usage Page (Consumer),       */
8822ca20b2SNikolai Kondrashov 	0x09, 0x01,        /*  Usage (Consumer Control),    */
8922ca20b2SNikolai Kondrashov 	0xA1, 0x01,        /*  Collection (Application),    */
9022ca20b2SNikolai Kondrashov 	0x85, 0x12,        /*    Report ID (18),            */
9122ca20b2SNikolai Kondrashov 	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),           */
9222ca20b2SNikolai Kondrashov 	0x0A, 0x79, 0x02,  /*    Usage (AC Redo Or Repeat), */
9322ca20b2SNikolai Kondrashov 	0x0A, 0x2D, 0x02,  /*    Usage (AC Zoom In),        */
9422ca20b2SNikolai Kondrashov 	0x0A, 0x2E, 0x02,  /*    Usage (AC Zoom Out),       */
954782c0e0SDavid Yang 	0x14,              /*    Logical Minimum (0),       */
964782c0e0SDavid Yang 	0x25, 0x01,        /*    Logical Maximum (1),       */
974782c0e0SDavid Yang 	0x75, 0x01,        /*    Report Size (1),           */
984782c0e0SDavid Yang 	0x95, 0x04,        /*    Report Count (4),          */
9922ca20b2SNikolai Kondrashov 	0x81, 0x02,        /*    Input (Variable),          */
1004782c0e0SDavid Yang 	0x95, 0x34,        /*    Report Count (52),         */
1014782c0e0SDavid Yang 	0x81, 0x01,        /*    Input (Constant),          */
10222ca20b2SNikolai Kondrashov 	0xC0               /*  End Collection               */
10322ca20b2SNikolai Kondrashov };
10422ca20b2SNikolai Kondrashov 
1054782c0e0SDavid Yang static const __u8 pensketch_m912_control_rdesc[] = {
106feb6faf1SMilan Plzik 	0x05, 0x0C,        /*  Usage Page (Consumer),        */
107feb6faf1SMilan Plzik 	0x09, 0x01,        /*  Usage (Consumer Control),     */
108feb6faf1SMilan Plzik 	0xA1, 0x01,        /*  Collection (Application),     */
109feb6faf1SMilan Plzik 	0x85, 0x12,        /*    Report ID (18),             */
110feb6faf1SMilan Plzik 	0x14,              /*    Logical Minimum (0),        */
111feb6faf1SMilan Plzik 	0x25, 0x01,        /*    Logical Maximum (1),        */
112feb6faf1SMilan Plzik 	0x75, 0x01,        /*    Report Size (1),            */
113feb6faf1SMilan Plzik 	0x95, 0x08,        /*    Report Count (8),           */
114feb6faf1SMilan Plzik 	0x05, 0x0C,        /*    Usage Page (Consumer),      */
115feb6faf1SMilan Plzik 	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),          */
116feb6faf1SMilan Plzik 	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),            */
117feb6faf1SMilan Plzik 	0x0A, 0x01, 0x02,  /*    Usage (AC New),             */
118feb6faf1SMilan Plzik 	0x0A, 0x2F, 0x02,  /*    Usage (AC Zoom),            */
119feb6faf1SMilan Plzik 	0x0A, 0x25, 0x02,  /*    Usage (AC Forward),         */
120feb6faf1SMilan Plzik 	0x0A, 0x24, 0x02,  /*    Usage (AC Back),            */
121feb6faf1SMilan Plzik 	0x0A, 0x2D, 0x02,  /*    Usage (AC Zoom In),         */
122feb6faf1SMilan Plzik 	0x0A, 0x2E, 0x02,  /*    Usage (AC Zoom Out),        */
123feb6faf1SMilan Plzik 	0x81, 0x02,        /*    Input (Variable),           */
124feb6faf1SMilan Plzik 	0x95, 0x30,        /*    Report Count (48),          */
125feb6faf1SMilan Plzik 	0x81, 0x03,        /*    Input (Constant, Variable), */
126feb6faf1SMilan Plzik 	0xC0               /*  End Collection                */
127feb6faf1SMilan Plzik };
128feb6faf1SMilan Plzik 
1292dd438cdSDavid Yang static const __u8 mousepen_m508wx_control_rdesc[] = {
1302dd438cdSDavid Yang 	0x05, 0x0C,        /*  Usage Page (Consumer),    */
1312dd438cdSDavid Yang 	0x09, 0x01,        /*  Usage (Consumer Control), */
1322dd438cdSDavid Yang 	0xA1, 0x01,        /*  Collection (Application), */
1332dd438cdSDavid Yang 	0x85, 0x12,        /*    Report ID (18),         */
1342dd438cdSDavid Yang 	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),        */
1352dd438cdSDavid Yang 	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),      */
1362dd438cdSDavid Yang 	0x0A, 0x2D, 0x02,  /*    Usage (AC Zoom In),     */
1372dd438cdSDavid Yang 	0x0A, 0x2E, 0x02,  /*    Usage (AC Zoom Out),    */
1382dd438cdSDavid Yang 	0x14,              /*    Logical Minimum (0),    */
1392dd438cdSDavid Yang 	0x25, 0x01,        /*    Logical Maximum (1),    */
1402dd438cdSDavid Yang 	0x75, 0x01,        /*    Report Size (1),        */
1412dd438cdSDavid Yang 	0x95, 0x04,        /*    Report Count (4),       */
1422dd438cdSDavid Yang 	0x81, 0x02,        /*    Input (Variable),       */
1432dd438cdSDavid Yang 	0x95, 0x34,        /*    Report Count (52),      */
1442dd438cdSDavid Yang 	0x81, 0x01,        /*    Input (Constant),       */
1452dd438cdSDavid Yang 	0xC0               /*  End Collection            */
1462dd438cdSDavid Yang };
1472dd438cdSDavid Yang 
1482dd438cdSDavid Yang static const __u8 mousepen_m508x_control_rdesc[] = {
1492dd438cdSDavid Yang 	0x05, 0x0C,        /*  Usage Page (Consumer),        */
1502dd438cdSDavid Yang 	0x09, 0x01,        /*  Usage (Consumer Control),     */
1512dd438cdSDavid Yang 	0xA1, 0x01,        /*  Collection (Application),     */
1522dd438cdSDavid Yang 	0x85, 0x12,        /*    Report ID (18),             */
1532dd438cdSDavid Yang 	0x0A, 0x01, 0x02,  /*    Usage (AC New),             */
1542dd438cdSDavid Yang 	0x09, 0x40,        /*    Usage (Menu),               */
1552dd438cdSDavid Yang 	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),          */
1562dd438cdSDavid Yang 	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),            */
1572dd438cdSDavid Yang 	0x14,              /*    Logical Minimum (0),        */
1582dd438cdSDavid Yang 	0x25, 0x01,        /*    Logical Maximum (1),        */
1592dd438cdSDavid Yang 	0x75, 0x01,        /*    Report Size (1),            */
1602dd438cdSDavid Yang 	0x95, 0x04,        /*    Report Count (4),           */
1612dd438cdSDavid Yang 	0x81, 0x02,        /*    Input (Variable),           */
1622dd438cdSDavid Yang 	0x81, 0x01,        /*    Input (Constant),           */
1632dd438cdSDavid Yang 	0x15, 0xFF,        /*    Logical Minimum (-1),       */
1642dd438cdSDavid Yang 	0x95, 0x10,        /*    Report Count (16),          */
1652dd438cdSDavid Yang 	0x81, 0x01,        /*    Input (Constant),           */
1662dd438cdSDavid Yang 	0x0A, 0x35, 0x02,  /*    Usage (AC Scroll),          */
1672dd438cdSDavid Yang 	0x0A, 0x2F, 0x02,  /*    Usage (AC Zoom),            */
1682dd438cdSDavid Yang 	0x0A, 0x38, 0x02,  /*    Usage (AC Pan),             */
1692dd438cdSDavid Yang 	0x75, 0x08,        /*    Report Size (8),            */
1702dd438cdSDavid Yang 	0x95, 0x03,        /*    Report Count (3),           */
1712dd438cdSDavid Yang 	0x81, 0x06,        /*    Input (Variable, Relative), */
1722dd438cdSDavid Yang 	0x95, 0x01,        /*    Report Count (1),           */
1732dd438cdSDavid Yang 	0x81, 0x01,        /*    Input (Constant),           */
1742dd438cdSDavid Yang 	0xC0               /*  End Collection                */
1752dd438cdSDavid Yang };
1762dd438cdSDavid Yang 
1774782c0e0SDavid Yang static const __u8 easypen_m406xe_control_rdesc[] = {
1785e55e2aaSNikolai Kondrashov 	0x05, 0x0C,        /*  Usage Page (Consumer),          */
1795e55e2aaSNikolai Kondrashov 	0x09, 0x01,        /*  Usage (Consumer Control),       */
1805e55e2aaSNikolai Kondrashov 	0xA1, 0x01,        /*  Collection (Application),       */
1815e55e2aaSNikolai Kondrashov 	0x85, 0x12,        /*      Report ID (18),             */
1825e55e2aaSNikolai Kondrashov 	0x14,              /*      Logical Minimum (0),        */
1835e55e2aaSNikolai Kondrashov 	0x25, 0x01,        /*      Logical Maximum (1),        */
1845e55e2aaSNikolai Kondrashov 	0x75, 0x01,        /*      Report Size (1),            */
1855e55e2aaSNikolai Kondrashov 	0x95, 0x04,        /*      Report Count (4),           */
1865e55e2aaSNikolai Kondrashov 	0x0A, 0x79, 0x02,  /*      Usage (AC Redo Or Repeat),  */
1875e55e2aaSNikolai Kondrashov 	0x0A, 0x1A, 0x02,  /*      Usage (AC Undo),            */
1885e55e2aaSNikolai Kondrashov 	0x0A, 0x2D, 0x02,  /*      Usage (AC Zoom In),         */
1895e55e2aaSNikolai Kondrashov 	0x0A, 0x2E, 0x02,  /*      Usage (AC Zoom Out),        */
1905e55e2aaSNikolai Kondrashov 	0x81, 0x02,        /*      Input (Variable),           */
1915e55e2aaSNikolai Kondrashov 	0x95, 0x34,        /*      Report Count (52),          */
1925e55e2aaSNikolai Kondrashov 	0x81, 0x03,        /*      Input (Constant, Variable), */
1935e55e2aaSNikolai Kondrashov 	0xC0               /*  End Collection                  */
1945e55e2aaSNikolai Kondrashov };
1955e55e2aaSNikolai Kondrashov 
1962dd438cdSDavid Yang static const __u8 pensketch_t609a_control_rdesc[] = {
1972dd438cdSDavid Yang 	0x05, 0x0C,        /*  Usage Page (Consumer),    */
1982dd438cdSDavid Yang 	0x09, 0x01,        /*  Usage (Consumer Control), */
1992dd438cdSDavid Yang 	0xA1, 0x01,        /*  Collection (Application), */
2002dd438cdSDavid Yang 	0x85, 0x12,        /*    Report ID (18),         */
2012dd438cdSDavid Yang 	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),      */
2022dd438cdSDavid Yang 	0x14,              /*    Logical Minimum (0),    */
2032dd438cdSDavid Yang 	0x25, 0x01,        /*    Logical Maximum (1),    */
2042dd438cdSDavid Yang 	0x75, 0x01,        /*    Report Size (1),        */
2052dd438cdSDavid Yang 	0x95, 0x08,        /*    Report Count (8),       */
2062dd438cdSDavid Yang 	0x81, 0x02,        /*    Input (Variable),       */
2072dd438cdSDavid Yang 	0x95, 0x37,        /*    Report Count (55),      */
2082dd438cdSDavid Yang 	0x81, 0x01,        /*    Input (Constant),       */
2092dd438cdSDavid Yang 	0xC0               /*  End Collection            */
2102dd438cdSDavid Yang };
2112dd438cdSDavid Yang 
212*0f6fac2cSDavid Yang /* Fix indexes in kye_tablet_fixup if you change this */
2134782c0e0SDavid Yang static const __u8 kye_tablet_rdesc[] = {
2144782c0e0SDavid Yang 	0x06, 0x00, 0xFF,             /*  Usage Page (FF00h),             */
2154782c0e0SDavid Yang 	0x09, 0x01,                   /*  Usage (01h),                    */
2164782c0e0SDavid Yang 	0xA1, 0x01,                   /*  Collection (Application),       */
2174782c0e0SDavid Yang 	0x85, 0x05,                   /*    Report ID (5),                */
2184782c0e0SDavid Yang 	0x09, 0x01,                   /*    Usage (01h),                  */
2194782c0e0SDavid Yang 	0x15, 0x81,                   /*    Logical Minimum (-127),       */
2204782c0e0SDavid Yang 	0x25, 0x7F,                   /*    Logical Maximum (127),        */
2214782c0e0SDavid Yang 	0x75, 0x08,                   /*    Report Size (8),              */
2224782c0e0SDavid Yang 	0x95, 0x07,                   /*    Report Count (7),             */
2234782c0e0SDavid Yang 	0xB1, 0x02,                   /*    Feature (Variable),           */
2244782c0e0SDavid Yang 	0xC0,                         /*  End Collection,                 */
2254782c0e0SDavid Yang 	0x05, 0x0D,                   /*  Usage Page (Digitizer),         */
2264782c0e0SDavid Yang 	0x09, 0x01,                   /*  Usage (Digitizer),              */
2274782c0e0SDavid Yang 	0xA1, 0x01,                   /*  Collection (Application),       */
2284782c0e0SDavid Yang 	0x85, 0x10,                   /*    Report ID (16),               */
2294782c0e0SDavid Yang 	0x09, 0x20,                   /*    Usage (Stylus),               */
2304782c0e0SDavid Yang 	0xA0,                         /*    Collection (Physical),        */
2314782c0e0SDavid Yang 	0x09, 0x42,                   /*      Usage (Tip Switch),         */
2324782c0e0SDavid Yang 	0x09, 0x44,                   /*      Usage (Barrel Switch),      */
2334782c0e0SDavid Yang 	0x09, 0x46,                   /*      Usage (Tablet Pick),        */
2344782c0e0SDavid Yang 	0x14,                         /*      Logical Minimum (0),        */
2354782c0e0SDavid Yang 	0x25, 0x01,                   /*      Logical Maximum (1),        */
2364782c0e0SDavid Yang 	0x75, 0x01,                   /*      Report Size (1),            */
2374782c0e0SDavid Yang 	0x95, 0x03,                   /*      Report Count (3),           */
2384782c0e0SDavid Yang 	0x81, 0x02,                   /*      Input (Variable),           */
2394782c0e0SDavid Yang 	0x95, 0x04,                   /*      Report Count (4),           */
2404782c0e0SDavid Yang 	0x81, 0x01,                   /*      Input (Constant),           */
2414782c0e0SDavid Yang 	0x09, 0x32,                   /*      Usage (In Range),           */
2424782c0e0SDavid Yang 	0x95, 0x01,                   /*      Report Count (1),           */
2434782c0e0SDavid Yang 	0x81, 0x02,                   /*      Input (Variable),           */
2444782c0e0SDavid Yang 	0x75, 0x10,                   /*      Report Size (16),           */
2454782c0e0SDavid Yang 	0xA4,                         /*      Push,                       */
2464782c0e0SDavid Yang 	0x05, 0x01,                   /*      Usage Page (Desktop),       */
2474782c0e0SDavid Yang 	0x09, 0x30,                   /*      Usage (X),                  */
2484782c0e0SDavid Yang 	0x27, 0xFF, 0x7F, 0x00, 0x00, /*      Logical Maximum (32767),    */
2494782c0e0SDavid Yang 	0x34,                         /*      Physical Minimum (0),       */
2504782c0e0SDavid Yang 	0x47, 0x00, 0x00, 0x00, 0x00, /*      Physical Maximum (0),       */
2514782c0e0SDavid Yang 	0x65, 0x11,                   /*      Unit (Centimeter),          */
2524782c0e0SDavid Yang 	0x55, 0x00,                   /*      Unit Exponent (0),          */
2534782c0e0SDavid Yang 	0x75, 0x10,                   /*      Report Size (16),           */
2544782c0e0SDavid Yang 	0x81, 0x02,                   /*      Input (Variable),           */
2554782c0e0SDavid Yang 	0x09, 0x31,                   /*      Usage (Y),                  */
2564782c0e0SDavid Yang 	0x27, 0xFF, 0x7F, 0x00, 0x00, /*      Logical Maximum (32767),    */
2574782c0e0SDavid Yang 	0x47, 0x00, 0x00, 0x00, 0x00, /*      Physical Maximum (0),       */
2584782c0e0SDavid Yang 	0x81, 0x02,                   /*      Input (Variable),           */
2594782c0e0SDavid Yang 	0xB4,                         /*      Pop,                        */
2604782c0e0SDavid Yang 	0x05, 0x0D,                   /*      Usage Page (Digitizer),     */
2614782c0e0SDavid Yang 	0x09, 0x30,                   /*      Usage (Tip Pressure),       */
2624782c0e0SDavid Yang 	0x27, 0xFF, 0x07, 0x00, 0x00, /*      Logical Maximum (2047),     */
2634782c0e0SDavid Yang 	0x81, 0x02,                   /*      Input (Variable),           */
2644782c0e0SDavid Yang 	0xC0,                         /*    End Collection,               */
2654782c0e0SDavid Yang 	0xC0,                         /*  End Collection,                 */
2664782c0e0SDavid Yang 	0x05, 0x0D,                   /*  Usage Page (Digitizer),         */
2674782c0e0SDavid Yang 	0x09, 0x21,                   /*  Usage (Puck),                   */
2684782c0e0SDavid Yang 	0xA1, 0x01,                   /*  Collection (Application),       */
2694782c0e0SDavid Yang 	0x85, 0x11,                   /*    Report ID (17),               */
2704782c0e0SDavid Yang 	0x09, 0x21,                   /*    Usage (Puck),                 */
2714782c0e0SDavid Yang 	0xA0,                         /*    Collection (Physical),        */
2724782c0e0SDavid Yang 	0x05, 0x09,                   /*      Usage Page (Button),        */
2734782c0e0SDavid Yang 	0x19, 0x01,                   /*      Usage Minimum (01h),        */
2744782c0e0SDavid Yang 	0x29, 0x03,                   /*      Usage Maximum (03h),        */
2754782c0e0SDavid Yang 	0x14,                         /*      Logical Minimum (0),        */
2764782c0e0SDavid Yang 	0x25, 0x01,                   /*      Logical Maximum (1),        */
2774782c0e0SDavid Yang 	0x75, 0x01,                   /*      Report Size (1),            */
2784782c0e0SDavid Yang 	0x95, 0x03,                   /*      Report Count (3),           */
2794782c0e0SDavid Yang 	0x81, 0x02,                   /*      Input (Variable),           */
2804782c0e0SDavid Yang 	0x95, 0x04,                   /*      Report Count (4),           */
2814782c0e0SDavid Yang 	0x81, 0x01,                   /*      Input (Constant),           */
2824782c0e0SDavid Yang 	0x05, 0x0D,                   /*      Usage Page (Digitizer),     */
2834782c0e0SDavid Yang 	0x09, 0x32,                   /*      Usage (In Range),           */
2844782c0e0SDavid Yang 	0x95, 0x01,                   /*      Report Count (1),           */
2854782c0e0SDavid Yang 	0x81, 0x02,                   /*      Input (Variable),           */
2864782c0e0SDavid Yang 	0x05, 0x01,                   /*      Usage Page (Desktop),       */
2874782c0e0SDavid Yang 	0xA4,                         /*      Push,                       */
2884782c0e0SDavid Yang 	0x09, 0x30,                   /*      Usage (X),                  */
2894782c0e0SDavid Yang 	0x27, 0xFF, 0x7F, 0x00, 0x00, /*      Logical Maximum (32767),    */
2904782c0e0SDavid Yang 	0x34,                         /*      Physical Minimum (0),       */
2914782c0e0SDavid Yang 	0x47, 0x00, 0x00, 0x00, 0x00, /*      Physical Maximum (0),       */
2924782c0e0SDavid Yang 	0x65, 0x11,                   /*      Unit (Centimeter),          */
2934782c0e0SDavid Yang 	0x55, 0x00,                   /*      Unit Exponent (0),          */
2944782c0e0SDavid Yang 	0x75, 0x10,                   /*      Report Size (16),           */
2954782c0e0SDavid Yang 	0x81, 0x02,                   /*      Input (Variable),           */
2964782c0e0SDavid Yang 	0x09, 0x31,                   /*      Usage (Y),                  */
2974782c0e0SDavid Yang 	0x27, 0xFF, 0x7F, 0x00, 0x00, /*      Logical Maximum (32767),    */
2984782c0e0SDavid Yang 	0x47, 0x00, 0x00, 0x00, 0x00, /*      Physical Maximum (0),       */
2994782c0e0SDavid Yang 	0x81, 0x02,                   /*      Input (Variable),           */
3004782c0e0SDavid Yang 	0xB4,                         /*      Pop,                        */
3014782c0e0SDavid Yang 	0x09, 0x38,                   /*      Usage (Wheel),              */
3024782c0e0SDavid Yang 	0x15, 0xFF,                   /*      Logical Minimum (-1),       */
3034782c0e0SDavid Yang 	0x75, 0x08,                   /*      Report Size (8),            */
3044782c0e0SDavid Yang 	0x95, 0x01,                   /*      Report Count (1),           */
3054782c0e0SDavid Yang 	0x81, 0x06,                   /*      Input (Variable, Relative), */
3064782c0e0SDavid Yang 	0x81, 0x01,                   /*      Input (Constant),           */
3074782c0e0SDavid Yang 	0xC0,                         /*    End Collection,               */
3084782c0e0SDavid Yang 	0xC0                          /*  End Collection                  */
3094782c0e0SDavid Yang };
3104782c0e0SDavid Yang 
311b8cd2d96SDavid Yang static const struct kye_tablet_info {
312b8cd2d96SDavid Yang 	__u32 product;
313b8cd2d96SDavid Yang 	__s32 x_logical_maximum;
314b8cd2d96SDavid Yang 	__s32 y_logical_maximum;
315b8cd2d96SDavid Yang 	__s32 pressure_logical_maximum;
316b8cd2d96SDavid Yang 	__s32 x_physical_maximum;
317b8cd2d96SDavid Yang 	__s32 y_physical_maximum;
318b8cd2d96SDavid Yang 	__s8 unit_exponent;
319b8cd2d96SDavid Yang 	__s8 unit;
320b8cd2d96SDavid Yang 	bool has_punk;
321b8cd2d96SDavid Yang 	unsigned int control_rsize;
322b8cd2d96SDavid Yang 	const __u8 *control_rdesc;
323b8cd2d96SDavid Yang } kye_tablets_info[] = {
3242dd438cdSDavid Yang 	{USB_DEVICE_ID_KYE_EASYPEN_M406,  /* 0x5005 */
3252dd438cdSDavid Yang 		15360, 10240, 1023,    6,   4,  0, 0x13, false,
3262dd438cdSDavid Yang 		sizeof(easypen_m406_control_rdesc), easypen_m406_control_rdesc},
3272dd438cdSDavid Yang 	{USB_DEVICE_ID_KYE_EASYPEN_M506,  /* 0x500F */
3282dd438cdSDavid Yang 		24576, 20480, 1023,    6,   5,  0, 0x13, false,
3292dd438cdSDavid Yang 		sizeof(easypen_m506_control_rdesc), easypen_m506_control_rdesc},
3304782c0e0SDavid Yang 	{USB_DEVICE_ID_KYE_EASYPEN_I405X,  /* 0x5010 */
3314782c0e0SDavid Yang 		14080, 10240, 1023,   55,  40, -1, 0x13, false},
3324782c0e0SDavid Yang 	{USB_DEVICE_ID_KYE_MOUSEPEN_I608X,  /* 0x5011 */
3334782c0e0SDavid Yang 		20480, 15360, 2047,    8,   6,  0, 0x13,  true},
3342dd438cdSDavid Yang 	{USB_DEVICE_ID_KYE_EASYPEN_M406W,  /* 0x5012 */
3352dd438cdSDavid Yang 		15360, 10240, 1023,    6,   4,  0, 0x13, false,
3362dd438cdSDavid Yang 		sizeof(easypen_m406w_control_rdesc), easypen_m406w_control_rdesc},
3374782c0e0SDavid Yang 	{USB_DEVICE_ID_KYE_EASYPEN_M610X,  /* 0x5013 */
3384782c0e0SDavid Yang 		40960, 25600, 1023, 1000, 625, -2, 0x13, false,
3394782c0e0SDavid Yang 		sizeof(easypen_m610x_control_rdesc), easypen_m610x_control_rdesc},
3402dd438cdSDavid Yang 	{USB_DEVICE_ID_KYE_EASYPEN_340,  /* 0x5014 */
3412dd438cdSDavid Yang 		10240,  7680, 1023,    4,   3,  0, 0x13, false},
3424782c0e0SDavid Yang 	{USB_DEVICE_ID_KYE_PENSKETCH_M912,  /* 0x5015 */
3434782c0e0SDavid Yang 		61440, 46080, 2047,   12,   9,  0, 0x13,  true,
3444782c0e0SDavid Yang 		sizeof(pensketch_m912_control_rdesc), pensketch_m912_control_rdesc},
3452dd438cdSDavid Yang 	{USB_DEVICE_ID_KYE_MOUSEPEN_M508WX,  /* 0x5016 */
3462dd438cdSDavid Yang 		40960, 25600, 2047,    8,   5,  0, 0x13,  true,
3472dd438cdSDavid Yang 		sizeof(mousepen_m508wx_control_rdesc), mousepen_m508wx_control_rdesc},
3482dd438cdSDavid Yang 	{USB_DEVICE_ID_KYE_MOUSEPEN_M508X,  /* 0x5017 */
3492dd438cdSDavid Yang 		40960, 25600, 2047,    8,   5,  0, 0x13,  true,
3502dd438cdSDavid Yang 		sizeof(mousepen_m508x_control_rdesc), mousepen_m508x_control_rdesc},
3514782c0e0SDavid Yang 	{USB_DEVICE_ID_KYE_EASYPEN_M406XE,  /* 0x5019 */
3524782c0e0SDavid Yang 		15360, 10240, 1023,    6,   4,  0, 0x13, false,
3534782c0e0SDavid Yang 		sizeof(easypen_m406xe_control_rdesc), easypen_m406xe_control_rdesc},
3544782c0e0SDavid Yang 	{USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2,  /* 0x501A */
3554782c0e0SDavid Yang 		40960, 30720, 2047,    8,   6,  0, 0x13,  true},
3562dd438cdSDavid Yang 	{USB_DEVICE_ID_KYE_PENSKETCH_T609A,  /* 0x501B */
3572dd438cdSDavid Yang 		43520, 28160, 1023,   85,  55, -1, 0x13, false,
3582dd438cdSDavid Yang 		sizeof(pensketch_t609a_control_rdesc), pensketch_t609a_control_rdesc},
359b8cd2d96SDavid Yang 	{}
360b8cd2d96SDavid Yang };
361b8cd2d96SDavid Yang 
kye_consumer_control_fixup(struct hid_device * hdev,__u8 * rdesc,unsigned int * rsize,int offset,const char * device_name)3620adb9c2cSBenjamin Tissoires static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc,
363b8cd2d96SDavid Yang 		unsigned int *rsize, int offset, const char *device_name)
364b8cd2d96SDavid Yang {
3650adb9c2cSBenjamin Tissoires 	/*
3660adb9c2cSBenjamin Tissoires 	 * the fixup that need to be done:
3673f8b6fb7SMasahiro Yamada 	 *   - change Usage Maximum in the Consumer Control
3680adb9c2cSBenjamin Tissoires 	 *     (report ID 3) to a reasonable value
3690adb9c2cSBenjamin Tissoires 	 */
3700adb9c2cSBenjamin Tissoires 	if (*rsize >= offset + 31 &&
3710adb9c2cSBenjamin Tissoires 	    /* Usage Page (Consumer Devices) */
3720adb9c2cSBenjamin Tissoires 	    rdesc[offset] == 0x05 && rdesc[offset + 1] == 0x0c &&
3730adb9c2cSBenjamin Tissoires 	    /* Usage (Consumer Control) */
3740adb9c2cSBenjamin Tissoires 	    rdesc[offset + 2] == 0x09 && rdesc[offset + 3] == 0x01 &&
3750adb9c2cSBenjamin Tissoires 	    /*   Usage Maximum > 12287 */
3760adb9c2cSBenjamin Tissoires 	    rdesc[offset + 10] == 0x2a && rdesc[offset + 12] > 0x2f) {
3770adb9c2cSBenjamin Tissoires 		hid_info(hdev, "fixing up %s report descriptor\n", device_name);
3780adb9c2cSBenjamin Tissoires 		rdesc[offset + 12] = 0x2f;
3790adb9c2cSBenjamin Tissoires 	}
3800adb9c2cSBenjamin Tissoires 	return rdesc;
3810adb9c2cSBenjamin Tissoires }
3820adb9c2cSBenjamin Tissoires 
383b8cd2d96SDavid Yang /*
384b8cd2d96SDavid Yang  * Fix tablet descriptor of so-called "DataFormat 2".
385b8cd2d96SDavid Yang  *
386b8cd2d96SDavid Yang  * Though we may achieve a usable descriptor from original vendor-defined one,
387b8cd2d96SDavid Yang  * some problems exist:
388b8cd2d96SDavid Yang  *  - Their Logical Maximum never exceed 32767 (7F FF), though device do report
389b8cd2d96SDavid Yang  *    values greater than that;
390b8cd2d96SDavid Yang  *  - Physical Maximums are arbitrarily filled (always equal to Logical
391b8cd2d96SDavid Yang  *    Maximum);
392b8cd2d96SDavid Yang  *  - Detail for control buttons are not provided (a vendor-defined Usage Page
393b8cd2d96SDavid Yang  *    with fixed content).
394b8cd2d96SDavid Yang  *
395b8cd2d96SDavid Yang  * Thus we use a pre-defined parameter table rather than digging it from
396b8cd2d96SDavid Yang  * original descriptor.
397b8cd2d96SDavid Yang  *
398b8cd2d96SDavid Yang  * We may as well write a fallback routine for unrecognized kye tablet, but it's
399b8cd2d96SDavid Yang  * clear kye are unlikely to produce new models in the foreseeable future, so we
400b8cd2d96SDavid Yang  * simply enumerate all possible models.
401b8cd2d96SDavid Yang  */
kye_tablet_fixup(struct hid_device * hdev,__u8 * rdesc,unsigned int * rsize)402b8cd2d96SDavid Yang static __u8 *kye_tablet_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize)
403b8cd2d96SDavid Yang {
404b8cd2d96SDavid Yang 	const struct kye_tablet_info *info;
405b8cd2d96SDavid Yang 	unsigned int newsize;
406b8cd2d96SDavid Yang 
407b8cd2d96SDavid Yang 	if (*rsize < sizeof(kye_tablet_rdesc)) {
408b8cd2d96SDavid Yang 		hid_warn(hdev,
409b8cd2d96SDavid Yang 			 "tablet report size too small, or kye_tablet_rdesc unexpectedly large\n");
410b8cd2d96SDavid Yang 		return rdesc;
411b8cd2d96SDavid Yang 	}
412b8cd2d96SDavid Yang 
413b8cd2d96SDavid Yang 	for (info = kye_tablets_info; info->product; info++) {
414b8cd2d96SDavid Yang 		if (hdev->product == info->product)
415b8cd2d96SDavid Yang 			break;
416b8cd2d96SDavid Yang 	}
417b8cd2d96SDavid Yang 
418b8cd2d96SDavid Yang 	if (!info->product) {
419b8cd2d96SDavid Yang 		hid_err(hdev, "tablet unknown, someone forget to add kye_tablet_info entry?\n");
420b8cd2d96SDavid Yang 		return rdesc;
421b8cd2d96SDavid Yang 	}
422b8cd2d96SDavid Yang 
423b8cd2d96SDavid Yang 	newsize = info->has_punk ? sizeof(kye_tablet_rdesc) : 112;
424b8cd2d96SDavid Yang 	memcpy(rdesc, kye_tablet_rdesc, newsize);
425b8cd2d96SDavid Yang 
426b8cd2d96SDavid Yang 	put_unaligned_le32(info->x_logical_maximum, rdesc + 66);
427b8cd2d96SDavid Yang 	put_unaligned_le32(info->x_physical_maximum, rdesc + 72);
428b8cd2d96SDavid Yang 	rdesc[77] = info->unit;
429b8cd2d96SDavid Yang 	rdesc[79] = info->unit_exponent;
430b8cd2d96SDavid Yang 	put_unaligned_le32(info->y_logical_maximum, rdesc + 87);
431b8cd2d96SDavid Yang 	put_unaligned_le32(info->y_physical_maximum, rdesc + 92);
432b8cd2d96SDavid Yang 	put_unaligned_le32(info->pressure_logical_maximum, rdesc + 104);
433b8cd2d96SDavid Yang 
434b8cd2d96SDavid Yang 	if (info->has_punk) {
435b8cd2d96SDavid Yang 		put_unaligned_le32(info->x_logical_maximum, rdesc + 156);
436b8cd2d96SDavid Yang 		put_unaligned_le32(info->x_physical_maximum, rdesc + 162);
437b8cd2d96SDavid Yang 		rdesc[167] = info->unit;
438b8cd2d96SDavid Yang 		rdesc[169] = info->unit_exponent;
439b8cd2d96SDavid Yang 		put_unaligned_le32(info->y_logical_maximum, rdesc + 177);
440b8cd2d96SDavid Yang 		put_unaligned_le32(info->y_physical_maximum, rdesc + 182);
441b8cd2d96SDavid Yang 	}
442b8cd2d96SDavid Yang 
443b8cd2d96SDavid Yang 	if (info->control_rsize) {
444b8cd2d96SDavid Yang 		if (newsize + info->control_rsize > *rsize)
445b8cd2d96SDavid Yang 			hid_err(hdev, "control rdesc unexpectedly large");
446b8cd2d96SDavid Yang 		else {
447b8cd2d96SDavid Yang 			memcpy(rdesc + newsize, info->control_rdesc, info->control_rsize);
448b8cd2d96SDavid Yang 			newsize += info->control_rsize;
449b8cd2d96SDavid Yang 		}
450b8cd2d96SDavid Yang 	}
451b8cd2d96SDavid Yang 
452b8cd2d96SDavid Yang 	*rsize = newsize;
453b8cd2d96SDavid Yang 	return rdesc;
454b8cd2d96SDavid Yang }
455b8cd2d96SDavid Yang 
kye_report_fixup(struct hid_device * hdev,__u8 * rdesc,unsigned int * rsize)45673e4008dSNikolai Kondrashov static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
45773e4008dSNikolai Kondrashov 		unsigned int *rsize)
45879422741SJiri Kosina {
45922ca20b2SNikolai Kondrashov 	switch (hdev->product) {
46022ca20b2SNikolai Kondrashov 	case USB_DEVICE_ID_KYE_ERGO_525V:
46122ca20b2SNikolai Kondrashov 		/* the fixups that need to be done:
46222ca20b2SNikolai Kondrashov 		 *   - change led usage page to button for extra buttons
46322ca20b2SNikolai Kondrashov 		 *   - report size 8 count 1 must be size 1 count 8 for button
46422ca20b2SNikolai Kondrashov 		 *     bitfield
46522ca20b2SNikolai Kondrashov 		 *   - change the button usage range to 4-7 for the extra
46622ca20b2SNikolai Kondrashov 		 *     buttons
46722ca20b2SNikolai Kondrashov 		 */
4684ab25786SJiri Kosina 		if (*rsize >= 75 &&
46979422741SJiri Kosina 			rdesc[61] == 0x05 && rdesc[62] == 0x08 &&
47079422741SJiri Kosina 			rdesc[63] == 0x19 && rdesc[64] == 0x08 &&
47179422741SJiri Kosina 			rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
47279422741SJiri Kosina 			rdesc[71] == 0x75 && rdesc[72] == 0x08 &&
47379422741SJiri Kosina 			rdesc[73] == 0x95 && rdesc[74] == 0x01) {
4744291ee30SJoe Perches 			hid_info(hdev,
47522ca20b2SNikolai Kondrashov 				 "fixing up Kye/Genius Ergo Mouse "
47622ca20b2SNikolai Kondrashov 				 "report descriptor\n");
47779422741SJiri Kosina 			rdesc[62] = 0x09;
47879422741SJiri Kosina 			rdesc[64] = 0x04;
47979422741SJiri Kosina 			rdesc[66] = 0x07;
48079422741SJiri Kosina 			rdesc[72] = 0x01;
48179422741SJiri Kosina 			rdesc[74] = 0x08;
48279422741SJiri Kosina 		}
48322ca20b2SNikolai Kondrashov 		break;
4848c7b79bcSDavid Yang 	case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE:
4858c7b79bcSDavid Yang 		rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104,
4868c7b79bcSDavid Yang 					"Genius Gila Gaming Mouse");
4878c7b79bcSDavid Yang 		break;
4888c7b79bcSDavid Yang 	case USB_DEVICE_ID_GENIUS_MANTICORE:
4898c7b79bcSDavid Yang 		rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104,
4908c7b79bcSDavid Yang 					"Genius Manticore Keyboard");
4918c7b79bcSDavid Yang 		break;
4928c7b79bcSDavid Yang 	case USB_DEVICE_ID_GENIUS_GX_IMPERATOR:
4938c7b79bcSDavid Yang 		rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83,
4948c7b79bcSDavid Yang 					"Genius Gx Imperator Keyboard");
4958c7b79bcSDavid Yang 		break;
496*0f6fac2cSDavid Yang 	case USB_DEVICE_ID_KYE_EASYPEN_M406:
497*0f6fac2cSDavid Yang 	case USB_DEVICE_ID_KYE_EASYPEN_M506:
49822ca20b2SNikolai Kondrashov 	case USB_DEVICE_ID_KYE_EASYPEN_I405X:
49922ca20b2SNikolai Kondrashov 	case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:
500*0f6fac2cSDavid Yang 	case USB_DEVICE_ID_KYE_EASYPEN_M406W:
50122ca20b2SNikolai Kondrashov 	case USB_DEVICE_ID_KYE_EASYPEN_M610X:
502*0f6fac2cSDavid Yang 	case USB_DEVICE_ID_KYE_EASYPEN_340:
503feb6faf1SMilan Plzik 	case USB_DEVICE_ID_KYE_PENSKETCH_M912:
504*0f6fac2cSDavid Yang 	case USB_DEVICE_ID_KYE_MOUSEPEN_M508WX:
505*0f6fac2cSDavid Yang 	case USB_DEVICE_ID_KYE_MOUSEPEN_M508X:
506*0f6fac2cSDavid Yang 	case USB_DEVICE_ID_KYE_EASYPEN_M406XE:
507*0f6fac2cSDavid Yang 	case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2:
508*0f6fac2cSDavid Yang 	case USB_DEVICE_ID_KYE_PENSKETCH_T609A:
5094782c0e0SDavid Yang 		rdesc = kye_tablet_fixup(hdev, rdesc, rsize);
510feb6faf1SMilan Plzik 		break;
51122ca20b2SNikolai Kondrashov 	}
51273e4008dSNikolai Kondrashov 	return rdesc;
51379422741SJiri Kosina }
51479422741SJiri Kosina 
kye_tablet_enable(struct hid_device * hdev)51522ca20b2SNikolai Kondrashov static int kye_tablet_enable(struct hid_device *hdev)
51622ca20b2SNikolai Kondrashov {
51722ca20b2SNikolai Kondrashov 	struct list_head *list;
51822ca20b2SNikolai Kondrashov 	struct list_head *head;
51922ca20b2SNikolai Kondrashov 	struct hid_report *report;
52022ca20b2SNikolai Kondrashov 	__s32 *value;
52122ca20b2SNikolai Kondrashov 
52222ca20b2SNikolai Kondrashov 	list = &hdev->report_enum[HID_FEATURE_REPORT].report_list;
52322ca20b2SNikolai Kondrashov 	list_for_each(head, list) {
52422ca20b2SNikolai Kondrashov 		report = list_entry(head, struct hid_report, list);
52522ca20b2SNikolai Kondrashov 		if (report->id == 5)
52622ca20b2SNikolai Kondrashov 			break;
52722ca20b2SNikolai Kondrashov 	}
52822ca20b2SNikolai Kondrashov 
52922ca20b2SNikolai Kondrashov 	if (head == list) {
53022ca20b2SNikolai Kondrashov 		hid_err(hdev, "tablet-enabling feature report not found\n");
53122ca20b2SNikolai Kondrashov 		return -ENODEV;
53222ca20b2SNikolai Kondrashov 	}
53322ca20b2SNikolai Kondrashov 
53422ca20b2SNikolai Kondrashov 	if (report->maxfield < 1 || report->field[0]->report_count < 7) {
53522ca20b2SNikolai Kondrashov 		hid_err(hdev, "invalid tablet-enabling feature report\n");
53622ca20b2SNikolai Kondrashov 		return -ENODEV;
53722ca20b2SNikolai Kondrashov 	}
53822ca20b2SNikolai Kondrashov 
53922ca20b2SNikolai Kondrashov 	value = report->field[0]->value;
54022ca20b2SNikolai Kondrashov 
541b8cd2d96SDavid Yang 	/*
542b8cd2d96SDavid Yang 	 * The code is for DataFormat 2 of config xml. They have no obvious
543b8cd2d96SDavid Yang 	 * meaning (at least not configurable in Windows driver) except enabling
544b8cd2d96SDavid Yang 	 * fully-functional tablet mode (absolute positioning). Otherwise, the
545b8cd2d96SDavid Yang 	 * tablet acts like a relative mouse.
546b8cd2d96SDavid Yang 	 *
547b8cd2d96SDavid Yang 	 * Though there're magic codes for DataFormat 3 and 4, no devices use
548b8cd2d96SDavid Yang 	 * these DataFormats.
549b8cd2d96SDavid Yang 	 */
55022ca20b2SNikolai Kondrashov 	value[0] = 0x12;
55122ca20b2SNikolai Kondrashov 	value[1] = 0x10;
55222ca20b2SNikolai Kondrashov 	value[2] = 0x11;
55322ca20b2SNikolai Kondrashov 	value[3] = 0x12;
55422ca20b2SNikolai Kondrashov 	value[4] = 0x00;
55522ca20b2SNikolai Kondrashov 	value[5] = 0x00;
55622ca20b2SNikolai Kondrashov 	value[6] = 0x00;
557d8814272SBenjamin Tissoires 	hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
55822ca20b2SNikolai Kondrashov 
55922ca20b2SNikolai Kondrashov 	return 0;
56022ca20b2SNikolai Kondrashov }
56122ca20b2SNikolai Kondrashov 
kye_probe(struct hid_device * hdev,const struct hid_device_id * id)56222ca20b2SNikolai Kondrashov static int kye_probe(struct hid_device *hdev, const struct hid_device_id *id)
56322ca20b2SNikolai Kondrashov {
56422ca20b2SNikolai Kondrashov 	int ret;
56522ca20b2SNikolai Kondrashov 
56622ca20b2SNikolai Kondrashov 	ret = hid_parse(hdev);
56722ca20b2SNikolai Kondrashov 	if (ret) {
56822ca20b2SNikolai Kondrashov 		hid_err(hdev, "parse failed\n");
56922ca20b2SNikolai Kondrashov 		goto err;
57022ca20b2SNikolai Kondrashov 	}
57122ca20b2SNikolai Kondrashov 
57222ca20b2SNikolai Kondrashov 	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
57322ca20b2SNikolai Kondrashov 	if (ret) {
57422ca20b2SNikolai Kondrashov 		hid_err(hdev, "hw start failed\n");
57522ca20b2SNikolai Kondrashov 		goto err;
57622ca20b2SNikolai Kondrashov 	}
57722ca20b2SNikolai Kondrashov 
57822ca20b2SNikolai Kondrashov 	switch (id->product) {
5798a396321SBenjamin Tissoires 	case USB_DEVICE_ID_GENIUS_MANTICORE:
5808a396321SBenjamin Tissoires 		/*
5818a396321SBenjamin Tissoires 		 * The manticore keyboard needs to have all the interfaces
5828a396321SBenjamin Tissoires 		 * opened at least once to be fully functional.
5838a396321SBenjamin Tissoires 		 */
5848a396321SBenjamin Tissoires 		if (hid_hw_open(hdev))
5858a396321SBenjamin Tissoires 			hid_hw_close(hdev);
5868a396321SBenjamin Tissoires 		break;
5872dd438cdSDavid Yang 	case USB_DEVICE_ID_KYE_EASYPEN_M406:
5882dd438cdSDavid Yang 	case USB_DEVICE_ID_KYE_EASYPEN_M506:
5898c7b79bcSDavid Yang 	case USB_DEVICE_ID_KYE_EASYPEN_I405X:
5908c7b79bcSDavid Yang 	case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:
5912dd438cdSDavid Yang 	case USB_DEVICE_ID_KYE_EASYPEN_M406W:
5928c7b79bcSDavid Yang 	case USB_DEVICE_ID_KYE_EASYPEN_M610X:
5932dd438cdSDavid Yang 	case USB_DEVICE_ID_KYE_EASYPEN_340:
5948c7b79bcSDavid Yang 	case USB_DEVICE_ID_KYE_PENSKETCH_M912:
5952dd438cdSDavid Yang 	case USB_DEVICE_ID_KYE_MOUSEPEN_M508WX:
5962dd438cdSDavid Yang 	case USB_DEVICE_ID_KYE_MOUSEPEN_M508X:
5978c7b79bcSDavid Yang 	case USB_DEVICE_ID_KYE_EASYPEN_M406XE:
5988c7b79bcSDavid Yang 	case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2:
5992dd438cdSDavid Yang 	case USB_DEVICE_ID_KYE_PENSKETCH_T609A:
6008c7b79bcSDavid Yang 		ret = kye_tablet_enable(hdev);
6018c7b79bcSDavid Yang 		if (ret) {
6028c7b79bcSDavid Yang 			hid_err(hdev, "tablet enabling failed\n");
6038c7b79bcSDavid Yang 			goto enabling_err;
6048c7b79bcSDavid Yang 		}
6058c7b79bcSDavid Yang 		break;
60622ca20b2SNikolai Kondrashov 	}
60722ca20b2SNikolai Kondrashov 
60822ca20b2SNikolai Kondrashov 	return 0;
60922ca20b2SNikolai Kondrashov enabling_err:
61022ca20b2SNikolai Kondrashov 	hid_hw_stop(hdev);
61122ca20b2SNikolai Kondrashov err:
61222ca20b2SNikolai Kondrashov 	return ret;
61322ca20b2SNikolai Kondrashov }
61422ca20b2SNikolai Kondrashov 
61579422741SJiri Kosina static const struct hid_device_id kye_devices[] = {
61679422741SJiri Kosina 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
61722ca20b2SNikolai Kondrashov 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6188c7b79bcSDavid Yang 				USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },
6198c7b79bcSDavid Yang 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6208c7b79bcSDavid Yang 				USB_DEVICE_ID_GENIUS_MANTICORE) },
6218c7b79bcSDavid Yang 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6228c7b79bcSDavid Yang 				USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },
6238c7b79bcSDavid Yang 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6242dd438cdSDavid Yang 				USB_DEVICE_ID_KYE_EASYPEN_M406) },
6252dd438cdSDavid Yang 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6262dd438cdSDavid Yang 				USB_DEVICE_ID_KYE_EASYPEN_M506) },
6272dd438cdSDavid Yang 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
62822ca20b2SNikolai Kondrashov 				USB_DEVICE_ID_KYE_EASYPEN_I405X) },
62922ca20b2SNikolai Kondrashov 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
63022ca20b2SNikolai Kondrashov 				USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },
63122ca20b2SNikolai Kondrashov 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6322dd438cdSDavid Yang 				USB_DEVICE_ID_KYE_EASYPEN_M406W) },
6332dd438cdSDavid Yang 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
63422ca20b2SNikolai Kondrashov 				USB_DEVICE_ID_KYE_EASYPEN_M610X) },
6353685c18eSBenjamin Tissoires 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6362dd438cdSDavid Yang 				USB_DEVICE_ID_KYE_EASYPEN_340) },
6372dd438cdSDavid Yang 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6388c7b79bcSDavid Yang 				USB_DEVICE_ID_KYE_PENSKETCH_M912) },
6398c7b79bcSDavid Yang 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6402dd438cdSDavid Yang 				USB_DEVICE_ID_KYE_MOUSEPEN_M508WX) },
6412dd438cdSDavid Yang 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6422dd438cdSDavid Yang 				USB_DEVICE_ID_KYE_MOUSEPEN_M508X) },
6432dd438cdSDavid Yang 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6445e55e2aaSNikolai Kondrashov 				USB_DEVICE_ID_KYE_EASYPEN_M406XE) },
6455e55e2aaSNikolai Kondrashov 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6468c7b79bcSDavid Yang 				USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2) },
6472dd438cdSDavid Yang 	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,
6482dd438cdSDavid Yang 				USB_DEVICE_ID_KYE_PENSKETCH_T609A) },
64979422741SJiri Kosina 	{ }
65079422741SJiri Kosina };
65179422741SJiri Kosina MODULE_DEVICE_TABLE(hid, kye_devices);
65279422741SJiri Kosina 
65379422741SJiri Kosina static struct hid_driver kye_driver = {
65479422741SJiri Kosina 	.name = "kye",
65579422741SJiri Kosina 	.id_table = kye_devices,
65622ca20b2SNikolai Kondrashov 	.probe = kye_probe,
65779422741SJiri Kosina 	.report_fixup = kye_report_fixup,
65879422741SJiri Kosina };
659f425458eSH Hartley Sweeten module_hid_driver(kye_driver);
66079422741SJiri Kosina 
66179422741SJiri Kosina MODULE_LICENSE("GPL");
662