Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

HID: cypress: Support Varmilo Keyboards' media hotkeys

The Varmilo VA104M Keyboard (04b4:07b1, reported as Varmilo Z104M)
exposes media control hotkeys as a USB HID consumer control device, but
these keys do not work in the current (5.8-rc1) kernel due to the
incorrect HID report descriptor. Fix the problem by modifying the
internal HID report descriptor.

More specifically, the keyboard report descriptor specifies the
logical boundary as 572~10754 (0x023c ~ 0x2a02) while the usage
boundary is specified as 0~10754 (0x00 ~ 0x2a02). This results in an
incorrect interpretation of input reports, causing inputs to be ignored.
By setting the Logical Minimum to zero, we align the logical boundary
with the Usage ID boundary.

Some notes:

* There seem to be multiple variants of the VA104M keyboard. This
patch specifically targets 04b4:07b1 variant.

* The device works out-of-the-box on Windows platform with the generic
consumer control device driver (hidserv.inf). This suggests that
Windows either ignores the Logical Minimum/Logical Maximum or
interprets the Usage ID assignment differently from the linux
implementation; Maybe there are other devices out there that only
works on Windows due to this problem?

Signed-off-by: Frank Yang <puilp0502@gmail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Frank Yang and committed by
Jiri Kosina
652f3d00 3c785a06

+41 -5
+39 -5
drivers/hid/hid-cypress.c
··· 23 23 #define CP_2WHEEL_MOUSE_HACK 0x02 24 24 #define CP_2WHEEL_MOUSE_HACK_ON 0x04 25 25 26 + #define VA_INVAL_LOGICAL_BOUNDARY 0x08 27 + 26 28 /* 27 29 * Some USB barcode readers from cypress have usage min and usage max in 28 30 * the wrong order 29 31 */ 30 - static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, 32 + static __u8 *cp_rdesc_fixup(struct hid_device *hdev, __u8 *rdesc, 31 33 unsigned int *rsize) 32 34 { 33 - unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 34 35 unsigned int i; 35 - 36 - if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX)) 37 - return rdesc; 38 36 39 37 if (*rsize < 4) 40 38 return rdesc; ··· 43 45 rdesc[i + 2] = 0x29; 44 46 swap(rdesc[i + 3], rdesc[i + 1]); 45 47 } 48 + return rdesc; 49 + } 50 + 51 + static __u8 *va_logical_boundary_fixup(struct hid_device *hdev, __u8 *rdesc, 52 + unsigned int *rsize) 53 + { 54 + /* 55 + * Varmilo VA104M (with VID Cypress and device ID 07B1) incorrectly 56 + * reports Logical Minimum of its Consumer Control device as 572 57 + * (0x02 0x3c). Fix this by setting its Logical Minimum to zero. 58 + */ 59 + if (*rsize == 25 && 60 + rdesc[0] == 0x05 && rdesc[1] == 0x0c && 61 + rdesc[2] == 0x09 && rdesc[3] == 0x01 && 62 + rdesc[6] == 0x19 && rdesc[7] == 0x00 && 63 + rdesc[11] == 0x16 && rdesc[12] == 0x3c && rdesc[13] == 0x02) { 64 + hid_info(hdev, 65 + "fixing up varmilo VA104M consumer control report descriptor\n"); 66 + rdesc[12] = 0x00; 67 + rdesc[13] = 0x00; 68 + } 69 + return rdesc; 70 + } 71 + 72 + static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc, 73 + unsigned int *rsize) 74 + { 75 + unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); 76 + 77 + if (quirks & CP_RDESC_SWAPPED_MIN_MAX) 78 + rdesc = cp_rdesc_fixup(hdev, rdesc, rsize); 79 + if (quirks & VA_INVAL_LOGICAL_BOUNDARY) 80 + rdesc = va_logical_boundary_fixup(hdev, rdesc, rsize); 81 + 46 82 return rdesc; 47 83 } 48 84 ··· 160 128 .driver_data = CP_RDESC_SWAPPED_MIN_MAX }, 161 129 { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE), 162 130 .driver_data = CP_2WHEEL_MOUSE_HACK }, 131 + { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_VARMILO_VA104M_07B1), 132 + .driver_data = VA_INVAL_LOGICAL_BOUNDARY }, 163 133 { } 164 134 }; 165 135 MODULE_DEVICE_TABLE(hid, cp_devices);
+2
drivers/hid/hid-ids.h
··· 331 331 #define USB_DEVICE_ID_CYPRESS_BARCODE_4 0xed81 332 332 #define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001 333 333 334 + #define USB_DEVICE_ID_CYPRESS_VARMILO_VA104M_07B1 0X07b1 335 + 334 336 #define USB_VENDOR_ID_DATA_MODUL 0x7374 335 337 #define USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH 0x1201 336 338