brintos

brintos / linux-shallow public Read only

0
0
Text · 27.9 KiB · bd96bfa Raw
676 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 *  HID driver for Kye/Genius devices not fully compliant with HID standard4 *5 *  Copyright (c) 2009 Jiri Kosina6 *  Copyright (c) 2009 Tomas Hanak7 *  Copyright (c) 2012 Nikolai Kondrashov8 *  Copyright (c) 2023 David Yang9 */10 11#include <linux/unaligned.h>12#include <linux/device.h>13#include <linux/hid.h>14#include <linux/module.h>15 16#include "hid-ids.h"17 18/* Data gathered from Database/VID0458_PID????/Vista/TBoard/default.xml in ioTablet driver19 *20 * TODO:21 *   - Add battery and sleep support for EasyPen M406W and MousePen M508WX22 *   - Investigate ScrollZ.MiceFMT buttons of EasyPen M40623 */24 25static const __u8 easypen_m406_control_rdesc[] = {26	0x05, 0x0C,        /*  Usage Page (Consumer),    */27	0x09, 0x01,        /*  Usage (Consumer Control), */28	0xA1, 0x01,        /*  Collection (Application), */29	0x85, 0x12,        /*    Report ID (18),         */30	0x0A, 0x45, 0x02,  /*    Usage (AC Rotate),      */31	0x09, 0x40,        /*    Usage (Menu),           */32	0x0A, 0x2F, 0x02,  /*    Usage (AC Zoom),        */33	0x0A, 0x46, 0x02,  /*    Usage (AC Resize),      */34	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),        */35	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),      */36	0x0A, 0x24, 0x02,  /*    Usage (AC Back),        */37	0x0A, 0x25, 0x02,  /*    Usage (AC Forward),     */38	0x14,              /*    Logical Minimum (0),    */39	0x25, 0x01,        /*    Logical Maximum (1),    */40	0x75, 0x01,        /*    Report Size (1),        */41	0x95, 0x08,        /*    Report Count (8),       */42	0x81, 0x02,        /*    Input (Variable),       */43	0x95, 0x30,        /*    Report Count (48),      */44	0x81, 0x01,        /*    Input (Constant),       */45	0xC0               /*  End Collection            */46};47 48static const __u8 easypen_m506_control_rdesc[] = {49	0x05, 0x0C,        /*  Usage Page (Consumer),    */50	0x09, 0x01,        /*  Usage (Consumer Control), */51	0xA1, 0x01,        /*  Collection (Application), */52	0x85, 0x12,        /*    Report ID (18),         */53	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),      */54	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),        */55	0x0A, 0x2D, 0x02,  /*    Usage (AC Zoom In),     */56	0x0A, 0x2E, 0x02,  /*    Usage (AC Zoom Out),    */57	0x14,              /*    Logical Minimum (0),    */58	0x25, 0x01,        /*    Logical Maximum (1),    */59	0x75, 0x01,        /*    Report Size (1),        */60	0x95, 0x04,        /*    Report Count (4),       */61	0x81, 0x02,        /*    Input (Variable),       */62	0x95, 0x34,        /*    Report Count (52),      */63	0x81, 0x01,        /*    Input (Constant),       */64	0xC0               /*  End Collection            */65};66 67static const __u8 easypen_m406w_control_rdesc[] = {68	0x05, 0x0C,        /*  Usage Page (Consumer),    */69	0x09, 0x01,        /*  Usage (Consumer Control), */70	0xA1, 0x01,        /*  Collection (Application), */71	0x85, 0x12,        /*    Report ID (18),         */72	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),      */73	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),        */74	0x0A, 0x01, 0x02,  /*    Usage (AC New),         */75	0x09, 0x40,        /*    Usage (Menu),           */76	0x14,              /*    Logical Minimum (0),    */77	0x25, 0x01,        /*    Logical Maximum (1),    */78	0x75, 0x01,        /*    Report Size (1),        */79	0x95, 0x04,        /*    Report Count (4),       */80	0x81, 0x02,        /*    Input (Variable),       */81	0x95, 0x34,        /*    Report Count (52),      */82	0x81, 0x01,        /*    Input (Constant),       */83	0xC0               /*  End Collection            */84};85 86static const __u8 easypen_m610x_control_rdesc[] = {87	0x05, 0x0C,        /*  Usage Page (Consumer),       */88	0x09, 0x01,        /*  Usage (Consumer Control),    */89	0xA1, 0x01,        /*  Collection (Application),    */90	0x85, 0x12,        /*    Report ID (18),            */91	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),           */92	0x0A, 0x79, 0x02,  /*    Usage (AC Redo Or Repeat), */93	0x0A, 0x2D, 0x02,  /*    Usage (AC Zoom In),        */94	0x0A, 0x2E, 0x02,  /*    Usage (AC Zoom Out),       */95	0x14,              /*    Logical Minimum (0),       */96	0x25, 0x01,        /*    Logical Maximum (1),       */97	0x75, 0x01,        /*    Report Size (1),           */98	0x95, 0x04,        /*    Report Count (4),          */99	0x81, 0x02,        /*    Input (Variable),          */100	0x95, 0x34,        /*    Report Count (52),         */101	0x81, 0x01,        /*    Input (Constant),          */102	0xC0               /*  End Collection               */103};104 105static const __u8 pensketch_m912_control_rdesc[] = {106	0x05, 0x0C,        /*  Usage Page (Consumer),        */107	0x09, 0x01,        /*  Usage (Consumer Control),     */108	0xA1, 0x01,        /*  Collection (Application),     */109	0x85, 0x12,        /*    Report ID (18),             */110	0x14,              /*    Logical Minimum (0),        */111	0x25, 0x01,        /*    Logical Maximum (1),        */112	0x75, 0x01,        /*    Report Size (1),            */113	0x95, 0x08,        /*    Report Count (8),           */114	0x05, 0x0C,        /*    Usage Page (Consumer),      */115	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),          */116	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),            */117	0x0A, 0x01, 0x02,  /*    Usage (AC New),             */118	0x0A, 0x2F, 0x02,  /*    Usage (AC Zoom),            */119	0x0A, 0x25, 0x02,  /*    Usage (AC Forward),         */120	0x0A, 0x24, 0x02,  /*    Usage (AC Back),            */121	0x0A, 0x2D, 0x02,  /*    Usage (AC Zoom In),         */122	0x0A, 0x2E, 0x02,  /*    Usage (AC Zoom Out),        */123	0x81, 0x02,        /*    Input (Variable),           */124	0x95, 0x30,        /*    Report Count (48),          */125	0x81, 0x03,        /*    Input (Constant, Variable), */126	0xC0               /*  End Collection                */127};128 129static const __u8 mousepen_m508wx_control_rdesc[] = {130	0x05, 0x0C,        /*  Usage Page (Consumer),    */131	0x09, 0x01,        /*  Usage (Consumer Control), */132	0xA1, 0x01,        /*  Collection (Application), */133	0x85, 0x12,        /*    Report ID (18),         */134	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),        */135	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),      */136	0x0A, 0x2D, 0x02,  /*    Usage (AC Zoom In),     */137	0x0A, 0x2E, 0x02,  /*    Usage (AC Zoom Out),    */138	0x14,              /*    Logical Minimum (0),    */139	0x25, 0x01,        /*    Logical Maximum (1),    */140	0x75, 0x01,        /*    Report Size (1),        */141	0x95, 0x04,        /*    Report Count (4),       */142	0x81, 0x02,        /*    Input (Variable),       */143	0x95, 0x34,        /*    Report Count (52),      */144	0x81, 0x01,        /*    Input (Constant),       */145	0xC0               /*  End Collection            */146};147 148static const __u8 mousepen_m508x_control_rdesc[] = {149	0x05, 0x0C,        /*  Usage Page (Consumer),        */150	0x09, 0x01,        /*  Usage (Consumer Control),     */151	0xA1, 0x01,        /*  Collection (Application),     */152	0x85, 0x12,        /*    Report ID (18),             */153	0x0A, 0x01, 0x02,  /*    Usage (AC New),             */154	0x09, 0x40,        /*    Usage (Menu),               */155	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),          */156	0x0A, 0x1A, 0x02,  /*    Usage (AC Undo),            */157	0x14,              /*    Logical Minimum (0),        */158	0x25, 0x01,        /*    Logical Maximum (1),        */159	0x75, 0x01,        /*    Report Size (1),            */160	0x95, 0x04,        /*    Report Count (4),           */161	0x81, 0x02,        /*    Input (Variable),           */162	0x81, 0x01,        /*    Input (Constant),           */163	0x15, 0xFF,        /*    Logical Minimum (-1),       */164	0x95, 0x10,        /*    Report Count (16),          */165	0x81, 0x01,        /*    Input (Constant),           */166	0x0A, 0x35, 0x02,  /*    Usage (AC Scroll),          */167	0x0A, 0x2F, 0x02,  /*    Usage (AC Zoom),            */168	0x0A, 0x38, 0x02,  /*    Usage (AC Pan),             */169	0x75, 0x08,        /*    Report Size (8),            */170	0x95, 0x03,        /*    Report Count (3),           */171	0x81, 0x06,        /*    Input (Variable, Relative), */172	0x95, 0x01,        /*    Report Count (1),           */173	0x81, 0x01,        /*    Input (Constant),           */174	0xC0               /*  End Collection                */175};176 177static const __u8 easypen_m406xe_control_rdesc[] = {178	0x05, 0x0C,        /*  Usage Page (Consumer),          */179	0x09, 0x01,        /*  Usage (Consumer Control),       */180	0xA1, 0x01,        /*  Collection (Application),       */181	0x85, 0x12,        /*      Report ID (18),             */182	0x14,              /*      Logical Minimum (0),        */183	0x25, 0x01,        /*      Logical Maximum (1),        */184	0x75, 0x01,        /*      Report Size (1),            */185	0x95, 0x04,        /*      Report Count (4),           */186	0x0A, 0x79, 0x02,  /*      Usage (AC Redo Or Repeat),  */187	0x0A, 0x1A, 0x02,  /*      Usage (AC Undo),            */188	0x0A, 0x2D, 0x02,  /*      Usage (AC Zoom In),         */189	0x0A, 0x2E, 0x02,  /*      Usage (AC Zoom Out),        */190	0x81, 0x02,        /*      Input (Variable),           */191	0x95, 0x34,        /*      Report Count (52),          */192	0x81, 0x03,        /*      Input (Constant, Variable), */193	0xC0               /*  End Collection                  */194};195 196static const __u8 pensketch_t609a_control_rdesc[] = {197	0x05, 0x0C,        /*  Usage Page (Consumer),    */198	0x09, 0x01,        /*  Usage (Consumer Control), */199	0xA1, 0x01,        /*  Collection (Application), */200	0x85, 0x12,        /*    Report ID (18),         */201	0x0A, 0x6A, 0x02,  /*    Usage (AC Delete),      */202	0x14,              /*    Logical Minimum (0),    */203	0x25, 0x01,        /*    Logical Maximum (1),    */204	0x75, 0x01,        /*    Report Size (1),        */205	0x95, 0x08,        /*    Report Count (8),       */206	0x81, 0x02,        /*    Input (Variable),       */207	0x95, 0x37,        /*    Report Count (55),      */208	0x81, 0x01,        /*    Input (Constant),       */209	0xC0               /*  End Collection            */210};211 212/* Fix indexes in kye_tablet_fixup() if you change this */213static const __u8 kye_tablet_rdesc[] = {214	0x06, 0x00, 0xFF,             /*  Usage Page (FF00h),             */215	0x09, 0x01,                   /*  Usage (01h),                    */216	0xA1, 0x01,                   /*  Collection (Application),       */217	0x85, 0x05,                   /*    Report ID (5),                */218	0x09, 0x01,                   /*    Usage (01h),                  */219	0x15, 0x81,                   /*    Logical Minimum (-127),       */220	0x25, 0x7F,                   /*    Logical Maximum (127),        */221	0x75, 0x08,                   /*    Report Size (8),              */222	0x95, 0x07,                   /*    Report Count (7),             */223	0xB1, 0x02,                   /*    Feature (Variable),           */224	0xC0,                         /*  End Collection,                 */225	0x05, 0x0D,                   /*  Usage Page (Digitizer),         */226	0x09, 0x01,                   /*  Usage (Digitizer),              */227	0xA1, 0x01,                   /*  Collection (Application),       */228	0x85, 0x10,                   /*    Report ID (16),               */229	0x09, 0x20,                   /*    Usage (Stylus),               */230	0xA0,                         /*    Collection (Physical),        */231	0x09, 0x42,                   /*      Usage (Tip Switch),         */232	0x09, 0x44,                   /*      Usage (Barrel Switch),      */233	0x09, 0x46,                   /*      Usage (Tablet Pick),        */234	0x14,                         /*      Logical Minimum (0),        */235	0x25, 0x01,                   /*      Logical Maximum (1),        */236	0x75, 0x01,                   /*      Report Size (1),            */237	0x95, 0x03,                   /*      Report Count (3),           */238	0x81, 0x02,                   /*      Input (Variable),           */239	0x95, 0x04,                   /*      Report Count (4),           */240	0x81, 0x01,                   /*      Input (Constant),           */241	0x09, 0x32,                   /*      Usage (In Range),           */242	0x95, 0x01,                   /*      Report Count (1),           */243	0x81, 0x02,                   /*      Input (Variable),           */244	0x75, 0x10,                   /*      Report Size (16),           */245	0xA4,                         /*      Push,                       */246	0x05, 0x01,                   /*      Usage Page (Desktop),       */247	0x09, 0x30,                   /*      Usage (X),                  */248	0x27, 0xFF, 0x7F, 0x00, 0x00, /*      Logical Maximum (32767),    */249	0x34,                         /*      Physical Minimum (0),       */250	0x47, 0x00, 0x00, 0x00, 0x00, /*      Physical Maximum (0),       */251	0x65, 0x11,                   /*      Unit (Centimeter),          */252	0x55, 0x00,                   /*      Unit Exponent (0),          */253	0x75, 0x10,                   /*      Report Size (16),           */254	0x81, 0x02,                   /*      Input (Variable),           */255	0x09, 0x31,                   /*      Usage (Y),                  */256	0x27, 0xFF, 0x7F, 0x00, 0x00, /*      Logical Maximum (32767),    */257	0x47, 0x00, 0x00, 0x00, 0x00, /*      Physical Maximum (0),       */258	0x81, 0x02,                   /*      Input (Variable),           */259	0xB4,                         /*      Pop,                        */260	0x05, 0x0D,                   /*      Usage Page (Digitizer),     */261	0x09, 0x30,                   /*      Usage (Tip Pressure),       */262	0x27, 0xFF, 0x07, 0x00, 0x00, /*      Logical Maximum (2047),     */263	0x81, 0x02,                   /*      Input (Variable),           */264	0xC0,                         /*    End Collection,               */265	0xC0                          /*  End Collection,                 */266};267 268/* Fix indexes in kye_tablet_fixup() if you change this */269static const __u8 kye_tablet_mouse_rdesc[] = {270	0x05, 0x01,                   /*  Usage Page (Desktop),           */271	0x09, 0x02,                   /*  Usage (Mouse),                  */272	0xA1, 0x01,                   /*  Collection (Application),       */273	0x85, 0x11,                   /*    Report ID (17),               */274	0x09, 0x01,                   /*    Usage (Pointer),              */275	0xA0,                         /*    Collection (Physical),        */276	0x05, 0x09,                   /*      Usage Page (Button),        */277	0x19, 0x01,                   /*      Usage Minimum (01h),        */278	0x29, 0x03,                   /*      Usage Maximum (03h),        */279	0x14,                         /*      Logical Minimum (0),        */280	0x25, 0x01,                   /*      Logical Maximum (1),        */281	0x75, 0x01,                   /*      Report Size (1),            */282	0x95, 0x03,                   /*      Report Count (3),           */283	0x81, 0x02,                   /*      Input (Variable),           */284	0x95, 0x04,                   /*      Report Count (4),           */285	0x81, 0x01,                   /*      Input (Constant),           */286	0x05, 0x0D,                   /*      Usage Page (Digitizer),     */287	0x09, 0x37,                   /*      Usage (Data Valid),         */288	0x95, 0x01,                   /*      Report Count (1),           */289	0x81, 0x02,                   /*      Input (Variable),           */290	0x05, 0x01,                   /*      Usage Page (Desktop),       */291	0xA4,                         /*      Push,                       */292	0x09, 0x30,                   /*      Usage (X),                  */293	0x27, 0xFF, 0x7F, 0x00, 0x00, /*      Logical Maximum (32767),    */294	0x34,                         /*      Physical Minimum (0),       */295	0x47, 0x00, 0x00, 0x00, 0x00, /*      Physical Maximum (0),       */296	0x65, 0x11,                   /*      Unit (Centimeter),          */297	0x55, 0x00,                   /*      Unit Exponent (0),          */298	0x75, 0x10,                   /*      Report Size (16),           */299	0x81, 0x02,                   /*      Input (Variable),           */300	0x09, 0x31,                   /*      Usage (Y),                  */301	0x27, 0xFF, 0x7F, 0x00, 0x00, /*      Logical Maximum (32767),    */302	0x47, 0x00, 0x00, 0x00, 0x00, /*      Physical Maximum (0),       */303	0x81, 0x02,                   /*      Input (Variable),           */304	0xB4,                         /*      Pop,                        */305	0x09, 0x38,                   /*      Usage (Wheel),              */306	0x15, 0xFF,                   /*      Logical Minimum (-1),       */307	0x75, 0x08,                   /*      Report Size (8),            */308	0x95, 0x01,                   /*      Report Count (1),           */309	0x81, 0x06,                   /*      Input (Variable, Relative), */310	0x81, 0x01,                   /*      Input (Constant),           */311	0xC0,                         /*    End Collection,               */312	0xC0                          /*  End Collection                  */313};314 315static const struct kye_tablet_info {316	__u32 product;317	__s32 x_logical_maximum;318	__s32 y_logical_maximum;319	__s32 pressure_logical_maximum;320	__s32 x_physical_maximum;321	__s32 y_physical_maximum;322	__s8 unit_exponent;323	__s8 unit;324	bool has_mouse;325	unsigned int control_rsize;326	const __u8 *control_rdesc;327} kye_tablets_info[] = {328	{USB_DEVICE_ID_KYE_EASYPEN_M406,  /* 0x5005 */329		15360, 10240, 1023,    6,   4,  0, 0x13, false,330		sizeof(easypen_m406_control_rdesc), easypen_m406_control_rdesc},331	{USB_DEVICE_ID_KYE_EASYPEN_M506,  /* 0x500F */332		24576, 20480, 1023,    6,   5,  0, 0x13, false,333		sizeof(easypen_m506_control_rdesc), easypen_m506_control_rdesc},334	{USB_DEVICE_ID_KYE_EASYPEN_I405X,  /* 0x5010 */335		14080, 10240, 1023,   55,  40, -1, 0x13, false},336	{USB_DEVICE_ID_KYE_MOUSEPEN_I608X,  /* 0x5011 */337		20480, 15360, 2047,    8,   6,  0, 0x13,  true},338	{USB_DEVICE_ID_KYE_EASYPEN_M406W,  /* 0x5012 */339		15360, 10240, 1023,    6,   4,  0, 0x13, false,340		sizeof(easypen_m406w_control_rdesc), easypen_m406w_control_rdesc},341	{USB_DEVICE_ID_KYE_EASYPEN_M610X,  /* 0x5013 */342		40960, 25600, 1023, 1000, 625, -2, 0x13, false,343		sizeof(easypen_m610x_control_rdesc), easypen_m610x_control_rdesc},344	{USB_DEVICE_ID_KYE_EASYPEN_340,  /* 0x5014 */345		10240,  7680, 1023,    4,   3,  0, 0x13, false},346	{USB_DEVICE_ID_KYE_PENSKETCH_M912,  /* 0x5015 */347		61440, 46080, 2047,   12,   9,  0, 0x13,  true,348		sizeof(pensketch_m912_control_rdesc), pensketch_m912_control_rdesc},349	{USB_DEVICE_ID_KYE_MOUSEPEN_M508WX,  /* 0x5016 */350		40960, 25600, 2047,    8,   5,  0, 0x13,  true,351		sizeof(mousepen_m508wx_control_rdesc), mousepen_m508wx_control_rdesc},352	{USB_DEVICE_ID_KYE_MOUSEPEN_M508X,  /* 0x5017 */353		40960, 25600, 2047,    8,   5,  0, 0x13,  true,354		sizeof(mousepen_m508x_control_rdesc), mousepen_m508x_control_rdesc},355	{USB_DEVICE_ID_KYE_EASYPEN_M406XE,  /* 0x5019 */356		15360, 10240, 1023,    6,   4,  0, 0x13, false,357		sizeof(easypen_m406xe_control_rdesc), easypen_m406xe_control_rdesc},358	{USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2,  /* 0x501A */359		40960, 30720, 2047,    8,   6,  0, 0x13,  true},360	{USB_DEVICE_ID_KYE_PENSKETCH_T609A,  /* 0x501B */361		43520, 28160, 1023,   85,  55, -1, 0x13, false,362		sizeof(pensketch_t609a_control_rdesc), pensketch_t609a_control_rdesc},363	{}364};365 366static __u8 *kye_consumer_control_fixup(struct hid_device *hdev, __u8 *rdesc,367		unsigned int *rsize, int offset, const char *device_name)368{369	/*370	 * the fixup that need to be done:371	 *   - change Usage Maximum in the Consumer Control372	 *     (report ID 3) to a reasonable value373	 */374	if (*rsize >= offset + 31 &&375	    /* Usage Page (Consumer Devices) */376	    rdesc[offset] == 0x05 && rdesc[offset + 1] == 0x0c &&377	    /* Usage (Consumer Control) */378	    rdesc[offset + 2] == 0x09 && rdesc[offset + 3] == 0x01 &&379	    /*   Usage Maximum > 12287 */380	    rdesc[offset + 10] == 0x2a && rdesc[offset + 12] > 0x2f) {381		hid_info(hdev, "fixing up %s report descriptor\n", device_name);382		rdesc[offset + 12] = 0x2f;383	}384	return rdesc;385}386 387/*388 * Fix tablet descriptor of so-called "DataFormat 2".389 *390 * Though we may achieve a usable descriptor from original vendor-defined one,391 * some problems exist:392 *  - Their Logical Maximum never exceed 32767 (7F FF), though device do report393 *    values greater than that;394 *  - Physical Maximums are arbitrarily filled (always equal to Logical395 *    Maximum);396 *  - Detail for control buttons are not provided (a vendor-defined Usage Page397 *    with fixed content).398 *399 * Thus we use a pre-defined parameter table rather than digging it from400 * original descriptor.401 *402 * We may as well write a fallback routine for unrecognized kye tablet, but it's403 * clear kye are unlikely to produce new models in the foreseeable future, so we404 * simply enumerate all possible models.405 */406static __u8 *kye_tablet_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int *rsize)407{408	const struct kye_tablet_info *info;409	__u8 *newdesc = rdesc;410 411	if (*rsize < sizeof(kye_tablet_rdesc)) {412		hid_warn(hdev,413			 "tablet report size too small, or kye_tablet_rdesc unexpectedly large\n");414		return rdesc;415	}416 417	for (info = kye_tablets_info; info->product; info++) {418		if (hdev->product == info->product)419			break;420	}421 422	if (!info->product) {423		hid_err(hdev, "tablet unknown, someone forget to add kye_tablet_info entry?\n");424		return rdesc;425	}426 427	memcpy(newdesc, kye_tablet_rdesc, sizeof(kye_tablet_rdesc));428 429	put_unaligned_le32(info->x_logical_maximum, newdesc + 66);430	put_unaligned_le32(info->x_physical_maximum, newdesc + 72);431	newdesc[77] = info->unit;432	newdesc[79] = info->unit_exponent;433	put_unaligned_le32(info->y_logical_maximum, newdesc + 87);434	put_unaligned_le32(info->y_physical_maximum, newdesc + 92);435	put_unaligned_le32(info->pressure_logical_maximum, newdesc + 104);436 437	newdesc += sizeof(kye_tablet_rdesc);438 439	if (info->has_mouse) {440		if (newdesc + sizeof(kye_tablet_mouse_rdesc) > rdesc + *rsize)441			hid_err(hdev, "control desc unexpectedly large\n");442		else {443			memcpy(newdesc, kye_tablet_mouse_rdesc, sizeof(kye_tablet_mouse_rdesc));444 445			put_unaligned_le32(info->x_logical_maximum, newdesc + 44);446			put_unaligned_le32(info->x_physical_maximum, newdesc + 50);447			newdesc[55] = info->unit;448			newdesc[57] = info->unit_exponent;449			put_unaligned_le32(info->y_logical_maximum, newdesc + 65);450			put_unaligned_le32(info->y_physical_maximum, newdesc + 70);451 452			newdesc += sizeof(kye_tablet_mouse_rdesc);453		}454	}455 456	if (info->control_rsize) {457		if (newdesc + info->control_rsize > rdesc + *rsize)458			hid_err(hdev, "control desc unexpectedly large\n");459		else {460			memcpy(newdesc, info->control_rdesc, info->control_rsize);461			newdesc += info->control_rsize;462		}463	}464 465	*rsize = newdesc - rdesc;466	return rdesc;467}468 469static const __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,470		unsigned int *rsize)471{472	switch (hdev->product) {473	case USB_DEVICE_ID_KYE_ERGO_525V:474		/* the fixups that need to be done:475		 *   - change led usage page to button for extra buttons476		 *   - report size 8 count 1 must be size 1 count 8 for button477		 *     bitfield478		 *   - change the button usage range to 4-7 for the extra479		 *     buttons480		 */481		if (*rsize >= 75 &&482			rdesc[61] == 0x05 && rdesc[62] == 0x08 &&483			rdesc[63] == 0x19 && rdesc[64] == 0x08 &&484			rdesc[65] == 0x29 && rdesc[66] == 0x0f &&485			rdesc[71] == 0x75 && rdesc[72] == 0x08 &&486			rdesc[73] == 0x95 && rdesc[74] == 0x01) {487			hid_info(hdev,488				 "fixing up Kye/Genius Ergo Mouse "489				 "report descriptor\n");490			rdesc[62] = 0x09;491			rdesc[64] = 0x04;492			rdesc[66] = 0x07;493			rdesc[72] = 0x01;494			rdesc[74] = 0x08;495		}496		break;497	case USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE:498		rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104,499					"Genius Gila Gaming Mouse");500		break;501	case USB_DEVICE_ID_GENIUS_MANTICORE:502		rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 104,503					"Genius Manticore Keyboard");504		break;505	case USB_DEVICE_ID_GENIUS_GX_IMPERATOR:506		rdesc = kye_consumer_control_fixup(hdev, rdesc, rsize, 83,507					"Genius Gx Imperator Keyboard");508		break;509	case USB_DEVICE_ID_KYE_EASYPEN_M406:510	case USB_DEVICE_ID_KYE_EASYPEN_M506:511	case USB_DEVICE_ID_KYE_EASYPEN_I405X:512	case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:513	case USB_DEVICE_ID_KYE_EASYPEN_M406W:514	case USB_DEVICE_ID_KYE_EASYPEN_M610X:515	case USB_DEVICE_ID_KYE_EASYPEN_340:516	case USB_DEVICE_ID_KYE_PENSKETCH_M912:517	case USB_DEVICE_ID_KYE_MOUSEPEN_M508WX:518	case USB_DEVICE_ID_KYE_MOUSEPEN_M508X:519	case USB_DEVICE_ID_KYE_EASYPEN_M406XE:520	case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2:521	case USB_DEVICE_ID_KYE_PENSKETCH_T609A:522		rdesc = kye_tablet_fixup(hdev, rdesc, rsize);523		break;524	}525	return rdesc;526}527 528static int kye_tablet_enable(struct hid_device *hdev)529{530	struct list_head *list;531	struct list_head *head;532	struct hid_report *report;533	__s32 *value;534 535	list = &hdev->report_enum[HID_FEATURE_REPORT].report_list;536	list_for_each(head, list) {537		report = list_entry(head, struct hid_report, list);538		if (report->id == 5)539			break;540	}541 542	if (head == list) {543		hid_err(hdev, "tablet-enabling feature report not found\n");544		return -ENODEV;545	}546 547	if (report->maxfield < 1 || report->field[0]->report_count < 7) {548		hid_err(hdev, "invalid tablet-enabling feature report\n");549		return -ENODEV;550	}551 552	value = report->field[0]->value;553 554	/*555	 * The code is for DataFormat 2 of config xml. They have no obvious556	 * meaning (at least not configurable in Windows driver) except enabling557	 * fully-functional tablet mode (absolute positioning). Otherwise, the558	 * tablet acts like a relative mouse.559	 *560	 * Though there're magic codes for DataFormat 3 and 4, no devices use561	 * these DataFormats.562	 */563	value[0] = 0x12;564	value[1] = 0x10;565	value[2] = 0x11;566	value[3] = 0x12;567	value[4] = 0x00;568	value[5] = 0x00;569	value[6] = 0x00;570	hid_hw_request(hdev, report, HID_REQ_SET_REPORT);571 572	return 0;573}574 575static int kye_probe(struct hid_device *hdev, const struct hid_device_id *id)576{577	int ret;578 579	ret = hid_parse(hdev);580	if (ret) {581		hid_err(hdev, "parse failed\n");582		goto err;583	}584 585	ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);586	if (ret) {587		hid_err(hdev, "hw start failed\n");588		goto err;589	}590 591	switch (id->product) {592	case USB_DEVICE_ID_GENIUS_MANTICORE:593		/*594		 * The manticore keyboard needs to have all the interfaces595		 * opened at least once to be fully functional.596		 */597		if (hid_hw_open(hdev))598			hid_hw_close(hdev);599		break;600	case USB_DEVICE_ID_KYE_EASYPEN_M406:601	case USB_DEVICE_ID_KYE_EASYPEN_M506:602	case USB_DEVICE_ID_KYE_EASYPEN_I405X:603	case USB_DEVICE_ID_KYE_MOUSEPEN_I608X:604	case USB_DEVICE_ID_KYE_EASYPEN_M406W:605	case USB_DEVICE_ID_KYE_EASYPEN_M610X:606	case USB_DEVICE_ID_KYE_EASYPEN_340:607	case USB_DEVICE_ID_KYE_PENSKETCH_M912:608	case USB_DEVICE_ID_KYE_MOUSEPEN_M508WX:609	case USB_DEVICE_ID_KYE_MOUSEPEN_M508X:610	case USB_DEVICE_ID_KYE_EASYPEN_M406XE:611	case USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2:612	case USB_DEVICE_ID_KYE_PENSKETCH_T609A:613		ret = kye_tablet_enable(hdev);614		if (ret) {615			hid_err(hdev, "tablet enabling failed\n");616			goto enabling_err;617		}618		break;619	}620 621	return 0;622enabling_err:623	hid_hw_stop(hdev);624err:625	return ret;626}627 628static const struct hid_device_id kye_devices[] = {629	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },630	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,631				USB_DEVICE_ID_GENIUS_GILA_GAMING_MOUSE) },632	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,633				USB_DEVICE_ID_GENIUS_MANTICORE) },634	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,635				USB_DEVICE_ID_GENIUS_GX_IMPERATOR) },636	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,637				USB_DEVICE_ID_KYE_EASYPEN_M406) },638	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,639				USB_DEVICE_ID_KYE_EASYPEN_M506) },640	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,641				USB_DEVICE_ID_KYE_EASYPEN_I405X) },642	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,643				USB_DEVICE_ID_KYE_MOUSEPEN_I608X) },644	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,645				USB_DEVICE_ID_KYE_EASYPEN_M406W) },646	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,647				USB_DEVICE_ID_KYE_EASYPEN_M610X) },648	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,649				USB_DEVICE_ID_KYE_EASYPEN_340) },650	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,651				USB_DEVICE_ID_KYE_PENSKETCH_M912) },652	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,653				USB_DEVICE_ID_KYE_MOUSEPEN_M508WX) },654	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,655				USB_DEVICE_ID_KYE_MOUSEPEN_M508X) },656	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,657				USB_DEVICE_ID_KYE_EASYPEN_M406XE) },658	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,659				USB_DEVICE_ID_KYE_MOUSEPEN_I608X_V2) },660	{ HID_USB_DEVICE(USB_VENDOR_ID_KYE,661				USB_DEVICE_ID_KYE_PENSKETCH_T609A) },662	{ }663};664MODULE_DEVICE_TABLE(hid, kye_devices);665 666static struct hid_driver kye_driver = {667	.name = "kye",668	.id_table = kye_devices,669	.probe = kye_probe,670	.report_fixup = kye_report_fixup,671};672module_hid_driver(kye_driver);673 674MODULE_DESCRIPTION("HID driver for Kye/Genius devices not fully compliant with HID standard");675MODULE_LICENSE("GPL");676