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/amd-sfh-hid/amd_sfh_client.c | 62 | ||||
-rw-r--r-- | drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 71 | ||||
-rw-r--r-- | drivers/hid/amd-sfh-hid/amd_sfh_pcie.h | 23 | ||||
-rw-r--r-- | drivers/hid/hid-apple.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-asus.c | 18 | ||||
-rw-r--r-- | drivers/hid/hid-cmedia.c | 90 | ||||
-rw-r--r-- | drivers/hid/hid-elo.c | 6 | ||||
-rw-r--r-- | drivers/hid/hid-ft260.c | 27 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 2 | ||||
-rw-r--r-- | drivers/hid/hid-quirks.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-sony.c | 3 | ||||
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid-core.c | 5 | ||||
-rw-r--r-- | drivers/hid/intel-ish-hid/ishtp-hid-client.c | 15 | ||||
-rw-r--r-- | drivers/hid/intel-ish-hid/ishtp-hid.h | 1 | ||||
-rw-r--r-- | drivers/hid/intel-ish-hid/ishtp/bus.c | 29 | ||||
-rw-r--r-- | drivers/hid/usbhid/Kconfig | 2 | ||||
-rw-r--r-- | drivers/hid/wacom_wac.c | 5 |
19 files changed, 311 insertions, 60 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 160554903ef9..33d28faddbc0 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -259,10 +259,11 @@ config HID_PRODIKEYS and some additional multimedia keys. config HID_CMEDIA - tristate "CMedia CM6533 HID audio jack controls" + tristate "CMedia audio chips" depends on HID help - Support for CMedia CM6533 HID audio jack controls. + Support for CMedia CM6533 HID audio jack controls + and HS100B mute buttons. config HID_CP2112 tristate "Silicon Labs CP2112 HID USB-to-SMBus Bridge support" @@ -576,7 +577,7 @@ config HID_LOGITECH_HIDPP depends on HID_LOGITECH select POWER_SUPPLY help - Support for Logitech devices relyingon the HID++ Logitech specification + Support for Logitech devices relying on the HID++ Logitech specification Say Y if you want support for Logitech devices relying on the HID++ specification. Such devices are the various Logitech Touchpads (T650, diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 1ea1a7c0b20f..e29efcb1c040 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -115,7 +115,6 @@ obj-$(CONFIG_HID_STEELSERIES) += hid-steelseries.o obj-$(CONFIG_HID_SUNPLUS) += hid-sunplus.o obj-$(CONFIG_HID_GREENASIA) += hid-gaff.o obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o hid-thrustmaster.o -obj-$(CONFIG_HID_TMINIT) += hid-tminit.o obj-$(CONFIG_HID_TIVO) += hid-tivo.o obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c index efb849411d25..840fd075c56f 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_client.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c @@ -17,7 +17,6 @@ #include "amd_sfh_pcie.h" #include "amd_sfh_hid.h" -#define AMD_SFH_IDLE_LOOP 200 struct request_list { struct hid_device *hid; @@ -123,14 +122,24 @@ static void amd_sfh_work_buffer(struct work_struct *work) int i; for (i = 0; i < cli_data->num_hid_devices; i++) { - report_size = get_input_report(i, cli_data->sensor_idx[i], cli_data->report_id[i], - in_data); - hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT, - in_data->input_report[i], report_size, 0); + if (cli_data->sensor_sts[i] == SENSOR_ENABLED) { + report_size = get_input_report + (i, cli_data->sensor_idx[i], cli_data->report_id[i], in_data); + hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT, + in_data->input_report[i], report_size, 0); + } } schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); } +u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts) +{ + if (mp2->mp2_ops->response) + sensor_sts = mp2->mp2_ops->response(mp2, sid, sensor_sts); + + return sensor_sts; +} + int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) { struct amd_input_data *in_data = &privdata->in_data; @@ -139,8 +148,8 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) struct device *dev; u32 feature_report_size; u32 input_report_size; + int rc, i, status; u8 cl_idx; - int rc, i; dev = &privdata->pdev->dev; @@ -155,7 +164,7 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) in_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8, &cl_data->sensor_dma_addr[i], GFP_KERNEL); - cl_data->sensor_sts[i] = 0; + cl_data->sensor_sts[i] = SENSOR_DISABLED; cl_data->sensor_requested_cnt[i] = 0; cl_data->cur_hid_dev = i; cl_idx = cl_data->sensor_idx[i]; @@ -184,7 +193,7 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) rc = -ENOMEM; goto cleanup; } - info.period = msecs_to_jiffies(AMD_SFH_IDLE_LOOP); + info.period = AMD_SFH_IDLE_LOOP; info.sensor_idx = cl_idx; info.dma_address = cl_data->sensor_dma_addr[i]; @@ -197,11 +206,25 @@ int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) rc = get_report_descriptor(cl_idx, cl_data->report_descr[i]); if (rc) return rc; - rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data); - if (rc) - return rc; privdata->mp2_ops->start(privdata, info); - cl_data->sensor_sts[i] = 1; + status = amd_sfh_wait_for_response + (privdata, cl_data->sensor_idx[i], SENSOR_ENABLED); + if (status == SENSOR_ENABLED) { + cl_data->sensor_sts[i] = SENSOR_ENABLED; + rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data); + if (rc) { + privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]); + status = amd_sfh_wait_for_response + (privdata, cl_data->sensor_idx[i], SENSOR_DISABLED); + if (status != SENSOR_ENABLED) + cl_data->sensor_sts[i] = SENSOR_DISABLED; + dev_dbg(dev, "sid 0x%x status 0x%x\n", + cl_data->sensor_idx[i], cl_data->sensor_sts[i]); + goto cleanup; + } + } + dev_dbg(dev, "sid 0x%x status 0x%x\n", + cl_data->sensor_idx[i], cl_data->sensor_sts[i]); } schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); return 0; @@ -224,10 +247,19 @@ int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata) { struct amdtp_cl_data *cl_data = privdata->cl_data; struct amd_input_data *in_data = cl_data->in_data; - int i; + int i, status; - for (i = 0; i < cl_data->num_hid_devices; i++) - privdata->mp2_ops->stop(privdata, i); + for (i = 0; i < cl_data->num_hid_devices; i++) { + if (cl_data->sensor_sts[i] == SENSOR_ENABLED) { + privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]); + status = amd_sfh_wait_for_response + (privdata, cl_data->sensor_idx[i], SENSOR_DISABLED); + if (status != SENSOR_ENABLED) + cl_data->sensor_sts[i] = SENSOR_DISABLED; + dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x status 0x%x\n", + cl_data->sensor_idx[i], cl_data->sensor_sts[i]); + } + } cancel_delayed_work_sync(&cl_data->work); cancel_delayed_work_sync(&cl_data->work_buffer); diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index 96e2577fa37e..79b138fd4261 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -13,6 +13,7 @@ #include <linux/dmi.h> #include <linux/interrupt.h> #include <linux/io-64-nonatomic-lo-hi.h> +#include <linux/iopoll.h> #include <linux/module.h> #include <linux/slab.h> @@ -31,6 +32,20 @@ static int sensor_mask_override = -1; module_param_named(sensor_mask, sensor_mask_override, int, 0444); MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask"); +static int amd_sfh_wait_response_v2(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts) +{ + union cmd_response cmd_resp; + + /* Get response with status within a max of 800 ms timeout */ + if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG(0), cmd_resp.resp, + (cmd_resp.response_v2.response == sensor_sts && + cmd_resp.response_v2.status == 0 && (sid == 0xff || + cmd_resp.response_v2.sensor_id == sid)), 500, 800000)) + return cmd_resp.response_v2.response; + + return SENSOR_DISABLED; +} + static void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) { union sfh_cmd_base cmd_base; @@ -58,7 +73,7 @@ static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx) cmd_base.cmd_v2.sensor_id = sensor_idx; cmd_base.cmd_v2.length = 16; - writeq(0x0, privdata->mmio + AMD_C2P_MSG2); + writeq(0x0, privdata->mmio + AMD_C2P_MSG1); writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); } @@ -183,6 +198,7 @@ static const struct amd_mp2_ops amd_sfh_ops_v2 = { .start = amd_start_sensor_v2, .stop = amd_stop_sensor_v2, .stop_all = amd_stop_all_sensor_v2, + .response = amd_sfh_wait_response_v2, }; static const struct amd_mp2_ops amd_sfh_ops = { @@ -248,6 +264,58 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i return amd_sfh_hid_client_init(privdata); } +static int __maybe_unused amd_mp2_pci_resume(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct amd_mp2_dev *mp2 = pci_get_drvdata(pdev); + struct amdtp_cl_data *cl_data = mp2->cl_data; + struct amd_mp2_sensor_info info; + int i, status; + + for (i = 0; i < cl_data->num_hid_devices; i++) { + if (cl_data->sensor_sts[i] == SENSOR_DISABLED) { + info.period = AMD_SFH_IDLE_LOOP; + info.sensor_idx = cl_data->sensor_idx[i]; + info.dma_address = cl_data->sensor_dma_addr[i]; + mp2->mp2_ops->start(mp2, info); + status = amd_sfh_wait_for_response + (mp2, cl_data->sensor_idx[i], SENSOR_ENABLED); + if (status == SENSOR_ENABLED) + cl_data->sensor_sts[i] = SENSOR_ENABLED; + dev_dbg(dev, "resume sid 0x%x status 0x%x\n", + cl_data->sensor_idx[i], cl_data->sensor_sts[i]); + } + } + + return 0; +} + +static int __maybe_unused amd_mp2_pci_suspend(struct device *dev) +{ + struct pci_dev *pdev = to_pci_dev(dev); + struct amd_mp2_dev *mp2 = pci_get_drvdata(pdev); + struct amdtp_cl_data *cl_data = mp2->cl_data; + int i, status; + + for (i = 0; i < cl_data->num_hid_devices; i++) { + if (cl_data->sensor_idx[i] != HPD_IDX && + cl_data->sensor_sts[i] == SENSOR_ENABLED) { + mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]); + status = amd_sfh_wait_for_response + (mp2, cl_data->sensor_idx[i], SENSOR_DISABLED); + if (status != SENSOR_ENABLED) + cl_data->sensor_sts[i] = SENSOR_DISABLED; + dev_dbg(dev, "suspend sid 0x%x status 0x%x\n", + cl_data->sensor_idx[i], cl_data->sensor_sts[i]); + } + } + + return 0; +} + +static SIMPLE_DEV_PM_OPS(amd_mp2_pm_ops, amd_mp2_pci_suspend, + amd_mp2_pci_resume); + static const struct pci_device_id amd_mp2_pci_tbl[] = { { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) }, { } @@ -258,6 +326,7 @@ static struct pci_driver amd_mp2_pci_driver = { .name = DRIVER_NAME, .id_table = amd_mp2_pci_tbl, .probe = amd_mp2_pci_probe, + .driver.pm = &amd_mp2_pm_ops, }; module_pci_driver(amd_mp2_pci_driver); diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h index 2d5c57e3782d..1ff6f83cb6fd 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h @@ -24,14 +24,20 @@ #define AMD_C2P_MSG2 0x10508 #define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4)) +#define AMD_P2C_MSG(regno) (0x10680 + ((regno) * 4)) /* MP2 P2C Message Registers */ #define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */ #define V2_STATUS 0x2 +#define SENSOR_ENABLED 4 +#define SENSOR_DISABLED 5 + #define HPD_IDX 16 +#define AMD_SFH_IDLE_LOOP 200 + /* SFH Command register */ union sfh_cmd_base { u32 ul; @@ -51,6 +57,19 @@ union sfh_cmd_base { } cmd_v2; }; +union cmd_response { + u32 resp; + struct { + u32 status : 2; + u32 out_in_c2p : 1; + u32 rsvd1 : 1; + u32 response : 4; + u32 sub_cmd : 8; + u32 sensor_id : 6; + u32 rsvd2 : 10; + } response_v2; +}; + union sfh_cmd_param { u32 ul; struct { @@ -112,10 +131,14 @@ void amd_stop_all_sensors(struct amd_mp2_dev *privdata); int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id); int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata); int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata); +u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts); +void amd_mp2_suspend(struct amd_mp2_dev *mp2); +void amd_mp2_resume(struct amd_mp2_dev *mp2); struct amd_mp2_ops { void (*start)(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info); void (*stop)(struct amd_mp2_dev *privdata, u16 sensor_idx); void (*stop_all)(struct amd_mp2_dev *privdata); + int (*response)(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts); }; #endif diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c index 6b8f0d004d34..dc6bd4299c54 100644 --- a/drivers/hid/hid-apple.c +++ b/drivers/hid/hid-apple.c @@ -501,6 +501,8 @@ static const struct hid_device_id apple_devices[] = { APPLE_RDESC_JIS }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI), .driver_data = APPLE_HAS_FN }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ANSI), + .driver_data = APPLE_HAS_FN }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO), .driver_data = APPLE_HAS_FN }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_REVB_ISO), diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index fca8fc78a78a..f3ecddc519ee 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -82,6 +82,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define QUIRK_T90CHI BIT(9) #define QUIRK_MEDION_E1239T BIT(10) #define QUIRK_ROG_NKEY_KEYBOARD BIT(11) +#define QUIRK_ROG_CLAYMORE_II_KEYBOARD BIT(12) #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ QUIRK_NO_INIT_REPORTS | \ @@ -366,6 +367,17 @@ static int asus_raw_event(struct hid_device *hdev, } + if (drvdata->quirks & QUIRK_ROG_CLAYMORE_II_KEYBOARD) { + /* + * CLAYMORE II keyboard sends this packet when it goes to sleep + * this causes the whole system to go into suspend. + */ + + if(size == 2 && data[0] == 0x02 && data[1] == 0x00) { + return -1; + } + } + return 0; } @@ -485,9 +497,6 @@ static void asus_kbd_backlight_set(struct led_classdev *led_cdev, { struct asus_kbd_leds *led = container_of(led_cdev, struct asus_kbd_leds, cdev); - if (led->brightness == brightness) - return; - led->brightness = brightness; schedule_work(&led->work); } @@ -1229,6 +1238,9 @@ static const struct hid_device_id asus_devices[] = { USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2), QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, + USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD), + QUIRK_ROG_CLAYMORE_II_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD), QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, diff --git a/drivers/hid/hid-cmedia.c b/drivers/hid/hid-cmedia.c index 3296c5050264..cab42047bc99 100644 --- a/drivers/hid/hid-cmedia.c +++ b/drivers/hid/hid-cmedia.c @@ -1,8 +1,10 @@ // SPDX-License-Identifier: GPL-2.0-only /* * HID driver for CMedia CM6533 audio jack controls + * and HS100B mute buttons * * Copyright (C) 2015 Ben Chen <ben_chen@bizlinktech.com> + * Copyright (C) 2021 Thomas Weißschuh <linux@weissschuh.net> */ #include <linux/device.h> @@ -11,13 +13,53 @@ #include "hid-ids.h" MODULE_AUTHOR("Ben Chen"); -MODULE_DESCRIPTION("CM6533 HID jack controls"); +MODULE_AUTHOR("Thomas Weißschuh"); +MODULE_DESCRIPTION("CM6533 HID jack controls and HS100B mute button"); MODULE_LICENSE("GPL"); #define CM6533_JD_TYPE_COUNT 1 #define CM6533_JD_RAWEV_LEN 16 #define CM6533_JD_SFX_OFFSET 8 +#define HS100B_RDESC_ORIG_SIZE 60 + +/* Fixed report descriptor of HS-100B audio chip + * Bit 4 is an abolute Microphone mute usage instead of being unassigned. + */ +static __u8 hs100b_rdesc_fixed[] = { + 0x05, 0x0C, /* Usage Page (Consumer), */ + 0x09, 0x01, /* Usage (Consumer Control), */ + 0xA1, 0x01, /* Collection (Application), */ + 0x15, 0x00, /* Logical Minimum (0), */ + 0x25, 0x01, /* Logical Maximum (1), */ + 0x09, 0xE9, /* Usage (Volume Inc), */ + 0x09, 0xEA, /* Usage (Volume Dec), */ + 0x75, 0x01, /* Report Size (1), */ + 0x95, 0x02, /* Report Count (2), */ + 0x81, 0x02, /* Input (Variable), */ + 0x09, 0xE2, /* Usage (Mute), */ + 0x95, 0x01, /* Report Count (1), */ + 0x81, 0x06, /* Input (Variable, Relative), */ + 0x05, 0x0B, /* Usage Page (Telephony), */ + 0x09, 0x2F, /* Usage (2Fh), */ + 0x81, 0x02, /* Input (Variable), */ + 0x09, 0x20, /* Usage (20h), */ + 0x81, 0x06, /* Input (Variable, Relative), */ + 0x05, 0x0C, /* Usage Page (Consumer), */ + 0x09, 0x00, /* Usage (00h), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x02, /* Input (Variable), */ + 0x26, 0xFF, 0x00, /* Logical Maximum (255), */ + 0x09, 0x00, /* Usage (00h), */ + 0x75, 0x08, /* Report Size (8), */ + 0x95, 0x03, /* Report Count (3), */ + 0x81, 0x02, /* Input (Variable), */ + 0x09, 0x00, /* Usage (00h), */ + 0x95, 0x04, /* Report Count (4), */ + 0x91, 0x02, /* Output (Variable), */ + 0xC0 /* End Collection */ +}; + /* * *CM6533 audio jack HID raw events: @@ -156,5 +198,49 @@ static struct hid_driver cmhid_driver = { .remove = cmhid_remove, .input_mapping = cmhid_input_mapping, }; -module_hid_driver(cmhid_driver); +static __u8 *cmhid_hs100b_report_fixup(struct hid_device *hid, __u8 *rdesc, + unsigned int *rsize) +{ + if (*rsize == HS100B_RDESC_ORIG_SIZE) { + hid_info(hid, "Fixing CMedia HS-100B report descriptor\n"); + rdesc = hs100b_rdesc_fixed; + *rsize = sizeof(hs100b_rdesc_fixed); + } + return rdesc; +} + +static const struct hid_device_id cmhid_hs100b_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_CMEDIA, USB_DEVICE_ID_CMEDIA_HS100B) }, + { } +}; +MODULE_DEVICE_TABLE(hid, cmhid_hs100b_devices); + +static struct hid_driver cmhid_hs100b_driver = { + .name = "cmedia_hs100b", + .id_table = cmhid_hs100b_devices, + .report_fixup = cmhid_hs100b_report_fixup, +}; + +static int cmedia_init(void) +{ + int ret; + + ret = hid_register_driver(&cmhid_driver); + if (ret) + return ret; + + ret = hid_register_driver(&cmhid_hs100b_driver); + if (ret) + hid_unregister_driver(&cmhid_driver); + + return ret; +} +module_init(cmedia_init); + +static void cmedia_exit(void) +{ + hid_unregister_driver(&cmhid_driver); + hid_unregister_driver(&cmhid_hs100b_driver); +} +module_exit(cmedia_exit); diff --git a/drivers/hid/hid-elo.c b/drivers/hid/hid-elo.c index 0d22713a3874..383dfda8c12f 100644 --- a/drivers/hid/hid-elo.c +++ b/drivers/hid/hid-elo.c @@ -228,13 +228,15 @@ static int elo_probe(struct hid_device *hdev, const struct hid_device_id *id) { struct elo_priv *priv; int ret; + struct usb_device *udev; priv = kzalloc(sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM; INIT_DELAYED_WORK(&priv->work, elo_work); - priv->usbdev = interface_to_usbdev(to_usb_interface(hdev->dev.parent)); + udev = interface_to_usbdev(to_usb_interface(hdev->dev.parent)); + priv->usbdev = usb_get_dev(udev); hid_set_drvdata(hdev, priv); @@ -265,6 +267,8 @@ static void elo_remove(struct hid_device *hdev) { struct elo_priv *priv = hid_get_drvdata(hdev); + usb_put_dev(priv->usbdev); + hid_hw_stop(hdev); cancel_delayed_work_sync(&priv->work); kfree(priv); diff --git a/drivers/hid/hid-ft260.c b/drivers/hid/hid-ft260.c index f43a8406cb9a..4ef1c3b8094e 100644 --- a/drivers/hid/hid-ft260.c +++ b/drivers/hid/hid-ft260.c @@ -742,7 +742,7 @@ static int ft260_is_interface_enabled(struct hid_device *hdev) int ret; ret = ft260_get_system_config(hdev, &cfg); - if (ret) + if (ret < 0) return ret; ft260_dbg("interface: 0x%02x\n", interface); @@ -754,23 +754,16 @@ static int ft260_is_interface_enabled(struct hid_device *hdev) switch (cfg.chip_mode) { case FT260_MODE_ALL: case FT260_MODE_BOTH: - if (interface == 1) { + if (interface == 1) hid_info(hdev, "uart interface is not supported\n"); - return 0; - } - ret = 1; + else + ret = 1; break; case FT260_MODE_UART: - if (interface == 0) { - hid_info(hdev, "uart is unsupported on interface 0\n"); - ret = 0; - } + hid_info(hdev, "uart interface is not supported\n"); break; case FT260_MODE_I2C: - if (interface == 1) { - hid_info(hdev, "i2c is unsupported on interface 1\n"); - ret = 0; - } + ret = 1; break; } return ret; @@ -785,7 +778,7 @@ static int ft260_byte_show(struct hid_device *hdev, int id, u8 *cfg, int len, if (ret < 0) return ret; - return scnprintf(buf, PAGE_SIZE, "%hi\n", *field); + return scnprintf(buf, PAGE_SIZE, "%d\n", *field); } static int ft260_word_show(struct hid_device *hdev, int id, u8 *cfg, int len, @@ -797,7 +790,7 @@ static int ft260_word_show(struct hid_device *hdev, int id, u8 *cfg, int len, if (ret < 0) return ret; - return scnprintf(buf, PAGE_SIZE, "%hi\n", le16_to_cpu(*field)); + return scnprintf(buf, PAGE_SIZE, "%d\n", le16_to_cpu(*field)); } #define FT260_ATTR_SHOW(name, reptype, id, type, func) \ @@ -1004,11 +997,9 @@ err_hid_stop: static void ft260_remove(struct hid_device *hdev) { - int ret; struct ft260_device *dev = hid_get_drvdata(hdev); - ret = ft260_is_interface_enabled(hdev); - if (ret <= 0) + if (!dev) return; sysfs_remove_group(&hdev->dev.kobj, &ft260_attr_group); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 8f1893e68112..c3997afecbc9 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -197,6 +197,7 @@ #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6 +#define USB_DEVICE_ID_ASUSTEK_ROG_CLAYMORE_II_KEYBOARD 0x196b #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 #define USB_VENDOR_ID_ATEN 0x0557 @@ -292,6 +293,7 @@ #define USB_VENDOR_ID_CMEDIA 0x0d8c #define USB_DEVICE_ID_CM109 0x000e +#define USB_DEVICE_ID_CMEDIA_HS100B 0x0014 #define USB_DEVICE_ID_CM6533 0x0022 #define USB_VENDOR_ID_CODEMERCS 0x07c0 diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index 51b39bda9a9d..2e104682c22b 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -662,8 +662,6 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65a) }, -#endif -#if IS_ENABLED(CONFIG_HID_TMINIT) { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb65d) }, #endif #if IS_ENABLED(CONFIG_HID_TIVO) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index b3722c51ec78..a2fef59063a6 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -2974,7 +2974,8 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) if (!strcmp(hdev->name, "FutureMax Dance Mat")) quirks |= FUTUREMAX_DANCE_MAT; - if (!strcmp(hdev->name, "SHANWAN PS3 GamePad")) + if (!strcmp(hdev->name, "SHANWAN PS3 GamePad") || + !strcmp(hdev->name, "ShanWan PS(R) Ga`epad")) quirks |= SHANWAN_GAMEPAD; sc = devm_kzalloc(&hdev->dev, sizeof(*sc), GFP_KERNEL); diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 46474612e73c..517141138b00 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -171,8 +171,6 @@ static const struct i2c_hid_quirks { I2C_HID_QUIRK_NO_IRQ_AFTER_RESET }, { I2C_VENDOR_ID_RAYDIUM, I2C_PRODUCT_ID_RAYDIUM_3118, I2C_HID_QUIRK_NO_IRQ_AFTER_RESET }, - { USB_VENDOR_ID_ELAN, HID_ANY_ID, - I2C_HID_QUIRK_BOGUS_IRQ }, { USB_VENDOR_ID_ALPS_JP, HID_ANY_ID, I2C_HID_QUIRK_RESET_ON_RESUME }, { I2C_VENDOR_ID_SYNAPTICS, I2C_PRODUCT_ID_SYNAPTICS_SYNA2393, @@ -183,7 +181,8 @@ static const struct i2c_hid_quirks { * Sending the wakeup after reset actually break ELAN touchscreen controller */ { USB_VENDOR_ID_ELAN, HID_ANY_ID, - I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET }, + I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET | + I2C_HID_QUIRK_BOGUS_IRQ }, { 0, 0 } }; diff --git a/drivers/hid/intel-ish-hid/ishtp-hid-client.c b/drivers/hid/intel-ish-hid/ishtp-hid-client.c index 6b1fa971b33e..91bf4d01e91a 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid-client.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid-client.c @@ -784,6 +784,17 @@ static void hid_ishtp_cl_reset_handler(struct work_struct *work) } } +static void hid_ishtp_cl_resume_handler(struct work_struct *work) +{ + struct ishtp_cl_data *client_data = container_of(work, struct ishtp_cl_data, resume_work); + struct ishtp_cl *hid_ishtp_cl = client_data->hid_ishtp_cl; + + if (ishtp_wait_resume(ishtp_get_ishtp_device(hid_ishtp_cl))) { + client_data->suspended = false; + wake_up_interruptible(&client_data->ishtp_resume_wait); + } +} + ishtp_print_log ishtp_hid_print_trace; /** @@ -822,6 +833,8 @@ static int hid_ishtp_cl_probe(struct ishtp_cl_device *cl_device) init_waitqueue_head(&client_data->ishtp_resume_wait); INIT_WORK(&client_data->work, hid_ishtp_cl_reset_handler); + INIT_WORK(&client_data->resume_work, hid_ishtp_cl_resume_handler); + ishtp_hid_print_trace = ishtp_trace_callback(cl_device); @@ -921,7 +934,7 @@ static int hid_ishtp_cl_resume(struct device *device) hid_ishtp_trace(client_data, "%s hid_ishtp_cl %p\n", __func__, hid_ishtp_cl); - client_data->suspended = false; + schedule_work(&client_data->resume_work); return 0; } diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.h b/drivers/hid/intel-ish-hid/ishtp-hid.h index f88443a7d935..6a5cc11aefd8 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid.h +++ b/drivers/hid/intel-ish-hid/ishtp-hid.h @@ -135,6 +135,7 @@ struct ishtp_cl_data { int multi_packet_cnt; struct work_struct work; + struct work_struct resume_work; struct ishtp_cl_device *cl_device; }; diff --git a/drivers/hid/intel-ish-hid/ishtp/bus.c b/drivers/hid/intel-ish-hid/ishtp/bus.c index f0802b047ed8..aa2c51624012 100644 --- a/drivers/hid/intel-ish-hid/ishtp/bus.c +++ b/drivers/hid/intel-ish-hid/ishtp/bus.c @@ -314,13 +314,6 @@ static int ishtp_cl_device_resume(struct device *dev) if (!device) return 0; - /* - * When ISH needs hard reset, it is done asynchrnously, hence bus - * resume will be called before full ISH resume - */ - if (device->ishtp_dev->resume_flag) - return 0; - driver = to_ishtp_cl_driver(dev->driver); if (driver && driver->driver.pm) { if (driver->driver.pm->resume) @@ -850,6 +843,28 @@ struct device *ishtp_device(struct ishtp_cl_device *device) EXPORT_SYMBOL(ishtp_device); /** + * ishtp_wait_resume() - Wait for IPC resume + * + * Wait for IPC resume + * + * Return: resume complete or not + */ +bool ishtp_wait_resume(struct ishtp_device *dev) +{ + /* 50ms to get resume response */ + #define WAIT_FOR_RESUME_ACK_MS 50 + + /* Waiting to get resume response */ + if (dev->resume_flag) + wait_event_interruptible_timeout(dev->resume_wait, + !dev->resume_flag, + msecs_to_jiffies(WAIT_FOR_RESUME_ACK_MS)); + + return (!dev->resume_flag); +} +EXPORT_SYMBOL_GPL(ishtp_wait_resume); + +/** * ishtp_get_pci_device() - Return PCI device dev pointer * This interface is used to return PCI device pointer * from ishtp_cl_device instance. diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig index dcf3a235870f..7c2032f7f44d 100644 --- a/drivers/hid/usbhid/Kconfig +++ b/drivers/hid/usbhid/Kconfig @@ -38,7 +38,7 @@ config USB_HIDDEV help Say Y here if you want to support HID devices (from the USB specification standpoint) that aren't strictly user interface - devices, like monitor controls and Uninterruptable Power Supplies. + devices, like monitor controls and Uninterruptible Power Supplies. This module supports these devices separately using a separate event interface on /dev/usb/hiddevX (char 180:96 to 180:111). diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 81d7d12bcf34..81ba642adcb7 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2548,6 +2548,9 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac, int slot; slot = input_mt_get_slot_by_key(input, hid_data->id); + if (slot < 0) + return; + input_mt_slot(input, slot); input_mt_report_slot_state(input, MT_TOOL_FINGER, prox); } @@ -3831,7 +3834,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, wacom_wac->shared->touch->product == 0xF6) { input_dev->evbit[0] |= BIT_MASK(EV_SW); __set_bit(SW_MUTE_DEVICE, input_dev->swbit); - wacom_wac->shared->has_mute_touch_switch = true; + wacom_wac->has_mute_touch_switch = true; } fallthrough; |