21.12.2011 11:25, Jiri Kosina wrote: > i.e. the device presents 32k of cosumer usages, which is beyond the limit > on the number of usages the current parser in the kernel supports (12288). > Bumping up the HID_MAX_USAGES constant would work around the problem, but > I don't believe the keyboard is actually generating such a wide range of > consumer page usages. Hi Jiri, I have the same Trust GXT 18 Gaming keyboard (http://www.trust.com/products/product.aspx?artnr=17468). I spent a week reading through the drivers/hid, drivers/input code, and came up with the following: The keyboard is pretty standard, with a boot interface and a report interface. The report interface has two problems: - as you noted, the device presents 2^15 consumer usages, much larger than the HID_MAX_USAGES=12288 limit - no LED usage block is presented, preventing any use of the num/caps/scroll LEDs in report mode I tried making a test module (code below) to make the keyboard work. It does the following: - provides a fixed report descriptor, correcting the 2^15 consumer usages problem - adds an LED usage block into the report descriptor, then redirects LED change events to the boot interface. The keyboard works when using the module, typing on it now :) When using it, the dmesg looks like: [10190.049600] usbhid 2-1.2:1.0: usb_probe_interface [10190.049607] usbhid 2-1.2:1.0: usb_probe_interface - got id [10190.059403] input: KB USB Keyboard as /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.0/input/input18 [10190.059440] usb 2-1.2: link qh8-0e01/ea8d2d40 start 0 [1/2 us] [10190.059661] holtek_kbd 0003:04D9:A055.0007: input,hidraw0: USB HID v1.10 Keyboard [KB USB Keyboard] on usb-0000:00:1d.0-1.2/input0 [10190.059720] usb 2-1.2: adding 2-1.2:1.1 (config #1, interface 1) [10190.059801] usbhid 2-1.2:1.1: usb_probe_interface [10190.059807] usbhid 2-1.2:1.1: usb_probe_interface - got id [10190.077504] input: KB USB Keyboard as /devices/pci0000:00/0000:00:1d.0/usb2/2-1/2-1.2/2-1.2:1.1/input/input19 [10190.077542] usb 2-1.2: link qh8-0e01/f42fae00 start 1 [1/2 us] [10190.077778] holtek_kbd 0003:04D9:A055.0008: input,hidraw1: USB HID v1.10 Keyboard [KB USB Keyboard] on usb-0000:00:1d.0-1.2/input1 Below is my first attempt at writing some kernel code. Are there any suggestions how to improve/replace the code below, to make a nice patch? thanks, Tom --- drivers/hid/Kconfig | 12 +++- drivers/hid/Makefile | 3 +- drivers/hid/hid-core.c | 1 + drivers/hid/hid-holtek-kbd.c | 172 ++++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-ids.h | 3 + 5 files changed, 188 insertions(+), 3 deletions(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index a3d0332..4172c90 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -178,10 +178,10 @@ config HID_EZKEY Support for Ezkey BTC 8193 keyboard. config HID_HOLTEK - tristate "Holtek On Line Grip based game controller support" + tristate "Holtek devices" depends on USB_HID ---help--- - Say Y here if you have a Holtek On Line Grip based game controller. + Support for Holtek based devices devices. config HOLTEK_FF bool "Holtek On Line Grip force feedback support" @@ -191,6 +191,14 @@ config HOLTEK_FF Say Y here if you have a Holtek On Line Grip based game controller and want to have force feedback support for it. +config HID_HOLTEK_KBD + tristate "Holtek based keyboard" + depends on HID_HOLTEK + ---help--- + Support for Holtek based keyboards with faulty HID descriptors. + Currently supported: + - Trust GXT 18 Gaming Keyboard + config HID_KEYTOUCH tristate "Keytouch HID devices" depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 22f1d16..edb4ae2 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -45,7 +45,8 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o -obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o +obj-$(CONFIG_HID_HOLTEK_FF) += hid-holtekff.o +obj-$(CONFIG_HID_HOLTEK_KBD) += hid-holtek-kbd.o obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 990fe19..0d949c9 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1435,6 +1435,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) }, { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) }, { HID_USB_DEVICE(USB_VENDOR_ID_HANVON_ALT, USB_DEVICE_ID_HANVON_ALT_MULTITOUCH) }, + { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, { HID_USB_DEVICE(USB_VENDOR_ID_IDEACOM, USB_DEVICE_ID_IDEACOM_IDC6650) }, { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) }, { HID_USB_DEVICE(USB_VENDOR_ID_ILITEK, USB_DEVICE_ID_ILITEK_MULTITOUCH) }, diff --git a/drivers/hid/hid-holtek-kbd.c b/drivers/hid/hid-holtek-kbd.c new file mode 100644 index 0000000..8aa8c8d --- /dev/null +++ b/drivers/hid/hid-holtek-kbd.c @@ -0,0 +1,172 @@ +/* + * HID driver for Holtek keyboard + * XXX name +*/ + +/* + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + */ + +#include <linux/device.h> +#include <linux/hid.h> +#include <linux/module.h> +#include <linux/usb.h> + +#include "hid-ids.h" +#include "usbhid/usbhid.h" + +static __u8 holtek_kbd_rdesc_fixed[] = { + /* Original report descriptor, with reduced number of consumer usages */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x80, /* Usage (Sys Control), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x01, /* Report ID (1), */ + 0x19, 0x81, /* Usage Minimum (Sys Power Down), */ + 0x29, 0x83, /* Usage Maximum (Sys Wake Up), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x75, 0x01, /* Report Size (1), */ + 0x81, 0x02, /* Input (Variable), */ + 0x95, 0x01, /* Report Count (1), */ + 0x75, 0x05, /* Report Size (5), */ + 0x81, 0x01, /* Input (Constant), */ + 0xC0, /* End Collection, */ + 0x05, 0x0C, /* Usage Page (Consumer), */ + 0x09, 0x01, /* Usage (Consumer Control), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x02, /* Report ID (2), */ + 0x19, 0x00, /* Usage Minimum (00h), */ + 0x2A, 0xFF, 0x2F, /* Usage Maximum (0x2FFF), previously 0x7FFF */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x26, 0xFF, 0x2F, /* Logical Maximum (0x2FFF),previously 0x7FFF*/ + 0x95, 0x01, /* Report Count (1), */ + 0x75, 0x10, /* Report Size (16), */ + 0x81, 0x00, /* Input, */ + 0xC0, /* End Collection, */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x06, /* Usage (Keyboard), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x03, /* Report ID (3), */ + 0x95, 0x38, /* Report Count (56), */ + 0x75, 0x01, /* Report Size (1), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x05, 0x07, /* Usage Page (Keyboard), */ + 0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */ + 0x29, 0xE7, /* Usage Maximum (KB Right GUI), */ + 0x19, 0x00, /* Usage Minimum (None), */ + 0x29, 0x2F, /* Usage Maximum (KB Lboxbracket And Lbrace),*/ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection, */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x06, /* Usage (Keyboard), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x85, 0x04, /* Report ID (4), */ + 0x95, 0x38, /* Report Count (56), */ + 0x75, 0x01, /* Report Size (1), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x05, 0x07, /* Usage Page (Keyboard), */ + 0x19, 0x30, /* Usage Minimum (KB Rboxbracket And Rbrace),*/ + 0x29, 0x67, /* Usage Maximum (KP Equals), */ + 0x81, 0x02, /* Input (Variable), */ + 0xC0, /* End Collection */ + + /* LED usage for the boot protocol interface */ + 0x05, 0x01, /* Usage Page (Desktop), */ + 0x09, 0x06, /* Usage (Keyboard), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x05, 0x08, /* Usage Page (LED), */ + 0x19, 0x01, /* Usage Minimum (01h), */ + 0x29, 0x03, /* Usage Maximum (03h), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x03, /* Report Count (3), */ + 0x91, 0x02, /* Output (Variable), */ + 0x95, 0x05, /* Report Count (5), */ + 0x91, 0x01, /* Output (Constant), */ + 0xC0, /* End Collection */ +}; + +static __u8 *holtek_kbd_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + + if (intf->cur_altsetting->desc.bInterfaceNumber == 1) { + rdesc = holtek_kbd_rdesc_fixed; + *rsize = sizeof(holtek_kbd_rdesc_fixed); + } + return rdesc; +} + +static int holtek_kbd_input_event(struct input_dev *dev, unsigned int type, + unsigned int code, + int value) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct usb_device *usb_dev = hid_to_usb_dev(hid); + + /* Locate the boot interface, to receive the LED change events */ + struct usb_interface *boot_interface = usb_ifnum_to_if(usb_dev, 0); + + /* XXX check here we actually get a struct hid_device*? */ + struct hid_device *boot_hid = usb_get_intfdata(boot_interface); + struct hid_input *boot_hid_input = list_first_entry(&boot_hid->inputs, + struct hid_input, list); + + return boot_hid_input->input->event(boot_hid_input->input, type, code, + value); +} + +static int holtek_kbd_probe(struct hid_device *hdev, + const struct hid_device_id *id) +{ + struct usb_interface *intf = to_usb_interface(hdev->dev.parent); + int ret = hid_parse(hdev); + + if (!ret) + ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); + + if (!ret && intf->cur_altsetting->desc.bInterfaceNumber == 1) { + struct hid_input *hidinput; + list_for_each_entry(hidinput, &hdev->inputs, list) { + hidinput->input->event = holtek_kbd_input_event; + } + } + + return ret; +} + +static const struct hid_device_id holtek_kbd_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, + USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) }, + { } +}; +MODULE_DEVICE_TABLE(hid, holtek_kbd_devices); + +static struct hid_driver holtek_kbd_driver = { + .name = "holtek_kbd", + .id_table = holtek_kbd_devices, + .report_fixup = holtek_kbd_report_fixup, + .probe = holtek_kbd_probe +}; + +static int __init holtek_kbd_init(void) +{ + return hid_register_driver(&holtek_kbd_driver); +} + +static void __exit holtek_kbd_exit(void) +{ + hid_unregister_driver(&holtek_kbd_driver); +} + +module_exit(holtek_kbd_exit); +module_init(holtek_kbd_init); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 3eb0090..6a88041 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -398,6 +398,9 @@ #define USB_VENDOR_ID_HOLTEK 0x1241 #define USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP 0x5015 +#define USB_VENDOR_ID_HOLTEK_ALT 0x04d9 +#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055 + #define USB_VENDOR_ID_IMATION 0x0718 #define USB_DEVICE_ID_DISC_STAKKA 0xd000 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html