Skip to content

Commit 652f3d0

Browse files
puilp0502Jiri Kosina
authored andcommitted
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>
1 parent 3c785a0 commit 652f3d0

2 files changed

Lines changed: 41 additions & 5 deletions

File tree

drivers/hid/hid-cypress.c

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,17 @@
2323
#define CP_2WHEEL_MOUSE_HACK 0x02
2424
#define CP_2WHEEL_MOUSE_HACK_ON 0x04
2525

26+
#define VA_INVAL_LOGICAL_BOUNDARY 0x08
27+
2628
/*
2729
* Some USB barcode readers from cypress have usage min and usage max in
2830
* the wrong order
2931
*/
30-
static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
32+
static __u8 *cp_rdesc_fixup(struct hid_device *hdev, __u8 *rdesc,
3133
unsigned int *rsize)
3234
{
33-
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
3435
unsigned int i;
3536

36-
if (!(quirks & CP_RDESC_SWAPPED_MIN_MAX))
37-
return rdesc;
38-
3937
if (*rsize < 4)
4038
return rdesc;
4139

@@ -48,6 +46,40 @@ static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
4846
return rdesc;
4947
}
5048

49+
static __u8 *va_logical_boundary_fixup(struct hid_device *hdev, __u8 *rdesc,
50+
unsigned int *rsize)
51+
{
52+
/*
53+
* Varmilo VA104M (with VID Cypress and device ID 07B1) incorrectly
54+
* reports Logical Minimum of its Consumer Control device as 572
55+
* (0x02 0x3c). Fix this by setting its Logical Minimum to zero.
56+
*/
57+
if (*rsize == 25 &&
58+
rdesc[0] == 0x05 && rdesc[1] == 0x0c &&
59+
rdesc[2] == 0x09 && rdesc[3] == 0x01 &&
60+
rdesc[6] == 0x19 && rdesc[7] == 0x00 &&
61+
rdesc[11] == 0x16 && rdesc[12] == 0x3c && rdesc[13] == 0x02) {
62+
hid_info(hdev,
63+
"fixing up varmilo VA104M consumer control report descriptor\n");
64+
rdesc[12] = 0x00;
65+
rdesc[13] = 0x00;
66+
}
67+
return rdesc;
68+
}
69+
70+
static __u8 *cp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
71+
unsigned int *rsize)
72+
{
73+
unsigned long quirks = (unsigned long)hid_get_drvdata(hdev);
74+
75+
if (quirks & CP_RDESC_SWAPPED_MIN_MAX)
76+
rdesc = cp_rdesc_fixup(hdev, rdesc, rsize);
77+
if (quirks & VA_INVAL_LOGICAL_BOUNDARY)
78+
rdesc = va_logical_boundary_fixup(hdev, rdesc, rsize);
79+
80+
return rdesc;
81+
}
82+
5183
static int cp_input_mapped(struct hid_device *hdev, struct hid_input *hi,
5284
struct hid_field *field, struct hid_usage *usage,
5385
unsigned long **bit, int *max)
@@ -128,6 +160,8 @@ static const struct hid_device_id cp_devices[] = {
128160
.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
129161
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE),
130162
.driver_data = CP_2WHEEL_MOUSE_HACK },
163+
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_VARMILO_VA104M_07B1),
164+
.driver_data = VA_INVAL_LOGICAL_BOUNDARY },
131165
{ }
132166
};
133167
MODULE_DEVICE_TABLE(hid, cp_devices);

drivers/hid/hid-ids.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -331,6 +331,8 @@
331331
#define USB_DEVICE_ID_CYPRESS_BARCODE_4 0xed81
332332
#define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001
333333

334+
#define USB_DEVICE_ID_CYPRESS_VARMILO_VA104M_07B1 0X07b1
335+
334336
#define USB_VENDOR_ID_DATA_MODUL 0x7374
335337
#define USB_VENDOR_ID_DATA_MODUL_EASYMAXTOUCH 0x1201
336338

0 commit comments

Comments
 (0)