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

HID: semitek: new driver for GK6X series keyboards

A number of USB keyboards, using the Semitek firmware, are capable of
handling arbitrary N-key rollover, but due to a buggy report
descriptor, keys beyond the sixth cannot be detected by the generic
HID driver.

There are numerous hardware variants sold by several vendors, mostly
using generic names like "GK61" for the 61-key version. These
keyboards are sometimes known collectively as the "GK6X" series.

The keyboard has three USB interfaces. Interface 0 uses the standard
HID boot protocol, limited to eight modifier keys and six normal keys;
interface 2 uses a custom report format that permits any number of
keys. If more than six keys are pressed simultaneously, the first six
are reported via interface 0 while subsequent keys are reported via
interface 2.

(Interface 1 uses a custom protocol for reprogramming the keyboard;
this can be controlled through userspace tools and is not of concern
for the present driver.)

The report descriptor for interface 2, however, is incorrect (for
report ID 0x04, the input field is marked as "array" rather than
"variable".) The descriptor appears to be correct in other respects,
so we simply replace the incorrect byte before parsing the descriptor.

Signed-off-by: Benjamin Moody <bmoody@member.fsf.org>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>

authored by

Benjamin Moody and committed by
Jiri Kosina
6a012686 efd8929b

+59
+15
drivers/hid/Kconfig
··· 922 922 help 923 923 Support for Samsung InfraRed remote control or keyboards. 924 924 925 + config HID_SEMITEK 926 + tristate "Semitek USB keyboards" 927 + depends on HID 928 + help 929 + Support for Semitek USB keyboards that are not fully compliant 930 + with the HID standard. 931 + 932 + There are many variants, including: 933 + - GK61, GK64, GK68, GK84, GK96, etc. 934 + - SK61, SK64, SK68, SK84, SK96, etc. 935 + - Dierya DK61/DK66 936 + - Tronsmart TK09R 937 + - Woo-dy 938 + - X-Bows Nature/Knight 939 + 925 940 config HID_SONY 926 941 tristate "Sony PS2/3/4 accessories" 927 942 depends on USB_HID
+1
drivers/hid/Makefile
··· 106 106 obj-$(CONFIG_HID_RMI) += hid-rmi.o 107 107 obj-$(CONFIG_HID_SAITEK) += hid-saitek.o 108 108 obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o 109 + obj-$(CONFIG_HID_SEMITEK) += hid-semitek.o 109 110 obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o 110 111 obj-$(CONFIG_HID_SONY) += hid-sony.o 111 112 obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o
+3
drivers/hid/hid-ids.h
··· 1060 1060 #define USB_DEVICE_ID_SEMICO_USB_KEYKOARD 0x0023 1061 1061 #define USB_DEVICE_ID_SEMICO_USB_KEYKOARD2 0x0027 1062 1062 1063 + #define USB_VENDOR_ID_SEMITEK 0x1ea7 1064 + #define USB_DEVICE_ID_SEMITEK_KEYBOARD 0x0907 1065 + 1063 1066 #define USB_VENDOR_ID_SENNHEISER 0x1395 1064 1067 #define USB_DEVICE_ID_SENNHEISER_BTD500USB 0x002c 1065 1068
+40
drivers/hid/hid-semitek.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * HID driver for Semitek keyboards 4 + * 5 + * Copyright (c) 2021 Benjamin Moody 6 + */ 7 + 8 + #include <linux/device.h> 9 + #include <linux/hid.h> 10 + #include <linux/module.h> 11 + 12 + #include "hid-ids.h" 13 + 14 + static __u8 *semitek_report_fixup(struct hid_device *hdev, __u8 *rdesc, 15 + unsigned int *rsize) 16 + { 17 + /* In the report descriptor for interface 2, fix the incorrect 18 + description of report ID 0x04 (the report contains a 19 + bitmask, not an array of keycodes.) */ 20 + if (*rsize == 0xcb && rdesc[0x83] == 0x81 && rdesc[0x84] == 0x00) { 21 + hid_info(hdev, "fixing up Semitek report descriptor\n"); 22 + rdesc[0x84] = 0x02; 23 + } 24 + return rdesc; 25 + } 26 + 27 + static const struct hid_device_id semitek_devices[] = { 28 + { HID_USB_DEVICE(USB_VENDOR_ID_SEMITEK, USB_DEVICE_ID_SEMITEK_KEYBOARD) }, 29 + { } 30 + }; 31 + MODULE_DEVICE_TABLE(hid, semitek_devices); 32 + 33 + static struct hid_driver semitek_driver = { 34 + .name = "semitek", 35 + .id_table = semitek_devices, 36 + .report_fixup = semitek_report_fixup, 37 + }; 38 + module_hid_driver(semitek_driver); 39 + 40 + MODULE_LICENSE("GPL");