Hi! So... I got two gaming keyboards. One is totally unusable (and it looks LEDs are not controllable from the host), and the second one is .. HyperX Elite RGB. Needs 2 USB connections, very buggy, probably needs repair, and I'd not recomend it to anyone. But that one seems to be usable for RGB keyboard development. (Unusable one is https://www.trust.com/en/product/23651-gxt-835-azor-illuminated-gaming-keyboard Usable one is 0951:16be Kingston Technology HyperX Alloy Elite RGB ) First step is to create some kind of driver, I believe. And I did that, userland version works quite good, and I started hacking kernel one. Version is below, and help would be welcome. Especially if someone knows how to do the probing right (it binds 3 times, log below). What is worse, loading this driver kills keyboard functionality -- input is no longer possible. Is there simple way to keep that functionality? Best regards, Pavel [ 9880.950973] input: HyperX Alloy Elite RGB HyperX Alloy Elite RGB System Control as /devices/p ci0000:00/0000:00:1d.0/usb1/1-1/1-1:1.2/0003:0951:16BE.0045/input/input216 [ 9881.009994] input: HyperX Alloy Elite RGB HyperX Alloy Elite RGB Consumer Control as /devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1:1.2/0003:0951:16BE.0045/input/input217 [ 9881.013758] input: HyperX Alloy Elite RGB HyperX Alloy Elite RGB Keyboard as /devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1:1.2/0003:0951:16BE.0045/input/input219 [ 9881.014528] hid-generic 0003:0951:16BE.0045: input,hiddev96,hidraw2: USB HID v1.11 Mouse [HyperX Alloy Elite RGB HyperX Alloy Elite RGB] on usb-0000:00:1d.0-1/input2 [ 9886.017646] input: HyperX Alloy Elite RGB HyperX Alloy Elite RGB as /devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1:1.0/0003:0951:16BE.0043/input/input221 [ 9886.218066] hx 0003:0951:16BE.0043: input,hidraw0: USB HID v1.11 Keyboard [HyperX Alloy Elite RGB HyperX Alloy Elite RGB] on usb-0000:00:1d.0-1/input0 [ 9886.218088] Have device. ... [ 9899.399088] input: HyperX Alloy Elite RGB HyperX Alloy Elite RGB as /devices/pci0000:00/0000:00:1d.0/usb1/1-1/1-1:1.1/0003:0951:16BE.0044/input/input222 [ 9899.537173] hx 0003:0951:16BE.0044: input,hidraw1: USB HID v1.11 Keyboard [HyperX Alloy Elite RGB HyperX Alloy Elite RGB] on usb-0000:00:1d.0-1/input1 [ 9899.537194] Have device. ... [ 9912.691800] input: HyperX Alloy Elite RGB HyperX Alloy Elite RGB as /devices/pci0000:00/0000: 00:1d.0/usb1/1-1/1-1:1.2/0003:0951:16BE.0045/input/input223 [ 9912.751478] hx 0003:0951:16BE.0045: input,hiddev96,hidraw2: USB HID v1.11 Mouse [HyperX Alloy Elite RGB HyperX Alloy Elite RGB] on usb-0000:00:1d.0-1/input2 [ 9912.751502] Have device. // SPDX-License-Identifier: GPL-2.0-or-later /* */ #include <linux/device.h> #include <linux/input.h> #include <linux/hid.h> #include <linux/module.h> #include <linux/slab.h> #include <linux/hid-roccat.h> #include <linux/usb.h> struct hx_device {}; static unsigned char keys[] = { 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x20, 0x21, 0x22, 0x23, 0x24, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, 0x30, 0x31, 0x32, 0x33, 0x34, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3E, 0x3F, 0x41, 0x44, 0x45, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x51, 0x54, 0x55, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5E, 0x5F, 0x61, 0x64, 0x65, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6E, 0x6F, 0x74, 0x75, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, 0x81, 0x84, 0x85, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x91, 0x94, 0x95 }; struct hid_device *one_hdev; static int set_direct_color(struct hid_device *hdev, int color, int val) { const int s = 264; unsigned char *buf = kmalloc(s, GFP_KERNEL); int i, ret; /* Zero out buffer */ memset(buf, 0x00, s); /* Set up Direct packet */ for (i = 0; i < sizeof(keys)/sizeof(keys[0]); i++) { buf[keys[i]] = val; } buf[0x00] = 0x07; buf[0x01] = 0x16; // HYPERX_ALLOY_ELITE_PACKET_ID_DIRECT buf[0x02] = color; // HYPERX_ALLOY_ELITE_COLOR_CHANNEL_GREEN buf[0x03] = 0xA0; ret = hid_hw_power(hdev, PM_HINT_FULLON); if (ret) { hid_err(hdev, "Failed to power on HID device\n"); return ret; } // ioctl(3, HIDIOCSFEATURE(264), 0xbfce5974) = 264 // -> hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT); // printk(KERN_INFO "Set feature report -- direct\n"); i = hid_hw_raw_request(hdev, buf[0], buf, s, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); printk("raw: %d, einval %d, eagain %d\n", i, -EINVAL, -EAGAIN); msleep(100); return 0; } #define SIZE 128 const int real_size = SIZE; static ssize_t hx_sysfs_read(struct file *fp, struct kobject *kobj, struct bin_attribute * b, char *buf, loff_t off, size_t count) { struct device *dev = kobj_to_dev(kobj); struct hx_device *hx = hid_get_drvdata(dev_get_drvdata(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); int retval; if (off >= real_size) return 0; if (off != 0 || count != real_size) return -EINVAL; printk("read\n"); set_direct_color(one_hdev, 2, 0xff); return retval ? retval : real_size; } static ssize_t hx_sysfs_write(struct file *fp, struct kobject *kobj, struct bin_attribute * b, void const *buf, loff_t off, size_t count) { struct device *dev = kobj_to_dev(kobj); struct hx_device *hx = hid_get_drvdata(dev_get_drvdata(dev)); struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev)); int retval; if (off != 0 || count != real_size) return -EINVAL; printk("Write\n"); return retval ? retval : real_size; } static struct bin_attribute hx_control_attr = { \ .attr = { .name = "thingy", .mode = 0660 }, \ .size = SIZE, \ .read = hx_sysfs_read, \ }; static int hx_create_sysfs_attributes(struct usb_interface *intf) { return sysfs_create_bin_file(&intf->dev.kobj, &hx_control_attr); } static void hx_remove_sysfs_attributes(struct usb_interface *intf) { sysfs_remove_bin_file(&intf->dev.kobj, &hx_control_attr); } static int hx_init_hx_device_struct(struct usb_device *usb_dev, struct hx_device *hx) { //mutex_init(&hx->hx_lock); return 0; } static int hx_init_specials(struct hid_device *hdev) { struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct usb_device *usb_dev = interface_to_usbdev(intf); struct hx_device *hx; int retval; hx = kzalloc(sizeof(*hx), GFP_KERNEL); if (!hx) { hid_err(hdev, "can't alloc device descriptor\n"); return -ENOMEM; } hid_set_drvdata(hdev, hx); retval = hx_create_sysfs_attributes(intf); if (retval) { hid_err(hdev, "cannot create sysfs files\n"); goto exit; } return 0; exit: kfree(hx); return retval; } static void hx_remove_specials(struct hid_device *hdev) { struct usb_interface *intf = to_usb_interface(hdev->dev.parent); struct hx_device *hx; hx_remove_sysfs_attributes(intf); hx = hid_get_drvdata(hdev); kfree(hx); } static int num; static int hx_probe(struct hid_device *hdev, const struct hid_device_id *id) { int retval; if (!hid_is_usb(hdev)) return -EINVAL; if (++num != 2) return -EINVAL; retval = hid_parse(hdev); if (retval) { hid_err(hdev, "parse failed\n"); goto exit; } retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT); if (retval) { hid_err(hdev, "hw start failed\n"); goto exit; } printk("Have device.\n"); if (!hid_is_usb(hdev)) { printk("Not an usb?\n"); } { struct usb_interface *interface = to_usb_interface(hdev->dev.parent); struct usb_device *dev = interface_to_usbdev(interface); struct usb_host_interface *iface_desc; struct usb_endpoint_descriptor *endpoint; char manufacturer[128]; char product[128]; // Retrieve manufacturer string retval = usb_string(dev, dev->descriptor.iManufacturer, manufacturer, sizeof(manufacturer)); if (retval > 0) printk(KERN_INFO "Manufacturer: %s\n", manufacturer); else printk(KERN_ERR "Failed to get manufacturer string\n"); // Retrieve product string retval = usb_string(dev, dev->descriptor.iProduct, product, sizeof(product)); if (retval > 0) printk(KERN_INFO "Product: %s\n", product); else printk(KERN_ERR "Failed to get product string\n"); } retval = hx_init_specials(hdev); if (retval) { hid_err(hdev, "couldn't install mouse\n"); goto exit_stop; } // Example call to set_direct_color function for (int i=0; i<20; i++) { set_direct_color(hdev, 0x01, 0); // Example values set_direct_color(hdev, 0x02, 0); // Example values set_direct_color(hdev, 0x03, 0); // Example values set_direct_color(hdev, 0x01, 0xFF); // Example values set_direct_color(hdev, 0x02, 0xFF); // Example values set_direct_color(hdev, 0x03, 0xFF); // Example values } one_hdev = hdev; return 0; exit_stop: hid_hw_stop(hdev); exit: return retval; } static void hx_remove(struct hid_device *hdev) { hx_remove_specials(hdev); hid_hw_stop(hdev); } static const struct hid_device_id hx_devices[] = { { HID_USB_DEVICE(0x0951, 0x16be) }, { } }; MODULE_DEVICE_TABLE(hid, hx_devices); static struct hid_driver hx_driver = { .name = "hx", .id_table = hx_devices, .probe = hx_probe, .remove = hx_remove }; module_hid_driver(hx_driver); MODULE_AUTHOR("Pavel Machek"); MODULE_DESCRIPTION("USB HyperX elite backlight driver"); MODULE_LICENSE("GPL v2"); -- People of Russia, stop Putin before his war on Ukraine escalates.
Attachment:
signature.asc
Description: PGP signature