diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-16 15:44:44 -0800 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2020-12-16 15:44:44 -0800 |
commit | de925e2fbb44eed8a2a7ce166b485fed5eae01aa (patch) | |
tree | 078ddd7b31e1cde13f554d741140c8f519cd8f90 /drivers | |
parent | 62746f92b10a4add6a7db87ff59b901276746b11 (diff) | |
parent | 85a694738f6e7ad36918a3fa0569701b102d06c2 (diff) |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid
Pull HID updates from Jiri Kosina:
- AMD SFH (Sensor Fusion Hub) support (Sandeep Singh)
- increase of maximum HID report size to 16KB in order to support some
of the modern devices (Dean Camera)
- control interface support for hidraw (Dean Camera)
- Sony DS4 power and firmware reporting fixes (Roderick Colenbrander)
- support for ghlive PS3/WII U dongles (Pascal Giard)
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (27 commits)
HID: i2c-hid: add Vero K147 to descriptor override
HID: ite: Add support for Acer S1002 keyboard-dock
HID: sony: support for ghlive ps3/wii u dongles
HID: hidraw: Add additional hidraw input/output report ioctls.
HID: Increase HID maximum report size to 16KB
HID: elecom: drop stray comment
HID: mf: add support for 0079:1846 Mayflash/Dragonrise USB Gamecube Adapter
HID: elecom: add support for EX-G M-XGL20DLBK wireless mouse
HID: elecom: rewrite report based on model specific parameters
HID: wacom: Constify attribute_groups
HID: input: Fix fall-through warnings for Clang
HID: usbhid: Fix fall-through warnings for Clang
HID: logitech-hidpp: Add hid_device_id for V470 bluetooth mouse
HID: intel-ish-hid: Remove unnecessary assignment to variable rv
HID: sony: Workaround for DS4 dongle hotplug kernel crash.
HID: sony: Don't use fw_version/hw_version for sysfs cleanup.
HID: sony: Report more accurate DS4 power status.
SFH: fix error return check for -ERESTARTSYS
HID: SFH: Add documentation
HID: hid-input: occasionally report stylus battery even if not changed
...
Diffstat (limited to 'drivers')
27 files changed, 2154 insertions, 91 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 612629678c84..7bdda1b5b221 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" @@ -1183,4 +1184,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_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 <Nehal-Bakulchandra.Shah@amd.com> + * Sandeep Singh <Sandeep.singh@amd.com> + */ + +#include <linux/dma-mapping.h> +#include <linux/hid.h> +#include <linux/list.h> +#include <linux/slab.h> +#include <linux/workqueue.h> +#include <linux/errno.h> + +#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..4f989483aa03 --- /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 <Nehal-bakulchandra.shah@amd.com> + * Sandeep Singh <sandeep.singh@amd.com> + */ +#include <linux/hid.h> +#include <linux/wait.h> +#include <linux/sched.h> + +#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 == -ERESTARTSYS) + return -ERESTARTSYS; + else if (ret < 0) + return -ETIMEDOUT; + 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 <Nehal-bakulchandra.shah@amd.com> + * Sandeep Singh <sandeep.singh@amd.com> + */ + +#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 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..a51c7b76283b --- /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 <Shyam-sundar.S-k@amd.com> + * Sandeep Singh <Sandeep.singh@amd.com> + */ + +#include <linux/bitops.h> +#include <linux/delay.h> +#include <linux/dma-mapping.h> +#include <linux/interrupt.h> +#include <linux/io-64-nonatomic-lo-hi.h> +#include <linux/module.h> +#include <linux/slab.h> + +#include "amd_sfh_pcie.h" + +#define DRIVER_NAME "pcie_mp2_amd" +#define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver" + +#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) +{ + 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 <Shyam-sundar.S-k@amd.com>"); +MODULE_AUTHOR("Sandeep Singh <Sandeep.singh@amd.com>"); 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 <Shyam-sundar.S-k@amd.com> + * Sandeep Singh <Sandeep.singh@amd.com> + */ + +#ifndef PCIE_MP2_AMD_H +#define PCIE_MP2_AMD_H + +#include <linux/pci.h> + +#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 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 <Nehal-Bakulchandra.Shah@amd.com> + * Sandeep Singh <sandeep.singh@amd.com> + */ + +#include <linux/kernel.h> +#include <linux/string.h> +#include <linux/slab.h> +#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..095c471d8fd6 --- /dev/null +++ b/drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h @@ -0,0 +1,107 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * HID report descriptors, structures and routines + * Copyright 2020 Advanced Micro Devices, Inc. + * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com> + * Sandeep Singh <Sandeep.singh@amd.com> + */ + +#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 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 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 <Nehal-bakulchandra.shah@amd.com> + * Sandeep Singh <Sandeep.singh@amd.com> + */ + +#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 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. */ @@ -1127,6 +1219,9 @@ static const struct hid_device_id asus_devices[] = { 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 }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c index 8c712d4bc075..e59e9911fc37 100644 --- a/drivers/hid/hid-elecom.c +++ b/drivers/hid/hid-elecom.c @@ -11,6 +11,7 @@ * Copyright (c) 2017 Diego Elio Pettenò <flameeyes@flameeyes.eu> * Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org> * Copyright (c) 2017 Tomasz Kramkowski <tk@the-tk.com> + * Copyright (c) 2020 YOSHIOKA Takuma <lo48576@hard-wi.red> */ /* @@ -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, @@ -62,16 +64,40 @@ 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: - 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); + /* + * 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; @@ -79,6 +105,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..4c5f23640f9c 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 @@ -359,6 +360,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 @@ -390,6 +392,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 @@ -1074,6 +1077,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 @@ -1133,6 +1139,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-input.c b/drivers/hid/hid-input.c index 4dca11392459..dc7f6b4a775c 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -537,9 +537,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); } } @@ -746,6 +749,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; } 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; @@ -103,6 +109,11 @@ static const struct hid_device_id ite_devices[] = { /* 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) }, { } }; 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 }, 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..d9ca874dffac 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 }, @@ -366,6 +367,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) }, @@ -484,6 +486,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) }, diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c index 2f073f536070..e3a557dc9ffd 100644 --- a/drivers/hid/hid-sony.c +++ b/drivers/hid/hid-sony.c @@ -11,6 +11,7 @@ * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com> * Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com> * Copyright (c) 2018 Todd Kelner + * Copyright (c) 2020 Pascal Giard <pascal.giard@etsmtl.ca> */ /* @@ -35,6 +36,8 @@ #include <linux/idr.h> #include <linux/input/mt.h> #include <linux/crc32.h> +#include <linux/usb.h> +#include <linux/timer.h> #include <asm/unaligned.h> #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[] = { @@ -550,7 +565,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 @@ -562,9 +579,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]; @@ -578,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); @@ -601,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) @@ -892,7 +991,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 +1004,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 +1041,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 +1147,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 (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; - if (!cable_state) - battery_capacity++; - if (battery_capacity > 10) - battery_capacity = 10; + if (battery_data < 10) + battery_capacity = battery_data * 10 + 5; + else /* 10 */ + battery_capacity = 100; - battery_capacity *= 10; + 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); /* @@ -1360,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; @@ -1597,16 +1720,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; @@ -2300,12 +2445,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 +2464,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; @@ -2723,19 +2862,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 @@ -2827,9 +2964,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); @@ -2902,6 +3039,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; } @@ -2909,15 +3052,18 @@ 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) 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); @@ -3020,6 +3166,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); 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/drivers/hid/i2c-hid/i2c-hid-core.c b/drivers/hid/i2c-hid/i2c-hid-core.c index aeff1ffb0c8b..bfe716d7ea44 100644 --- a/drivers/hid/i2c-hid/i2c-hid-core.c +++ b/drivers/hid/i2c-hid/i2c-hid-core.c @@ -1106,8 +1106,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) 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 */ }; 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) { 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 */ 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, \ } |