From 302f0dad8c97a11abcf145ff3c7036f8f80e1a1e Mon Sep 17 00:00:00 2001 From: Sandeep Singh Date: Sat, 10 Oct 2020 01:31:35 +0530 Subject: [PATCH 01/27] SFH: Add maintainers and documentation for AMD SFH based on HID framework Add Maintainers for AMD SFH(SENSOR FUSION HUB) Solution and work flow document. Co-developed-by: Nehal Shah Signed-off-by: Nehal Shah Signed-off-by: Sandeep Singh Signed-off-by: Jiri Kosina --- Documentation/hid/index.rst | 1 + MAINTAINERS | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/Documentation/hid/index.rst b/Documentation/hid/index.rst index 737d66dc16a1..e50f513c579c 100644 --- a/Documentation/hid/index.rst +++ b/Documentation/hid/index.rst @@ -16,3 +16,4 @@ Human Interface Devices (HID) hid-alps intel-ish-hid + amd-sfh-hid diff --git a/MAINTAINERS b/MAINTAINERS index dd1887c3c5bf..9d12f61d0519 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -950,6 +950,14 @@ S: Supported F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi F: drivers/net/ethernet/amd/xgbe/ +AMD SENSOR FUSION HUB DRIVER +M: Nehal Shah +M: Sandeep Singh +L: linux-input@vger.kernel.org +S: Maintained +F: Documentation/hid/amd-sfh* +F: drivers/hid/amd-sfh-hid/ + AMS AS73211 DRIVER M: Christian Eggers L: linux-iio@vger.kernel.org From 4f567b9f8141a86c7d878fadf136e5d1408e3e61 Mon Sep 17 00:00:00 2001 From: Sandeep Singh Date: Sat, 10 Oct 2020 01:31:36 +0530 Subject: [PATCH 02/27] SFH: PCIe driver to add support of AMD sensor fusion hub AMD SFH (Sensor Fusion Hub) is a solution running on MP2 (which is ARM core connected to x86 for processing sensor data). AMD SFH uses HID over PCI bus to form the HID descriptors and talks to HID clients like the monitor-sensor/iio-proxy. MP2 which is exposed as a PCI device to the x86, uses mailboxes to talk to MP2 firmware to send/receive commands. Co-developed-by: Nehal Shah Signed-off-by: Nehal Shah Signed-off-by: Sandeep Singh Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 2 + drivers/hid/Makefile | 2 + drivers/hid/amd-sfh-hid/Kconfig | 18 +++ drivers/hid/amd-sfh-hid/Makefile | 13 +++ drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 152 +++++++++++++++++++++++++ drivers/hid/amd-sfh-hid/amd_sfh_pcie.h | 79 +++++++++++++ 6 files changed, 266 insertions(+) create mode 100644 drivers/hid/amd-sfh-hid/Kconfig create mode 100644 drivers/hid/amd-sfh-hid/Makefile create mode 100644 drivers/hid/amd-sfh-hid/amd_sfh_pcie.c create mode 100644 drivers/hid/amd-sfh-hid/amd_sfh_pcie.h diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 612629678c84..fff3963ba02b 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -1183,4 +1183,6 @@ source "drivers/hid/i2c-hid/Kconfig" source "drivers/hid/intel-ish-hid/Kconfig" +source "drivers/hid/amd-sfh-hid/Kconfig" + endmenu diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 4acb583c92a6..014d21fe7dac 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -142,3 +142,5 @@ obj-$(CONFIG_I2C_HID) += i2c-hid/ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ + +obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ diff --git a/drivers/hid/amd-sfh-hid/Kconfig b/drivers/hid/amd-sfh-hid/Kconfig new file mode 100644 index 000000000000..db069a83e9a2 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/Kconfig @@ -0,0 +1,18 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +menu "AMD SFH HID Support" + depends on X86_64 || COMPILE_TEST + depends on PCI + depends on HID + +config AMD_SFH_HID + tristate "AMD Sensor Fusion Hub" + help + If you say yes to this option, support will be included for the + AMD Sensor Fusion Hub. + This driver will enable sensors functionality on AMD platforms + starting from 17h family of RYZEN parts. + + This driver can also be built as a module. If so, the module will + be called amd-sfh. + Say Y or M here if you want to support AMD SFH. If unsure, say N. +endmenu diff --git a/drivers/hid/amd-sfh-hid/Makefile b/drivers/hid/amd-sfh-hid/Makefile new file mode 100644 index 000000000000..35e704da5612 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/Makefile @@ -0,0 +1,13 @@ +# SPDX-License-Identifier: GPL-2.0-or-later +# +# Makefile - AMD SFH HID drivers +# Copyright (c) 2019-2020, Advanced Micro Devices, Inc. +# +# +obj-$(CONFIG_AMD_SFH_HID) += amd_sfh.o +amd_sfh-objs := amd_sfh_hid.o +amd_sfh-objs += amd_sfh_client.o +amd_sfh-objs += amd_sfh_pcie.o +amd_sfh-objs += hid_descriptor/amd_sfh_hid_desc.o + +ccflags-y += -I $(srctree)/$(src)/ diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c new file mode 100644 index 000000000000..9c5eb442e1a6 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD MP2 PCIe communication driver + * Copyright 2020 Advanced Micro Devices, Inc. + * + * Authors: Shyam Sundar S K + * Sandeep Singh + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "amd_sfh_pcie.h" + +#define DRIVER_NAME "pcie_mp2_amd" +#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver" + +#define ACEL_EN BIT(1) +#define GYRO_EN BIT(2) +#define MAGNO_EN BIT(3) +#define ALS_EN BIT(19) + +void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) +{ + union sfh_cmd_param cmd_param; + union sfh_cmd_base cmd_base; + + /* fill up command register */ + memset(&cmd_base, 0, sizeof(cmd_base)); + cmd_base.s.cmd_id = ENABLE_SENSOR; + cmd_base.s.period = info.period; + cmd_base.s.sensor_id = info.sensor_idx; + + /* fill up command param register */ + memset(&cmd_param, 0, sizeof(cmd_param)); + cmd_param.s.buf_layout = 1; + cmd_param.s.buf_length = 16; + + writeq(info.phys_address, privdata->mmio + AMD_C2P_MSG2); + writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1); + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); +} + +void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx) +{ + union sfh_cmd_base cmd_base; + + /* fill up command register */ + memset(&cmd_base, 0, sizeof(cmd_base)); + cmd_base.s.cmd_id = DISABLE_SENSOR; + cmd_base.s.period = 0; + cmd_base.s.sensor_id = sensor_idx; + + writeq(0x0, privdata->mmio + AMD_C2P_MSG2); + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); +} + +void amd_stop_all_sensors(struct amd_mp2_dev *privdata) +{ + union sfh_cmd_base cmd_base; + + /* fill up command register */ + memset(&cmd_base, 0, sizeof(cmd_base)); + cmd_base.s.cmd_id = STOP_ALL_SENSORS; + cmd_base.s.period = 0; + cmd_base.s.sensor_id = 0; + + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); +} + +int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id) +{ + int activestatus, num_of_sensors = 0; + + privdata->activecontrolstatus = readl(privdata->mmio + AMD_P2C_MSG3); + activestatus = privdata->activecontrolstatus >> 4; + if (ACEL_EN & activestatus) + sensor_id[num_of_sensors++] = accel_idx; + + if (GYRO_EN & activestatus) + sensor_id[num_of_sensors++] = gyro_idx; + + if (MAGNO_EN & activestatus) + sensor_id[num_of_sensors++] = mag_idx; + + if (ALS_EN & activestatus) + sensor_id[num_of_sensors++] = als_idx; + + return num_of_sensors; +} + +static void amd_mp2_pci_remove(void *privdata) +{ + amd_sfh_hid_client_deinit(privdata); + amd_stop_all_sensors(privdata); +} + +static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) +{ + struct amd_mp2_dev *privdata; + int rc; + + privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL); + if (!privdata) + return -ENOMEM; + + privdata->pdev = pdev; + pci_set_drvdata(pdev, privdata); + rc = pcim_enable_device(pdev); + if (rc) + return rc; + + rc = pcim_iomap_regions(pdev, BIT(2), DRIVER_NAME); + if (rc) + return rc; + + privdata->mmio = pcim_iomap_table(pdev)[2]; + pci_set_master(pdev); + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); + if (rc) { + rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + return rc; + } + rc = devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata); + if (rc) + return rc; + + return amd_sfh_hid_client_init(privdata); +} + +static const struct pci_device_id amd_mp2_pci_tbl[] = { + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) }, + { } +}; +MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl); + +static struct pci_driver amd_mp2_pci_driver = { + .name = DRIVER_NAME, + .id_table = amd_mp2_pci_tbl, + .probe = amd_mp2_pci_probe, +}; +module_pci_driver(amd_mp2_pci_driver); + +MODULE_DESCRIPTION(DRIVER_DESC); +MODULE_LICENSE("Dual BSD/GPL"); +MODULE_AUTHOR("Shyam Sundar S K "); +MODULE_AUTHOR("Sandeep Singh "); diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h new file mode 100644 index 000000000000..e8be94f935b7 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h @@ -0,0 +1,79 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * AMD MP2 PCIe communication driver + * Copyright 2020 Advanced Micro Devices, Inc. + * Authors: Shyam Sundar S K + * Sandeep Singh + */ + +#ifndef PCIE_MP2_AMD_H +#define PCIE_MP2_AMD_H + +#include + +#define PCI_DEVICE_ID_AMD_MP2 0x15E4 + +#define ENABLE_SENSOR 1 +#define DISABLE_SENSOR 2 +#define STOP_ALL_SENSORS 8 + +/* MP2 C2P Message Registers */ +#define AMD_C2P_MSG0 0x10500 +#define AMD_C2P_MSG1 0x10504 +#define AMD_C2P_MSG2 0x10508 + +/* MP2 P2C Message Registers */ +#define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */ + +/* SFH Command register */ +union sfh_cmd_base { + u32 ul; + struct { + u32 cmd_id : 8; + u32 sensor_id : 8; + u32 period : 16; + } s; +}; + +union sfh_cmd_param { + u32 ul; + struct { + u32 buf_layout : 2; + u32 buf_length : 6; + u32 rsvd : 24; + } s; +}; + +struct sfh_cmd_reg { + union sfh_cmd_base cmd_base; + union sfh_cmd_param cmd_param; + phys_addr_t phys_addr; +}; + +enum sensor_idx { + accel_idx = 0, + gyro_idx = 1, + mag_idx = 2, + als_idx = 19 +}; + +struct amd_mp2_dev { + struct pci_dev *pdev; + struct amdtp_cl_data *cl_data; + void __iomem *mmio; + u32 activecontrolstatus; +}; + +struct amd_mp2_sensor_info { + u8 sensor_idx; + u32 period; + phys_addr_t phys_address; +}; + +void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info); +void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx); +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); +#endif From 4b2c53d93a4bc9d52cc0ec354629cfc9dc217f93 Mon Sep 17 00:00:00 2001 From: Sandeep Singh Date: Sat, 10 Oct 2020 01:31:37 +0530 Subject: [PATCH 03/27] SFH:Transport Driver to add support of AMD Sensor Fusion Hub (SFH) To support AMD Sensor Fusion Hub (SFH) via the HID client's we need to register the client with the HID framework. Here we mostly address on how to register the client with the framework and define the interfaces for communication. Co-developed-by: Nehal Shah Signed-off-by: Nehal Shah Signed-off-by: Sandeep Singh Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_client.c | 246 +++++++++++++++++++++++ drivers/hid/amd-sfh-hid/amd_sfh_hid.c | 174 ++++++++++++++++ drivers/hid/amd-sfh-hid/amd_sfh_hid.h | 67 ++++++ 3 files changed, 487 insertions(+) create mode 100644 drivers/hid/amd-sfh-hid/amd_sfh_client.c create mode 100644 drivers/hid/amd-sfh-hid/amd_sfh_hid.c create mode 100644 drivers/hid/amd-sfh-hid/amd_sfh_hid.h diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_client.c b/drivers/hid/amd-sfh-hid/amd_sfh_client.c new file mode 100644 index 000000000000..3d1ccac5d99a --- /dev/null +++ b/drivers/hid/amd-sfh-hid/amd_sfh_client.c @@ -0,0 +1,246 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD SFH Client Layer + * Copyright 2020 Advanced Micro Devices, Inc. + * Authors: Nehal Bakulchandra Shah + * Sandeep Singh + */ + +#include +#include +#include +#include +#include +#include + +#include "hid_descriptor/amd_sfh_hid_desc.h" +#include "amd_sfh_pcie.h" +#include "amd_sfh_hid.h" + +#define AMD_SFH_IDLE_LOOP 200 + +struct request_list { + struct hid_device *hid; + struct list_head list; + u8 report_id; + u8 sensor_idx; + u8 report_type; + u8 current_index; +}; + +static struct request_list req_list; + +void amd_sfh_set_report(struct hid_device *hid, int report_id, + int report_type) +{ + struct amdtp_hid_data *hid_data = hid->driver_data; + struct amdtp_cl_data *cli_data = hid_data->cli_data; + int i; + + for (i = 0; i < cli_data->num_hid_devices; i++) { + if (cli_data->hid_sensor_hubs[i] == hid) { + cli_data->cur_hid_dev = i; + break; + } + } + amdtp_hid_wakeup(hid); +} + +int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type) +{ + struct amdtp_hid_data *hid_data = hid->driver_data; + struct amdtp_cl_data *cli_data = hid_data->cli_data; + int i; + + for (i = 0; i < cli_data->num_hid_devices; i++) { + if (cli_data->hid_sensor_hubs[i] == hid) { + struct request_list *new = kzalloc(sizeof(*new), GFP_KERNEL); + + if (!new) + return -ENOMEM; + + new->current_index = i; + new->sensor_idx = cli_data->sensor_idx[i]; + new->hid = hid; + new->report_type = report_type; + new->report_id = report_id; + cli_data->report_id[i] = report_id; + cli_data->request_done[i] = false; + list_add(&new->list, &req_list.list); + break; + } + } + schedule_delayed_work(&cli_data->work, 0); + return 0; +} + +static void amd_sfh_work(struct work_struct *work) +{ + struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work); + struct request_list *req_node; + u8 current_index, sensor_index; + u8 report_id, node_type; + u8 report_size = 0; + + req_node = list_last_entry(&req_list.list, struct request_list, list); + list_del(&req_node->list); + current_index = req_node->current_index; + sensor_index = req_node->sensor_idx; + report_id = req_node->report_id; + node_type = req_node->report_type; + + if (node_type == HID_FEATURE_REPORT) { + report_size = get_feature_report(sensor_index, report_id, + cli_data->feature_report[current_index]); + if (report_size) + hid_input_report(cli_data->hid_sensor_hubs[current_index], + cli_data->report_type[current_index], + cli_data->feature_report[current_index], report_size, 0); + else + pr_err("AMDSFH: Invalid report size\n"); + + } else if (node_type == HID_INPUT_REPORT) { + report_size = get_input_report(sensor_index, report_id, + cli_data->input_report[current_index], + cli_data->sensor_virt_addr[current_index]); + if (report_size) + hid_input_report(cli_data->hid_sensor_hubs[current_index], + cli_data->report_type[current_index], + cli_data->input_report[current_index], report_size, 0); + else + pr_err("AMDSFH: Invalid report size\n"); + } + cli_data->cur_hid_dev = current_index; + cli_data->sensor_requested_cnt[current_index] = 0; + amdtp_hid_wakeup(cli_data->hid_sensor_hubs[current_index]); +} + +static void amd_sfh_work_buffer(struct work_struct *work) +{ + struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work); + u8 report_size; + int i; + + for (i = 0; i < cli_data->num_hid_devices; i++) { + report_size = get_input_report(cli_data->sensor_idx[i], cli_data->report_id[i], + cli_data->input_report[i], + cli_data->sensor_virt_addr[i]); + hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT, + cli_data->input_report[i], report_size, 0); + } + schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); +} + +int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) +{ + struct amdtp_cl_data *cl_data = privdata->cl_data; + struct amd_mp2_sensor_info info; + struct device *dev; + u32 feature_report_size; + u32 input_report_size; + u8 cl_idx; + int rc, i; + + dev = &privdata->pdev->dev; + cl_data = kzalloc(sizeof(*cl_data), GFP_KERNEL); + if (!cl_data) + return -ENOMEM; + + cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]); + + INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work); + INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer); + INIT_LIST_HEAD(&req_list.list); + + for (i = 0; i < cl_data->num_hid_devices; i++) { + cl_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8, + &cl_data->sensor_phys_addr[i], + GFP_KERNEL); + cl_data->sensor_sts[i] = 0; + cl_data->sensor_requested_cnt[i] = 0; + cl_data->cur_hid_dev = i; + cl_idx = cl_data->sensor_idx[i]; + cl_data->report_descr_sz[i] = get_descr_sz(cl_idx, descr_size); + if (!cl_data->report_descr_sz[i]) { + rc = -EINVAL; + goto cleanup; + } + feature_report_size = get_descr_sz(cl_idx, feature_size); + if (!feature_report_size) { + rc = -EINVAL; + goto cleanup; + } + input_report_size = get_descr_sz(cl_idx, input_size); + if (!input_report_size) { + rc = -EINVAL; + goto cleanup; + } + cl_data->feature_report[i] = kzalloc(feature_report_size, GFP_KERNEL); + if (!cl_data->feature_report[i]) { + rc = -ENOMEM; + goto cleanup; + } + cl_data->input_report[i] = kzalloc(input_report_size, GFP_KERNEL); + if (!cl_data->input_report[i]) { + rc = -ENOMEM; + goto cleanup; + } + info.period = msecs_to_jiffies(AMD_SFH_IDLE_LOOP); + info.sensor_idx = cl_idx; + info.phys_address = cl_data->sensor_phys_addr[i]; + + cl_data->report_descr[i] = kzalloc(cl_data->report_descr_sz[i], GFP_KERNEL); + if (!cl_data->report_descr[i]) { + rc = -ENOMEM; + goto cleanup; + } + 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; + amd_start_sensor(privdata, info); + cl_data->sensor_sts[i] = 1; + } + privdata->cl_data = cl_data; + schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); + return 0; + +cleanup: + for (i = 0; i < cl_data->num_hid_devices; i++) { + if (cl_data->sensor_virt_addr[i]) { + dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int), + cl_data->sensor_virt_addr[i], + cl_data->sensor_phys_addr[i]); + } + kfree(cl_data->feature_report[i]); + kfree(cl_data->input_report[i]); + kfree(cl_data->report_descr[i]); + } + kfree(cl_data); + return rc; +} + +int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata) +{ + struct amdtp_cl_data *cl_data = privdata->cl_data; + int i; + + for (i = 0; i < cl_data->num_hid_devices; i++) + amd_stop_sensor(privdata, i); + + cancel_delayed_work_sync(&cl_data->work); + cancel_delayed_work_sync(&cl_data->work_buffer); + amdtp_hid_remove(cl_data); + + for (i = 0; i < cl_data->num_hid_devices; i++) { + if (cl_data->sensor_virt_addr[i]) { + dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int), + cl_data->sensor_virt_addr[i], + cl_data->sensor_phys_addr[i]); + } + } + kfree(cl_data); + return 0; +} diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c new file mode 100644 index 000000000000..a471079a3bd0 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c @@ -0,0 +1,174 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD MP2 Sensors transport driver + * + * Authors: Nehal Bakulchandra Shah + * Sandeep Singh + */ +#include +#include +#include + +#include "amd_sfh_hid.h" + +#define AMD_SFH_RESPONSE_TIMEOUT 1500 + +/** + * amdtp_hid_parse() - hid-core .parse() callback + * @hid: hid device instance + * + * This function gets called during call to hid_add_device + * + * Return: 0 on success and non zero on error + */ +static int amdtp_hid_parse(struct hid_device *hid) +{ + struct amdtp_hid_data *hid_data = hid->driver_data; + struct amdtp_cl_data *cli_data = hid_data->cli_data; + + return hid_parse_report(hid, cli_data->report_descr[hid_data->index], + cli_data->report_descr_sz[hid_data->index]); +} + +/* Empty callbacks with success return code */ +static int amdtp_hid_start(struct hid_device *hid) +{ + return 0; +} + +static void amdtp_hid_stop(struct hid_device *hid) +{ +} + +static int amdtp_hid_open(struct hid_device *hid) +{ + return 0; +} + +static void amdtp_hid_close(struct hid_device *hid) +{ +} + +static int amdtp_raw_request(struct hid_device *hdev, u8 reportnum, + u8 *buf, size_t len, u8 rtype, int reqtype) +{ + return 0; +} + +static void amdtp_hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype) +{ + int rc; + + switch (reqtype) { + case HID_REQ_GET_REPORT: + rc = amd_sfh_get_report(hid, rep->id, rep->type); + if (rc) + dev_err(&hid->dev, "AMDSFH get report error\n"); + break; + case HID_REQ_SET_REPORT: + amd_sfh_set_report(hid, rep->id, reqtype); + break; + default: + break; + } +} + +static int amdtp_wait_for_response(struct hid_device *hid) +{ + struct amdtp_hid_data *hid_data = hid->driver_data; + struct amdtp_cl_data *cli_data = hid_data->cli_data; + int i, ret = 0; + + for (i = 0; i < cli_data->num_hid_devices; i++) { + if (cli_data->hid_sensor_hubs[i] == hid) + break; + } + + if (!cli_data->request_done[i]) + ret = wait_event_interruptible_timeout(hid_data->hid_wait, + cli_data->request_done[i], + msecs_to_jiffies(AMD_SFH_RESPONSE_TIMEOUT)); + if (ret < 0) + return -ETIMEDOUT; + else if (ret == -ERESTARTSYS) + return -ERESTARTSYS; + else + return 0; +} + +void amdtp_hid_wakeup(struct hid_device *hid) +{ + struct amdtp_hid_data *hid_data = hid->driver_data; + struct amdtp_cl_data *cli_data = hid_data->cli_data; + + cli_data->request_done[cli_data->cur_hid_dev] = true; + wake_up_interruptible(&hid_data->hid_wait); +} + +static struct hid_ll_driver amdtp_hid_ll_driver = { + .parse = amdtp_hid_parse, + .start = amdtp_hid_start, + .stop = amdtp_hid_stop, + .open = amdtp_hid_open, + .close = amdtp_hid_close, + .request = amdtp_hid_request, + .wait = amdtp_wait_for_response, + .raw_request = amdtp_raw_request, +}; + +int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data) +{ + struct hid_device *hid; + struct amdtp_hid_data *hid_data; + int rc; + + hid = hid_allocate_device(); + if (IS_ERR(hid)) + return PTR_ERR(hid); + + hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL); + if (!hid_data) { + rc = -ENOMEM; + goto err_hid_data; + } + + hid->ll_driver = &amdtp_hid_ll_driver; + hid_data->index = cur_hid_dev; + hid_data->cli_data = cli_data; + init_waitqueue_head(&hid_data->hid_wait); + + hid->driver_data = hid_data; + cli_data->hid_sensor_hubs[cur_hid_dev] = hid; + hid->bus = BUS_AMD_AMDTP; + hid->vendor = AMD_SFH_HID_VENDOR; + hid->product = AMD_SFH_HID_PRODUCT; + snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-amdtp", + hid->vendor, hid->product); + + rc = hid_add_device(hid); + if (rc) + goto err_hid_device; + return 0; + +err_hid_device: + kfree(hid_data); +err_hid_data: + hid_destroy_device(hid); + return rc; +} + +void amdtp_hid_remove(struct amdtp_cl_data *cli_data) +{ + int i; + + for (i = 0; i < cli_data->num_hid_devices; ++i) { + kfree(cli_data->feature_report[i]); + kfree(cli_data->input_report[i]); + kfree(cli_data->report_descr[i]); + if (cli_data->hid_sensor_hubs[i]) { + kfree(cli_data->hid_sensor_hubs[i]->driver_data); + hid_destroy_device(cli_data->hid_sensor_hubs[i]); + cli_data->hid_sensor_hubs[i] = NULL; + } + } +} diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.h b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h new file mode 100644 index 000000000000..6be0783d885c --- /dev/null +++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.h @@ -0,0 +1,67 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * AMD MP2 Sensors transport driver + * + * Authors: Nehal Bakulchandra Shah + * Sandeep Singh + */ + +#ifndef AMDSFH_HID_H +#define AMDSFH_HID_H + +#define MAX_HID_DEVICES 4 +#define BUS_AMD_AMDTP 0x20 +#define AMD_SFH_HID_VENDOR 0x1022 +#define AMD_SFH_HID_PRODUCT 0x0001 + +struct amdtp_cl_data { + u8 init_done; + u32 cur_hid_dev; + u32 hid_dev_count; + u32 num_hid_devices; + struct device_info *hid_devices; + u8 *report_descr[MAX_HID_DEVICES]; + int report_descr_sz[MAX_HID_DEVICES]; + struct hid_device *hid_sensor_hubs[MAX_HID_DEVICES]; + u8 *hid_descr[MAX_HID_DEVICES]; + int hid_descr_size[MAX_HID_DEVICES]; + phys_addr_t phys_addr_base; + u32 *sensor_virt_addr[MAX_HID_DEVICES]; + phys_addr_t sensor_phys_addr[MAX_HID_DEVICES]; + u32 sensor_sts[MAX_HID_DEVICES]; + u32 sensor_requested_cnt[MAX_HID_DEVICES]; + u8 report_type[MAX_HID_DEVICES]; + u8 report_id[MAX_HID_DEVICES]; + u8 sensor_idx[MAX_HID_DEVICES]; + u8 *feature_report[MAX_HID_DEVICES]; + u8 *input_report[MAX_HID_DEVICES]; + u8 request_done[MAX_HID_DEVICES]; + struct delayed_work work; + struct delayed_work work_buffer; +}; + +/** + * struct amdtp_hid_data - Per instance HID data + * @index: Device index in the order of enumeration + * @request_done: Get Feature/Input report complete flag + * used during get/set request from hid core + * @cli_data: Link to the client instance + * @hid_wait: Completion waitq + * + * Used to tie hid->driver data to driver client instance + */ +struct amdtp_hid_data { + int index; + struct amdtp_cl_data *cli_data; + wait_queue_head_t hid_wait; +}; + +/* Interface functions between HID LL driver and AMD SFH client */ +void hid_amdtp_set_feature(struct hid_device *hid, char *buf, u32 len, int report_id); +void hid_amdtp_get_report(struct hid_device *hid, int report_id, int report_type); +int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data); +void amdtp_hid_remove(struct amdtp_cl_data *cli_data); +int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type); +void amd_sfh_set_report(struct hid_device *hid, int report_id, int report_type); +void amdtp_hid_wakeup(struct hid_device *hid); +#endif From 1434f9fc0e476362f3f3d153d48c0fc5c940a50a Mon Sep 17 00:00:00 2001 From: Sandeep Singh Date: Sat, 10 Oct 2020 01:31:38 +0530 Subject: [PATCH 04/27] SFH: Create HID report to Enable support of AMD sensor fusion Hub (SFH) Communication between HID devices and HID core is mostly done via HID reports. HID reports are formed based on the data received from the PCI layer into the HID report descriptors. Co-developed-by: Nehal Shah Signed-off-by: Nehal Shah Signed-off-by: Sandeep Singh Signed-off-by: Jiri Kosina --- .../hid_descriptor/amd_sfh_hid_desc.c | 224 ++++++ .../hid_descriptor/amd_sfh_hid_desc.h | 121 ++++ .../hid_descriptor/amd_sfh_hid_report_desc.h | 645 ++++++++++++++++++ 3 files changed, 990 insertions(+) create mode 100644 drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c create mode 100644 drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h create mode 100644 drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c new file mode 100644 index 000000000000..6e3ad66e57a4 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c @@ -0,0 +1,224 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * AMD SFH Report Descriptor generator + * Copyright 2020 Advanced Micro Devices, Inc. + * Authors: Nehal Bakulchandra Shah + * Sandeep Singh + */ + +#include +#include +#include +#include "amd_sfh_pcie.h" +#include "amd_sfh_hid_desc.h" +#include "amd_sfh_hid_report_desc.h" + +#define AMD_SFH_FW_MULTIPLIER (1000) +#define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x41 +#define HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x51 +#define HID_DEFAULT_REPORT_INTERVAL 0x50 +#define HID_DEFAULT_MIN_VALUE 0X7F +#define HID_DEFAULT_MAX_VALUE 0x80 +#define HID_DEFAULT_SENSITIVITY 0x7F +#define HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM 0x01 +/* state enums */ +#define HID_USAGE_SENSOR_STATE_READY_ENUM 0x02 +#define HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM 0x05 +#define HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM 0x04 + +int get_report_descriptor(int sensor_idx, u8 *rep_desc) +{ + switch (sensor_idx) { + case accel_idx: /* accel */ + memset(rep_desc, 0, sizeof(accel3_report_descriptor)); + memcpy(rep_desc, accel3_report_descriptor, + sizeof(accel3_report_descriptor)); + break; + case gyro_idx: /* gyro */ + memset(rep_desc, 0, sizeof(gyro3_report_descriptor)); + memcpy(rep_desc, gyro3_report_descriptor, + sizeof(gyro3_report_descriptor)); + break; + case mag_idx: /* Magnetometer */ + memset(rep_desc, 0, sizeof(comp3_report_descriptor)); + memcpy(rep_desc, comp3_report_descriptor, + sizeof(comp3_report_descriptor)); + break; + case als_idx: /* ambient light sensor */ + memset(rep_desc, 0, sizeof(als_report_descriptor)); + memcpy(rep_desc, als_report_descriptor, + sizeof(als_report_descriptor)); + break; + default: + break; + } + return 0; +} + +u32 get_descr_sz(int sensor_idx, int descriptor_name) +{ + switch (sensor_idx) { + case accel_idx: + switch (descriptor_name) { + case descr_size: + return sizeof(accel3_report_descriptor); + case input_size: + return sizeof(struct accel3_input_report); + case feature_size: + return sizeof(struct accel3_feature_report); + } + break; + case gyro_idx: + switch (descriptor_name) { + case descr_size: + return sizeof(gyro3_report_descriptor); + case input_size: + return sizeof(struct gyro_input_report); + case feature_size: + return sizeof(struct gyro_feature_report); + } + break; + case mag_idx: + switch (descriptor_name) { + case descr_size: + return sizeof(comp3_report_descriptor); + case input_size: + return sizeof(struct magno_input_report); + case feature_size: + return sizeof(struct magno_feature_report); + } + break; + case als_idx: + switch (descriptor_name) { + case descr_size: + return sizeof(als_report_descriptor); + case input_size: + return sizeof(struct als_input_report); + case feature_size: + return sizeof(struct als_feature_report); + } + break; + default: + break; + } + return 0; +} + +static void get_common_features(struct common_feature_property *common, int report_id) +{ + common->report_id = report_id; + common->connection_type = HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM; + common->report_state = HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM; + common->power_state = HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM; + common->sensor_state = HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM; + common->report_interval = HID_DEFAULT_REPORT_INTERVAL; +} + +u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report) +{ + struct accel3_feature_report acc_feature; + struct gyro_feature_report gyro_feature; + struct magno_feature_report magno_feature; + struct als_feature_report als_feature; + u8 report_size = 0; + + if (!feature_report) + return report_size; + + switch (sensor_idx) { + case accel_idx: /* accel */ + get_common_features(&acc_feature.common_property, report_id); + acc_feature.accel_change_sesnitivity = HID_DEFAULT_SENSITIVITY; + acc_feature.accel_sensitivity_min = HID_DEFAULT_MIN_VALUE; + acc_feature.accel_sensitivity_max = HID_DEFAULT_MAX_VALUE; + memcpy(feature_report, &acc_feature, sizeof(acc_feature)); + report_size = sizeof(acc_feature); + break; + case gyro_idx: /* gyro */ + get_common_features(&gyro_feature.common_property, report_id); + gyro_feature.gyro_change_sesnitivity = HID_DEFAULT_SENSITIVITY; + gyro_feature.gyro_sensitivity_min = HID_DEFAULT_MIN_VALUE; + gyro_feature.gyro_sensitivity_max = HID_DEFAULT_MAX_VALUE; + memcpy(feature_report, &gyro_feature, sizeof(gyro_feature)); + report_size = sizeof(gyro_feature); + break; + case mag_idx: /* Magnetometer */ + get_common_features(&magno_feature.common_property, report_id); + magno_feature.magno_headingchange_sensitivity = HID_DEFAULT_SENSITIVITY; + magno_feature.heading_min = HID_DEFAULT_MIN_VALUE; + magno_feature.heading_max = HID_DEFAULT_MAX_VALUE; + magno_feature.flux_change_sensitivity = HID_DEFAULT_MIN_VALUE; + magno_feature.flux_min = HID_DEFAULT_MIN_VALUE; + magno_feature.flux_max = HID_DEFAULT_MAX_VALUE; + memcpy(feature_report, &magno_feature, sizeof(magno_feature)); + report_size = sizeof(magno_feature); + break; + case als_idx: /* ambient light sensor */ + get_common_features(&als_feature.common_property, report_id); + als_feature.als_change_sesnitivity = HID_DEFAULT_SENSITIVITY; + als_feature.als_sensitivity_min = HID_DEFAULT_MIN_VALUE; + als_feature.als_sensitivity_max = HID_DEFAULT_MAX_VALUE; + memcpy(feature_report, &als_feature, sizeof(als_feature)); + report_size = sizeof(als_feature); + break; + default: + break; + } + return report_size; +} + +static void get_common_inputs(struct common_input_property *common, int report_id) +{ + common->report_id = report_id; + common->sensor_state = HID_USAGE_SENSOR_STATE_READY_ENUM; + common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM; +} + +u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor_virt_addr) +{ + struct accel3_input_report acc_input; + struct gyro_input_report gyro_input; + struct magno_input_report magno_input; + struct als_input_report als_input; + u8 report_size = 0; + + if (!sensor_virt_addr || !input_report) + return report_size; + + switch (sensor_idx) { + case accel_idx: /* accel */ + get_common_inputs(&acc_input.common_property, report_id); + acc_input.in_accel_x_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; + acc_input.in_accel_y_value = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER; + acc_input.in_accel_z_value = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER; + memcpy(input_report, &acc_input, sizeof(acc_input)); + report_size = sizeof(acc_input); + break; + case gyro_idx: /* gyro */ + get_common_inputs(&gyro_input.common_property, report_id); + gyro_input.in_angel_x_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; + gyro_input.in_angel_y_value = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER; + gyro_input.in_angel_z_value = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER; + memcpy(input_report, &gyro_input, sizeof(gyro_input)); + report_size = sizeof(gyro_input); + break; + case mag_idx: /* Magnetometer */ + get_common_inputs(&magno_input.common_property, report_id); + magno_input.in_magno_x = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; + magno_input.in_magno_y = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER; + magno_input.in_magno_z = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER; + magno_input.in_magno_accuracy = (u16)sensor_virt_addr[3] / AMD_SFH_FW_MULTIPLIER; + memcpy(input_report, &magno_input, sizeof(magno_input)); + report_size = sizeof(magno_input); + break; + case als_idx: /* Als */ + get_common_inputs(&als_input.common_property, report_id); + als_input.illuminance_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; + report_size = sizeof(als_input); + memcpy(input_report, &als_input, sizeof(als_input)); + break; + default: + break; + } + return report_size; +} diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h new file mode 100644 index 000000000000..ac9a01cc1454 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h @@ -0,0 +1,121 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * HID report descriptors, structures and routines + * Copyright 2020 Advanced Micro Devices, Inc. + * Authors: Nehal Bakulchandra Shah + * Sandeep Singh + */ + +#ifndef AMD_SFH_HID_DESCRIPTOR_H +#define AMD_SFH_HID_DESCRIPTOR_H + +enum desc_type { + /* Report descriptor name */ + descr_size = 1, + input_size, + feature_size, +}; + +struct _hid_report_descriptor { + u8 bDescriptorType; + u8 wDescriptorLength; +}; + +struct common_feature_property { + /* common properties */ + u8 report_id; + u8 connection_type; + u8 report_state; + u8 power_state; + u8 sensor_state; + u32 report_interval; +} __packed; + +struct common_input_property { + /* common properties */ + u8 report_id; + u8 sensor_state; + u8 event_type; +} __packed; + +struct _hid_device_descriptor { + u8 bLength; + u8 bDescriptorType; + u8 bcdHID[2]; + u8 bCountryCode; + u8 bNumDescriptors; + struct _hid_report_descriptor *reports; +}; + +struct accel3_feature_report { + struct common_feature_property common_property; + /* properties specific to this sensor */ + u16 accel_change_sesnitivity; + s16 accel_sensitivity_max; + s16 accel_sensitivity_min; +} __packed; + +struct accel3_input_report { + struct common_input_property common_property; + /* values specific to this sensor */ + int in_accel_x_value; + int in_accel_y_value; + int in_accel_z_value; + /* include if required to support the "shake" event */ + u8 in_accel_shake_detection; +} __packed; + +struct gyro_feature_report { + struct common_feature_property common_property; + /* properties specific to this sensor */ + u16 gyro_change_sesnitivity; + s16 gyro_sensitivity_max; + s16 gyro_sensitivity_min; +} __packed; + +struct gyro_input_report { + struct common_input_property common_property; + /* values specific to this sensor */ + int in_angel_x_value; + int in_angel_y_value; + int in_angel_z_value; +} __packed; + +struct magno_feature_report { + struct common_feature_property common_property; + /*properties specific to this sensor */ + u16 magno_headingchange_sensitivity; + s16 heading_min; + s16 heading_max; + u16 flux_change_sensitivity; + s16 flux_min; + s16 flux_max; +} __packed; + +struct magno_input_report { + struct common_input_property common_property; + int in_magno_x; + int in_magno_y; + int in_magno_z; + int in_magno_accuracy; +} __packed; + +struct als_feature_report { + struct common_feature_property common_property; + /* properties specific to this sensor */ + u16 als_change_sesnitivity; + s16 als_sensitivity_max; + s16 als_sensitivity_min; +} __packed; + +struct als_input_report { + struct common_input_property common_property; + /* values specific to this sensor */ + int illuminance_value; +} __packed; + +int get_report_descriptor(int sensor_idx, u8 rep_desc[]); +u32 get_descr_sz(int sensor_idx, int descriptor_name); +u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report); +u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor_virt_addr); +#endif diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h new file mode 100644 index 000000000000..44271d39b322 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_report_desc.h @@ -0,0 +1,645 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * HID descriptor stuructures + * Copyright 2020 Advanced Micro Devices, Inc. + * Authors: Nehal Bakulchandra Shah + * Sandeep Singh + */ + +#ifndef AMD_SFH_HID_REPORT_DESCRIPTOR_H +#define AMD_SFH_HID_REPORT_DESCRIPTOR_H + +// Accelerometer 3D Sensor +static const u8 accel3_report_descriptor[] = { +0x05, 0x20, /* Usage page */ +0x09, 0x73, /* Motion type Accel 3D */ +0xA1, 0x00, /* HID Collection (Physical) */ + +//feature reports(xmit/receive) +0x85, 1, /* HID Report ID */ +0x05, 0x20, /* HID usage page sensor */ +0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */ +0x15, 0, /* HID logical MIN_8(0) */ +0x25, 2, /* HID logical MAX_8(2) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection (logical) */ +0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel*/ +0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */ +0x0A, 0x32, 0x08, /* Sensor property connection type external sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 5, /* HID logical Max_8(5) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection(logical) */ +0x0A, 0x40, 0x08, /* Sensor property report state no events sel */ +0x0A, 0x41, 0x08, /* Sensor property report state all events sel */ +0x0A, 0x42, 0x08, /* Sensor property report state threshold events sel */ +0x0A, 0x43, 0x08, /* Sensor property report state no events wake sel */ +0x0A, 0x44, 0x08, /* Sensor property report state all events wake sel */ +0x0A, 0x45, 0x08, /* Sensor property report state threshold events wake sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x19, 0x03, /* HID usage sensor property power state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 5, /* HID logical Max_8(5) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection(logical) */ +0x0A, 0x50, 0x08, /* Sensor property power state undefined sel */ +0x0A, 0x51, 0x08, /* Sensor property power state D0 full power sel */ +0x0A, 0x52, 0x08, /* Sensor property power state D1 low power sel */ +0x0A, 0x53, 0x08, /* Sensor property power state D2 standby with wake sel */ +0x0A, 0x54, 0x08, /* Sensor property power state D3 sleep with wake sel */ +0x0A, 0x55, 0x08, /* Sensor property power state D4 power off sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x01, 0x02, /* HID usage sensor state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 6, /* HID logical Max_8(6) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection(logical) */ +0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ +0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ +0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ +0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ +0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ +0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ +0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */ +0x15, 0, /* HID logical Min_8(0) */ +0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */ + +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count(1) */ +0x55, 0, /* HID unit exponent(0) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0x52, 0x14, /* Sensor data motion accel and mod change sensitivity ABS) */ + +0x15, 0, /* HID logical Min_8(0) */ +0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */ + +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0x52, 0x24, /* HID usage sensor data (motion accel and mod max) */ + +0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ + +0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ + +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0x52, 0x34, /* HID usage sensor data (motion accel and mod min) */ + +0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ + +0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ + +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ + +//input report (transmit) +0x05, 0x20, /* HID usage page sensors */ +0x0A, 0x01, 0x02, /* HID usage sensor state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 6, /* HID logical Max_8(6) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count (1) */ +0xA1, 0x02, /* HID end collection (logical) */ +0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ +0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ +0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ +0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ +0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ +0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ +0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ +0X81, 0x00, /* HID Input (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x02, 0x02, /* HID usage sensor event */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 5, /* HID logical Max_8(5) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count (1) */ +0xA1, 0x02, /* HID end collection (logical) */ +0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */ +0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */ +0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */ +0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */ +0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */ +0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */ +0X81, 0x00, /* HID Input (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x53, 0x04, /* HID usage sensor data motion Acceleration X axis */ +0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ + +0x27, 0xFF, 0xff, 0XFF, 0XFF, /* HID logical Max_32 */ + +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ +0x0A, 0x54, 0x04, /* HID usage sensor data motion Acceleration Y axis */ +0x17, 0X00, 0X00, 0x01, 0x80, /* HID logical Min_32 */ + +0x27, 0xFF, 0xFF, 0XFF, 0XFF, /* HID logical Max_32 */ + +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ +0x0A, 0x55, 0x04, /* HID usage sensor data motion Acceleration Z axis */ +0x17, 0X00, 0X00, 0x01, 0x80, /* HID logical Min_32 */ + +0x27, 0XFF, 0XFF, 0xFF, 0x7F, /* HID logical Max_32 */ + +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ + +0x0A, 0x51, 0x04, /* HID usage sensor data motion state */ +0x15, 0, /* HID logical Min_8(0) False = Still*/ +0x25, 1, /* HID logical Min_8(1) True = In motion */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count (1) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ +0xC0 /* HID end collection */ +}; + +const u8 gyro3_report_descriptor[] = { +0x05, 0x20, /* Usage page */ +0x09, 0x76, /* Motion type Gyro3D */ +0xA1, 0x00, /* HID Collection (Physical) */ + +0x85, 2, /* HID Report ID */ +0x05, 0x20, /* HID usage page sensor */ +0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */ +0x15, 0, /* HID logical MIN_8(0) */ +0x25, 2, /* HID logical MAX_8(2) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection (logical) */ +0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */ +0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */ +0x0A, 0x32, 0x08, /* Sensor property connection type external sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 5, /* HID logical Max_8(5) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection(logical) */ +0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */ +0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */ +0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */ +0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */ +0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */ +0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x19, 0x03, /* HID usage sensor property power state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 5, /* HID logical Max_8(5) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection(logical) */ +0x0A, 0x50, 0x08, /* Sensor power state undefined sel */ +0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */ +0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */ +0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */ +0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */ +0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x01, 0x02, /* HID usage sensor state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 6, /* HID logical Max_8(6) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection(logical) */ +0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ +0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ +0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ +0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ +0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ +0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ +0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */ +0x15, 0, /* HID logical Min_8(0) */ +0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */ + +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count(1) */ +0x55, 0, /* HID unit exponent(0) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0x56, 0x14, /* Angular velocity and mod change sensitivity ABS)*/ + +0x15, 0, /* HID logical Min_8(0) */ +0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */ + +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0x56, 0x24, /* Sensor data (motion angular velocity and mod max) */ + +0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ + +0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ + +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0x56, 0x34, /* HID usage sensor data (motion accel and mod min) */ + +0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ + +0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ + +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ + +//Input reports(transmit) +0x05, 0x20, /* HID usage page sensors */ +0x0A, 0x01, 0x02, /* HID usage sensor state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 6, /* HID logical Max_8(6) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count (1) */ +0xA1, 0x02, /* HID end collection (logical) */ +0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ +0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ +0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ +0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ +0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ +0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ +0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ +0X81, 0x00, /* HID Input (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x02, 0x02, /* HID usage sensor event */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 5, /* HID logical Max_8(5) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count (1) */ +0xA1, 0x02, /* HID end collection (logical) */ +0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */ +0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */ +0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */ +0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */ +0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */ +0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */ +0X81, 0x00, /* HID Input (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x57, 0x04, /* Sensor data motion Angular velocity X axis */ +0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ + +0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ + +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ +0x0A, 0x58, 0x04, /* Sensor data motion Angular velocity Y axis */ +0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ + +0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ + +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ +0x0A, 0x59, 0x04, /* Sensor data motion Angular velocity Z axis */ +0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ + +0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ + +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ + +0xC0, /* HID end collection */ +}; + +const u8 comp3_report_descriptor[] = { +0x05, 0x20, /* Usage page */ +0x09, 0x83, /* Motion type Orientation compass 3D */ +0xA1, 0x00, /* HID Collection (Physical) */ + +0x85, 3, /* HID Report ID */ +0x05, 0x20, /* HID usage page sensor */ +0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */ +0x15, 0, /* HID logical MIN_8(0) */ +0x25, 2, /* HID logical MAX_8(2) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection (logical) */ +0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */ +0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */ +0x0A, 0x32, 0x08, /* Sensor property connection type external sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 5, /* HID logical Max_8(5) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection(logical) */ +0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */ +0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */ +0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */ +0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */ +0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */ +0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x19, 0x03, /* HID usage sensor property power state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 5, /* HID logical Max_8(5) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection(logical) */ +0x0A, 0x50, 0x08, /* Sensor power state undefined sel */ +0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */ +0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */ +0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */ +0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */ +0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x01, 0x02, /* HID usage sensor state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 6, /* HID logical Max_8(6) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection(logical) */ +0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ +0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ +0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ +0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ +0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ +0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ +0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */ +0x15, 0, /* HID logical Min_8(0) */ +0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */ +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count(1) */ +0x55, 0, /* HID unit exponent(0) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0x71, 0x14, /* Orientation and mod change sensitivity ABS)*/ +0x15, 0, /* HID logical Min_8(0) */ +0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */ +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0x71, 0x24, /* Sensor data (motion orientation and mod max) */ +0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ +0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0F, /* HID unit exponent(0x0F) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0x71, 0x34, /* Sensor data (motion orientation and mod min) */ +0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ +0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0F, /* HID unit exponent(0x0F) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0x84, 0x14, /* Maganetic flux and change sensitivity ABS) */ +0x15, 0, /* HID logical Min_8(0) */ +0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */ +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0x84, 0x24, /* Maganetic flux and mod change sensitivity Max) */ +0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ +0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0F, /* HID unit exponent(0x0F) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0x84, 0x34, /* Maganetic flux and mod change sensitivity Min */ +0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ +0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0F, /* HID unit exponent(0x0F) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ + +//Input reports(transmit) +0x05, 0x20, /* HID usage page sensors */ +0x0A, 0x01, 0x02, /* HID usage sensor state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 6, /* HID logical Max_8(6) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count (1) */ +0xA1, 0x02, /* HID end collection (logical) */ +0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ +0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ +0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ +0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ +0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ +0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ +0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ +0X81, 0x00, /* HID Input (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x02, 0x02, /* HID usage sensor event */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 5, /* HID logical Max_8(5) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count (1) */ +0xA1, 0x02, /* HID end collection (logical) */ +0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */ +0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */ +0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */ +0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */ +0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */ +0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */ +0X81, 0x00, /* HID Input (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x85, 0x04, /* Sensor data orientation magnetic flux X axis */ +0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ +0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0x55, 0x0D, /* HID unit exponent(0x0D) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ +0x0A, 0x86, 0x04, /* Sensor data orientation magnetic flux Y axis */ +0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ +0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0x55, 0x0D, /* HID unit exponent(0x0D) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ +0x0A, 0x87, 0x04, /* Sensor data orientation magnetic flux Z axis */ +0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ +0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0x55, 0x0D, /* HID unit exponent(0x0D) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ +0x0A, 0x88, 0x04, /* Sensor data orientation magnetometer accuracy */ +0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ +0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ +0xC0 /* HID end collection */ +}; + +const u8 als_report_descriptor[] = { +0x05, 0x20, /* HID usage page sensor */ +0x09, 0x41, /* HID usage sensor type Ambientlight */ +0xA1, 0x00, /* HID Collection (Physical) */ + +//feature reports(xmit/receive)// +0x85, 4, /* HID Report ID */ +0x05, 0x20, /* HID usage page sensor */ +0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */ +0x15, 0, /* HID logical MIN_8(0) */ +0x25, 2, /* HID logical MAX_8(2) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection (logical) */ +0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */ +0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */ +0x0A, 0x32, 0x08, /* Sensor property connection type external sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 5, /* HID logical Max_8(5) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection(logical) */ +0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */ +0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */ +0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */ +0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */ +0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */ +0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x19, 0x03, /* HID usage sensor property power state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 5, /* HID logical Max_8(5) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection(logical) */ +0x0A, 0x50, 0x08, /* Sensor power state undefined sel */ +0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */ +0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */ +0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */ +0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */ +0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x01, 0x02, /* HID usage sensor state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 6, /* HID logical Max_8(6) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count(1) */ +0xA1, 0x02, /* HID collection(logical) */ +0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ +0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ +0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ +0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ +0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ +0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ +0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ +0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */ +0x15, 0, /* HID logical Min_8(0) */ +0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */ +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count(1) */ +0x55, 0, /* HID unit exponent(0) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0xD1, 0xE4, /* Light illuminance and sensitivity REL PCT) */ +0x15, 0, /* HID logical Min_8(0) */ +0x26, 0x10, 0x27, /* HID logical Max_16(0x10,0x27) */ +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0E, /* HID unit exponent(0x0E) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0xD1, 0x24, /* Sensor data (Light illuminance and mod max) */ +0x15, 0, /* HID logical Min_8(0) */ +0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */ +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0F, /* HID unit exponent(0x0F) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ +0x0A, 0xD1, 0x34, /* Sensor data (Light illuminance and mod min) */ +0x15, 0, /* HID logical Min_8(0) */ +0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */ +0x75, 16, /* HID report size(16) */ +0x95, 1, /* HID report count(1) */ +0x55, 0x0F, /* HID unit exponent(0x0F) */ +0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ + +//Input reports (transmit) +0x05, 0x20, /* HID usage page sensors */ +0x0A, 0x01, 0x02, /* HID usage sensor state */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 6, /* HID logical Max_8(6) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count (1) */ +0xA1, 0x02, /* HID end collection (logical) */ +0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ +0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ +0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ +0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ +0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ +0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ +0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ +0X81, 0x00, /* HID Input (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0x02, 0x02, /* HID usage sensor event */ +0x15, 0, /* HID logical Min_8(0) */ +0x25, 5, /* HID logical Max_8(5) */ +0x75, 8, /* HID report size(8) */ +0x95, 1, /* HID report count (1) */ +0xA1, 0x02, /* HID end collection (logical) */ +0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */ +0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */ +0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */ +0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */ +0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */ +0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */ +0X81, 0x00, /* HID Input (Data_Arr_Abs) */ +0xC0, /* HID end collection */ +0x0A, 0xD1, 0x04, /* HID usage sensor data light illuminance */ +0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ +0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ +0x55, 0x0F, /* HID unit exponent(0x0F) */ +0x75, 32, /* HID report size(32) */ +0x95, 1, /* HID report count (1) */ +0X81, 0x02, /* HID Input (Data_Arr_Abs) */ +0xC0 /* HID end collection */ +}; +#endif From b92b80246e06269c1407face33fd8a57a763a145 Mon Sep 17 00:00:00 2001 From: Luke D Jones Date: Tue, 27 Oct 2020 10:02:17 +1300 Subject: [PATCH 05/27] HID: asus: Add support for ASUS N-Key keyboard The ASUS N-Key keyboard uses the productId of 0x1866 and is used in almost all modern ASUS gaming laptops with slight changes to the firmware. This patch enables: Fn+key hotkeys, keyboard backlight brightness control. Additionally this keyboard requires the LED interface to be initialized before such things as keyboard backlight control work. Signed-off-by: Luke D Jones Reviewed-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/hid-asus.c | 123 ++++++++++++++++++++++++++++++++++++----- drivers/hid/hid-ids.h | 1 + 2 files changed, 110 insertions(+), 14 deletions(-) diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index c183caf89d49..1dfe184ebf5a 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -48,6 +48,8 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define INPUT_REPORT_ID 0x5d #define FEATURE_KBD_REPORT_ID 0x5a #define FEATURE_KBD_REPORT_SIZE 16 +#define FEATURE_KBD_LED_REPORT_ID1 0x5d +#define FEATURE_KBD_LED_REPORT_ID2 0x5e #define SUPPORT_KBD_BACKLIGHT BIT(0) @@ -80,6 +82,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); #define QUIRK_T101HA_DOCK BIT(9) #define QUIRK_T90CHI BIT(10) #define QUIRK_MEDION_E1239T BIT(11) +#define QUIRK_ROG_NKEY_KEYBOARD BIT(12) #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ QUIRK_NO_INIT_REPORTS | \ @@ -332,6 +335,28 @@ static int asus_raw_event(struct hid_device *hdev, if (drvdata->quirks & QUIRK_MEDION_E1239T) return asus_e1239t_event(drvdata, data, size); + if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { + /* + * Skip these report ID, the device emits a continuous stream associated + * with the AURA mode it is in which looks like an 'echo'. + */ + if (report->id == FEATURE_KBD_LED_REPORT_ID1 || + report->id == FEATURE_KBD_LED_REPORT_ID2) { + return -1; + /* Additional report filtering */ + } else if (report->id == FEATURE_KBD_REPORT_ID) { + /* + * G14 and G15 send these codes on some keypresses with no + * discernable reason for doing so. We'll filter them out to avoid + * unmapped warning messages later. + */ + if (data[1] == 0xea || data[1] == 0xec || data[1] == 0x02 || + data[1] == 0x8a || data[1] == 0x9e) { + return -1; + } + } + } + return 0; } @@ -344,7 +369,11 @@ static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size if (!dmabuf) return -ENOMEM; - ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, dmabuf, + /* + * The report ID should be set from the incoming buffer due to LED and key + * interfaces having different pages + */ + ret = hid_hw_raw_request(hdev, buf[0], dmabuf, buf_size, HID_FEATURE_REPORT, HID_REQ_SET_REPORT); kfree(dmabuf); @@ -397,6 +426,51 @@ static int asus_kbd_get_functions(struct hid_device *hdev, return ret; } +static int rog_nkey_led_init(struct hid_device *hdev) +{ + u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 }; + u8 buf_init2[] = { FEATURE_KBD_LED_REPORT_ID1, 0x41, 0x53, 0x55, 0x53, 0x20, + 0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; + u8 buf_init3[] = { FEATURE_KBD_LED_REPORT_ID1, + 0x05, 0x20, 0x31, 0x00, 0x08 }; + int ret; + + hid_info(hdev, "Asus initialise N-KEY Device"); + /* The first message is an init start */ + ret = asus_kbd_set_report(hdev, buf_init_start, sizeof(buf_init_start)); + if (ret < 0) { + hid_warn(hdev, "Asus failed to send init start command: %d\n", ret); + return ret; + } + /* Followed by a string */ + ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2)); + if (ret < 0) { + hid_warn(hdev, "Asus failed to send init command 1.0: %d\n", ret); + return ret; + } + /* Followed by a string */ + ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3)); + if (ret < 0) { + hid_warn(hdev, "Asus failed to send init command 1.1: %d\n", ret); + return ret; + } + + /* begin second report ID with same data */ + buf_init2[0] = FEATURE_KBD_LED_REPORT_ID2; + buf_init3[0] = FEATURE_KBD_LED_REPORT_ID2; + + ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2)); + if (ret < 0) { + hid_warn(hdev, "Asus failed to send init command 2.0: %d\n", ret); + return ret; + } + ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3)); + if (ret < 0) + hid_warn(hdev, "Asus failed to send init command 2.1: %d\n", ret); + + return ret; +} + static void asus_kbd_backlight_set(struct led_classdev *led_cdev, enum led_brightness brightness) { @@ -460,19 +534,25 @@ static int asus_kbd_register_leds(struct hid_device *hdev) unsigned char kbd_func; int ret; - /* Initialize keyboard */ - ret = asus_kbd_init(hdev); - if (ret < 0) - return ret; + if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { + ret = rog_nkey_led_init(hdev); + if (ret < 0) + return ret; + } else { + /* Initialize keyboard */ + ret = asus_kbd_init(hdev); + if (ret < 0) + return ret; - /* Get keyboard functions */ - ret = asus_kbd_get_functions(hdev, &kbd_func); - if (ret < 0) - return ret; + /* Get keyboard functions */ + ret = asus_kbd_get_functions(hdev, &kbd_func); + if (ret < 0) + return ret; - /* Check for backlight support */ - if (!(kbd_func & SUPPORT_KBD_BACKLIGHT)) - return -ENODEV; + /* Check for backlight support */ + if (!(kbd_func & SUPPORT_KBD_BACKLIGHT)) + return -ENODEV; + } drvdata->kbd_backlight = devm_kzalloc(&hdev->dev, sizeof(struct asus_kbd_leds), @@ -751,8 +831,8 @@ static int asus_input_mapping(struct hid_device *hdev, usage->hid == (HID_UP_GENDEVCTRLS | 0x0026))) return -1; - /* ASUS-specific keyboard hotkeys */ - if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) { + /* ASUS-specific keyboard hotkeys and led backlight */ + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR) { switch (usage->hid & HID_USAGE) { case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break; case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break; @@ -780,6 +860,18 @@ static int asus_input_mapping(struct hid_device *hdev, /* Fn+F5 "fan" symbol on FX503VD */ case 0x99: asus_map_key_clear(KEY_PROG4); break; + /* Fn+F5 "fan" symbol on N-Key keyboard */ + case 0xae: asus_map_key_clear(KEY_PROG4); break; + + /* Fn+Ret "Calc" symbol on N-Key keyboard */ + case 0x92: asus_map_key_clear(KEY_CALC); break; + + /* Fn+Left Aura mode previous on N-Key keyboard */ + case 0xb2: asus_map_key_clear(KEY_PROG2); break; + + /* Fn+Right Aura mode next on N-Key keyboard */ + case 0xb3: asus_map_key_clear(KEY_PROG3); break; + default: /* ASUS lazily declares 256 usages, ignore the rest, * as some make the keyboard appear as a pointer device. */ @@ -1126,6 +1218,9 @@ static const struct hid_device_id asus_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD), QUIRK_USE_KBD_BACKLIGHT }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, + USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD), + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD), QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d69842f79fc6..5077c05fada1 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -190,6 +190,7 @@ #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854 #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837 #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822 +#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866 #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 #define USB_VENDOR_ID_ATEN 0x0557 From 4b393f0f76c8e3ce80b3bd524dc40bd674a29101 Mon Sep 17 00:00:00 2001 From: Sandeep Singh Date: Wed, 28 Oct 2020 14:30:10 +0530 Subject: [PATCH 06/27] AMD_SFH: Fix for incorrect Sensor index It appears like the accelerometer/magnetometer and gyroscope indices were interchanged in the patch series which got into for-5.11/amd-sfh-hid until Mandoli/Richard reported to us. Ideally sensor indices should be 0,1,2 for the accelerometer, Gyroscope, Magnetometer respectively, but this interchanged possibly could be because i was using a test MP2 firmware on my machine. This patch fixes the earlier commit with the right sensor indices and also removing unused structures _hid_report_descriptor, _hid_device_descriptor as reported by Richard. Fixes: 4f567b9f8141 ("SFH: PCIe driver to add support of AMD sensor fusion hub 4f567b9f8141") Reported-by: Mandoli Reported-by: Richard Neumann Signed-off-by: Sandeep Singh Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 6 +++--- .../amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h | 14 -------------- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index 9c5eb442e1a6..a51c7b76283b 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -20,9 +20,9 @@ #define DRIVER_NAME "pcie_mp2_amd" #define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver" -#define ACEL_EN BIT(1) -#define GYRO_EN BIT(2) -#define MAGNO_EN BIT(3) +#define ACEL_EN BIT(0) +#define GYRO_EN BIT(1) +#define MAGNO_EN BIT(2) #define ALS_EN BIT(19) void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) diff --git a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h index ac9a01cc1454..095c471d8fd6 100644 --- a/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h @@ -16,11 +16,6 @@ enum desc_type { feature_size, }; -struct _hid_report_descriptor { - u8 bDescriptorType; - u8 wDescriptorLength; -}; - struct common_feature_property { /* common properties */ u8 report_id; @@ -38,15 +33,6 @@ struct common_input_property { u8 event_type; } __packed; -struct _hid_device_descriptor { - u8 bLength; - u8 bDescriptorType; - u8 bcdHID[2]; - u8 bCountryCode; - u8 bNumDescriptors; - struct _hid_report_descriptor *reports; -}; - struct accel3_feature_report { struct common_feature_property common_property; /* properties specific to this sensor */ From afdd34c5fa4028976ee5103ac499edbddedc813e Mon Sep 17 00:00:00 2001 From: Coiby Xu Date: Wed, 21 Oct 2020 22:33:05 +0800 Subject: [PATCH 07/27] HID: i2c-hid: show the error when failing to fetch the HID descriptor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit i2c_hid_probe() should notify the user of the error of failing to fetch the HID Descriptor instead of silently exiting. Link: https://forum.manjaro.org/t/elan-touchpad-working-in-live-but-not-in-native-os/31860/55 Cc: Barnabás Pőcze Signed-off-by: Coiby Xu Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-core.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index 786e3e9af1c9..577d324be16d 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -1099,8 +1099,11 @@ static int i2c_hid_probe(struct i2c_client *client, } ret = i2c_hid_fetch_hid_descriptor(ihid); - if (ret < 0) + if (ret < 0) { + dev_err(&client->dev, + "Failed to fetch the HID Descriptor\n"); goto err_regulator; + } ret = i2c_hid_init_irq(client); if (ret < 0) From c6838eeef2fbc7e3e1f83759aa016ae6b70c643e Mon Sep 17 00:00:00 2001 From: "dmitry.torokhov@gmail.com" Date: Wed, 30 Sep 2020 15:47:13 -0700 Subject: [PATCH 08/27] HID: hid-input: occasionally report stylus battery even if not changed There are styluses that only report their battery status when they are touching the touchscreen; additionally we currently suppress battery reports if capacity has not changed. To help userspace recognize how long ago the device reported battery status, let's send the change event through if either capacity has changed, or at least 30 seconds have passed since last report we've let through. Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 5 ++++- include/linux/hid.h | 1 + 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 9770db624bfa..b0db2a2ac15a 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -534,9 +534,12 @@ static void hidinput_update_battery(struct hid_device *dev, int value) capacity = hidinput_scale_battery_capacity(dev, value); if (dev->battery_status != HID_BATTERY_REPORTED || - capacity != dev->battery_capacity) { + capacity != dev->battery_capacity || + ktime_after(ktime_get_coarse(), dev->battery_ratelimit_time)) { dev->battery_capacity = capacity; dev->battery_status = HID_BATTERY_REPORTED; + dev->battery_ratelimit_time = + ktime_add_ms(ktime_get_coarse(), 30 * 1000); power_supply_changed(dev->battery); } } diff --git a/include/linux/hid.h b/include/linux/hid.h index 58684657960b..b079146850e6 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -585,6 +585,7 @@ struct hid_device { /* device report descriptor */ __s32 battery_report_id; enum hid_battery_status battery_status; bool battery_avoid_query; + ktime_t battery_ratelimit_time; #endif unsigned long status; /* see STAT flags above */ From 907286d1420d28bead47da37b9a081377c070322 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 3 Nov 2020 11:30:49 +0100 Subject: [PATCH 09/27] HID: SFH: Add documentation Add Documentation/hid/amd-sfh-hid.rst file which was by mistake dropped by me when applying the series. Fixes: 302f0dad8c97a11ab ("SFH: Add maintainers and documentation for AMD SFH based on HID framework") Reported-by: Lukas Bulwahn Originally-by: Sandeep Singh Signed-off-by: Jiri Kosina --- Documentation/hid/amd-sfh-hid.rst | 145 ++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 Documentation/hid/amd-sfh-hid.rst diff --git a/Documentation/hid/amd-sfh-hid.rst b/Documentation/hid/amd-sfh-hid.rst new file mode 100644 index 000000000000..1f2fe29ccd4f --- /dev/null +++ b/Documentation/hid/amd-sfh-hid.rst @@ -0,0 +1,145 @@ +.. SPDX-License-Identifier: GPL-2.0 + + +AMD Sensor Fusion Hub +===================== +AMD Sensor Fusion Hub (SFH) is part of an SOC starting from Ryzen based platforms. +The solution is working well on several OEM products. AMD SFH uses HID over PCIe bus. +In terms of architecture it resembles ISH, however the major difference is all +the HID reports are generated as part of the kernel driver. + +1. Block Diagram +================ + +:: + + --------------------------------- + | HID User Space Applications | + - ------------------------------- + + --------------------------------------------- + --------------------------------- + | HID Core | + --------------------------------- + + --------------------------------- + | AMD HID Transport | + --------------------------------- + + -------------------------------- + | AMD HID Client | + | with HID Report Generator| + -------------------------------- + + -------------------------------- + | AMD MP2 PCIe Driver | + -------------------------------- + OS + --------------------------------------------- + Hardware + Firmware + -------------------------------- + | SFH MP2 Processor | + -------------------------------- + + +AMD HID Transport Layer +----------------------- +AMD SFH transport is also implemented as a bus. Each client application executing in the AMD MP2 is +registered as a device on this bus. Here: MP2 which is an ARM core connected to x86 for processing +sensor data. The layer, which binds each device (AMD SFH HID driver) identifies the device type and +registers with the hid core. Transport layer attach a constant "struct hid_ll_driver" object with +each device. Once a device is registered with HID core, the callbacks provided via this struct are +used by HID core to communicate with the device. AMD HID Transport layer implements the synchronous calls. + +AMD HID Client Layer +-------------------- +This layer is responsible to implement HID request and descriptors. As firmware is OS agnostic, HID +client layer fills the HID request structure and descriptors. HID client layer is complex as it is +interface between MP2 PCIe layer and HID. HID client layer initialized the MP2 PCIe layer and holds +the instance of MP2 layer. It identifies the number of sensors connected using MP2-PCIe layer. Base +on that allocates the DRAM address for each and every sensor and pass it to MP2-PCIe driver.On +enumeration of each the sensor, client layer fills the HID Descriptor structure and HID input repor +structure. HID Feature report structure is optional. The report descriptor structure varies from +sensor to sensor. + +AMD MP2 PCIe layer +------------------ +MP2 PCIe Layer is responsible for making all transactions with the firmware over PCIe. +The connection establishment between firmware and PCIe happens here. + +The communication between X86 and MP2 is split into three parts. +1. Command transfer via the C2P mailbox registers. +2. Data transfer via DRAM. +3. Supported sensor info via P2C registers. + +Commands are sent to MP2 using C2P Mailbox registers. Writing into C2P Message registers generate +interrupt to MP2. The client layer allocates the physical memory and the same is sent to MP2 via +the PCI layer. MP2 firmware writes the command output to the access DRAM memory which the client +layer has allocated. Firmware always writes minimum of 32 bytes into DRAM. So as a protocol driver +shall allocate minimum of 32 bytes DRAM space. + +Enumeration and Probing flow +---------------------------- +:: + + HID AMD AMD AMD -PCIe MP2 + Core Transport Client layer layer FW + | | | | | + | | | on Boot Driver Loaded | + | | | | | + | | | MP2-PCIe Int | + | | | | | + | | |---Get Number of sensors-> | | + | | | Read P2C | + | | | Register | + | | | | | + | | | Loop(for No of Sensors) | | + | | |----------------------| | | + | | | Create HID Descriptor| | | + | | | Create Input report | | | + | | | Descriptor Map | | | + | | | the MP2 FW Index to | | | + | | | HID Index | | | + | | | Allocate the DRAM | Enable | + | | | address | Sensors | + | | |----------------------| | | + | | HID transport| | Enable | + | |<--Probe------| |---Sensor CMD--> | + | | Create the | | | + | | HID device | | | + | | (MFD) | | | + | | by Populating| | | + | | the HID | | | + | | ll_driver | | | + | HID | | | | + | add | | | | + |Device | | | | + |<------------- | | | | + + +Data Flow from Application to the AMD SFH Driver +------------------------------------------------ + +:: + + | | | | | + | | | | | + | | | | | + | | | | | + | | | | | + |HID_req | | | | + |get_report | | | | + |------------->| | | | + | | HID_get_input| | | + | | report | | | + | |------------->|------------------------| | | + | | | Read the DRAM data for| | | + | | | requested sensor and | | | + | | | create the HID input | | | + | | | report | | | + | | |------------------------| | | + | |Data received | | | + | | in HID report| | | + To |<-------------|<-------------| | | + Applications| | | | | + <-------| | | | | From 6e6eae04f5123b7b2f4265f7a702b5200fa5863b Mon Sep 17 00:00:00 2001 From: Colin Ian King Date: Fri, 30 Oct 2020 14:30:02 +0000 Subject: [PATCH 10/27] SFH: fix error return check for -ERESTARTSYS Currently the check for the error return code -ERESTARTSYS is dead code and never executed because a previous check for ret < 0 is catching this and returning -ETIMEDOUT instead. Fix this by checking for -ERESTARTSYS before the more generic negative error code. Addresses-Coverity: ("Logically dead code") Fixes: 4b2c53d93a4b ("SFH:Transport Driver to add support of AMD Sensor Fusion Hub (SFH)") Signed-off-by: Colin Ian King Reviewed-by: Sandeep Singh Signed-off-by: Jiri Kosina --- drivers/hid/amd-sfh-hid/amd_sfh_hid.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c index a471079a3bd0..4f989483aa03 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_hid.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_hid.c @@ -88,10 +88,10 @@ static int amdtp_wait_for_response(struct hid_device *hid) ret = wait_event_interruptible_timeout(hid_data->hid_wait, cli_data->request_done[i], msecs_to_jiffies(AMD_SFH_RESPONSE_TIMEOUT)); - if (ret < 0) - return -ETIMEDOUT; - else if (ret == -ERESTARTSYS) + if (ret == -ERESTARTSYS) return -ERESTARTSYS; + else if (ret < 0) + return -ETIMEDOUT; else return 0; } From a76a6c1893b0806657cb747c3c8949d3103fbc3f Mon Sep 17 00:00:00 2001 From: Roderick Colenbrander Date: Mon, 9 Nov 2020 23:22:27 -0800 Subject: [PATCH 11/27] HID: sony: Report more accurate DS4 power status. This patch moves the power supply status logic to DS3/DS4 parse_report, to allow for more accurate DS4 status reporting. The DS4 power status code was actually incorrect, but reported okay'ish data in most cases. There was a different interpretation of the battery_info values 0-10 or 0-9 depending on cable state. It added +1 to extend the range to 0-10. This is actually incorrect, there is no different range. Values higher than 11 actually indicates 'full' and 14/15 'error' for which we reported 100% and a valid power state. Moving the status logic to parse_report avoids having to pass more state to the generic sony_battery_get_property and simplifies the code. Signed-off-by: Roderick Colenbrander Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 85 +++++++++++++++++++++++++----------------- 1 file changed, 50 insertions(+), 35 deletions(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 2f073f536070..81d526a5d003 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -562,9 +562,8 @@ struct sony_sc { u8 hotplug_worker_initialized; u8 state_worker_initialized; u8 defer_initialization; - u8 cable_state; - u8 battery_charging; u8 battery_capacity; + int battery_status; u8 led_state[MAX_LEDS]; u8 led_delay_on[MAX_LEDS]; u8 led_delay_off[MAX_LEDS]; @@ -892,7 +891,8 @@ static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size) static const u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 }; unsigned long flags; int offset; - u8 cable_state, battery_capacity, battery_charging; + u8 battery_capacity; + int battery_status; /* * The sixaxis is charging if the battery value is 0xee @@ -904,19 +904,16 @@ static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size) if (rd[offset] >= 0xee) { battery_capacity = 100; - battery_charging = !(rd[offset] & 0x01); - cable_state = 1; + battery_status = (rd[offset] & 0x01) ? POWER_SUPPLY_STATUS_FULL : POWER_SUPPLY_STATUS_CHARGING; } else { u8 index = rd[offset] <= 5 ? rd[offset] : 5; battery_capacity = sixaxis_battery_capacity[index]; - battery_charging = 0; - cable_state = 0; + battery_status = POWER_SUPPLY_STATUS_DISCHARGING; } spin_lock_irqsave(&sc->lock, flags); - sc->cable_state = cable_state; sc->battery_capacity = battery_capacity; - sc->battery_charging = battery_charging; + sc->battery_status = battery_status; spin_unlock_irqrestore(&sc->lock, flags); if (sc->quirks & SIXAXIS_CONTROLLER) { @@ -944,7 +941,8 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) struct input_dev *input_dev = hidinput->input; unsigned long flags; int n, m, offset, num_touch_data, max_touch_data; - u8 cable_state, battery_capacity, battery_charging; + u8 cable_state, battery_capacity; + int battery_status; u16 timestamp; /* When using Bluetooth the header is 2 bytes longer, so skip these. */ @@ -1049,29 +1047,52 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) */ offset = data_offset + DS4_INPUT_REPORT_BATTERY_OFFSET; cable_state = (rd[offset] >> 4) & 0x01; - battery_capacity = rd[offset] & 0x0F; /* - * When a USB power source is connected the battery level ranges from - * 0 to 10, and when running on battery power it ranges from 0 to 9. - * A battery level above 10 when plugged in means charge completed. + * Interpretation of the battery_capacity data depends on the cable state. + * When no cable is connected (bit4 is 0): + * - 0:10: percentage in units of 10%. + * When a cable is plugged in: + * - 0-10: percentage in units of 10%. + * - 11: battery is full + * - 14: not charging due to Voltage or temperature error + * - 15: charge error */ - if (!cable_state || battery_capacity > 10) - battery_charging = 0; - else - battery_charging = 1; + if (cable_state) { + u8 battery_data = rd[offset] & 0xf; - if (!cable_state) - battery_capacity++; - if (battery_capacity > 10) - battery_capacity = 10; + if (battery_data < 10) { + /* Take the mid-point for each battery capacity value, + * because on the hardware side 0 = 0-9%, 1=10-19%, etc. + * This matches official platform behavior, which does + * the same. + */ + battery_capacity = battery_data * 10 + 5; + battery_status = POWER_SUPPLY_STATUS_CHARGING; + } else if (battery_data == 10) { + battery_capacity = 100; + battery_status = POWER_SUPPLY_STATUS_CHARGING; + } else if (battery_data == 11) { + battery_capacity = 100; + battery_status = POWER_SUPPLY_STATUS_FULL; + } else { /* 14, 15 and undefined values */ + battery_capacity = 0; + battery_status = POWER_SUPPLY_STATUS_UNKNOWN; + } + } else { + u8 battery_data = rd[offset] & 0xf; - battery_capacity *= 10; + if (battery_data < 10) + battery_capacity = battery_data * 10 + 5; + else /* 10 */ + battery_capacity = 100; + + battery_status = POWER_SUPPLY_STATUS_DISCHARGING; + } spin_lock_irqsave(&sc->lock, flags); - sc->cable_state = cable_state; sc->battery_capacity = battery_capacity; - sc->battery_charging = battery_charging; + sc->battery_status = battery_status; spin_unlock_irqrestore(&sc->lock, flags); /* @@ -2300,12 +2321,12 @@ static int sony_battery_get_property(struct power_supply *psy, struct sony_sc *sc = power_supply_get_drvdata(psy); unsigned long flags; int ret = 0; - u8 battery_charging, battery_capacity, cable_state; + u8 battery_capacity; + int battery_status; spin_lock_irqsave(&sc->lock, flags); - battery_charging = sc->battery_charging; battery_capacity = sc->battery_capacity; - cable_state = sc->cable_state; + battery_status = sc->battery_status; spin_unlock_irqrestore(&sc->lock, flags); switch (psp) { @@ -2319,13 +2340,7 @@ static int sony_battery_get_property(struct power_supply *psy, val->intval = battery_capacity; break; case POWER_SUPPLY_PROP_STATUS: - if (battery_charging) - val->intval = POWER_SUPPLY_STATUS_CHARGING; - else - if (battery_capacity == 100 && cable_state) - val->intval = POWER_SUPPLY_STATUS_FULL; - else - val->intval = POWER_SUPPLY_STATUS_DISCHARGING; + val->intval = battery_status; break; default: ret = -EINVAL; From 1a8212e8fd1f50249f30e995460b17c0850c3212 Mon Sep 17 00:00:00 2001 From: Roderick Colenbrander Date: Mon, 9 Nov 2020 23:22:29 -0800 Subject: [PATCH 12/27] HID: sony: Don't use fw_version/hw_version for sysfs cleanup. The DS4 dongle reports fw_version and hw_version as 0 when no actual DS4 is connected to it. This prevents cleaning up sysfs nodes upon device remove. This patch decouples sysfs cleanup from the fw_version and hw_version values by introducing boolean values. Signed-off-by: Roderick Colenbrander Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 81d526a5d003..485455c300f2 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -550,7 +550,9 @@ struct sony_sc { struct power_supply_desc battery_desc; int device_id; unsigned fw_version; + bool fw_version_created; unsigned hw_version; + bool hw_version_created; u8 *output_report_dmabuf; #ifdef CONFIG_SONY_FF @@ -2738,19 +2740,17 @@ static int sony_input_configured(struct hid_device *hdev, ret = device_create_file(&sc->hdev->dev, &dev_attr_firmware_version); if (ret) { - /* Make zero for cleanup reasons of sysfs entries. */ - sc->fw_version = 0; - sc->hw_version = 0; hid_err(sc->hdev, "can't create sysfs firmware_version attribute err: %d\n", ret); goto err_stop; } + sc->fw_version_created = true; ret = device_create_file(&sc->hdev->dev, &dev_attr_hardware_version); if (ret) { - sc->hw_version = 0; hid_err(sc->hdev, "can't create sysfs hardware_version attribute err: %d\n", ret); goto err_stop; } + sc->hw_version_created = true; /* * The Dualshock 4 touchpad supports 2 touches and has a @@ -2842,9 +2842,9 @@ err_stop: */ if (sc->ds4_bt_poll_interval) device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); - if (sc->fw_version) + if (sc->fw_version_created) device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version); - if (sc->hw_version) + if (sc->hw_version_created) device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version); sony_cancel_work_sync(sc); sony_remove_dev_list(sc); @@ -2929,10 +2929,10 @@ static void sony_remove(struct hid_device *hdev) if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); - if (sc->fw_version) + if (sc->fw_version_created) device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version); - if (sc->hw_version) + if (sc->hw_version_created) device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version); sony_cancel_work_sync(sc); From f5dc93b7875bcb8be77baa792cc9432aaf65365b Mon Sep 17 00:00:00 2001 From: Roderick Colenbrander Date: Mon, 9 Nov 2020 23:22:28 -0800 Subject: [PATCH 13/27] HID: sony: Workaround for DS4 dongle hotplug kernel crash. The hid-sony driver has custom DS4 connect/disconnect logic for the DS4 dongle, which is a USB dongle acting as a proxy to Bluetooth connected DS4. The connect/disconnect logic works fine generally, however not in conjunction with Steam. Steam implements its own DS4 driver using hidraw. Both hid-sony and Steam are issuing their own HID requests and are racing each other during DS4 dongle connect/disconnect resulting in a kernel crash in hid-sony. The problem is that upon a DS4 connect to the dongle, hid-sony kicks of 'ds4_get_calibration_data' from within its dongle hotplug code. The calibration code issues raw HID feature report for reportID 0x02. When Steam is running, it issues a feature report for reportID 0x12 typically just prior to hid-sony requesting feature reportID 0x02. The result is that 'ds4_get_calibration_data' receives the data Steam requested as that's the HID report returing first. Currently this results in it processing invalid data, which ultimately results in a divide by zero upon a future 'dualshock4_parse_report'. The solution for now is to check within 'ds4_get_calibration_data' to check if we received data for the feature report we issued and if not retry. This fixes bug 206785. Signed-off-by: Roderick Colenbrander Signed-off-by: Jiri Kosina --- drivers/hid/hid-sony.c | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 2f073f536070..c7baedfc78bd 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -1597,16 +1597,38 @@ static int dualshock4_get_calibration_data(struct sony_sc *sc) * of the controller, so that it sends input reports of type 0x11. */ if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) { + int retries; + buf = kmalloc(DS4_FEATURE_REPORT_0x02_SIZE, GFP_KERNEL); if (!buf) return -ENOMEM; - ret = hid_hw_raw_request(sc->hdev, 0x02, buf, - DS4_FEATURE_REPORT_0x02_SIZE, - HID_FEATURE_REPORT, - HID_REQ_GET_REPORT); - if (ret < 0) - goto err_stop; + /* We should normally receive the feature report data we asked + * for, but hidraw applications such as Steam can issue feature + * reports as well. In particular for Dongle reconnects, Steam + * and this function are competing resulting in often receiving + * data for a different HID report, so retry a few times. + */ + for (retries = 0; retries < 3; retries++) { + ret = hid_hw_raw_request(sc->hdev, 0x02, buf, + DS4_FEATURE_REPORT_0x02_SIZE, + HID_FEATURE_REPORT, + HID_REQ_GET_REPORT); + if (ret < 0) + goto err_stop; + + if (buf[0] != 0x02) { + if (retries < 2) { + hid_warn(sc->hdev, "Retrying DualShock 4 get calibration report (0x02) request\n"); + continue; + } else { + ret = -EILSEQ; + goto err_stop; + } + } else { + break; + } + } } else { u8 bthdr = 0xA3; u32 crc; From 9735d9deb109afaab747fb853b804cb5dc144c0a Mon Sep 17 00:00:00 2001 From: Jing Xiangfeng Date: Tue, 10 Nov 2020 11:20:49 +0800 Subject: [PATCH 14/27] HID: intel-ish-hid: Remove unnecessary assignment to variable rv This assignment to rv is unused in an error path. So remove it. Signed-off-by: Jing Xiangfeng Signed-off-by: Jiri Kosina --- drivers/hid/intel-ish-hid/ishtp-hid.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/drivers/hid/intel-ish-hid/ishtp-hid.c b/drivers/hid/intel-ish-hid/ishtp-hid.c index b8aae69ad15d..393bed0abee9 100644 --- a/drivers/hid/intel-ish-hid/ishtp-hid.c +++ b/drivers/hid/intel-ish-hid/ishtp-hid.c @@ -211,10 +211,8 @@ int ishtp_hid_probe(unsigned int cur_hid_dev, struct ishtp_hid_data *hid_data; hid = hid_allocate_device(); - if (IS_ERR(hid)) { - rv = PTR_ERR(hid); - return -ENOMEM; - } + if (IS_ERR(hid)) + return PTR_ERR(hid); hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL); if (!hid_data) { From ba876cdc6ac9702138000d06613484de3de760db Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Thu, 19 Nov 2020 14:27:27 +0100 Subject: [PATCH 15/27] HID: logitech-hidpp: Add hid_device_id for V470 bluetooth mouse The Logitech V470 bluetooth mouse supports HID++-1.0 over bluetooth, add its id to the hidpp driver so that it handles it. This enables battery monitoring support. Note this mouse does not support hi-resolution scroll-wheel events. Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/hid-logitech-hidpp.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hid/hid-logitech-hidpp.c b/drivers/hid/hid-logitech-hidpp.c index 0ca723119547..f85781464807 100644 --- a/drivers/hid/hid-logitech-hidpp.c +++ b/drivers/hid/hid-logitech-hidpp.c @@ -4048,6 +4048,8 @@ static const struct hid_device_id hidpp_devices[] = { { /* MX5500 keyboard over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b), .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, + { /* M-RCQ142 V470 Cordless Laser Mouse over Bluetooth */ + HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb008) }, { /* MX Master mouse over Bluetooth */ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb012), .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, From cae96a5d2bf38401b0e380f9025c375e99ac5a57 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 20 Nov 2020 12:33:24 -0600 Subject: [PATCH 16/27] HID: usbhid: Fix fall-through warnings for Clang In preparation to enable -Wimplicit-fallthrough for Clang, fix a couple of warnings by explicitly adding a couple of break statements instead of letting the code fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hid-core.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c index 17a29ee0ac6c..86257ce6d619 100644 --- a/drivers/hid/usbhid/hid-core.c +++ b/drivers/hid/usbhid/hid-core.c @@ -438,6 +438,7 @@ static void hid_irq_out(struct urb *urb) break; case -ESHUTDOWN: /* unplug */ unplug = 1; + break; case -EILSEQ: /* protocol error or unplug */ case -EPROTO: /* protocol error or unplug */ case -ECONNRESET: /* unlink */ @@ -489,6 +490,7 @@ static void hid_ctrl(struct urb *urb) break; case -ESHUTDOWN: /* unplug */ unplug = 1; + break; case -EILSEQ: /* protocol error or unplug */ case -EPROTO: /* protocol error or unplug */ case -ECONNRESET: /* unlink */ From 6b5542752605ccf2184f495fae518fac1d573226 Mon Sep 17 00:00:00 2001 From: "Gustavo A. R. Silva" Date: Fri, 20 Nov 2020 12:33:29 -0600 Subject: [PATCH 17/27] HID: input: Fix fall-through warnings for Clang In preparation to enable -Wimplicit-fallthrough for Clang, fix a warning by explicitly adding a goto statement instead of letting the code fall through to the next case. Link: https://github.com/KSPP/linux/issues/115 Signed-off-by: Gustavo A. R. Silva Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 1 + 1 file changed, 1 insertion(+) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index b0db2a2ac15a..fb565902a8c3 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -746,6 +746,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel field->flags |= HID_MAIN_ITEM_RELATIVE; break; } + goto unknown; default: goto unknown; } From 2a6a35a9ecddb2b1d58f4948f471b3be8c506640 Mon Sep 17 00:00:00 2001 From: Rikard Falkeborn Date: Wed, 25 Nov 2020 00:01:09 +0100 Subject: [PATCH 18/27] HID: wacom: Constify attribute_groups These are never modified, so make them const to allow the compiler to put them in read-only memory. It also allows the compiler to shrink the resulting module with ~900 bytes, test-built with gcc 10.2 on x86_64. text data bss dec hex filename 204377 42832 576 247785 3c7e9 drivers/hid/wacom_old.ko 204240 42064 576 246880 3c460 drivers/hid/wacom_new.ko Signed-off-by: Rikard Falkeborn Signed-off-by: Jiri Kosina --- drivers/hid/wacom_sys.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/drivers/hid/wacom_sys.c b/drivers/hid/wacom_sys.c index cd71e7133944..045c464228d9 100644 --- a/drivers/hid/wacom_sys.c +++ b/drivers/hid/wacom_sys.c @@ -1173,7 +1173,7 @@ static struct attribute *cintiq_led_attrs[] = { NULL }; -static struct attribute_group cintiq_led_attr_group = { +static const struct attribute_group cintiq_led_attr_group = { .name = "wacom_led", .attrs = cintiq_led_attrs, }; @@ -1194,7 +1194,7 @@ static struct attribute *intuos4_led_attrs[] = { NULL }; -static struct attribute_group intuos4_led_attr_group = { +static const struct attribute_group intuos4_led_attr_group = { .name = "wacom_led", .attrs = intuos4_led_attrs, }; @@ -1205,7 +1205,7 @@ static struct attribute *intuos5_led_attrs[] = { NULL }; -static struct attribute_group intuos5_led_attr_group = { +static const struct attribute_group intuos5_led_attr_group = { .name = "wacom_led", .attrs = intuos5_led_attrs, }; @@ -1216,13 +1216,13 @@ static struct attribute *generic_led_attrs[] = { NULL }; -static struct attribute_group generic_led_attr_group = { +static const struct attribute_group generic_led_attr_group = { .name = "wacom_led", .attrs = generic_led_attrs, }; struct wacom_sysfs_group_devres { - struct attribute_group *group; + const struct attribute_group *group; struct kobject *root; }; @@ -1238,7 +1238,7 @@ static void wacom_devm_sysfs_group_release(struct device *dev, void *res) static int __wacom_devm_sysfs_create_group(struct wacom *wacom, struct kobject *root, - struct attribute_group *group) + const struct attribute_group *group) { struct wacom_sysfs_group_devres *devres; int error; @@ -1264,7 +1264,7 @@ static int __wacom_devm_sysfs_create_group(struct wacom *wacom, } static int wacom_devm_sysfs_create_group(struct wacom *wacom, - struct attribute_group *group) + const struct attribute_group *group) { return __wacom_devm_sysfs_create_group(wacom, &wacom->hdev->dev.kobj, group); @@ -1847,7 +1847,7 @@ static struct attribute *remote##SET_ID##_serial_attrs[] = { \ &remote##SET_ID##_mode_attr.attr, \ NULL \ }; \ -static struct attribute_group remote##SET_ID##_serial_group = { \ +static const struct attribute_group remote##SET_ID##_serial_group = { \ .name = NULL, \ .attrs = remote##SET_ID##_serial_attrs, \ } From 68d09380a62784ee5abd67462d2c04d094f3a4d2 Mon Sep 17 00:00:00 2001 From: YOSHIOKA Takuma Date: Sun, 22 Nov 2020 05:54:37 +0900 Subject: [PATCH 19/27] HID: elecom: rewrite report based on model specific parameters The report descriptor for EX-G wireless mouse (M-XGL20DLBK) is a bit different from that for trackball mice such as DEFT. For such mouse, the current `mouse_button_fixup` cannot be used as is, because it uses hard-coded indices for a report descriptor. Add parameters to `mouse_button_fixup` function, in order to support fixing report descriptors for more models. Signed-off-by: YOSHIOKA Takuma Signed-off-by: Jiri Kosina --- drivers/hid/hid-elecom.c | 41 ++++++++++++++++++++++++++++------------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c index 8c712d4bc075..233188100884 100644 --- a/drivers/hid/hid-elecom.c +++ b/drivers/hid/hid-elecom.c @@ -11,6 +11,7 @@ * Copyright (c) 2017 Diego Elio Pettenò * Copyright (c) 2017 Alex Manoussakis * Copyright (c) 2017 Tomasz Kramkowski + * Copyright (c) 2020 YOSHIOKA Takuma */ /* @@ -29,25 +30,26 @@ * report descriptor but it does not appear that these enable software to * control what the extra buttons map to. The only simple and straightforward * solution seems to involve fixing up the report descriptor. - * - * Report descriptor format: - * Positions 13, 15, 21 and 31 store the button bit count, button usage minimum, - * button usage maximum and padding bit count respectively. */ #define MOUSE_BUTTONS_MAX 8 static void mouse_button_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int rsize, + unsigned int button_bit_count, + unsigned int padding_bit, + unsigned int button_report_size, + unsigned int button_usage_maximum, int nbuttons) { - if (rsize < 32 || rdesc[12] != 0x95 || - rdesc[14] != 0x75 || rdesc[15] != 0x01 || - rdesc[20] != 0x29 || rdesc[30] != 0x75) + if (rsize < 32 || rdesc[button_bit_count] != 0x95 || + rdesc[button_report_size] != 0x75 || + rdesc[button_report_size + 1] != 0x01 || + rdesc[button_usage_maximum] != 0x29 || rdesc[padding_bit] != 0x75) return; hid_info(hdev, "Fixing up Elecom mouse button count\n"); nbuttons = clamp(nbuttons, 0, MOUSE_BUTTONS_MAX); - rdesc[13] = nbuttons; - rdesc[21] = nbuttons; - rdesc[31] = MOUSE_BUTTONS_MAX - nbuttons; + rdesc[button_bit_count + 1] = nbuttons; + rdesc[button_usage_maximum + 1] = nbuttons; + rdesc[padding_bit + 1] = MOUSE_BUTTONS_MAX - nbuttons; } static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, @@ -65,13 +67,28 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, case USB_DEVICE_ID_ELECOM_M_XT3URBK: case USB_DEVICE_ID_ELECOM_M_XT3DRBK: case USB_DEVICE_ID_ELECOM_M_XT4DRBK: - mouse_button_fixup(hdev, rdesc, *rsize, 6); + /* + * Report descriptor format: + * 12: button bit count + * 30: padding bit count + * 14: button report size + * 20: button usage maximum + */ + mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 6); break; case USB_DEVICE_ID_ELECOM_M_DT1URBK: case USB_DEVICE_ID_ELECOM_M_DT1DRBK: case USB_DEVICE_ID_ELECOM_M_HT1URBK: case USB_DEVICE_ID_ELECOM_M_HT1DRBK: - mouse_button_fixup(hdev, rdesc, *rsize, 8); + /*mouse_button_fixup(hdev, rdesc, *rsize, 13, 15, 21, 31, 8);*/ + /* + * Report descriptor format: + * 12: button bit count + * 30: padding bit count + * 14: button report size + * 20: button usage maximum + */ + mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 8); break; } return rdesc; From 55633e681afb57c9a8ff8a3b22083d44cbaee9e8 Mon Sep 17 00:00:00 2001 From: YOSHIOKA Takuma Date: Sun, 22 Nov 2020 05:54:38 +0900 Subject: [PATCH 20/27] HID: elecom: add support for EX-G M-XGL20DLBK wireless mouse Enables three buttons (Fn1, Fn2, and Fn3) on the ELECOM M-XGL20DLBK wireless mouse. While this mouse is EX-G brand, report descriptor is a bit different from EX-G trackball mouse. To enable extra buttons, report should be rewritten in a similar way to trackballs, but with different position parameters. Signed-off-by: YOSHIOKA Takuma Signed-off-by: Jiri Kosina --- drivers/hid/hid-elecom.c | 11 +++++++++++ drivers/hid/hid-ids.h | 1 + drivers/hid/hid-quirks.c | 1 + 3 files changed, 13 insertions(+) diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c index 233188100884..3bd7207de2e8 100644 --- a/drivers/hid/hid-elecom.c +++ b/drivers/hid/hid-elecom.c @@ -64,6 +64,16 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, rdesc[47] = 0x00; } break; + case USB_DEVICE_ID_ELECOM_M_XGL20DLBK: + /* + * Report descriptor format: + * 20: button bit count + * 28: padding bit count + * 22: button report size + * 14: button usage maximum + */ + mouse_button_fixup(hdev, rdesc, *rsize, 20, 28, 22, 14, 8); + break; case USB_DEVICE_ID_ELECOM_M_XT3URBK: case USB_DEVICE_ID_ELECOM_M_XT3DRBK: case USB_DEVICE_ID_ELECOM_M_XT4DRBK: @@ -96,6 +106,7 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, static const struct hid_device_id elecom_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, + { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index f170feaac40b..7fcbd3c02458 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -390,6 +390,7 @@ #define USB_VENDOR_ID_ELECOM 0x056e #define USB_DEVICE_ID_ELECOM_BM084 0x0061 +#define USB_DEVICE_ID_ELECOM_M_XGL20DLBK 0x00e6 #define USB_DEVICE_ID_ELECOM_M_XT3URBK 0x00fb #define USB_DEVICE_ID_ELECOM_M_XT3DRBK 0x00fc #define USB_DEVICE_ID_ELECOM_M_XT4DRBK 0x00fd diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index bf7ecab5d9e5..c94e44d6e652 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -366,6 +366,7 @@ static const struct hid_device_id hid_have_special_driver[] = { #endif #if IS_ENABLED(CONFIG_HID_ELECOM) { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) }, { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, From 1008230f2abeb624f6d71b2e1c424fa4eeebbf84 Mon Sep 17 00:00:00 2001 From: Ethan Warth Date: Tue, 17 Nov 2020 09:48:00 +0100 Subject: [PATCH 21/27] HID: mf: add support for 0079:1846 Mayflash/Dragonrise USB Gamecube Adapter Mayflash/Dragonrise seems to have yet another device ID for one of their Gamecube controller adapters. Previous to this commit, the adapter registered only one /dev/input/js* device, and all controller inputs (from any controller) were mapped to this device. This patch defines the 1846 USB device ID and enables the HID_QUIRK_MULTI_INPUT quirk for it, which fixes that (with the patch, four /dev/input/js* devices are created, one for each of the four controller ports). Signed-off-by: Ethan Warth Tested-by: Wladimir J. van der Laan Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-mf.c | 2 ++ drivers/hid/hid-quirks.c | 2 ++ 3 files changed, 5 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index f170feaac40b..d1841fece116 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -359,6 +359,7 @@ #define USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR 0x1803 #define USB_DEVICE_ID_DRAGONRISE_GAMECUBE1 0x1843 #define USB_DEVICE_ID_DRAGONRISE_GAMECUBE2 0x1844 +#define USB_DEVICE_ID_DRAGONRISE_GAMECUBE3 0x1846 #define USB_VENDOR_ID_DWAV 0x0eef #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 diff --git a/drivers/hid/hid-mf.c b/drivers/hid/hid-mf.c index fc75f30f537c..92d7ecd41a78 100644 --- a/drivers/hid/hid-mf.c +++ b/drivers/hid/hid-mf.c @@ -153,6 +153,8 @@ static const struct hid_device_id mf_devices[] = { .driver_data = HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2), .driver_data = 0 }, /* No quirk required */ + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3), + .driver_data = HID_QUIRK_MULTI_INPUT }, { } }; MODULE_DEVICE_TABLE(hid, mf_devices); diff --git a/drivers/hid/hid-quirks.c b/drivers/hid/hid-quirks.c index bf7ecab5d9e5..2e38340e19df 100644 --- a/drivers/hid/hid-quirks.c +++ b/drivers/hid/hid-quirks.c @@ -72,6 +72,7 @@ static const struct hid_device_id hid_quirks[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), HID_QUIRK_MULTI_INPUT }, + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU), HID_QUIRK_MULTI_INPUT }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER), HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET }, @@ -484,6 +485,7 @@ static const struct hid_device_id hid_have_special_driver[] = { { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2) }, + { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3) }, #endif #if IS_ENABLED(CONFIG_HID_MICROSOFT) { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) }, From 82514ecd61435c2d47c235e1343872b38db17be4 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Wed, 25 Nov 2020 17:40:23 +0100 Subject: [PATCH 22/27] HID: elecom: drop stray comment Drop spurious leftover comment. Signed-off-by: Jiri Kosina --- drivers/hid/hid-elecom.c | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c index 3bd7207de2e8..e59e9911fc37 100644 --- a/drivers/hid/hid-elecom.c +++ b/drivers/hid/hid-elecom.c @@ -90,7 +90,6 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, case USB_DEVICE_ID_ELECOM_M_DT1DRBK: case USB_DEVICE_ID_ELECOM_M_HT1URBK: case USB_DEVICE_ID_ELECOM_M_HT1DRBK: - /*mouse_button_fixup(hdev, rdesc, *rsize, 13, 15, 21, 31, 8);*/ /* * Report descriptor format: * 12: button bit count From 6a0eaf5123e0e1223252b88cd5775f74105e27bd Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Thu, 26 Nov 2020 09:39:34 +1100 Subject: [PATCH 23/27] HID: Increase HID maximum report size to 16KB Currently the maximum HID report size which can be buffered by the kernel is 8KB. This is sufficient for the vast majority of HID devices on the market, as most HID reports are fairly small. However, some unusual devices such as the Elgate Stream Deck exist which use a report size slightly over 8KB for the image data that is sent to the device. Reports these large cannot be buffered by the regular HID subsystem currently, thus the only way to use such device is to bypass the HID subsystem entirely. This increases the maximum HID report size to 16KB, which should cover all sanely designed HID devices. Signed-off-by: Dean Camera Signed-off-by: Jiri Kosina --- include/linux/hid.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/linux/hid.h b/include/linux/hid.h index b079146850e6..c39d71eb1fd0 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -494,7 +494,7 @@ struct hid_report_enum { }; #define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */ -#define HID_MAX_BUFFER_SIZE 8192 /* 8kb */ +#define HID_MAX_BUFFER_SIZE 16384 /* 16kb */ #define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ #define HID_OUTPUT_FIFO_SIZE 64 From f43d3870cafa2a0f3854c1819c8385733db8f9ae Mon Sep 17 00:00:00 2001 From: Dean Camera Date: Thu, 26 Nov 2020 09:39:57 +1100 Subject: [PATCH 24/27] HID: hidraw: Add additional hidraw input/output report ioctls. Currently the hidraw module can only read and write feature HID reports on demand, via dedicated ioctls. Input reports are read from the device through the read() interface, while output reports are written through the write interface(). This is insufficient; it is desirable in many situations to be able to read and write input and output reports through the control interface to cover additional scenarios: - Reading an input report by its report ID, to get initial state - Writing an input report, to set initial input state in the device - Reading an output report by its report ID, to obtain current state - Writing an output report by its report ID, out of band This patch adds these missing ioctl requests to read and write the remaining HID report types. Note that not all HID backends will neccesarily support this (e.g. while the USB link layer supports setting Input reports, others may not). Also included are documentation and example updates. The current hidraw documentation states that feature reports read from the device does *not* include the report ID, however this is not the case and the returned report will have its report ID prepended by conforming HID devices, as the report data sent from the device over the control endpoint must be indentical in format to those sent over the regular transport. Signed-off-by: Dean Camera Signed-off-by: Jiri Kosina --- Documentation/hid/hidraw.rst | 45 ++++++++++++++++++++++++++++++++++-- drivers/hid/hidraw.c | 24 ++++++++++++++++++- include/uapi/linux/hidraw.h | 6 +++++ samples/hidraw/hid-example.c | 2 +- 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/Documentation/hid/hidraw.rst b/Documentation/hid/hidraw.rst index 4a4a0ba1f362..f41c1f0f6252 100644 --- a/Documentation/hid/hidraw.rst +++ b/Documentation/hid/hidraw.rst @@ -123,8 +123,49 @@ HIDIOCGFEATURE(len): This ioctl will request a feature report from the device using the control endpoint. The first byte of the supplied buffer should be set to the report number of the requested report. For devices which do not use numbered -reports, set the first byte to 0. The report will be returned starting at -the first byte of the buffer (ie: the report number is not returned). +reports, set the first byte to 0. The returned report buffer will contain the +report number in the first byte, followed by the report data read from the +device. For devices which do not use numbered reports, the report data will +begin at the first byte of the returned buffer. + +HIDIOCSINPUT(len): + Send an Input Report + +This ioctl will send an input report to the device, using the control endpoint. +In most cases, setting an input HID report on a device is meaningless and has +no effect, but some devices may choose to use this to set or reset an initial +state of a report. The format of the buffer issued with this report is identical +to that of HIDIOCSFEATURE. + +HIDIOCGINPUT(len): + Get an Input Report + +This ioctl will request an input report from the device using the control +endpoint. This is slower on most devices where a dedicated In endpoint exists +for regular input reports, but allows the host to request the value of a +specific report number. Typically, this is used to request the initial states of +an input report of a device, before an application listens for normal reports via +the regular device read() interface. The format of the buffer issued with this report +is identical to that of HIDIOCGFEATURE. + +HIDIOCSOUTPUT(len): + Send an Output Report + +This ioctl will send an output report to the device, using the control endpoint. +This is slower on most devices where a dedicated Out endpoint exists for regular +output reports, but is added for completeness. Typically, this is used to set +the initial states of an output report of a device, before an application sends +updates via the regular device write() interface. The format of the buffer issued +with this report is identical to that of HIDIOCSFEATURE. + +HIDIOCGOUTPUT(len): + Get an Output Report + +This ioctl will request an output report from the device using the control +endpoint. Typically, this is used to retrive the initial state of +an output report of a device, before an application updates it as necessary either +via a HIDIOCSOUTPUT request, or the regular device write() interface. The format +of the buffer issued with this report is identical to that of HIDIOCGFEATURE. Example ------- diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 2eee5e31c2b7..79faac87a06f 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -170,7 +170,7 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t /* * This function performs a Get_Report transfer over the control endpoint * per section 7.2.1 of the HID specification, version 1.1. The first byte - * of buffer is the report number to request, or 0x0 if the defice does not + * of buffer is the report number to request, or 0x0 if the device does not * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT * or HID_INPUT_REPORT. */ @@ -428,6 +428,28 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, break; } + if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSINPUT(0))) { + int len = _IOC_SIZE(cmd); + ret = hidraw_send_report(file, user_arg, len, HID_INPUT_REPORT); + break; + } + if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGINPUT(0))) { + int len = _IOC_SIZE(cmd); + ret = hidraw_get_report(file, user_arg, len, HID_INPUT_REPORT); + break; + } + + if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSOUTPUT(0))) { + int len = _IOC_SIZE(cmd); + ret = hidraw_send_report(file, user_arg, len, HID_OUTPUT_REPORT); + break; + } + if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGOUTPUT(0))) { + int len = _IOC_SIZE(cmd); + ret = hidraw_get_report(file, user_arg, len, HID_OUTPUT_REPORT); + break; + } + /* Begin Read-only ioctls. */ if (_IOC_DIR(cmd) != _IOC_READ) { ret = -EINVAL; diff --git a/include/uapi/linux/hidraw.h b/include/uapi/linux/hidraw.h index 4913539e5bcc..33ebad81720a 100644 --- a/include/uapi/linux/hidraw.h +++ b/include/uapi/linux/hidraw.h @@ -40,6 +40,12 @@ struct hidraw_devinfo { #define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len) #define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len) #define HIDIOCGRAWUNIQ(len) _IOC(_IOC_READ, 'H', 0x08, len) +/* The first byte of SINPUT and GINPUT is the report number */ +#define HIDIOCSINPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x09, len) +#define HIDIOCGINPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0A, len) +/* The first byte of SOUTPUT and GOUTPUT is the report number */ +#define HIDIOCSOUTPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0B, len) +#define HIDIOCGOUTPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0C, len) #define HIDRAW_FIRST_MINOR 0 #define HIDRAW_MAX_DEVICES 64 diff --git a/samples/hidraw/hid-example.c b/samples/hidraw/hid-example.c index 37a0ffcb4d63..0f73ace3c6c3 100644 --- a/samples/hidraw/hid-example.c +++ b/samples/hidraw/hid-example.c @@ -128,7 +128,7 @@ int main(int argc, char **argv) perror("HIDIOCGFEATURE"); } else { printf("ioctl HIDIOCGFEATURE returned: %d\n", res); - printf("Report data (not containing the report number):\n\t"); + printf("Report data:\n\t"); for (i = 0; i < res; i++) printf("%hhx ", buf[i]); puts("\n"); From cc894ac553605c9193a7a94372ff2f8af5766f46 Mon Sep 17 00:00:00 2001 From: Pascal Giard Date: Wed, 25 Nov 2020 22:02:30 -0500 Subject: [PATCH 25/27] HID: sony: support for ghlive ps3/wii u dongles This commit adds support for the Guitar Hero Live PS3 and Wii U dongles. These dongles require a "magic" USB control message [1] to be sent approximately every 10 seconds otherwise the dongle will not report events where the strumbar is hit while a fret is being held. Also, inspired by a patch sent on linux-input by Sanjay Govind [2], the accelerometer is mapped to ABS_RY for tilt. Interestingly, the Wii U and PS3 dongles share the same VID and PID. [1] https://github.com/ghlre/GHLtarUtility/ [2] https://marc.info/?l=linux-input&m=157242835928542&w=2 Signed-off-by: Pascal Giard Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 + drivers/hid/hid-ids.h | 3 ++ drivers/hid/hid-sony.c | 112 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 116 insertions(+) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 612629678c84..18b3ad50e1ca 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -907,6 +907,7 @@ config HID_SONY * Buzz controllers * Sony PS3 Blue-ray Disk Remote Control (Bluetooth) * Logitech Harmony adapter for Sony Playstation 3 (Bluetooth) + * Guitar Hero Live PS3 and Wii U guitar dongles config SONY_FF bool "Sony PS2/3/4 accessories force feedback support" diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index f170feaac40b..eee6e27d5f1e 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1074,6 +1074,9 @@ #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002 #define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER 0x1000 +#define USB_VENDOR_ID_SONY_GHLIVE 0x12ba +#define USB_DEVICE_ID_SONY_PS3WIIU_GHLIVE_DONGLE 0x074b + #define USB_VENDOR_ID_SINO_LITE 0x1345 #define USB_DEVICE_ID_SINO_LITE_CONTROLLER 0x3008 diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 485455c300f2..326c4bdbd0ea 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -11,6 +11,7 @@ * Copyright (c) 2013 Colin Leitner * Copyright (c) 2014-2016 Frank Praznik * Copyright (c) 2018 Todd Kelner + * Copyright (c) 2020 Pascal Giard */ /* @@ -35,6 +36,8 @@ #include #include #include +#include +#include #include #include "hid-ids.h" @@ -56,6 +59,7 @@ #define NSG_MR5U_REMOTE_BT BIT(14) #define NSG_MR7U_REMOTE_BT BIT(15) #define SHANWAN_GAMEPAD BIT(16) +#define GHL_GUITAR_PS3WIIU BIT(17) #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) @@ -79,6 +83,17 @@ #define NSG_MRXU_MAX_X 1667 #define NSG_MRXU_MAX_Y 1868 +#define GHL_GUITAR_POKE_INTERVAL 10 /* In seconds */ +#define GHL_GUITAR_TILT_USAGE 44 + +/* Magic value and data taken from GHLtarUtility: + * https://github.com/ghlre/GHLtarUtility/blob/master/PS3Guitar.cs + * Note: The Wii U and PS3 dongles happen to share the same! + */ +static const u16 ghl_ps3wiiu_magic_value = 0x201; +static const char ghl_ps3wiiu_magic_data[] = { + 0x02, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00 +}; /* PS/3 Motion controller */ static u8 motion_rdesc[] = { @@ -579,6 +594,10 @@ struct sony_sc { enum ds4_dongle_state ds4_dongle_state; /* DS4 calibration data */ struct ds4_calibration_data ds4_calib_data[6]; + /* GH Live */ + struct timer_list ghl_poke_timer; + struct usb_ctrlrequest *ghl_cr; + u8 *ghl_databuf; }; static void sony_set_leds(struct sony_sc *sc); @@ -602,6 +621,85 @@ static inline void sony_schedule_work(struct sony_sc *sc, } } +static void ghl_magic_poke_cb(struct urb *urb) +{ + if (urb) { + /* Free sc->ghl_cr and sc->ghl_databuf allocated in + * ghl_magic_poke() + */ + kfree(urb->setup_packet); + kfree(urb->transfer_buffer); + } +} + +static void ghl_magic_poke(struct timer_list *t) +{ + struct sony_sc *sc = from_timer(sc, t, ghl_poke_timer); + + int ret; + unsigned int pipe; + struct urb *urb; + struct usb_device *usbdev = to_usb_device(sc->hdev->dev.parent->parent); + const u16 poke_size = + ARRAY_SIZE(ghl_ps3wiiu_magic_data); + + pipe = usb_sndctrlpipe(usbdev, 0); + + if (!sc->ghl_cr) { + sc->ghl_cr = kzalloc(sizeof(*sc->ghl_cr), GFP_ATOMIC); + if (!sc->ghl_cr) + goto resched; + } + + if (!sc->ghl_databuf) { + sc->ghl_databuf = kzalloc(poke_size, GFP_ATOMIC); + if (!sc->ghl_databuf) + goto resched; + } + + urb = usb_alloc_urb(0, GFP_ATOMIC); + if (!urb) + goto resched; + + sc->ghl_cr->bRequestType = + USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT; + sc->ghl_cr->bRequest = USB_REQ_SET_CONFIGURATION; + sc->ghl_cr->wValue = cpu_to_le16(ghl_ps3wiiu_magic_value); + sc->ghl_cr->wIndex = 0; + sc->ghl_cr->wLength = cpu_to_le16(poke_size); + memcpy(sc->ghl_databuf, ghl_ps3wiiu_magic_data, poke_size); + + usb_fill_control_urb( + urb, usbdev, pipe, + (unsigned char *) sc->ghl_cr, sc->ghl_databuf, + poke_size, ghl_magic_poke_cb, NULL); + ret = usb_submit_urb(urb, GFP_ATOMIC); + if (ret < 0) { + kfree(sc->ghl_databuf); + kfree(sc->ghl_cr); + } + usb_free_urb(urb); + +resched: + /* Reschedule for next time */ + mod_timer(&sc->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ); +} + +static int guitar_mapping(struct hid_device *hdev, struct hid_input *hi, + struct hid_field *field, struct hid_usage *usage, + unsigned long **bit, int *max) +{ + if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) { + unsigned int abs = usage->hid & HID_USAGE; + + if (abs == GHL_GUITAR_TILT_USAGE) { + hid_map_usage_clear(hi, usage, bit, max, EV_ABS, ABS_RY); + return 1; + } + } + return 0; +} + static ssize_t ds4_show_poll_interval(struct device *dev, struct device_attribute *attr, char *buf) @@ -1383,6 +1481,8 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi, if (sc->quirks & DUALSHOCK4_CONTROLLER) return ds4_mapping(hdev, hi, field, usage, bit, max); + if (sc->quirks & GHL_GUITAR_PS3WIIU) + return guitar_mapping(hdev, hi, field, usage, bit, max); /* Let hid-core decide for the others */ return 0; @@ -2917,6 +3017,12 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) return -ENODEV; } + if (sc->quirks & GHL_GUITAR_PS3WIIU) { + timer_setup(&sc->ghl_poke_timer, ghl_magic_poke, 0); + mod_timer(&sc->ghl_poke_timer, + jiffies + GHL_GUITAR_POKE_INTERVAL*HZ); + } + return ret; } @@ -2924,6 +3030,9 @@ static void sony_remove(struct hid_device *hdev) { struct sony_sc *sc = hid_get_drvdata(hdev); + if (sc->quirks & GHL_GUITAR_PS3WIIU) + del_timer_sync(&sc->ghl_poke_timer); + hid_hw_close(hdev); if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) @@ -3035,6 +3144,9 @@ static const struct hid_device_id sony_devices[] = { /* SMK-Link NSG-MR7U Remote Control */ { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE), .driver_data = NSG_MR7U_REMOTE_BT }, + /* Guitar Hero Live PS3 and Wii U guitar dongles */ + { HID_USB_DEVICE(USB_VENDOR_ID_SONY_GHLIVE, USB_DEVICE_ID_SONY_PS3WIIU_GHLIVE_DONGLE), + .driver_data = GHL_GUITAR_PS3WIIU}, { } }; MODULE_DEVICE_TABLE(hid, sony_devices); From c961facb5b19634eee5bcdd91fc5bf3f1c545bc5 Mon Sep 17 00:00:00 2001 From: Hans de Goede Date: Wed, 25 Nov 2020 23:37:45 +0100 Subject: [PATCH 26/27] HID: ite: Add support for Acer S1002 keyboard-dock Make the hid-ite driver handle the Acer S1002 keyboard-dock, this leads to 2 improvements: 1. The non working wifi-toggle hotkey now works. 2. Toggling the touchpad on of with the hotkey will no show OSD notifications in e.g. GNOME3. The actual toggling is handled inside the keyboard, this adds support for notifying evdev listeners about this. Signed-off-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 1 + drivers/hid/hid-ite.c | 13 ++++++++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index d1841fece116..787b20d02451 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -1134,6 +1134,7 @@ #define USB_DEVICE_ID_SYNAPTICS_DELL_K12A 0x2819 #define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012 0x2968 #define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710 +#define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002 0x73f4 #define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003 0x73f5 #define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5 0x81a7 diff --git a/drivers/hid/hid-ite.c b/drivers/hid/hid-ite.c index 742c052b0110..22bfbebceaf4 100644 --- a/drivers/hid/hid-ite.c +++ b/drivers/hid/hid-ite.c @@ -18,10 +18,16 @@ static __u8 *ite_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); if (quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) { + /* For Acer Aspire Switch 10 SW5-012 keyboard-dock */ if (*rsize == 188 && rdesc[162] == 0x81 && rdesc[163] == 0x02) { - hid_info(hdev, "Fixing up ITE keyboard report descriptor\n"); + hid_info(hdev, "Fixing up Acer Sw5-012 ITE keyboard report descriptor\n"); rdesc[163] = HID_MAIN_ITEM_RELATIVE; } + /* For Acer One S1002 keyboard-dock */ + if (*rsize == 188 && rdesc[185] == 0x81 && rdesc[186] == 0x02) { + hid_info(hdev, "Fixing up Acer S1002 ITE keyboard report descriptor\n"); + rdesc[186] = HID_MAIN_ITEM_RELATIVE; + } } return rdesc; @@ -101,6 +107,11 @@ static const struct hid_device_id ite_devices[] = { USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012), .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */ + { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, + USB_VENDOR_ID_SYNAPTICS, + USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002), + .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, + /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */ { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003) }, From c870d50ce387d84b6438211a7044c60afbd5d60a Mon Sep 17 00:00:00 2001 From: Julian Sax Date: Thu, 26 Nov 2020 18:51:58 +0100 Subject: [PATCH 27/27] HID: i2c-hid: add Vero K147 to descriptor override This device uses the SIPODEV SP1064 touchpad, which does not supply descriptors, so it has to be added to the override list. Cc: stable@vger.kernel.org Signed-off-by: Julian Sax Reviewed-by: Hans de Goede Signed-off-by: Jiri Kosina --- drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c index 35f3bfc3e6f5..8e0f67455c09 100644 --- a/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c +++ b/drivers/hid/i2c-hid/i2c-hid-dmi-quirks.c @@ -405,6 +405,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { }, .driver_data = (void *)&sipodev_desc }, + { + .ident = "Vero K147", + .matches = { + DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VERO"), + DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "K147"), + }, + .driver_data = (void *)&sipodev_desc + }, { } /* Terminate list */ };