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