diff options
Diffstat (limited to 'drivers/hid')
-rw-r--r-- | drivers/hid/Kconfig | 7 | ||||
-rw-r--r-- | drivers/hid/Makefile | 1 | ||||
-rw-r--r-- | drivers/hid/hid-alps.c | 30 | ||||
-rw-r--r-- | drivers/hid/hid-core.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 1 | ||||
-rw-r--r-- | drivers/hid/hid-redragon.c | 86 |
6 files changed, 121 insertions, 6 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index c75b12ded7af..a49a10437c40 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -575,6 +575,13 @@ config HID_MAYFLASH Say Y here if you have HJZ Mayflash PS3 game controller adapters and want to enable force feedback support. +config HID_REDRAGON + tristate "Redragon keyboards" + depends on HID + default !EXPERT + ---help--- + Support for Redragon keyboards that need fix-ups to work properly. + config HID_MICROSOFT tristate "Microsoft non-fully HID-compliant devices" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index b646e67abc5f..511e1cbff768 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -86,6 +86,7 @@ hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o obj-$(CONFIG_HID_PRIMAX) += hid-primax.o +obj-$(CONFIG_HID_REDRAGON) += hid-redragon.o obj-$(CONFIG_HID_RETRODE) += hid-retrode.o obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \ hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \ diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c index b1eeb4839bfc..aec253b44156 100644 --- a/drivers/hid/hid-alps.c +++ b/drivers/hid/hid-alps.c @@ -171,7 +171,7 @@ static int t4_read_write_register(struct hid_device *hdev, u32 address, int ret; u16 check_sum; u8 *input; - u8 *readbuf; + u8 *readbuf = NULL; input = kzalloc(T4_FEATURE_REPORT_LEN, GFP_KERNEL); if (!input) @@ -204,8 +204,8 @@ static int t4_read_write_register(struct hid_device *hdev, u32 address, goto exit; } - readbuf = kzalloc(T4_FEATURE_REPORT_LEN, GFP_KERNEL); if (read_flag) { + readbuf = kzalloc(T4_FEATURE_REPORT_LEN, GFP_KERNEL); if (!readbuf) { ret = -ENOMEM; goto exit; @@ -219,22 +219,24 @@ static int t4_read_write_register(struct hid_device *hdev, u32 address, goto exit_readbuf; } + ret = -EINVAL; + if (*(u32 *)&readbuf[6] != address) { dev_err(&hdev->dev, "read register address error (%x,%x)\n", - *(u32 *)&readbuf[6], address); + *(u32 *)&readbuf[6], address); goto exit_readbuf; } if (*(u16 *)&readbuf[10] != 1) { dev_err(&hdev->dev, "read register size error (%x)\n", - *(u16 *)&readbuf[10]); + *(u16 *)&readbuf[10]); goto exit_readbuf; } check_sum = t4_calc_check_sum(readbuf, 6, 7); if (*(u16 *)&readbuf[13] != check_sum) { dev_err(&hdev->dev, "read register checksum error (%x,%x)\n", - *(u16 *)&readbuf[13], check_sum); + *(u16 *)&readbuf[13], check_sum); goto exit_readbuf; } @@ -458,17 +460,35 @@ static int __maybe_unused alps_post_reset(struct hid_device *hdev) case T4: ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_1, NULL, T4_I2C_ABS, false); + if (ret < 0) { + dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_1 (%d)\n", + ret); + goto exit; + } + ret = t4_read_write_register(hdev, T4_PRM_FEED_CONFIG_4, NULL, T4_FEEDCFG4_ADVANCED_ABS_ENABLE, false); + if (ret < 0) { + dev_err(&hdev->dev, "failed T4_PRM_FEED_CONFIG_4 (%d)\n", + ret); + goto exit; + } break; case U1: ret = u1_read_write_register(hdev, ADDRESS_U1_DEV_CTRL_1, NULL, U1_TP_ABS_MODE | U1_SP_ABS_MODE, false); + if (ret < 0) { + dev_err(&hdev->dev, "failed to change TP mode (%d)\n", + ret); + goto exit; + } break; default: break; } + +exit: return ret; } diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 5d7cc6bbbac6..720be70ae74a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1798,7 +1798,7 @@ EXPORT_SYMBOL_GPL(hid_hw_stop); * * Tell underlying HW to start delivering events from the device. * This function should be called sometime after successful call - * to hid_hiw_start(). + * to hid_hw_start(). */ int hid_hw_open(struct hid_device *hdev) { diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index e293506be7aa..a85634fe033f 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -615,6 +615,7 @@ #define USB_VENDOR_ID_JESS 0x0c45 #define USB_DEVICE_ID_JESS_YUREX 0x1010 #define USB_DEVICE_ID_ASUS_MD_5112 0x5112 +#define USB_DEVICE_ID_REDRAGON_ASURA 0x760b #define USB_VENDOR_ID_JESS2 0x0f30 #define USB_DEVICE_ID_JESS2_COLOR_RUMBLE_PAD 0x0111 diff --git a/drivers/hid/hid-redragon.c b/drivers/hid/hid-redragon.c new file mode 100644 index 000000000000..daf59578bf93 --- /dev/null +++ b/drivers/hid/hid-redragon.c @@ -0,0 +1,86 @@ +/* + * HID driver for Redragon keyboards + * + * Copyright (c) 2017 Robert Munteanu + * SPDX-License-Identifier: GPL-2.0+ + */ + +/* + * 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 "hid-ids.h" + + +/* + * The Redragon Asura keyboard sends an incorrect HID descriptor. + * At byte 100 it contains + * + * 0x81, 0x00 + * + * which is Input (Data, Arr, Abs), but it should be + * + * 0x81, 0x02 + * + * which is Input (Data, Var, Abs), which is consistent with the way + * key codes are generated. + */ + +static __u8 *redragon_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int *rsize) +{ + if (*rsize >= 102 && rdesc[100] == 0x81 && rdesc[101] == 0x00) { + dev_info(&hdev->dev, "Fixing Redragon ASURA report descriptor.\n"); + rdesc[101] = 0x02; + } + + return rdesc; +} + +static int redragon_probe(struct hid_device *dev, + const struct hid_device_id *id) +{ + int ret; + + ret = hid_parse(dev); + if (ret) { + hid_err(dev, "parse failed\n"); + return ret; + } + + /* do not register unused input device */ + if (dev->maxapplication == 1) + return 0; + + ret = hid_hw_start(dev, HID_CONNECT_DEFAULT); + if (ret) { + hid_err(dev, "hw start failed\n"); + return ret; + } + + return 0; +} +static const struct hid_device_id redragon_devices[] = { + {HID_USB_DEVICE(USB_VENDOR_ID_JESS, USB_DEVICE_ID_REDRAGON_ASURA)}, + {} +}; + +MODULE_DEVICE_TABLE(hid, redragon_devices); + +static struct hid_driver redragon_driver = { + .name = "redragon", + .id_table = redragon_devices, + .report_fixup = redragon_report_fixup, + .probe = redragon_probe +}; + +module_hid_driver(redragon_driver); + +MODULE_LICENSE("GPL"); |