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 ...
Unified · Split
| @@ -0,0 +1,145 @@ | |||
| 1 | .. SPDX-License-Identifier: GPL-2.0 | ||
| 2 | |||
| 3 | |||
| 4 | AMD Sensor Fusion Hub | ||
| 5 | ===================== | ||
| 6 | AMD Sensor Fusion Hub (SFH) is part of an SOC starting from Ryzen based platforms. | ||
| 7 | The solution is working well on several OEM products. AMD SFH uses HID over PCIe bus. | ||
| 8 | In terms of architecture it resembles ISH, however the major difference is all | ||
| 9 | the HID reports are generated as part of the kernel driver. | ||
| 10 | |||
| 11 | 1. Block Diagram | ||
| 12 | ================ | ||
| 13 | |||
| 14 | :: | ||
| 15 | |||
| 16 | --------------------------------- | ||
| 17 | | HID User Space Applications | | ||
| 18 | - ------------------------------- | ||
| 19 | |||
| 20 | --------------------------------------------- | ||
| 21 | --------------------------------- | ||
| 22 | | HID Core | | ||
| 23 | --------------------------------- | ||
| 24 | |||
| 25 | --------------------------------- | ||
| 26 | | AMD HID Transport | | ||
| 27 | --------------------------------- | ||
| 28 | |||
| 29 | -------------------------------- | ||
| 30 | | AMD HID Client | | ||
| 31 | | with HID Report Generator| | ||
| 32 | -------------------------------- | ||
| 33 | |||
| 34 | -------------------------------- | ||
| 35 | | AMD MP2 PCIe Driver | | ||
| 36 | -------------------------------- | ||
| 37 | OS | ||
| 38 | --------------------------------------------- | ||
| 39 | Hardware + Firmware | ||
| 40 | -------------------------------- | ||
| 41 | | SFH MP2 Processor | | ||
| 42 | -------------------------------- | ||
| 43 | |||
| 44 | |||
| 45 | AMD HID Transport Layer | ||
| 46 | ----------------------- | ||
| 47 | AMD SFH transport is also implemented as a bus. Each client application executing in the AMD MP2 is | ||
| 48 | registered as a device on this bus. Here: MP2 which is an ARM core connected to x86 for processing | ||
| 49 | sensor data. The layer, which binds each device (AMD SFH HID driver) identifies the device type and | ||
| 50 | registers with the hid core. Transport layer attach a constant "struct hid_ll_driver" object with | ||
| 51 | each device. Once a device is registered with HID core, the callbacks provided via this struct are | ||
| 52 | used by HID core to communicate with the device. AMD HID Transport layer implements the synchronous calls. | ||
| 53 | |||
| 54 | AMD HID Client Layer | ||
| 55 | -------------------- | ||
| 56 | This layer is responsible to implement HID request and descriptors. As firmware is OS agnostic, HID | ||
| 57 | client layer fills the HID request structure and descriptors. HID client layer is complex as it is | ||
| 58 | interface between MP2 PCIe layer and HID. HID client layer initialized the MP2 PCIe layer and holds | ||
| 59 | the instance of MP2 layer. It identifies the number of sensors connected using MP2-PCIe layer. Base | ||
| 60 | on that allocates the DRAM address for each and every sensor and pass it to MP2-PCIe driver.On | ||
| 61 | enumeration of each the sensor, client layer fills the HID Descriptor structure and HID input repor | ||
| 62 | structure. HID Feature report structure is optional. The report descriptor structure varies from | ||
| 63 | sensor to sensor. | ||
| 64 | |||
| 65 | AMD MP2 PCIe layer | ||
| 66 | ------------------ | ||
| 67 | MP2 PCIe Layer is responsible for making all transactions with the firmware over PCIe. | ||
| 68 | The connection establishment between firmware and PCIe happens here. | ||
| 69 | |||
| 70 | The communication between X86 and MP2 is split into three parts. | ||
| 71 | 1. Command transfer via the C2P mailbox registers. | ||
| 72 | 2. Data transfer via DRAM. | ||
| 73 | 3. Supported sensor info via P2C registers. | ||
| 74 | |||
| 75 | Commands are sent to MP2 using C2P Mailbox registers. Writing into C2P Message registers generate | ||
| 76 | interrupt to MP2. The client layer allocates the physical memory and the same is sent to MP2 via | ||
| 77 | the PCI layer. MP2 firmware writes the command output to the access DRAM memory which the client | ||
| 78 | layer has allocated. Firmware always writes minimum of 32 bytes into DRAM. So as a protocol driver | ||
| 79 | shall allocate minimum of 32 bytes DRAM space. | ||
| 80 | |||
| 81 | Enumeration and Probing flow | ||
| 82 | ---------------------------- | ||
| 83 | :: | ||
| 84 | |||
| 85 | HID AMD AMD AMD -PCIe MP2 | ||
| 86 | Core Transport Client layer layer FW | ||
| 87 | | | | | | | ||
| 88 | | | | on Boot Driver Loaded | | ||
| 89 | | | | | | | ||
| 90 | | | | MP2-PCIe Int | | ||
| 91 | | | | | | | ||
| 92 | | | |---Get Number of sensors-> | | | ||
| 93 | | | | Read P2C | | ||
| 94 | | | | Register | | ||
| 95 | | | | | | | ||
| 96 | | | | Loop(for No of Sensors) | | | ||
| 97 | | | |----------------------| | | | ||
| 98 | | | | Create HID Descriptor| | | | ||
| 99 | | | | Create Input report | | | | ||
| 100 | | | | Descriptor Map | | | | ||
| 101 | | | | the MP2 FW Index to | | | | ||
| 102 | | | | HID Index | | | | ||
| 103 | | | | Allocate the DRAM | Enable | | ||
| 104 | | | | address | Sensors | | ||
| 105 | | | |----------------------| | | | ||
| 106 | | | HID transport| | Enable | | ||
| 107 | | |<--Probe------| |---Sensor CMD--> | | ||
| 108 | | | Create the | | | | ||
| 109 | | | HID device | | | | ||
| 110 | | | (MFD) | | | | ||
| 111 | | | by Populating| | | | ||
| 112 | | | the HID | | | | ||
| 113 | | | ll_driver | | | | ||
| 114 | | HID | | | | | ||
| 115 | | add | | | | | ||
| 116 | |Device | | | | | ||
| 117 | |<------------- | | | | | ||
| 118 | |||
| 119 | |||
| 120 | Data Flow from Application to the AMD SFH Driver | ||
| 121 | ------------------------------------------------ | ||
| 122 | |||
| 123 | :: | ||
| 124 | |||
| 125 | | | | | | | ||
| 126 | | | | | | | ||
| 127 | | | | | | | ||
| 128 | | | | | | | ||
| 129 | | | | | | | ||
| 130 | |HID_req | | | | | ||
| 131 | |get_report | | | | | ||
| 132 | |------------->| | | | | ||
| 133 | | | HID_get_input| | | | ||
| 134 | | | report | | | | ||
| 135 | | |------------->|------------------------| | | | ||
| 136 | | | | Read the DRAM data for| | | | ||
| 137 | | | | requested sensor and | | | | ||
| 138 | | | | create the HID input | | | | ||
| 139 | | | | report | | | | ||
| 140 | | | |------------------------| | | | ||
| 141 | | |Data received | | | | ||
| 142 | | | in HID report| | | | ||
| 143 | To |<-------------|<-------------| | | | ||
| 144 | Applications| | | | | | ||
| 145 | <-------| | | | | | ||
| @@ -123,8 +123,49 @@ HIDIOCGFEATURE(len): · 122 unmodified lines | |||
| 123 | This ioctl will request a feature report from the device using the control | 123 | This ioctl will request a feature report from the device using the control |
| 124 | endpoint. The first byte of the supplied buffer should be set to the report | 124 | endpoint. The first byte of the supplied buffer should be set to the report |
| 125 | number of the requested report. For devices which do not use numbered | 125 | number of the requested report. For devices which do not use numbered |
| 126 | reports, set the first byte to 0. The report will be returned starting at | 126 | reports, set the first byte to 0. The returned report buffer will contain the |
| 127 | the first byte of the buffer (ie: the report number is not returned). | 127 | report number in the first byte, followed by the report data read from the |
| 128 | device. For devices which do not use numbered reports, the report data will | ||
| 129 | begin at the first byte of the returned buffer. | ||
| 130 | |||
| 131 | HIDIOCSINPUT(len): | ||
| 132 | Send an Input Report | ||
| 133 | |||
| 134 | This ioctl will send an input report to the device, using the control endpoint. | ||
| 135 | In most cases, setting an input HID report on a device is meaningless and has | ||
| 136 | no effect, but some devices may choose to use this to set or reset an initial | ||
| 137 | state of a report. The format of the buffer issued with this report is identical | ||
| 138 | to that of HIDIOCSFEATURE. | ||
| 139 | |||
| 140 | HIDIOCGINPUT(len): | ||
| 141 | Get an Input Report | ||
| 142 | |||
| 143 | This ioctl will request an input report from the device using the control | ||
| 144 | endpoint. This is slower on most devices where a dedicated In endpoint exists | ||
| 145 | for regular input reports, but allows the host to request the value of a | ||
| 146 | specific report number. Typically, this is used to request the initial states of | ||
| 147 | an input report of a device, before an application listens for normal reports via | ||
| 148 | the regular device read() interface. The format of the buffer issued with this report | ||
| 149 | is identical to that of HIDIOCGFEATURE. | ||
| 150 | |||
| 151 | HIDIOCSOUTPUT(len): | ||
| 152 | Send an Output Report | ||
| 153 | |||
| 154 | This ioctl will send an output report to the device, using the control endpoint. | ||
| 155 | This is slower on most devices where a dedicated Out endpoint exists for regular | ||
| 156 | output reports, but is added for completeness. Typically, this is used to set | ||
| 157 | the initial states of an output report of a device, before an application sends | ||
| 158 | updates via the regular device write() interface. The format of the buffer issued | ||
| 159 | with this report is identical to that of HIDIOCSFEATURE. | ||
| 160 | |||
| 161 | HIDIOCGOUTPUT(len): | ||
| 162 | Get an Output Report | ||
| 163 | |||
| 164 | This ioctl will request an output report from the device using the control | ||
| 165 | endpoint. Typically, this is used to retrive the initial state of | ||
| 166 | an output report of a device, before an application updates it as necessary either | ||
| 167 | via a HIDIOCSOUTPUT request, or the regular device write() interface. The format | ||
| 168 | of the buffer issued with this report is identical to that of HIDIOCGFEATURE. | ||
| 128 | 169 | ||
| 129 | Example | 170 | Example |
| 130 | ------- | 171 | ------- |
| @@ -16,3 +16,4 @@ Human Interface Devices (HID) · 15 unmodified lines | |||
| 16 | 16 | ||
| 17 | hid-alps | 17 | hid-alps |
| 18 | intel-ish-hid | 18 | intel-ish-hid |
| 19 | amd-sfh-hid | ||
| @@ -956,6 +956,14 @@ S: Supported · 955 unmodified lines | |||
| 956 | F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi | 956 | F: arch/arm64/boot/dts/amd/amd-seattle-xgbe*.dtsi |
| 957 | F: drivers/net/ethernet/amd/xgbe/ | 957 | F: drivers/net/ethernet/amd/xgbe/ |
| 958 | 958 | ||
| 959 | AMD SENSOR FUSION HUB DRIVER | ||
| 960 | M: Nehal Shah <nehal-bakulchandra.shah@amd.com> | ||
| 961 | M: Sandeep Singh <sandeep.singh@amd.com> | ||
| 962 | L: linux-input@vger.kernel.org | ||
| 963 | S: Maintained | ||
| 964 | F: Documentation/hid/amd-sfh* | ||
| 965 | F: drivers/hid/amd-sfh-hid/ | ||
| 966 | |||
| 959 | AMS AS73211 DRIVER | 967 | AMS AS73211 DRIVER |
| 960 | M: Christian Eggers <ceggers@arri.de> | 968 | M: Christian Eggers <ceggers@arri.de> |
| 961 | L: linux-iio@vger.kernel.org | 969 | L: linux-iio@vger.kernel.org |
| @@ -907,6 +907,7 @@ config HID_SONY · 906 unmodified lines | |||
| 907 | * Buzz controllers | 907 | * Buzz controllers |
| 908 | * Sony PS3 Blue-ray Disk Remote Control (Bluetooth) | 908 | * Sony PS3 Blue-ray Disk Remote Control (Bluetooth) |
| 909 | * Logitech Harmony adapter for Sony Playstation 3 (Bluetooth) | 909 | * Logitech Harmony adapter for Sony Playstation 3 (Bluetooth) |
| 910 | * Guitar Hero Live PS3 and Wii U guitar dongles | ||
| 910 | 911 | ||
| 911 | config SONY_FF | 912 | config SONY_FF |
| 912 | bool "Sony PS2/3/4 accessories force feedback support" | 913 | bool "Sony PS2/3/4 accessories force feedback support" |
| @@ -1183,4 +1184,6 @@ source "drivers/hid/i2c-hid/Kconfig" · 270 unmodified lines | |||
| 1183 | 1184 | ||
| 1184 | source "drivers/hid/intel-ish-hid/Kconfig" | 1185 | source "drivers/hid/intel-ish-hid/Kconfig" |
| 1185 | 1186 | ||
| 1187 | source "drivers/hid/amd-sfh-hid/Kconfig" | ||
| 1188 | |||
| 1186 | endmenu | 1189 | endmenu |
| @@ -142,3 +142,5 @@ obj-$(CONFIG_I2C_HID) += i2c-hid/ · 141 unmodified lines | |||
| 142 | 142 | ||
| 143 | obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ | 143 | obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ |
| 144 | obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ | 144 | obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/ |
| 145 | |||
| 146 | obj-$(CONFIG_AMD_SFH_HID) += amd-sfh-hid/ | ||
| @@ -0,0 +1,18 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | menu "AMD SFH HID Support" | ||
| 3 | depends on X86_64 || COMPILE_TEST | ||
| 4 | depends on PCI | ||
| 5 | depends on HID | ||
| 6 | |||
| 7 | config AMD_SFH_HID | ||
| 8 | tristate "AMD Sensor Fusion Hub" | ||
| 9 | help | ||
| 10 | If you say yes to this option, support will be included for the | ||
| 11 | AMD Sensor Fusion Hub. | ||
| 12 | This driver will enable sensors functionality on AMD platforms | ||
| 13 | starting from 17h family of RYZEN parts. | ||
| 14 | |||
| 15 | This driver can also be built as a module. If so, the module will | ||
| 16 | be called amd-sfh. | ||
| 17 | Say Y or M here if you want to support AMD SFH. If unsure, say N. | ||
| 18 | endmenu | ||
| @@ -0,0 +1,13 @@ | |||
| 1 | # SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | # | ||
| 3 | # Makefile - AMD SFH HID drivers | ||
| 4 | # Copyright (c) 2019-2020, Advanced Micro Devices, Inc. | ||
| 5 | # | ||
| 6 | # | ||
| 7 | obj-$(CONFIG_AMD_SFH_HID) += amd_sfh.o | ||
| 8 | amd_sfh-objs := amd_sfh_hid.o | ||
| 9 | amd_sfh-objs += amd_sfh_client.o | ||
| 10 | amd_sfh-objs += amd_sfh_pcie.o | ||
| 11 | amd_sfh-objs += hid_descriptor/amd_sfh_hid_desc.o | ||
| 12 | |||
| 13 | ccflags-y += -I $(srctree)/$(src)/ | ||
| @@ -0,0 +1,246 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | /* | ||
| 3 | * AMD SFH Client Layer | ||
| 4 | * Copyright 2020 Advanced Micro Devices, Inc. | ||
| 5 | * Authors: Nehal Bakulchandra Shah <Nehal-Bakulchandra.Shah@amd.com> | ||
| 6 | * Sandeep Singh <Sandeep.singh@amd.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/dma-mapping.h> | ||
| 10 | #include <linux/hid.h> | ||
| 11 | #include <linux/list.h> | ||
| 12 | #include <linux/slab.h> | ||
| 13 | #include <linux/workqueue.h> | ||
| 14 | #include <linux/errno.h> | ||
| 15 | |||
| 16 | #include "hid_descriptor/amd_sfh_hid_desc.h" | ||
| 17 | #include "amd_sfh_pcie.h" | ||
| 18 | #include "amd_sfh_hid.h" | ||
| 19 | |||
| 20 | #define AMD_SFH_IDLE_LOOP 200 | ||
| 21 | |||
| 22 | struct request_list { | ||
| 23 | struct hid_device *hid; | ||
| 24 | struct list_head list; | ||
| 25 | u8 report_id; | ||
| 26 | u8 sensor_idx; | ||
| 27 | u8 report_type; | ||
| 28 | u8 current_index; | ||
| 29 | }; | ||
| 30 | |||
| 31 | static struct request_list req_list; | ||
| 32 | |||
| 33 | void amd_sfh_set_report(struct hid_device *hid, int report_id, | ||
| 34 | int report_type) | ||
| 35 | { | ||
| 36 | struct amdtp_hid_data *hid_data = hid->driver_data; | ||
| 37 | struct amdtp_cl_data *cli_data = hid_data->cli_data; | ||
| 38 | int i; | ||
| 39 | |||
| 40 | for (i = 0; i < cli_data->num_hid_devices; i++) { | ||
| 41 | if (cli_data->hid_sensor_hubs[i] == hid) { | ||
| 42 | cli_data->cur_hid_dev = i; | ||
| 43 | break; | ||
| 44 | } | ||
| 45 | } | ||
| 46 | amdtp_hid_wakeup(hid); | ||
| 47 | } | ||
| 48 | |||
| 49 | int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type) | ||
| 50 | { | ||
| 51 | struct amdtp_hid_data *hid_data = hid->driver_data; | ||
| 52 | struct amdtp_cl_data *cli_data = hid_data->cli_data; | ||
| 53 | int i; | ||
| 54 | |||
| 55 | for (i = 0; i < cli_data->num_hid_devices; i++) { | ||
| 56 | if (cli_data->hid_sensor_hubs[i] == hid) { | ||
| 57 | struct request_list *new = kzalloc(sizeof(*new), GFP_KERNEL); | ||
| 58 | |||
| 59 | if (!new) | ||
| 60 | return -ENOMEM; | ||
| 61 | |||
| 62 | new->current_index = i; | ||
| 63 | new->sensor_idx = cli_data->sensor_idx[i]; | ||
| 64 | new->hid = hid; | ||
| 65 | new->report_type = report_type; | ||
| 66 | new->report_id = report_id; | ||
| 67 | cli_data->report_id[i] = report_id; | ||
| 68 | cli_data->request_done[i] = false; | ||
| 69 | list_add(&new->list, &req_list.list); | ||
| 70 | break; | ||
| 71 | } | ||
| 72 | } | ||
| 73 | schedule_delayed_work(&cli_data->work, 0); | ||
| 74 | return 0; | ||
| 75 | } | ||
| 76 | |||
| 77 | static void amd_sfh_work(struct work_struct *work) | ||
| 78 | { | ||
| 79 | struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work); | ||
| 80 | struct request_list *req_node; | ||
| 81 | u8 current_index, sensor_index; | ||
| 82 | u8 report_id, node_type; | ||
| 83 | u8 report_size = 0; | ||
| 84 | |||
| 85 | req_node = list_last_entry(&req_list.list, struct request_list, list); | ||
| 86 | list_del(&req_node->list); | ||
| 87 | current_index = req_node->current_index; | ||
| 88 | sensor_index = req_node->sensor_idx; | ||
| 89 | report_id = req_node->report_id; | ||
| 90 | node_type = req_node->report_type; | ||
| 91 | |||
| 92 | if (node_type == HID_FEATURE_REPORT) { | ||
| 93 | report_size = get_feature_report(sensor_index, report_id, | ||
| 94 | cli_data->feature_report[current_index]); | ||
| 95 | if (report_size) | ||
| 96 | hid_input_report(cli_data->hid_sensor_hubs[current_index], | ||
| 97 | cli_data->report_type[current_index], | ||
| 98 | cli_data->feature_report[current_index], report_size, 0); | ||
| 99 | else | ||
| 100 | pr_err("AMDSFH: Invalid report size\n"); | ||
| 101 | |||
| 102 | } else if (node_type == HID_INPUT_REPORT) { | ||
| 103 | report_size = get_input_report(sensor_index, report_id, | ||
| 104 | cli_data->input_report[current_index], | ||
| 105 | cli_data->sensor_virt_addr[current_index]); | ||
| 106 | if (report_size) | ||
| 107 | hid_input_report(cli_data->hid_sensor_hubs[current_index], | ||
| 108 | cli_data->report_type[current_index], | ||
| 109 | cli_data->input_report[current_index], report_size, 0); | ||
| 110 | else | ||
| 111 | pr_err("AMDSFH: Invalid report size\n"); | ||
| 112 | } | ||
| 113 | cli_data->cur_hid_dev = current_index; | ||
| 114 | cli_data->sensor_requested_cnt[current_index] = 0; | ||
| 115 | amdtp_hid_wakeup(cli_data->hid_sensor_hubs[current_index]); | ||
| 116 | } | ||
| 117 | |||
| 118 | static void amd_sfh_work_buffer(struct work_struct *work) | ||
| 119 | { | ||
| 120 | struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work); | ||
| 121 | u8 report_size; | ||
| 122 | int i; | ||
| 123 | |||
| 124 | for (i = 0; i < cli_data->num_hid_devices; i++) { | ||
| 125 | report_size = get_input_report(cli_data->sensor_idx[i], cli_data->report_id[i], | ||
| 126 | cli_data->input_report[i], | ||
| 127 | cli_data->sensor_virt_addr[i]); | ||
| 128 | hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT, | ||
| 129 | cli_data->input_report[i], report_size, 0); | ||
| 130 | } | ||
| 131 | schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); | ||
| 132 | } | ||
| 133 | |||
| 134 | int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) | ||
| 135 | { | ||
| 136 | struct amdtp_cl_data *cl_data = privdata->cl_data; | ||
| 137 | struct amd_mp2_sensor_info info; | ||
| 138 | struct device *dev; | ||
| 139 | u32 feature_report_size; | ||
| 140 | u32 input_report_size; | ||
| 141 | u8 cl_idx; | ||
| 142 | int rc, i; | ||
| 143 | |||
| 144 | dev = &privdata->pdev->dev; | ||
| 145 | cl_data = kzalloc(sizeof(*cl_data), GFP_KERNEL); | ||
| 146 | if (!cl_data) | ||
| 147 | return -ENOMEM; | ||
| 148 | |||
| 149 | cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]); | ||
| 150 | |||
| 151 | INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work); | ||
| 152 | INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer); | ||
| 153 | INIT_LIST_HEAD(&req_list.list); | ||
| 154 | |||
| 155 | for (i = 0; i < cl_data->num_hid_devices; i++) { | ||
| 156 | cl_data->sensor_virt_addr[i] = dma_alloc_coherent(dev, sizeof(int) * 8, | ||
| 157 | &cl_data->sensor_phys_addr[i], | ||
| 158 | GFP_KERNEL); | ||
| 159 | cl_data->sensor_sts[i] = 0; | ||
| 160 | cl_data->sensor_requested_cnt[i] = 0; | ||
| 161 | cl_data->cur_hid_dev = i; | ||
| 162 | cl_idx = cl_data->sensor_idx[i]; | ||
| 163 | cl_data->report_descr_sz[i] = get_descr_sz(cl_idx, descr_size); | ||
| 164 | if (!cl_data->report_descr_sz[i]) { | ||
| 165 | rc = -EINVAL; | ||
| 166 | goto cleanup; | ||
| 167 | } | ||
| 168 | feature_report_size = get_descr_sz(cl_idx, feature_size); | ||
| 169 | if (!feature_report_size) { | ||
| 170 | rc = -EINVAL; | ||
| 171 | goto cleanup; | ||
| 172 | } | ||
| 173 | input_report_size = get_descr_sz(cl_idx, input_size); | ||
| 174 | if (!input_report_size) { | ||
| 175 | rc = -EINVAL; | ||
| 176 | goto cleanup; | ||
| 177 | } | ||
| 178 | cl_data->feature_report[i] = kzalloc(feature_report_size, GFP_KERNEL); | ||
| 179 | if (!cl_data->feature_report[i]) { | ||
| 180 | rc = -ENOMEM; | ||
| 181 | goto cleanup; | ||
| 182 | } | ||
| 183 | cl_data->input_report[i] = kzalloc(input_report_size, GFP_KERNEL); | ||
| 184 | if (!cl_data->input_report[i]) { | ||
| 185 | rc = -ENOMEM; | ||
| 186 | goto cleanup; | ||
| 187 | } | ||
| 188 | info.period = msecs_to_jiffies(AMD_SFH_IDLE_LOOP); | ||
| 189 | info.sensor_idx = cl_idx; | ||
| 190 | info.phys_address = cl_data->sensor_phys_addr[i]; | ||
| 191 | |||
| 192 | cl_data->report_descr[i] = kzalloc(cl_data->report_descr_sz[i], GFP_KERNEL); | ||
| 193 | if (!cl_data->report_descr[i]) { | ||
| 194 | rc = -ENOMEM; | ||
| 195 | goto cleanup; | ||
| 196 | } | ||
| 197 | rc = get_report_descriptor(cl_idx, cl_data->report_descr[i]); | ||
| 198 | if (rc) | ||
| 199 | return rc; | ||
| 200 | rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data); | ||
| 201 | if (rc) | ||
| 202 | return rc; | ||
| 203 | amd_start_sensor(privdata, info); | ||
| 204 | cl_data->sensor_sts[i] = 1; | ||
| 205 | } | ||
| 206 | privdata->cl_data = cl_data; | ||
| 207 | schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); | ||
| 208 | return 0; | ||
| 209 | |||
| 210 | cleanup: | ||
| 211 | for (i = 0; i < cl_data->num_hid_devices; i++) { | ||
| 212 | if (cl_data->sensor_virt_addr[i]) { | ||
| 213 | dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int), | ||
| 214 | cl_data->sensor_virt_addr[i], | ||
| 215 | cl_data->sensor_phys_addr[i]); | ||
| 216 | } | ||
| 217 | kfree(cl_data->feature_report[i]); | ||
| 218 | kfree(cl_data->input_report[i]); | ||
| 219 | kfree(cl_data->report_descr[i]); | ||
| 220 | } | ||
| 221 | kfree(cl_data); | ||
| 222 | return rc; | ||
| 223 | } | ||
| 224 | |||
| 225 | int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata) | ||
| 226 | { | ||
| 227 | struct amdtp_cl_data *cl_data = privdata->cl_data; | ||
| 228 | int i; | ||
| 229 | |||
| 230 | for (i = 0; i < cl_data->num_hid_devices; i++) | ||
| 231 | amd_stop_sensor(privdata, i); | ||
| 232 | |||
| 233 | cancel_delayed_work_sync(&cl_data->work); | ||
| 234 | cancel_delayed_work_sync(&cl_data->work_buffer); | ||
| 235 | amdtp_hid_remove(cl_data); | ||
| 236 | |||
| 237 | for (i = 0; i < cl_data->num_hid_devices; i++) { | ||
| 238 | if (cl_data->sensor_virt_addr[i]) { | ||
| 239 | dma_free_coherent(&privdata->pdev->dev, 8 * sizeof(int), | ||
| 240 | cl_data->sensor_virt_addr[i], | ||
| 241 | cl_data->sensor_phys_addr[i]); | ||
| 242 | } | ||
| 243 | } | ||
| 244 | kfree(cl_data); | ||
| 245 | return 0; | ||
| 246 | } | ||
| @@ -0,0 +1,174 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | /* | ||
| 3 | * AMD MP2 Sensors transport driver | ||
| 4 | * | ||
| 5 | * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com> | ||
| 6 | * Sandeep Singh <sandeep.singh@amd.com> | ||
| 7 | */ | ||
| 8 | #include <linux/hid.h> | ||
| 9 | #include <linux/wait.h> | ||
| 10 | #include <linux/sched.h> | ||
| 11 | |||
| 12 | #include "amd_sfh_hid.h" | ||
| 13 | |||
| 14 | #define AMD_SFH_RESPONSE_TIMEOUT 1500 | ||
| 15 | |||
| 16 | /** | ||
| 17 | * amdtp_hid_parse() - hid-core .parse() callback | ||
| 18 | * @hid: hid device instance | ||
| 19 | * | ||
| 20 | * This function gets called during call to hid_add_device | ||
| 21 | * | ||
| 22 | * Return: 0 on success and non zero on error | ||
| 23 | */ | ||
| 24 | static int amdtp_hid_parse(struct hid_device *hid) | ||
| 25 | { | ||
| 26 | struct amdtp_hid_data *hid_data = hid->driver_data; | ||
| 27 | struct amdtp_cl_data *cli_data = hid_data->cli_data; | ||
| 28 | |||
| 29 | return hid_parse_report(hid, cli_data->report_descr[hid_data->index], | ||
| 30 | cli_data->report_descr_sz[hid_data->index]); | ||
| 31 | } | ||
| 32 | |||
| 33 | /* Empty callbacks with success return code */ | ||
| 34 | static int amdtp_hid_start(struct hid_device *hid) | ||
| 35 | { | ||
| 36 | return 0; | ||
| 37 | } | ||
| 38 | |||
| 39 | static void amdtp_hid_stop(struct hid_device *hid) | ||
| 40 | { | ||
| 41 | } | ||
| 42 | |||
| 43 | static int amdtp_hid_open(struct hid_device *hid) | ||
| 44 | { | ||
| 45 | return 0; | ||
| 46 | } | ||
| 47 | |||
| 48 | static void amdtp_hid_close(struct hid_device *hid) | ||
| 49 | { | ||
| 50 | } | ||
| 51 | |||
| 52 | static int amdtp_raw_request(struct hid_device *hdev, u8 reportnum, | ||
| 53 | u8 *buf, size_t len, u8 rtype, int reqtype) | ||
| 54 | { | ||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | static void amdtp_hid_request(struct hid_device *hid, struct hid_report *rep, int reqtype) | ||
| 59 | { | ||
| 60 | int rc; | ||
| 61 | |||
| 62 | switch (reqtype) { | ||
| 63 | case HID_REQ_GET_REPORT: | ||
| 64 | rc = amd_sfh_get_report(hid, rep->id, rep->type); | ||
| 65 | if (rc) | ||
| 66 | dev_err(&hid->dev, "AMDSFH get report error\n"); | ||
| 67 | break; | ||
| 68 | case HID_REQ_SET_REPORT: | ||
| 69 | amd_sfh_set_report(hid, rep->id, reqtype); | ||
| 70 | break; | ||
| 71 | default: | ||
| 72 | break; | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 76 | static int amdtp_wait_for_response(struct hid_device *hid) | ||
| 77 | { | ||
| 78 | struct amdtp_hid_data *hid_data = hid->driver_data; | ||
| 79 | struct amdtp_cl_data *cli_data = hid_data->cli_data; | ||
| 80 | int i, ret = 0; | ||
| 81 | |||
| 82 | for (i = 0; i < cli_data->num_hid_devices; i++) { | ||
| 83 | if (cli_data->hid_sensor_hubs[i] == hid) | ||
| 84 | break; | ||
| 85 | } | ||
| 86 | |||
| 87 | if (!cli_data->request_done[i]) | ||
| 88 | ret = wait_event_interruptible_timeout(hid_data->hid_wait, | ||
| 89 | cli_data->request_done[i], | ||
| 90 | msecs_to_jiffies(AMD_SFH_RESPONSE_TIMEOUT)); | ||
| 91 | if (ret == -ERESTARTSYS) | ||
| 92 | return -ERESTARTSYS; | ||
| 93 | else if (ret < 0) | ||
| 94 | return -ETIMEDOUT; | ||
| 95 | else | ||
| 96 | return 0; | ||
| 97 | } | ||
| 98 | |||
| 99 | void amdtp_hid_wakeup(struct hid_device *hid) | ||
| 100 | { | ||
| 101 | struct amdtp_hid_data *hid_data = hid->driver_data; | ||
| 102 | struct amdtp_cl_data *cli_data = hid_data->cli_data; | ||
| 103 | |||
| 104 | cli_data->request_done[cli_data->cur_hid_dev] = true; | ||
| 105 | wake_up_interruptible(&hid_data->hid_wait); | ||
| 106 | } | ||
| 107 | |||
| 108 | static struct hid_ll_driver amdtp_hid_ll_driver = { | ||
| 109 | .parse = amdtp_hid_parse, | ||
| 110 | .start = amdtp_hid_start, | ||
| 111 | .stop = amdtp_hid_stop, | ||
| 112 | .open = amdtp_hid_open, | ||
| 113 | .close = amdtp_hid_close, | ||
| 114 | .request = amdtp_hid_request, | ||
| 115 | .wait = amdtp_wait_for_response, | ||
| 116 | .raw_request = amdtp_raw_request, | ||
| 117 | }; | ||
| 118 | |||
| 119 | int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data) | ||
| 120 | { | ||
| 121 | struct hid_device *hid; | ||
| 122 | struct amdtp_hid_data *hid_data; | ||
| 123 | int rc; | ||
| 124 | |||
| 125 | hid = hid_allocate_device(); | ||
| 126 | if (IS_ERR(hid)) | ||
| 127 | return PTR_ERR(hid); | ||
| 128 | |||
| 129 | hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL); | ||
| 130 | if (!hid_data) { | ||
| 131 | rc = -ENOMEM; | ||
| 132 | goto err_hid_data; | ||
| 133 | } | ||
| 134 | |||
| 135 | hid->ll_driver = &amdtp_hid_ll_driver; | ||
| 136 | hid_data->index = cur_hid_dev; | ||
| 137 | hid_data->cli_data = cli_data; | ||
| 138 | init_waitqueue_head(&hid_data->hid_wait); | ||
| 139 | |||
| 140 | hid->driver_data = hid_data; | ||
| 141 | cli_data->hid_sensor_hubs[cur_hid_dev] = hid; | ||
| 142 | hid->bus = BUS_AMD_AMDTP; | ||
| 143 | hid->vendor = AMD_SFH_HID_VENDOR; | ||
| 144 | hid->product = AMD_SFH_HID_PRODUCT; | ||
| 145 | snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-amdtp", | ||
| 146 | hid->vendor, hid->product); | ||
| 147 | |||
| 148 | rc = hid_add_device(hid); | ||
| 149 | if (rc) | ||
| 150 | goto err_hid_device; | ||
| 151 | return 0; | ||
| 152 | |||
| 153 | err_hid_device: | ||
| 154 | kfree(hid_data); | ||
| 155 | err_hid_data: | ||
| 156 | hid_destroy_device(hid); | ||
| 157 | return rc; | ||
| 158 | } | ||
| 159 | |||
| 160 | void amdtp_hid_remove(struct amdtp_cl_data *cli_data) | ||
| 161 | { | ||
| 162 | int i; | ||
| 163 | |||
| 164 | for (i = 0; i < cli_data->num_hid_devices; ++i) { | ||
| 165 | kfree(cli_data->feature_report[i]); | ||
| 166 | kfree(cli_data->input_report[i]); | ||
| 167 | kfree(cli_data->report_descr[i]); | ||
| 168 | if (cli_data->hid_sensor_hubs[i]) { | ||
| 169 | kfree(cli_data->hid_sensor_hubs[i]->driver_data); | ||
| 170 | hid_destroy_device(cli_data->hid_sensor_hubs[i]); | ||
| 171 | cli_data->hid_sensor_hubs[i] = NULL; | ||
| 172 | } | ||
| 173 | } | ||
| 174 | } | ||
| @@ -0,0 +1,67 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
| 2 | /* | ||
| 3 | * AMD MP2 Sensors transport driver | ||
| 4 | * | ||
| 5 | * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com> | ||
| 6 | * Sandeep Singh <sandeep.singh@amd.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef AMDSFH_HID_H | ||
| 10 | #define AMDSFH_HID_H | ||
| 11 | |||
| 12 | #define MAX_HID_DEVICES 4 | ||
| 13 | #define BUS_AMD_AMDTP 0x20 | ||
| 14 | #define AMD_SFH_HID_VENDOR 0x1022 | ||
| 15 | #define AMD_SFH_HID_PRODUCT 0x0001 | ||
| 16 | |||
| 17 | struct amdtp_cl_data { | ||
| 18 | u8 init_done; | ||
| 19 | u32 cur_hid_dev; | ||
| 20 | u32 hid_dev_count; | ||
| 21 | u32 num_hid_devices; | ||
| 22 | struct device_info *hid_devices; | ||
| 23 | u8 *report_descr[MAX_HID_DEVICES]; | ||
| 24 | int report_descr_sz[MAX_HID_DEVICES]; | ||
| 25 | struct hid_device *hid_sensor_hubs[MAX_HID_DEVICES]; | ||
| 26 | u8 *hid_descr[MAX_HID_DEVICES]; | ||
| 27 | int hid_descr_size[MAX_HID_DEVICES]; | ||
| 28 | phys_addr_t phys_addr_base; | ||
| 29 | u32 *sensor_virt_addr[MAX_HID_DEVICES]; | ||
| 30 | phys_addr_t sensor_phys_addr[MAX_HID_DEVICES]; | ||
| 31 | u32 sensor_sts[MAX_HID_DEVICES]; | ||
| 32 | u32 sensor_requested_cnt[MAX_HID_DEVICES]; | ||
| 33 | u8 report_type[MAX_HID_DEVICES]; | ||
| 34 | u8 report_id[MAX_HID_DEVICES]; | ||
| 35 | u8 sensor_idx[MAX_HID_DEVICES]; | ||
| 36 | u8 *feature_report[MAX_HID_DEVICES]; | ||
| 37 | u8 *input_report[MAX_HID_DEVICES]; | ||
| 38 | u8 request_done[MAX_HID_DEVICES]; | ||
| 39 | struct delayed_work work; | ||
| 40 | struct delayed_work work_buffer; | ||
| 41 | }; | ||
| 42 | |||
| 43 | /** | ||
| 44 | * struct amdtp_hid_data - Per instance HID data | ||
| 45 | * @index: Device index in the order of enumeration | ||
| 46 | * @request_done: Get Feature/Input report complete flag | ||
| 47 | * used during get/set request from hid core | ||
| 48 | * @cli_data: Link to the client instance | ||
| 49 | * @hid_wait: Completion waitq | ||
| 50 | * | ||
| 51 | * Used to tie hid->driver data to driver client instance | ||
| 52 | */ | ||
| 53 | struct amdtp_hid_data { | ||
| 54 | int index; | ||
| 55 | struct amdtp_cl_data *cli_data; | ||
| 56 | wait_queue_head_t hid_wait; | ||
| 57 | }; | ||
| 58 | |||
| 59 | /* Interface functions between HID LL driver and AMD SFH client */ | ||
| 60 | void hid_amdtp_set_feature(struct hid_device *hid, char *buf, u32 len, int report_id); | ||
| 61 | void hid_amdtp_get_report(struct hid_device *hid, int report_id, int report_type); | ||
| 62 | int amdtp_hid_probe(u32 cur_hid_dev, struct amdtp_cl_data *cli_data); | ||
| 63 | void amdtp_hid_remove(struct amdtp_cl_data *cli_data); | ||
| 64 | int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type); | ||
| 65 | void amd_sfh_set_report(struct hid_device *hid, int report_id, int report_type); | ||
| 66 | void amdtp_hid_wakeup(struct hid_device *hid); | ||
| 67 | #endif | ||
| @@ -0,0 +1,152 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | /* | ||
| 3 | * AMD MP2 PCIe communication driver | ||
| 4 | * Copyright 2020 Advanced Micro Devices, Inc. | ||
| 5 | * | ||
| 6 | * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> | ||
| 7 | * Sandeep Singh <Sandeep.singh@amd.com> | ||
| 8 | */ | ||
| 9 | |||
| 10 | #include <linux/bitops.h> | ||
| 11 | #include <linux/delay.h> | ||
| 12 | #include <linux/dma-mapping.h> | ||
| 13 | #include <linux/interrupt.h> | ||
| 14 | #include <linux/io-64-nonatomic-lo-hi.h> | ||
| 15 | #include <linux/module.h> | ||
| 16 | #include <linux/slab.h> | ||
| 17 | |||
| 18 | #include "amd_sfh_pcie.h" | ||
| 19 | |||
| 20 | #define DRIVER_NAME "pcie_mp2_amd" | ||
| 21 | #define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver" | ||
| 22 | |||
| 23 | #define ACEL_EN BIT(0) | ||
| 24 | #define GYRO_EN BIT(1) | ||
| 25 | #define MAGNO_EN BIT(2) | ||
| 26 | #define ALS_EN BIT(19) | ||
| 27 | |||
| 28 | void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) | ||
| 29 | { | ||
| 30 | union sfh_cmd_param cmd_param; | ||
| 31 | union sfh_cmd_base cmd_base; | ||
| 32 | |||
| 33 | /* fill up command register */ | ||
| 34 | memset(&cmd_base, 0, sizeof(cmd_base)); | ||
| 35 | cmd_base.s.cmd_id = ENABLE_SENSOR; | ||
| 36 | cmd_base.s.period = info.period; | ||
| 37 | cmd_base.s.sensor_id = info.sensor_idx; | ||
| 38 | |||
| 39 | /* fill up command param register */ | ||
| 40 | memset(&cmd_param, 0, sizeof(cmd_param)); | ||
| 41 | cmd_param.s.buf_layout = 1; | ||
| 42 | cmd_param.s.buf_length = 16; | ||
| 43 | |||
| 44 | writeq(info.phys_address, privdata->mmio + AMD_C2P_MSG2); | ||
| 45 | writel(cmd_param.ul, privdata->mmio + AMD_C2P_MSG1); | ||
| 46 | writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); | ||
| 47 | } | ||
| 48 | |||
| 49 | void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx) | ||
| 50 | { | ||
| 51 | union sfh_cmd_base cmd_base; | ||
| 52 | |||
| 53 | /* fill up command register */ | ||
| 54 | memset(&cmd_base, 0, sizeof(cmd_base)); | ||
| 55 | cmd_base.s.cmd_id = DISABLE_SENSOR; | ||
| 56 | cmd_base.s.period = 0; | ||
| 57 | cmd_base.s.sensor_id = sensor_idx; | ||
| 58 | |||
| 59 | writeq(0x0, privdata->mmio + AMD_C2P_MSG2); | ||
| 60 | writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); | ||
| 61 | } | ||
| 62 | |||
| 63 | void amd_stop_all_sensors(struct amd_mp2_dev *privdata) | ||
| 64 | { | ||
| 65 | union sfh_cmd_base cmd_base; | ||
| 66 | |||
| 67 | /* fill up command register */ | ||
| 68 | memset(&cmd_base, 0, sizeof(cmd_base)); | ||
| 69 | cmd_base.s.cmd_id = STOP_ALL_SENSORS; | ||
| 70 | cmd_base.s.period = 0; | ||
| 71 | cmd_base.s.sensor_id = 0; | ||
| 72 | |||
| 73 | writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); | ||
| 74 | } | ||
| 75 | |||
| 76 | int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id) | ||
| 77 | { | ||
| 78 | int activestatus, num_of_sensors = 0; | ||
| 79 | |||
| 80 | privdata->activecontrolstatus = readl(privdata->mmio + AMD_P2C_MSG3); | ||
| 81 | activestatus = privdata->activecontrolstatus >> 4; | ||
| 82 | if (ACEL_EN & activestatus) | ||
| 83 | sensor_id[num_of_sensors++] = accel_idx; | ||
| 84 | |||
| 85 | if (GYRO_EN & activestatus) | ||
| 86 | sensor_id[num_of_sensors++] = gyro_idx; | ||
| 87 | |||
| 88 | if (MAGNO_EN & activestatus) | ||
| 89 | sensor_id[num_of_sensors++] = mag_idx; | ||
| 90 | |||
| 91 | if (ALS_EN & activestatus) | ||
| 92 | sensor_id[num_of_sensors++] = als_idx; | ||
| 93 | |||
| 94 | return num_of_sensors; | ||
| 95 | } | ||
| 96 | |||
| 97 | static void amd_mp2_pci_remove(void *privdata) | ||
| 98 | { | ||
| 99 | amd_sfh_hid_client_deinit(privdata); | ||
| 100 | amd_stop_all_sensors(privdata); | ||
| 101 | } | ||
| 102 | |||
| 103 | static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id) | ||
| 104 | { | ||
| 105 | struct amd_mp2_dev *privdata; | ||
| 106 | int rc; | ||
| 107 | |||
| 108 | privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL); | ||
| 109 | if (!privdata) | ||
| 110 | return -ENOMEM; | ||
| 111 | |||
| 112 | privdata->pdev = pdev; | ||
| 113 | pci_set_drvdata(pdev, privdata); | ||
| 114 | rc = pcim_enable_device(pdev); | ||
| 115 | if (rc) | ||
| 116 | return rc; | ||
| 117 | |||
| 118 | rc = pcim_iomap_regions(pdev, BIT(2), DRIVER_NAME); | ||
| 119 | if (rc) | ||
| 120 | return rc; | ||
| 121 | |||
| 122 | privdata->mmio = pcim_iomap_table(pdev)[2]; | ||
| 123 | pci_set_master(pdev); | ||
| 124 | rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64)); | ||
| 125 | if (rc) { | ||
| 126 | rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); | ||
| 127 | return rc; | ||
| 128 | } | ||
| 129 | rc = devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata); | ||
| 130 | if (rc) | ||
| 131 | return rc; | ||
| 132 | |||
| 133 | return amd_sfh_hid_client_init(privdata); | ||
| 134 | } | ||
| 135 | |||
| 136 | static const struct pci_device_id amd_mp2_pci_tbl[] = { | ||
| 137 | { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) }, | ||
| 138 | { } | ||
| 139 | }; | ||
| 140 | MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl); | ||
| 141 | |||
| 142 | static struct pci_driver amd_mp2_pci_driver = { | ||
| 143 | .name = DRIVER_NAME, | ||
| 144 | .id_table = amd_mp2_pci_tbl, | ||
| 145 | .probe = amd_mp2_pci_probe, | ||
| 146 | }; | ||
| 147 | module_pci_driver(amd_mp2_pci_driver); | ||
| 148 | |||
| 149 | MODULE_DESCRIPTION(DRIVER_DESC); | ||
| 150 | MODULE_LICENSE("Dual BSD/GPL"); | ||
| 151 | MODULE_AUTHOR("Shyam Sundar S K <Shyam-sundar.S-k@amd.com>"); | ||
| 152 | MODULE_AUTHOR("Sandeep Singh <Sandeep.singh@amd.com>"); | ||
| @@ -0,0 +1,79 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
| 2 | /* | ||
| 3 | * AMD MP2 PCIe communication driver | ||
| 4 | * Copyright 2020 Advanced Micro Devices, Inc. | ||
| 5 | * Authors: Shyam Sundar S K <Shyam-sundar.S-k@amd.com> | ||
| 6 | * Sandeep Singh <Sandeep.singh@amd.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef PCIE_MP2_AMD_H | ||
| 10 | #define PCIE_MP2_AMD_H | ||
| 11 | |||
| 12 | #include <linux/pci.h> | ||
| 13 | |||
| 14 | #define PCI_DEVICE_ID_AMD_MP2 0x15E4 | ||
| 15 | |||
| 16 | #define ENABLE_SENSOR 1 | ||
| 17 | #define DISABLE_SENSOR 2 | ||
| 18 | #define STOP_ALL_SENSORS 8 | ||
| 19 | |||
| 20 | /* MP2 C2P Message Registers */ | ||
| 21 | #define AMD_C2P_MSG0 0x10500 | ||
| 22 | #define AMD_C2P_MSG1 0x10504 | ||
| 23 | #define AMD_C2P_MSG2 0x10508 | ||
| 24 | |||
| 25 | /* MP2 P2C Message Registers */ | ||
| 26 | #define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */ | ||
| 27 | |||
| 28 | /* SFH Command register */ | ||
| 29 | union sfh_cmd_base { | ||
| 30 | u32 ul; | ||
| 31 | struct { | ||
| 32 | u32 cmd_id : 8; | ||
| 33 | u32 sensor_id : 8; | ||
| 34 | u32 period : 16; | ||
| 35 | } s; | ||
| 36 | }; | ||
| 37 | |||
| 38 | union sfh_cmd_param { | ||
| 39 | u32 ul; | ||
| 40 | struct { | ||
| 41 | u32 buf_layout : 2; | ||
| 42 | u32 buf_length : 6; | ||
| 43 | u32 rsvd : 24; | ||
| 44 | } s; | ||
| 45 | }; | ||
| 46 | |||
| 47 | struct sfh_cmd_reg { | ||
| 48 | union sfh_cmd_base cmd_base; | ||
| 49 | union sfh_cmd_param cmd_param; | ||
| 50 | phys_addr_t phys_addr; | ||
| 51 | }; | ||
| 52 | |||
| 53 | enum sensor_idx { | ||
| 54 | accel_idx = 0, | ||
| 55 | gyro_idx = 1, | ||
| 56 | mag_idx = 2, | ||
| 57 | als_idx = 19 | ||
| 58 | }; | ||
| 59 | |||
| 60 | struct amd_mp2_dev { | ||
| 61 | struct pci_dev *pdev; | ||
| 62 | struct amdtp_cl_data *cl_data; | ||
| 63 | void __iomem *mmio; | ||
| 64 | u32 activecontrolstatus; | ||
| 65 | }; | ||
| 66 | |||
| 67 | struct amd_mp2_sensor_info { | ||
| 68 | u8 sensor_idx; | ||
| 69 | u32 period; | ||
| 70 | phys_addr_t phys_address; | ||
| 71 | }; | ||
| 72 | |||
| 73 | void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info); | ||
| 74 | void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx); | ||
| 75 | void amd_stop_all_sensors(struct amd_mp2_dev *privdata); | ||
| 76 | int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id); | ||
| 77 | int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata); | ||
| 78 | int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata); | ||
| 79 | #endif | ||
| @@ -0,0 +1,224 @@ | |||
| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 2 | /* | ||
| 3 | * AMD SFH Report Descriptor generator | ||
| 4 | * Copyright 2020 Advanced Micro Devices, Inc. | ||
| 5 | * Authors: Nehal Bakulchandra Shah <Nehal-Bakulchandra.Shah@amd.com> | ||
| 6 | * Sandeep Singh <sandeep.singh@amd.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/kernel.h> | ||
| 10 | #include <linux/string.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include "amd_sfh_pcie.h" | ||
| 13 | #include "amd_sfh_hid_desc.h" | ||
| 14 | #include "amd_sfh_hid_report_desc.h" | ||
| 15 | |||
| 16 | #define AMD_SFH_FW_MULTIPLIER (1000) | ||
| 17 | #define HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x41 | ||
| 18 | #define HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM 0x51 | ||
| 19 | #define HID_DEFAULT_REPORT_INTERVAL 0x50 | ||
| 20 | #define HID_DEFAULT_MIN_VALUE 0X7F | ||
| 21 | #define HID_DEFAULT_MAX_VALUE 0x80 | ||
| 22 | #define HID_DEFAULT_SENSITIVITY 0x7F | ||
| 23 | #define HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM 0x01 | ||
| 24 | /* state enums */ | ||
| 25 | #define HID_USAGE_SENSOR_STATE_READY_ENUM 0x02 | ||
| 26 | #define HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM 0x05 | ||
| 27 | #define HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM 0x04 | ||
| 28 | |||
| 29 | int get_report_descriptor(int sensor_idx, u8 *rep_desc) | ||
| 30 | { | ||
| 31 | switch (sensor_idx) { | ||
| 32 | case accel_idx: /* accel */ | ||
| 33 | memset(rep_desc, 0, sizeof(accel3_report_descriptor)); | ||
| 34 | memcpy(rep_desc, accel3_report_descriptor, | ||
| 35 | sizeof(accel3_report_descriptor)); | ||
| 36 | break; | ||
| 37 | case gyro_idx: /* gyro */ | ||
| 38 | memset(rep_desc, 0, sizeof(gyro3_report_descriptor)); | ||
| 39 | memcpy(rep_desc, gyro3_report_descriptor, | ||
| 40 | sizeof(gyro3_report_descriptor)); | ||
| 41 | break; | ||
| 42 | case mag_idx: /* Magnetometer */ | ||
| 43 | memset(rep_desc, 0, sizeof(comp3_report_descriptor)); | ||
| 44 | memcpy(rep_desc, comp3_report_descriptor, | ||
| 45 | sizeof(comp3_report_descriptor)); | ||
| 46 | break; | ||
| 47 | case als_idx: /* ambient light sensor */ | ||
| 48 | memset(rep_desc, 0, sizeof(als_report_descriptor)); | ||
| 49 | memcpy(rep_desc, als_report_descriptor, | ||
| 50 | sizeof(als_report_descriptor)); | ||
| 51 | break; | ||
| 52 | default: | ||
| 53 | break; | ||
| 54 | } | ||
| 55 | return 0; | ||
| 56 | } | ||
| 57 | |||
| 58 | u32 get_descr_sz(int sensor_idx, int descriptor_name) | ||
| 59 | { | ||
| 60 | switch (sensor_idx) { | ||
| 61 | case accel_idx: | ||
| 62 | switch (descriptor_name) { | ||
| 63 | case descr_size: | ||
| 64 | return sizeof(accel3_report_descriptor); | ||
| 65 | case input_size: | ||
| 66 | return sizeof(struct accel3_input_report); | ||
| 67 | case feature_size: | ||
| 68 | return sizeof(struct accel3_feature_report); | ||
| 69 | } | ||
| 70 | break; | ||
| 71 | case gyro_idx: | ||
| 72 | switch (descriptor_name) { | ||
| 73 | case descr_size: | ||
| 74 | return sizeof(gyro3_report_descriptor); | ||
| 75 | case input_size: | ||
| 76 | return sizeof(struct gyro_input_report); | ||
| 77 | case feature_size: | ||
| 78 | return sizeof(struct gyro_feature_report); | ||
| 79 | } | ||
| 80 | break; | ||
| 81 | case mag_idx: | ||
| 82 | switch (descriptor_name) { | ||
| 83 | case descr_size: | ||
| 84 | return sizeof(comp3_report_descriptor); | ||
| 85 | case input_size: | ||
| 86 | return sizeof(struct magno_input_report); | ||
| 87 | case feature_size: | ||
| 88 | return sizeof(struct magno_feature_report); | ||
| 89 | } | ||
| 90 | break; | ||
| 91 | case als_idx: | ||
| 92 | switch (descriptor_name) { | ||
| 93 | case descr_size: | ||
| 94 | return sizeof(als_report_descriptor); | ||
| 95 | case input_size: | ||
| 96 | return sizeof(struct als_input_report); | ||
| 97 | case feature_size: | ||
| 98 | return sizeof(struct als_feature_report); | ||
| 99 | } | ||
| 100 | break; | ||
| 101 | default: | ||
| 102 | break; | ||
| 103 | } | ||
| 104 | return 0; | ||
| 105 | } | ||
| 106 | |||
| 107 | static void get_common_features(struct common_feature_property *common, int report_id) | ||
| 108 | { | ||
| 109 | common->report_id = report_id; | ||
| 110 | common->connection_type = HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM; | ||
| 111 | common->report_state = HID_USAGE_SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM; | ||
| 112 | common->power_state = HID_USAGE_SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM; | ||
| 113 | common->sensor_state = HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM; | ||
| 114 | common->report_interval = HID_DEFAULT_REPORT_INTERVAL; | ||
| 115 | } | ||
| 116 | |||
| 117 | u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report) | ||
| 118 | { | ||
| 119 | struct accel3_feature_report acc_feature; | ||
| 120 | struct gyro_feature_report gyro_feature; | ||
| 121 | struct magno_feature_report magno_feature; | ||
| 122 | struct als_feature_report als_feature; | ||
| 123 | u8 report_size = 0; | ||
| 124 | |||
| 125 | if (!feature_report) | ||
| 126 | return report_size; | ||
| 127 | |||
| 128 | switch (sensor_idx) { | ||
| 129 | case accel_idx: /* accel */ | ||
| 130 | get_common_features(&acc_feature.common_property, report_id); | ||
| 131 | acc_feature.accel_change_sesnitivity = HID_DEFAULT_SENSITIVITY; | ||
| 132 | acc_feature.accel_sensitivity_min = HID_DEFAULT_MIN_VALUE; | ||
| 133 | acc_feature.accel_sensitivity_max = HID_DEFAULT_MAX_VALUE; | ||
| 134 | memcpy(feature_report, &acc_feature, sizeof(acc_feature)); | ||
| 135 | report_size = sizeof(acc_feature); | ||
| 136 | break; | ||
| 137 | case gyro_idx: /* gyro */ | ||
| 138 | get_common_features(&gyro_feature.common_property, report_id); | ||
| 139 | gyro_feature.gyro_change_sesnitivity = HID_DEFAULT_SENSITIVITY; | ||
| 140 | gyro_feature.gyro_sensitivity_min = HID_DEFAULT_MIN_VALUE; | ||
| 141 | gyro_feature.gyro_sensitivity_max = HID_DEFAULT_MAX_VALUE; | ||
| 142 | memcpy(feature_report, &gyro_feature, sizeof(gyro_feature)); | ||
| 143 | report_size = sizeof(gyro_feature); | ||
| 144 | break; | ||
| 145 | case mag_idx: /* Magnetometer */ | ||
| 146 | get_common_features(&magno_feature.common_property, report_id); | ||
| 147 | magno_feature.magno_headingchange_sensitivity = HID_DEFAULT_SENSITIVITY; | ||
| 148 | magno_feature.heading_min = HID_DEFAULT_MIN_VALUE; | ||
| 149 | magno_feature.heading_max = HID_DEFAULT_MAX_VALUE; | ||
| 150 | magno_feature.flux_change_sensitivity = HID_DEFAULT_MIN_VALUE; | ||
| 151 | magno_feature.flux_min = HID_DEFAULT_MIN_VALUE; | ||
| 152 | magno_feature.flux_max = HID_DEFAULT_MAX_VALUE; | ||
| 153 | memcpy(feature_report, &magno_feature, sizeof(magno_feature)); | ||
| 154 | report_size = sizeof(magno_feature); | ||
| 155 | break; | ||
| 156 | case als_idx: /* ambient light sensor */ | ||
| 157 | get_common_features(&als_feature.common_property, report_id); | ||
| 158 | als_feature.als_change_sesnitivity = HID_DEFAULT_SENSITIVITY; | ||
| 159 | als_feature.als_sensitivity_min = HID_DEFAULT_MIN_VALUE; | ||
| 160 | als_feature.als_sensitivity_max = HID_DEFAULT_MAX_VALUE; | ||
| 161 | memcpy(feature_report, &als_feature, sizeof(als_feature)); | ||
| 162 | report_size = sizeof(als_feature); | ||
| 163 | break; | ||
| 164 | default: | ||
| 165 | break; | ||
| 166 | } | ||
| 167 | return report_size; | ||
| 168 | } | ||
| 169 | |||
| 170 | static void get_common_inputs(struct common_input_property *common, int report_id) | ||
| 171 | { | ||
| 172 | common->report_id = report_id; | ||
| 173 | common->sensor_state = HID_USAGE_SENSOR_STATE_READY_ENUM; | ||
| 174 | common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM; | ||
| 175 | } | ||
| 176 | |||
| 177 | u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor_virt_addr) | ||
| 178 | { | ||
| 179 | struct accel3_input_report acc_input; | ||
| 180 | struct gyro_input_report gyro_input; | ||
| 181 | struct magno_input_report magno_input; | ||
| 182 | struct als_input_report als_input; | ||
| 183 | u8 report_size = 0; | ||
| 184 | |||
| 185 | if (!sensor_virt_addr || !input_report) | ||
| 186 | return report_size; | ||
| 187 | |||
| 188 | switch (sensor_idx) { | ||
| 189 | case accel_idx: /* accel */ | ||
| 190 | get_common_inputs(&acc_input.common_property, report_id); | ||
| 191 | acc_input.in_accel_x_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; | ||
| 192 | acc_input.in_accel_y_value = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER; | ||
| 193 | acc_input.in_accel_z_value = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER; | ||
| 194 | memcpy(input_report, &acc_input, sizeof(acc_input)); | ||
| 195 | report_size = sizeof(acc_input); | ||
| 196 | break; | ||
| 197 | case gyro_idx: /* gyro */ | ||
| 198 | get_common_inputs(&gyro_input.common_property, report_id); | ||
| 199 | gyro_input.in_angel_x_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; | ||
| 200 | gyro_input.in_angel_y_value = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER; | ||
| 201 | gyro_input.in_angel_z_value = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER; | ||
| 202 | memcpy(input_report, &gyro_input, sizeof(gyro_input)); | ||
| 203 | report_size = sizeof(gyro_input); | ||
| 204 | break; | ||
| 205 | case mag_idx: /* Magnetometer */ | ||
| 206 | get_common_inputs(&magno_input.common_property, report_id); | ||
| 207 | magno_input.in_magno_x = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; | ||
| 208 | magno_input.in_magno_y = (int)sensor_virt_addr[1] / AMD_SFH_FW_MULTIPLIER; | ||
| 209 | magno_input.in_magno_z = (int)sensor_virt_addr[2] / AMD_SFH_FW_MULTIPLIER; | ||
| 210 | magno_input.in_magno_accuracy = (u16)sensor_virt_addr[3] / AMD_SFH_FW_MULTIPLIER; | ||
| 211 | memcpy(input_report, &magno_input, sizeof(magno_input)); | ||
| 212 | report_size = sizeof(magno_input); | ||
| 213 | break; | ||
| 214 | case als_idx: /* Als */ | ||
| 215 | get_common_inputs(&als_input.common_property, report_id); | ||
| 216 | als_input.illuminance_value = (int)sensor_virt_addr[0] / AMD_SFH_FW_MULTIPLIER; | ||
| 217 | report_size = sizeof(als_input); | ||
| 218 | memcpy(input_report, &als_input, sizeof(als_input)); | ||
| 219 | break; | ||
| 220 | default: | ||
| 221 | break; | ||
| 222 | } | ||
| 223 | return report_size; | ||
| 224 | } | ||
| @@ -0,0 +1,107 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
| 2 | /* | ||
| 3 | * HID report descriptors, structures and routines | ||
| 4 | * Copyright 2020 Advanced Micro Devices, Inc. | ||
| 5 | * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com> | ||
| 6 | * Sandeep Singh <Sandeep.singh@amd.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef AMD_SFH_HID_DESCRIPTOR_H | ||
| 10 | #define AMD_SFH_HID_DESCRIPTOR_H | ||
| 11 | |||
| 12 | enum desc_type { | ||
| 13 | /* Report descriptor name */ | ||
| 14 | descr_size = 1, | ||
| 15 | input_size, | ||
| 16 | feature_size, | ||
| 17 | }; | ||
| 18 | |||
| 19 | struct common_feature_property { | ||
| 20 | /* common properties */ | ||
| 21 | u8 report_id; | ||
| 22 | u8 connection_type; | ||
| 23 | u8 report_state; | ||
| 24 | u8 power_state; | ||
| 25 | u8 sensor_state; | ||
| 26 | u32 report_interval; | ||
| 27 | } __packed; | ||
| 28 | |||
| 29 | struct common_input_property { | ||
| 30 | /* common properties */ | ||
| 31 | u8 report_id; | ||
| 32 | u8 sensor_state; | ||
| 33 | u8 event_type; | ||
| 34 | } __packed; | ||
| 35 | |||
| 36 | struct accel3_feature_report { | ||
| 37 | struct common_feature_property common_property; | ||
| 38 | /* properties specific to this sensor */ | ||
| 39 | u16 accel_change_sesnitivity; | ||
| 40 | s16 accel_sensitivity_max; | ||
| 41 | s16 accel_sensitivity_min; | ||
| 42 | } __packed; | ||
| 43 | |||
| 44 | struct accel3_input_report { | ||
| 45 | struct common_input_property common_property; | ||
| 46 | /* values specific to this sensor */ | ||
| 47 | int in_accel_x_value; | ||
| 48 | int in_accel_y_value; | ||
| 49 | int in_accel_z_value; | ||
| 50 | /* include if required to support the "shake" event */ | ||
| 51 | u8 in_accel_shake_detection; | ||
| 52 | } __packed; | ||
| 53 | |||
| 54 | struct gyro_feature_report { | ||
| 55 | struct common_feature_property common_property; | ||
| 56 | /* properties specific to this sensor */ | ||
| 57 | u16 gyro_change_sesnitivity; | ||
| 58 | s16 gyro_sensitivity_max; | ||
| 59 | s16 gyro_sensitivity_min; | ||
| 60 | } __packed; | ||
| 61 | |||
| 62 | struct gyro_input_report { | ||
| 63 | struct common_input_property common_property; | ||
| 64 | /* values specific to this sensor */ | ||
| 65 | int in_angel_x_value; | ||
| 66 | int in_angel_y_value; | ||
| 67 | int in_angel_z_value; | ||
| 68 | } __packed; | ||
| 69 | |||
| 70 | struct magno_feature_report { | ||
| 71 | struct common_feature_property common_property; | ||
| 72 | /*properties specific to this sensor */ | ||
| 73 | u16 magno_headingchange_sensitivity; | ||
| 74 | s16 heading_min; | ||
| 75 | s16 heading_max; | ||
| 76 | u16 flux_change_sensitivity; | ||
| 77 | s16 flux_min; | ||
| 78 | s16 flux_max; | ||
| 79 | } __packed; | ||
| 80 | |||
| 81 | struct magno_input_report { | ||
| 82 | struct common_input_property common_property; | ||
| 83 | int in_magno_x; | ||
| 84 | int in_magno_y; | ||
| 85 | int in_magno_z; | ||
| 86 | int in_magno_accuracy; | ||
| 87 | } __packed; | ||
| 88 | |||
| 89 | struct als_feature_report { | ||
| 90 | struct common_feature_property common_property; | ||
| 91 | /* properties specific to this sensor */ | ||
| 92 | u16 als_change_sesnitivity; | ||
| 93 | s16 als_sensitivity_max; | ||
| 94 | s16 als_sensitivity_min; | ||
| 95 | } __packed; | ||
| 96 | |||
| 97 | struct als_input_report { | ||
| 98 | struct common_input_property common_property; | ||
| 99 | /* values specific to this sensor */ | ||
| 100 | int illuminance_value; | ||
| 101 | } __packed; | ||
| 102 | |||
| 103 | int get_report_descriptor(int sensor_idx, u8 rep_desc[]); | ||
| 104 | u32 get_descr_sz(int sensor_idx, int descriptor_name); | ||
| 105 | u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report); | ||
| 106 | u8 get_input_report(int sensor_idx, int report_id, u8 *input_report, u32 *sensor_virt_addr); | ||
| 107 | #endif | ||
| @@ -0,0 +1,645 @@ | |||
| 1 | /* SPDX-License-Identifier: GPL-2.0-or-later */ | ||
| 2 | /* | ||
| 3 | * HID descriptor stuructures | ||
| 4 | * Copyright 2020 Advanced Micro Devices, Inc. | ||
| 5 | * Authors: Nehal Bakulchandra Shah <Nehal-bakulchandra.shah@amd.com> | ||
| 6 | * Sandeep Singh <Sandeep.singh@amd.com> | ||
| 7 | */ | ||
| 8 | |||
| 9 | #ifndef AMD_SFH_HID_REPORT_DESCRIPTOR_H | ||
| 10 | #define AMD_SFH_HID_REPORT_DESCRIPTOR_H | ||
| 11 | |||
| 12 | // Accelerometer 3D Sensor | ||
| 13 | static const u8 accel3_report_descriptor[] = { | ||
| 14 | 0x05, 0x20, /* Usage page */ | ||
| 15 | 0x09, 0x73, /* Motion type Accel 3D */ | ||
| 16 | 0xA1, 0x00, /* HID Collection (Physical) */ | ||
| 17 | |||
| 18 | //feature reports(xmit/receive) | ||
| 19 | 0x85, 1, /* HID Report ID */ | ||
| 20 | 0x05, 0x20, /* HID usage page sensor */ | ||
| 21 | 0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */ | ||
| 22 | 0x15, 0, /* HID logical MIN_8(0) */ | ||
| 23 | 0x25, 2, /* HID logical MAX_8(2) */ | ||
| 24 | 0x75, 8, /* HID report size(8) */ | ||
| 25 | 0x95, 1, /* HID report count(1) */ | ||
| 26 | 0xA1, 0x02, /* HID collection (logical) */ | ||
| 27 | 0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel*/ | ||
| 28 | 0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */ | ||
| 29 | 0x0A, 0x32, 0x08, /* Sensor property connection type external sel */ | ||
| 30 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 31 | 0xC0, /* HID end collection */ | ||
| 32 | 0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */ | ||
| 33 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 34 | 0x25, 5, /* HID logical Max_8(5) */ | ||
| 35 | 0x75, 8, /* HID report size(8) */ | ||
| 36 | 0x95, 1, /* HID report count(1) */ | ||
| 37 | 0xA1, 0x02, /* HID collection(logical) */ | ||
| 38 | 0x0A, 0x40, 0x08, /* Sensor property report state no events sel */ | ||
| 39 | 0x0A, 0x41, 0x08, /* Sensor property report state all events sel */ | ||
| 40 | 0x0A, 0x42, 0x08, /* Sensor property report state threshold events sel */ | ||
| 41 | 0x0A, 0x43, 0x08, /* Sensor property report state no events wake sel */ | ||
| 42 | 0x0A, 0x44, 0x08, /* Sensor property report state all events wake sel */ | ||
| 43 | 0x0A, 0x45, 0x08, /* Sensor property report state threshold events wake sel */ | ||
| 44 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 45 | 0xC0, /* HID end collection */ | ||
| 46 | 0x0A, 0x19, 0x03, /* HID usage sensor property power state */ | ||
| 47 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 48 | 0x25, 5, /* HID logical Max_8(5) */ | ||
| 49 | 0x75, 8, /* HID report size(8) */ | ||
| 50 | 0x95, 1, /* HID report count(1) */ | ||
| 51 | 0xA1, 0x02, /* HID collection(logical) */ | ||
| 52 | 0x0A, 0x50, 0x08, /* Sensor property power state undefined sel */ | ||
| 53 | 0x0A, 0x51, 0x08, /* Sensor property power state D0 full power sel */ | ||
| 54 | 0x0A, 0x52, 0x08, /* Sensor property power state D1 low power sel */ | ||
| 55 | 0x0A, 0x53, 0x08, /* Sensor property power state D2 standby with wake sel */ | ||
| 56 | 0x0A, 0x54, 0x08, /* Sensor property power state D3 sleep with wake sel */ | ||
| 57 | 0x0A, 0x55, 0x08, /* Sensor property power state D4 power off sel */ | ||
| 58 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 59 | 0xC0, /* HID end collection */ | ||
| 60 | 0x0A, 0x01, 0x02, /* HID usage sensor state */ | ||
| 61 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 62 | 0x25, 6, /* HID logical Max_8(6) */ | ||
| 63 | 0x75, 8, /* HID report size(8) */ | ||
| 64 | 0x95, 1, /* HID report count(1) */ | ||
| 65 | 0xA1, 0x02, /* HID collection(logical) */ | ||
| 66 | 0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ | ||
| 67 | 0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ | ||
| 68 | 0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ | ||
| 69 | 0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ | ||
| 70 | 0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ | ||
| 71 | 0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ | ||
| 72 | 0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ | ||
| 73 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 74 | 0xC0, /* HID end collection */ | ||
| 75 | 0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */ | ||
| 76 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 77 | 0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */ | ||
| 78 | |||
| 79 | 0x75, 32, /* HID report size(32) */ | ||
| 80 | 0x95, 1, /* HID report count(1) */ | ||
| 81 | 0x55, 0, /* HID unit exponent(0) */ | ||
| 82 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 83 | 0x0A, 0x52, 0x14, /* Sensor data motion accel and mod change sensitivity ABS) */ | ||
| 84 | |||
| 85 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 86 | 0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */ | ||
| 87 | |||
| 88 | 0x75, 16, /* HID report size(16) */ | ||
| 89 | 0x95, 1, /* HID report count(1) */ | ||
| 90 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 91 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 92 | 0x0A, 0x52, 0x24, /* HID usage sensor data (motion accel and mod max) */ | ||
| 93 | |||
| 94 | 0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ | ||
| 95 | |||
| 96 | 0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ | ||
| 97 | |||
| 98 | 0x75, 16, /* HID report size(16) */ | ||
| 99 | 0x95, 1, /* HID report count(1) */ | ||
| 100 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 101 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 102 | 0x0A, 0x52, 0x34, /* HID usage sensor data (motion accel and mod min) */ | ||
| 103 | |||
| 104 | 0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ | ||
| 105 | |||
| 106 | 0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ | ||
| 107 | |||
| 108 | 0x75, 16, /* HID report size(16) */ | ||
| 109 | 0x95, 1, /* HID report count(1) */ | ||
| 110 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 111 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 112 | |||
| 113 | //input report (transmit) | ||
| 114 | 0x05, 0x20, /* HID usage page sensors */ | ||
| 115 | 0x0A, 0x01, 0x02, /* HID usage sensor state */ | ||
| 116 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 117 | 0x25, 6, /* HID logical Max_8(6) */ | ||
| 118 | 0x75, 8, /* HID report size(8) */ | ||
| 119 | 0x95, 1, /* HID report count (1) */ | ||
| 120 | 0xA1, 0x02, /* HID end collection (logical) */ | ||
| 121 | 0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ | ||
| 122 | 0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ | ||
| 123 | 0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ | ||
| 124 | 0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ | ||
| 125 | 0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ | ||
| 126 | 0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ | ||
| 127 | 0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ | ||
| 128 | 0X81, 0x00, /* HID Input (Data_Arr_Abs) */ | ||
| 129 | 0xC0, /* HID end collection */ | ||
| 130 | 0x0A, 0x02, 0x02, /* HID usage sensor event */ | ||
| 131 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 132 | 0x25, 5, /* HID logical Max_8(5) */ | ||
| 133 | 0x75, 8, /* HID report size(8) */ | ||
| 134 | 0x95, 1, /* HID report count (1) */ | ||
| 135 | 0xA1, 0x02, /* HID end collection (logical) */ | ||
| 136 | 0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */ | ||
| 137 | 0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */ | ||
| 138 | 0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */ | ||
| 139 | 0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */ | ||
| 140 | 0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */ | ||
| 141 | 0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */ | ||
| 142 | 0X81, 0x00, /* HID Input (Data_Arr_Abs) */ | ||
| 143 | 0xC0, /* HID end collection */ | ||
| 144 | 0x0A, 0x53, 0x04, /* HID usage sensor data motion Acceleration X axis */ | ||
| 145 | 0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ | ||
| 146 | |||
| 147 | 0x27, 0xFF, 0xff, 0XFF, 0XFF, /* HID logical Max_32 */ | ||
| 148 | |||
| 149 | 0x75, 32, /* HID report size(32) */ | ||
| 150 | 0x95, 1, /* HID report count (1) */ | ||
| 151 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 152 | 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ | ||
| 153 | 0x0A, 0x54, 0x04, /* HID usage sensor data motion Acceleration Y axis */ | ||
| 154 | 0x17, 0X00, 0X00, 0x01, 0x80, /* HID logical Min_32 */ | ||
| 155 | |||
| 156 | 0x27, 0xFF, 0xFF, 0XFF, 0XFF, /* HID logical Max_32 */ | ||
| 157 | |||
| 158 | 0x75, 32, /* HID report size(32) */ | ||
| 159 | 0x95, 1, /* HID report count (1) */ | ||
| 160 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 161 | 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ | ||
| 162 | 0x0A, 0x55, 0x04, /* HID usage sensor data motion Acceleration Z axis */ | ||
| 163 | 0x17, 0X00, 0X00, 0x01, 0x80, /* HID logical Min_32 */ | ||
| 164 | |||
| 165 | 0x27, 0XFF, 0XFF, 0xFF, 0x7F, /* HID logical Max_32 */ | ||
| 166 | |||
| 167 | 0x75, 32, /* HID report size(32) */ | ||
| 168 | 0x95, 1, /* HID report count (1) */ | ||
| 169 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 170 | 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ | ||
| 171 | |||
| 172 | 0x0A, 0x51, 0x04, /* HID usage sensor data motion state */ | ||
| 173 | 0x15, 0, /* HID logical Min_8(0) False = Still*/ | ||
| 174 | 0x25, 1, /* HID logical Min_8(1) True = In motion */ | ||
| 175 | 0x75, 8, /* HID report size(8) */ | ||
| 176 | 0x95, 1, /* HID report count (1) */ | ||
| 177 | 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ | ||
| 178 | 0xC0 /* HID end collection */ | ||
| 179 | }; | ||
| 180 | |||
| 181 | const u8 gyro3_report_descriptor[] = { | ||
| 182 | 0x05, 0x20, /* Usage page */ | ||
| 183 | 0x09, 0x76, /* Motion type Gyro3D */ | ||
| 184 | 0xA1, 0x00, /* HID Collection (Physical) */ | ||
| 185 | |||
| 186 | 0x85, 2, /* HID Report ID */ | ||
| 187 | 0x05, 0x20, /* HID usage page sensor */ | ||
| 188 | 0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */ | ||
| 189 | 0x15, 0, /* HID logical MIN_8(0) */ | ||
| 190 | 0x25, 2, /* HID logical MAX_8(2) */ | ||
| 191 | 0x75, 8, /* HID report size(8) */ | ||
| 192 | 0x95, 1, /* HID report count(1) */ | ||
| 193 | 0xA1, 0x02, /* HID collection (logical) */ | ||
| 194 | 0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */ | ||
| 195 | 0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */ | ||
| 196 | 0x0A, 0x32, 0x08, /* Sensor property connection type external sel */ | ||
| 197 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 198 | 0xC0, /* HID end collection */ | ||
| 199 | 0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */ | ||
| 200 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 201 | 0x25, 5, /* HID logical Max_8(5) */ | ||
| 202 | 0x75, 8, /* HID report size(8) */ | ||
| 203 | 0x95, 1, /* HID report count(1) */ | ||
| 204 | 0xA1, 0x02, /* HID collection(logical) */ | ||
| 205 | 0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */ | ||
| 206 | 0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */ | ||
| 207 | 0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */ | ||
| 208 | 0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */ | ||
| 209 | 0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */ | ||
| 210 | 0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */ | ||
| 211 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 212 | 0xC0, /* HID end collection */ | ||
| 213 | 0x0A, 0x19, 0x03, /* HID usage sensor property power state */ | ||
| 214 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 215 | 0x25, 5, /* HID logical Max_8(5) */ | ||
| 216 | 0x75, 8, /* HID report size(8) */ | ||
| 217 | 0x95, 1, /* HID report count(1) */ | ||
| 218 | 0xA1, 0x02, /* HID collection(logical) */ | ||
| 219 | 0x0A, 0x50, 0x08, /* Sensor power state undefined sel */ | ||
| 220 | 0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */ | ||
| 221 | 0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */ | ||
| 222 | 0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */ | ||
| 223 | 0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */ | ||
| 224 | 0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */ | ||
| 225 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 226 | 0xC0, /* HID end collection */ | ||
| 227 | 0x0A, 0x01, 0x02, /* HID usage sensor state */ | ||
| 228 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 229 | 0x25, 6, /* HID logical Max_8(6) */ | ||
| 230 | 0x75, 8, /* HID report size(8) */ | ||
| 231 | 0x95, 1, /* HID report count(1) */ | ||
| 232 | 0xA1, 0x02, /* HID collection(logical) */ | ||
| 233 | 0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ | ||
| 234 | 0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ | ||
| 235 | 0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ | ||
| 236 | 0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ | ||
| 237 | 0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ | ||
| 238 | 0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ | ||
| 239 | 0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ | ||
| 240 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 241 | 0xC0, /* HID end collection */ | ||
| 242 | 0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */ | ||
| 243 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 244 | 0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */ | ||
| 245 | |||
| 246 | 0x75, 32, /* HID report size(32) */ | ||
| 247 | 0x95, 1, /* HID report count(1) */ | ||
| 248 | 0x55, 0, /* HID unit exponent(0) */ | ||
| 249 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 250 | 0x0A, 0x56, 0x14, /* Angular velocity and mod change sensitivity ABS)*/ | ||
| 251 | |||
| 252 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 253 | 0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */ | ||
| 254 | |||
| 255 | 0x75, 16, /* HID report size(16) */ | ||
| 256 | 0x95, 1, /* HID report count(1) */ | ||
| 257 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 258 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 259 | 0x0A, 0x56, 0x24, /* Sensor data (motion angular velocity and mod max) */ | ||
| 260 | |||
| 261 | 0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ | ||
| 262 | |||
| 263 | 0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ | ||
| 264 | |||
| 265 | 0x75, 16, /* HID report size(16) */ | ||
| 266 | 0x95, 1, /* HID report count(1) */ | ||
| 267 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 268 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 269 | 0x0A, 0x56, 0x34, /* HID usage sensor data (motion accel and mod min) */ | ||
| 270 | |||
| 271 | 0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ | ||
| 272 | |||
| 273 | 0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ | ||
| 274 | |||
| 275 | 0x75, 16, /* HID report size(16) */ | ||
| 276 | 0x95, 1, /* HID report count(1) */ | ||
| 277 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 278 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 279 | |||
| 280 | //Input reports(transmit) | ||
| 281 | 0x05, 0x20, /* HID usage page sensors */ | ||
| 282 | 0x0A, 0x01, 0x02, /* HID usage sensor state */ | ||
| 283 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 284 | 0x25, 6, /* HID logical Max_8(6) */ | ||
| 285 | 0x75, 8, /* HID report size(8) */ | ||
| 286 | 0x95, 1, /* HID report count (1) */ | ||
| 287 | 0xA1, 0x02, /* HID end collection (logical) */ | ||
| 288 | 0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ | ||
| 289 | 0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ | ||
| 290 | 0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ | ||
| 291 | 0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ | ||
| 292 | 0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ | ||
| 293 | 0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ | ||
| 294 | 0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ | ||
| 295 | 0X81, 0x00, /* HID Input (Data_Arr_Abs) */ | ||
| 296 | 0xC0, /* HID end collection */ | ||
| 297 | 0x0A, 0x02, 0x02, /* HID usage sensor event */ | ||
| 298 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 299 | 0x25, 5, /* HID logical Max_8(5) */ | ||
| 300 | 0x75, 8, /* HID report size(8) */ | ||
| 301 | 0x95, 1, /* HID report count (1) */ | ||
| 302 | 0xA1, 0x02, /* HID end collection (logical) */ | ||
| 303 | 0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */ | ||
| 304 | 0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */ | ||
| 305 | 0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */ | ||
| 306 | 0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */ | ||
| 307 | 0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */ | ||
| 308 | 0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */ | ||
| 309 | 0X81, 0x00, /* HID Input (Data_Arr_Abs) */ | ||
| 310 | 0xC0, /* HID end collection */ | ||
| 311 | 0x0A, 0x57, 0x04, /* Sensor data motion Angular velocity X axis */ | ||
| 312 | 0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ | ||
| 313 | |||
| 314 | 0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ | ||
| 315 | |||
| 316 | 0x75, 32, /* HID report size(32) */ | ||
| 317 | 0x95, 1, /* HID report count (1) */ | ||
| 318 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 319 | 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ | ||
| 320 | 0x0A, 0x58, 0x04, /* Sensor data motion Angular velocity Y axis */ | ||
| 321 | 0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ | ||
| 322 | |||
| 323 | 0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ | ||
| 324 | |||
| 325 | 0x75, 32, /* HID report size(32) */ | ||
| 326 | 0x95, 1, /* HID report count (1) */ | ||
| 327 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 328 | 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ | ||
| 329 | 0x0A, 0x59, 0x04, /* Sensor data motion Angular velocity Z axis */ | ||
| 330 | 0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ | ||
| 331 | |||
| 332 | 0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ | ||
| 333 | |||
| 334 | 0x75, 32, /* HID report size(32) */ | ||
| 335 | 0x95, 1, /* HID report count (1) */ | ||
| 336 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 337 | 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ | ||
| 338 | |||
| 339 | 0xC0, /* HID end collection */ | ||
| 340 | }; | ||
| 341 | |||
| 342 | const u8 comp3_report_descriptor[] = { | ||
| 343 | 0x05, 0x20, /* Usage page */ | ||
| 344 | 0x09, 0x83, /* Motion type Orientation compass 3D */ | ||
| 345 | 0xA1, 0x00, /* HID Collection (Physical) */ | ||
| 346 | |||
| 347 | 0x85, 3, /* HID Report ID */ | ||
| 348 | 0x05, 0x20, /* HID usage page sensor */ | ||
| 349 | 0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */ | ||
| 350 | 0x15, 0, /* HID logical MIN_8(0) */ | ||
| 351 | 0x25, 2, /* HID logical MAX_8(2) */ | ||
| 352 | 0x75, 8, /* HID report size(8) */ | ||
| 353 | 0x95, 1, /* HID report count(1) */ | ||
| 354 | 0xA1, 0x02, /* HID collection (logical) */ | ||
| 355 | 0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */ | ||
| 356 | 0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */ | ||
| 357 | 0x0A, 0x32, 0x08, /* Sensor property connection type external sel */ | ||
| 358 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 359 | 0xC0, /* HID end collection */ | ||
| 360 | 0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */ | ||
| 361 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 362 | 0x25, 5, /* HID logical Max_8(5) */ | ||
| 363 | 0x75, 8, /* HID report size(8) */ | ||
| 364 | 0x95, 1, /* HID report count(1) */ | ||
| 365 | 0xA1, 0x02, /* HID collection(logical) */ | ||
| 366 | 0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */ | ||
| 367 | 0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */ | ||
| 368 | 0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */ | ||
| 369 | 0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */ | ||
| 370 | 0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */ | ||
| 371 | 0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */ | ||
| 372 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 373 | 0xC0, /* HID end collection */ | ||
| 374 | 0x0A, 0x19, 0x03, /* HID usage sensor property power state */ | ||
| 375 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 376 | 0x25, 5, /* HID logical Max_8(5) */ | ||
| 377 | 0x75, 8, /* HID report size(8) */ | ||
| 378 | 0x95, 1, /* HID report count(1) */ | ||
| 379 | 0xA1, 0x02, /* HID collection(logical) */ | ||
| 380 | 0x0A, 0x50, 0x08, /* Sensor power state undefined sel */ | ||
| 381 | 0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */ | ||
| 382 | 0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */ | ||
| 383 | 0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */ | ||
| 384 | 0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */ | ||
| 385 | 0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */ | ||
| 386 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 387 | 0xC0, /* HID end collection */ | ||
| 388 | 0x0A, 0x01, 0x02, /* HID usage sensor state */ | ||
| 389 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 390 | 0x25, 6, /* HID logical Max_8(6) */ | ||
| 391 | 0x75, 8, /* HID report size(8) */ | ||
| 392 | 0x95, 1, /* HID report count(1) */ | ||
| 393 | 0xA1, 0x02, /* HID collection(logical) */ | ||
| 394 | 0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ | ||
| 395 | 0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ | ||
| 396 | 0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ | ||
| 397 | 0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ | ||
| 398 | 0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ | ||
| 399 | 0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ | ||
| 400 | 0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ | ||
| 401 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 402 | 0xC0, /* HID end collection */ | ||
| 403 | 0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */ | ||
| 404 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 405 | 0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */ | ||
| 406 | 0x75, 32, /* HID report size(32) */ | ||
| 407 | 0x95, 1, /* HID report count(1) */ | ||
| 408 | 0x55, 0, /* HID unit exponent(0) */ | ||
| 409 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 410 | 0x0A, 0x71, 0x14, /* Orientation and mod change sensitivity ABS)*/ | ||
| 411 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 412 | 0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */ | ||
| 413 | 0x75, 16, /* HID report size(16) */ | ||
| 414 | 0x95, 1, /* HID report count(1) */ | ||
| 415 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 416 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 417 | 0x0A, 0x71, 0x24, /* Sensor data (motion orientation and mod max) */ | ||
| 418 | 0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ | ||
| 419 | 0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ | ||
| 420 | 0x75, 16, /* HID report size(16) */ | ||
| 421 | 0x95, 1, /* HID report count(1) */ | ||
| 422 | 0x55, 0x0F, /* HID unit exponent(0x0F) */ | ||
| 423 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 424 | 0x0A, 0x71, 0x34, /* Sensor data (motion orientation and mod min) */ | ||
| 425 | 0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ | ||
| 426 | 0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ | ||
| 427 | 0x75, 16, /* HID report size(16) */ | ||
| 428 | 0x95, 1, /* HID report count(1) */ | ||
| 429 | 0x55, 0x0F, /* HID unit exponent(0x0F) */ | ||
| 430 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 431 | 0x0A, 0x84, 0x14, /* Maganetic flux and change sensitivity ABS) */ | ||
| 432 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 433 | 0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */ | ||
| 434 | 0x75, 16, /* HID report size(16) */ | ||
| 435 | 0x95, 1, /* HID report count(1) */ | ||
| 436 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 437 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 438 | 0x0A, 0x84, 0x24, /* Maganetic flux and mod change sensitivity Max) */ | ||
| 439 | 0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ | ||
| 440 | 0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ | ||
| 441 | 0x75, 16, /* HID report size(16) */ | ||
| 442 | 0x95, 1, /* HID report count(1) */ | ||
| 443 | 0x55, 0x0F, /* HID unit exponent(0x0F) */ | ||
| 444 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 445 | 0x0A, 0x84, 0x34, /* Maganetic flux and mod change sensitivity Min */ | ||
| 446 | 0x16, 0x01, 0x80, /* HID logical Min_16(0x01,0x80) */ | ||
| 447 | 0x26, 0xFF, 0x7F, /* HID logical Max_16(0xFF,0x7F) */ | ||
| 448 | 0x75, 16, /* HID report size(16) */ | ||
| 449 | 0x95, 1, /* HID report count(1) */ | ||
| 450 | 0x55, 0x0F, /* HID unit exponent(0x0F) */ | ||
| 451 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 452 | |||
| 453 | //Input reports(transmit) | ||
| 454 | 0x05, 0x20, /* HID usage page sensors */ | ||
| 455 | 0x0A, 0x01, 0x02, /* HID usage sensor state */ | ||
| 456 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 457 | 0x25, 6, /* HID logical Max_8(6) */ | ||
| 458 | 0x75, 8, /* HID report size(8) */ | ||
| 459 | 0x95, 1, /* HID report count (1) */ | ||
| 460 | 0xA1, 0x02, /* HID end collection (logical) */ | ||
| 461 | 0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ | ||
| 462 | 0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ | ||
| 463 | 0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ | ||
| 464 | 0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ | ||
| 465 | 0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ | ||
| 466 | 0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ | ||
| 467 | 0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ | ||
| 468 | 0X81, 0x00, /* HID Input (Data_Arr_Abs) */ | ||
| 469 | 0xC0, /* HID end collection */ | ||
| 470 | 0x0A, 0x02, 0x02, /* HID usage sensor event */ | ||
| 471 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 472 | 0x25, 5, /* HID logical Max_8(5) */ | ||
| 473 | 0x75, 8, /* HID report size(8) */ | ||
| 474 | 0x95, 1, /* HID report count (1) */ | ||
| 475 | 0xA1, 0x02, /* HID end collection (logical) */ | ||
| 476 | 0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */ | ||
| 477 | 0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */ | ||
| 478 | 0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */ | ||
| 479 | 0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */ | ||
| 480 | 0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */ | ||
| 481 | 0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */ | ||
| 482 | 0X81, 0x00, /* HID Input (Data_Arr_Abs) */ | ||
| 483 | 0xC0, /* HID end collection */ | ||
| 484 | 0x0A, 0x85, 0x04, /* Sensor data orientation magnetic flux X axis */ | ||
| 485 | 0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ | ||
| 486 | 0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ | ||
| 487 | 0x75, 32, /* HID report size(32) */ | ||
| 488 | 0x95, 1, /* HID report count (1) */ | ||
| 489 | 0x55, 0x0D, /* HID unit exponent(0x0D) */ | ||
| 490 | 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ | ||
| 491 | 0x0A, 0x86, 0x04, /* Sensor data orientation magnetic flux Y axis */ | ||
| 492 | 0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ | ||
| 493 | 0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ | ||
| 494 | 0x75, 32, /* HID report size(32) */ | ||
| 495 | 0x95, 1, /* HID report count (1) */ | ||
| 496 | 0x55, 0x0D, /* HID unit exponent(0x0D) */ | ||
| 497 | 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ | ||
| 498 | 0x0A, 0x87, 0x04, /* Sensor data orientation magnetic flux Z axis */ | ||
| 499 | 0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ | ||
| 500 | 0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ | ||
| 501 | 0x75, 32, /* HID report size(32) */ | ||
| 502 | 0x95, 1, /* HID report count (1) */ | ||
| 503 | 0x55, 0x0D, /* HID unit exponent(0x0D) */ | ||
| 504 | 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ | ||
| 505 | 0x0A, 0x88, 0x04, /* Sensor data orientation magnetometer accuracy */ | ||
| 506 | 0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ | ||
| 507 | 0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ | ||
| 508 | 0x75, 32, /* HID report size(32) */ | ||
| 509 | 0x95, 1, /* HID report count (1) */ | ||
| 510 | 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ | ||
| 511 | 0xC0 /* HID end collection */ | ||
| 512 | }; | ||
| 513 | |||
| 514 | const u8 als_report_descriptor[] = { | ||
| 515 | 0x05, 0x20, /* HID usage page sensor */ | ||
| 516 | 0x09, 0x41, /* HID usage sensor type Ambientlight */ | ||
| 517 | 0xA1, 0x00, /* HID Collection (Physical) */ | ||
| 518 | |||
| 519 | //feature reports(xmit/receive)// | ||
| 520 | 0x85, 4, /* HID Report ID */ | ||
| 521 | 0x05, 0x20, /* HID usage page sensor */ | ||
| 522 | 0x0A, 0x09, 0x03, /* Sensor property and sensor connection type */ | ||
| 523 | 0x15, 0, /* HID logical MIN_8(0) */ | ||
| 524 | 0x25, 2, /* HID logical MAX_8(2) */ | ||
| 525 | 0x75, 8, /* HID report size(8) */ | ||
| 526 | 0x95, 1, /* HID report count(1) */ | ||
| 527 | 0xA1, 0x02, /* HID collection (logical) */ | ||
| 528 | 0x0A, 0x30, 0x08, /* Sensor property connection type intergated sel */ | ||
| 529 | 0x0A, 0x31, 0x08, /* Sensor property connection type attached sel */ | ||
| 530 | 0x0A, 0x32, 0x08, /* Sensor property connection type external sel */ | ||
| 531 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 532 | 0xC0, /* HID end collection */ | ||
| 533 | 0x0A, 0x16, 0x03, /* HID usage sensor property reporting state */ | ||
| 534 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 535 | 0x25, 5, /* HID logical Max_8(5) */ | ||
| 536 | 0x75, 8, /* HID report size(8) */ | ||
| 537 | 0x95, 1, /* HID report count(1) */ | ||
| 538 | 0xA1, 0x02, /* HID collection(logical) */ | ||
| 539 | 0x0A, 0x40, 0x08, /* Sensor reporting state no events sel */ | ||
| 540 | 0x0A, 0x41, 0x08, /* Sensor reporting state all events sel */ | ||
| 541 | 0x0A, 0x42, 0x08, /* Sensor reporting state threshold events sel */ | ||
| 542 | 0x0A, 0x43, 0x08, /* Sensor reporting state no events wake sel */ | ||
| 543 | 0x0A, 0x44, 0x08, /* Sensor reporting state all events wake sel */ | ||
| 544 | 0x0A, 0x45, 0x08, /* Sensor reporting state threshold events wake sel */ | ||
| 545 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 546 | 0xC0, /* HID end collection */ | ||
| 547 | 0x0A, 0x19, 0x03, /* HID usage sensor property power state */ | ||
| 548 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 549 | 0x25, 5, /* HID logical Max_8(5) */ | ||
| 550 | 0x75, 8, /* HID report size(8) */ | ||
| 551 | 0x95, 1, /* HID report count(1) */ | ||
| 552 | 0xA1, 0x02, /* HID collection(logical) */ | ||
| 553 | 0x0A, 0x50, 0x08, /* Sensor power state undefined sel */ | ||
| 554 | 0x0A, 0x51, 0x08, /* Sensor power state D0 full power sel */ | ||
| 555 | 0x0A, 0x52, 0x08, /* Sensor power state D1 low power sel */ | ||
| 556 | 0x0A, 0x53, 0x08, /* Sensor power state D2 standby with wake sel */ | ||
| 557 | 0x0A, 0x54, 0x08, /* Sensor power state D3 sleep with wake sel */ | ||
| 558 | 0x0A, 0x55, 0x08, /* Sensor power state D4 power off sel */ | ||
| 559 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 560 | 0xC0, /* HID end collection */ | ||
| 561 | 0x0A, 0x01, 0x02, /* HID usage sensor state */ | ||
| 562 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 563 | 0x25, 6, /* HID logical Max_8(6) */ | ||
| 564 | 0x75, 8, /* HID report size(8) */ | ||
| 565 | 0x95, 1, /* HID report count(1) */ | ||
| 566 | 0xA1, 0x02, /* HID collection(logical) */ | ||
| 567 | 0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ | ||
| 568 | 0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ | ||
| 569 | 0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ | ||
| 570 | 0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ | ||
| 571 | 0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ | ||
| 572 | 0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ | ||
| 573 | 0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ | ||
| 574 | 0xB1, 0x00, /* HID feature (Data_Arr_Abs) */ | ||
| 575 | 0xC0, /* HID end collection */ | ||
| 576 | 0x0A, 0x0E, 0x03, /* HID usage sensor property report interval */ | ||
| 577 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 578 | 0x27, 0xFF, 0xFF, 0xFF, 0xFF, /* HID logical Max_32 */ | ||
| 579 | 0x75, 32, /* HID report size(32) */ | ||
| 580 | 0x95, 1, /* HID report count(1) */ | ||
| 581 | 0x55, 0, /* HID unit exponent(0) */ | ||
| 582 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 583 | 0x0A, 0xD1, 0xE4, /* Light illuminance and sensitivity REL PCT) */ | ||
| 584 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 585 | 0x26, 0x10, 0x27, /* HID logical Max_16(0x10,0x27) */ | ||
| 586 | 0x75, 16, /* HID report size(16) */ | ||
| 587 | 0x95, 1, /* HID report count(1) */ | ||
| 588 | 0x55, 0x0E, /* HID unit exponent(0x0E) */ | ||
| 589 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 590 | 0x0A, 0xD1, 0x24, /* Sensor data (Light illuminance and mod max) */ | ||
| 591 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 592 | 0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */ | ||
| 593 | 0x75, 16, /* HID report size(16) */ | ||
| 594 | 0x95, 1, /* HID report count(1) */ | ||
| 595 | 0x55, 0x0F, /* HID unit exponent(0x0F) */ | ||
| 596 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 597 | 0x0A, 0xD1, 0x34, /* Sensor data (Light illuminance and mod min) */ | ||
| 598 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 599 | 0x26, 0xFF, 0xFF, /* HID logical Max_16(0xFF,0xFF) */ | ||
| 600 | 0x75, 16, /* HID report size(16) */ | ||
| 601 | 0x95, 1, /* HID report count(1) */ | ||
| 602 | 0x55, 0x0F, /* HID unit exponent(0x0F) */ | ||
| 603 | 0xB1, 0x02, /* HID feature (Data_Arr_Abs) */ | ||
| 604 | |||
| 605 | //Input reports (transmit) | ||
| 606 | 0x05, 0x20, /* HID usage page sensors */ | ||
| 607 | 0x0A, 0x01, 0x02, /* HID usage sensor state */ | ||
| 608 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 609 | 0x25, 6, /* HID logical Max_8(6) */ | ||
| 610 | 0x75, 8, /* HID report size(8) */ | ||
| 611 | 0x95, 1, /* HID report count (1) */ | ||
| 612 | 0xA1, 0x02, /* HID end collection (logical) */ | ||
| 613 | 0x0A, 0x00, 0x08, /* HID usage sensor state unknown sel */ | ||
| 614 | 0x0A, 0x01, 0x08, /* HID usage sensor state ready sel */ | ||
| 615 | 0x0A, 0x02, 0x08, /* HID usage sensor state not available sel */ | ||
| 616 | 0x0A, 0x03, 0x08, /* HID usage sensor state no data sel */ | ||
| 617 | 0x0A, 0x04, 0x08, /* HID usage sensor state initializing sel */ | ||
| 618 | 0x0A, 0x05, 0x08, /* HID usage sensor state access denied sel */ | ||
| 619 | 0x0A, 0x06, 0x08, /* HID usage sensor state error sel */ | ||
| 620 | 0X81, 0x00, /* HID Input (Data_Arr_Abs) */ | ||
| 621 | 0xC0, /* HID end collection */ | ||
| 622 | 0x0A, 0x02, 0x02, /* HID usage sensor event */ | ||
| 623 | 0x15, 0, /* HID logical Min_8(0) */ | ||
| 624 | 0x25, 5, /* HID logical Max_8(5) */ | ||
| 625 | 0x75, 8, /* HID report size(8) */ | ||
| 626 | 0x95, 1, /* HID report count (1) */ | ||
| 627 | 0xA1, 0x02, /* HID end collection (logical) */ | ||
| 628 | 0x0A, 0x10, 0x08, /* HID usage sensor event unknown sel */ | ||
| 629 | 0x0A, 0x11, 0x08, /* HID usage sensor event state changed sel */ | ||
| 630 | 0x0A, 0x12, 0x08, /* HID usage sensor event property changed sel */ | ||
| 631 | 0x0A, 0x13, 0x08, /* HID usage sensor event data updated sel */ | ||
| 632 | 0x0A, 0x14, 0x08, /* HID usage sensor event poll response sel */ | ||
| 633 | 0x0A, 0x15, 0x08, /* HID usage sensor event change sensitivity sel */ | ||
| 634 | 0X81, 0x00, /* HID Input (Data_Arr_Abs) */ | ||
| 635 | 0xC0, /* HID end collection */ | ||
| 636 | 0x0A, 0xD1, 0x04, /* HID usage sensor data light illuminance */ | ||
| 637 | 0x17, 0x00, 0x00, 0x01, 0x80, /* HID logical Min_32 */ | ||
| 638 | 0x27, 0xFF, 0xFF, 0xFF, 0x7F, /* HID logical Max_32 */ | ||
| 639 | 0x55, 0x0F, /* HID unit exponent(0x0F) */ | ||
| 640 | 0x75, 32, /* HID report size(32) */ | ||
| 641 | 0x95, 1, /* HID report count (1) */ | ||
| 642 | 0X81, 0x02, /* HID Input (Data_Arr_Abs) */ | ||
| 643 | 0xC0 /* HID end collection */ | ||
| 644 | }; | ||
| 645 | #endif | ||
| @@ -48,6 +48,8 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); · 47 unmodified lines | |||
| 48 | #define INPUT_REPORT_ID 0x5d | 48 | #define INPUT_REPORT_ID 0x5d |
| 49 | #define FEATURE_KBD_REPORT_ID 0x5a | 49 | #define FEATURE_KBD_REPORT_ID 0x5a |
| 50 | #define FEATURE_KBD_REPORT_SIZE 16 | 50 | #define FEATURE_KBD_REPORT_SIZE 16 |
| 51 | #define FEATURE_KBD_LED_REPORT_ID1 0x5d | ||
| 52 | #define FEATURE_KBD_LED_REPORT_ID2 0x5e | ||
| 51 | 53 | ||
| 52 | #define SUPPORT_KBD_BACKLIGHT BIT(0) | 54 | #define SUPPORT_KBD_BACKLIGHT BIT(0) |
| 53 | 55 | ||
| @@ -80,6 +82,7 @@ MODULE_DESCRIPTION("Asus HID Keyboard and TouchPad"); · 26 unmodified lines | |||
| 80 | #define QUIRK_T101HA_DOCK BIT(9) | 82 | #define QUIRK_T101HA_DOCK BIT(9) |
| 81 | #define QUIRK_T90CHI BIT(10) | 83 | #define QUIRK_T90CHI BIT(10) |
| 82 | #define QUIRK_MEDION_E1239T BIT(11) | 84 | #define QUIRK_MEDION_E1239T BIT(11) |
| 85 | #define QUIRK_ROG_NKEY_KEYBOARD BIT(12) | ||
| 83 | 86 | ||
| 84 | #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ | 87 | #define I2C_KEYBOARD_QUIRKS (QUIRK_FIX_NOTEBOOK_REPORT | \ |
| 85 | QUIRK_NO_INIT_REPORTS | \ | 88 | QUIRK_NO_INIT_REPORTS | \ |
| @@ -332,6 +335,28 @@ static int asus_raw_event(struct hid_device *hdev, · 246 unmodified lines | |||
| 332 | if (drvdata->quirks & QUIRK_MEDION_E1239T) | 335 | if (drvdata->quirks & QUIRK_MEDION_E1239T) |
| 333 | return asus_e1239t_event(drvdata, data, size); | 336 | return asus_e1239t_event(drvdata, data, size); |
| 334 | 337 | ||
| 338 | if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { | ||
| 339 | /* | ||
| 340 | * Skip these report ID, the device emits a continuous stream associated | ||
| 341 | * with the AURA mode it is in which looks like an 'echo'. | ||
| 342 | */ | ||
| 343 | if (report->id == FEATURE_KBD_LED_REPORT_ID1 || | ||
| 344 | report->id == FEATURE_KBD_LED_REPORT_ID2) { | ||
| 345 | return -1; | ||
| 346 | /* Additional report filtering */ | ||
| 347 | } else if (report->id == FEATURE_KBD_REPORT_ID) { | ||
| 348 | /* | ||
| 349 | * G14 and G15 send these codes on some keypresses with no | ||
| 350 | * discernable reason for doing so. We'll filter them out to avoid | ||
| 351 | * unmapped warning messages later. | ||
| 352 | */ | ||
| 353 | if (data[1] == 0xea || data[1] == 0xec || data[1] == 0x02 || | ||
| 354 | data[1] == 0x8a || data[1] == 0x9e) { | ||
| 355 | return -1; | ||
| 356 | } | ||
| 357 | } | ||
| 358 | } | ||
| 359 | |||
| 335 | return 0; | 360 | return 0; |
| 336 | } | 361 | } |
| 337 | 362 | ||
| @@ -344,7 +369,11 @@ static int asus_kbd_set_report(struct hid_device *hdev, u8 *buf, size_t buf_size · 6 unmodified lines | |||
| 344 | if (!dmabuf) | 369 | if (!dmabuf) |
| 345 | return -ENOMEM; | 370 | return -ENOMEM; |
| 346 | 371 | ||
| 347 | ret = hid_hw_raw_request(hdev, FEATURE_KBD_REPORT_ID, dmabuf, | 372 | /* |
| 373 | * The report ID should be set from the incoming buffer due to LED and key | ||
| 374 | * interfaces having different pages | ||
| 375 | */ | ||
| 376 | ret = hid_hw_raw_request(hdev, buf[0], dmabuf, | ||
| 348 | buf_size, HID_FEATURE_REPORT, | 377 | buf_size, HID_FEATURE_REPORT, |
| 349 | HID_REQ_SET_REPORT); | 378 | HID_REQ_SET_REPORT); |
| 350 | kfree(dmabuf); | 379 | kfree(dmabuf); |
| @@ -397,6 +426,51 @@ static int asus_kbd_get_functions(struct hid_device *hdev, · 46 unmodified lines | |||
| 397 | return ret; | 426 | return ret; |
| 398 | } | 427 | } |
| 399 | 428 | ||
| 429 | static int rog_nkey_led_init(struct hid_device *hdev) | ||
| 430 | { | ||
| 431 | u8 buf_init_start[] = { FEATURE_KBD_LED_REPORT_ID1, 0xB9 }; | ||
| 432 | u8 buf_init2[] = { FEATURE_KBD_LED_REPORT_ID1, 0x41, 0x53, 0x55, 0x53, 0x20, | ||
| 433 | 0x54, 0x65, 0x63, 0x68, 0x2e, 0x49, 0x6e, 0x63, 0x2e, 0x00 }; | ||
| 434 | u8 buf_init3[] = { FEATURE_KBD_LED_REPORT_ID1, | ||
| 435 | 0x05, 0x20, 0x31, 0x00, 0x08 }; | ||
| 436 | int ret; | ||
| 437 | |||
| 438 | hid_info(hdev, "Asus initialise N-KEY Device"); | ||
| 439 | /* The first message is an init start */ | ||
| 440 | ret = asus_kbd_set_report(hdev, buf_init_start, sizeof(buf_init_start)); | ||
| 441 | if (ret < 0) { | ||
| 442 | hid_warn(hdev, "Asus failed to send init start command: %d\n", ret); | ||
| 443 | return ret; | ||
| 444 | } | ||
| 445 | /* Followed by a string */ | ||
| 446 | ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2)); | ||
| 447 | if (ret < 0) { | ||
| 448 | hid_warn(hdev, "Asus failed to send init command 1.0: %d\n", ret); | ||
| 449 | return ret; | ||
| 450 | } | ||
| 451 | /* Followed by a string */ | ||
| 452 | ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3)); | ||
| 453 | if (ret < 0) { | ||
| 454 | hid_warn(hdev, "Asus failed to send init command 1.1: %d\n", ret); | ||
| 455 | return ret; | ||
| 456 | } | ||
| 457 | |||
| 458 | /* begin second report ID with same data */ | ||
| 459 | buf_init2[0] = FEATURE_KBD_LED_REPORT_ID2; | ||
| 460 | buf_init3[0] = FEATURE_KBD_LED_REPORT_ID2; | ||
| 461 | |||
| 462 | ret = asus_kbd_set_report(hdev, buf_init2, sizeof(buf_init2)); | ||
| 463 | if (ret < 0) { | ||
| 464 | hid_warn(hdev, "Asus failed to send init command 2.0: %d\n", ret); | ||
| 465 | return ret; | ||
| 466 | } | ||
| 467 | ret = asus_kbd_set_report(hdev, buf_init3, sizeof(buf_init3)); | ||
| 468 | if (ret < 0) | ||
| 469 | hid_warn(hdev, "Asus failed to send init command 2.1: %d\n", ret); | ||
| 470 | |||
| 471 | return ret; | ||
| 472 | } | ||
| 473 | |||
| 400 | static void asus_kbd_backlight_set(struct led_classdev *led_cdev, | 474 | static void asus_kbd_backlight_set(struct led_classdev *led_cdev, |
| 401 | enum led_brightness brightness) | 475 | enum led_brightness brightness) |
| 402 | { | 476 | { |
| @@ -460,19 +534,25 @@ static int asus_kbd_register_leds(struct hid_device *hdev) · 57 unmodified lines | |||
| 460 | unsigned char kbd_func; | 534 | unsigned char kbd_func; |
| 461 | int ret; | 535 | int ret; |
| 462 | 536 | ||
| 463 | /* Initialize keyboard */ | 537 | if (drvdata->quirks & QUIRK_ROG_NKEY_KEYBOARD) { |
| 464 | ret = asus_kbd_init(hdev); | 538 | ret = rog_nkey_led_init(hdev); |
| 465 | if (ret < 0) | 539 | if (ret < 0) |
| 466 | return ret; | 540 | return ret; |
| 541 | } else { | ||
| 542 | /* Initialize keyboard */ | ||
| 543 | ret = asus_kbd_init(hdev); | ||
| 544 | if (ret < 0) | ||
| 545 | return ret; | ||
| 467 | 546 | ||
| 468 | /* Get keyboard functions */ | 547 | /* Get keyboard functions */ |
| 469 | ret = asus_kbd_get_functions(hdev, &kbd_func); | 548 | ret = asus_kbd_get_functions(hdev, &kbd_func); |
| 470 | if (ret < 0) | 549 | if (ret < 0) |
| 471 | return ret; | 550 | return ret; |
| 472 | 551 | ||
| 473 | /* Check for backlight support */ | 552 | /* Check for backlight support */ |
| 474 | if (!(kbd_func & SUPPORT_KBD_BACKLIGHT)) | 553 | if (!(kbd_func & SUPPORT_KBD_BACKLIGHT)) |
| 475 | return -ENODEV; | 554 | return -ENODEV; |
| 555 | } | ||
| 476 | 556 | ||
| 477 | drvdata->kbd_backlight = devm_kzalloc(&hdev->dev, | 557 | drvdata->kbd_backlight = devm_kzalloc(&hdev->dev, |
| 478 | sizeof(struct asus_kbd_leds), | 558 | sizeof(struct asus_kbd_leds), |
| @@ -751,8 +831,8 @@ static int asus_input_mapping(struct hid_device *hdev, · 272 unmodified lines | |||
| 751 | usage->hid == (HID_UP_GENDEVCTRLS | 0x0026))) | 831 | usage->hid == (HID_UP_GENDEVCTRLS | 0x0026))) |
| 752 | return -1; | 832 | return -1; |
| 753 | 833 | ||
| 754 | /* ASUS-specific keyboard hotkeys */ | 834 | /* ASUS-specific keyboard hotkeys and led backlight */ |
| 755 | if ((usage->hid & HID_USAGE_PAGE) == 0xff310000) { | 835 | if ((usage->hid & HID_USAGE_PAGE) == HID_UP_ASUSVENDOR) { |
| 756 | switch (usage->hid & HID_USAGE) { | 836 | switch (usage->hid & HID_USAGE) { |
| 757 | case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break; | 837 | case 0x10: asus_map_key_clear(KEY_BRIGHTNESSDOWN); break; |
| 758 | case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break; | 838 | case 0x20: asus_map_key_clear(KEY_BRIGHTNESSUP); break; |
| @@ -780,6 +860,18 @@ static int asus_input_mapping(struct hid_device *hdev, · 21 unmodified lines | |||
| 780 | /* Fn+F5 "fan" symbol on FX503VD */ | 860 | /* Fn+F5 "fan" symbol on FX503VD */ |
| 781 | case 0x99: asus_map_key_clear(KEY_PROG4); break; | 861 | case 0x99: asus_map_key_clear(KEY_PROG4); break; |
| 782 | 862 | ||
| 863 | /* Fn+F5 "fan" symbol on N-Key keyboard */ | ||
| 864 | case 0xae: asus_map_key_clear(KEY_PROG4); break; | ||
| 865 | |||
| 866 | /* Fn+Ret "Calc" symbol on N-Key keyboard */ | ||
| 867 | case 0x92: asus_map_key_clear(KEY_CALC); break; | ||
| 868 | |||
| 869 | /* Fn+Left Aura mode previous on N-Key keyboard */ | ||
| 870 | case 0xb2: asus_map_key_clear(KEY_PROG2); break; | ||
| 871 | |||
| 872 | /* Fn+Right Aura mode next on N-Key keyboard */ | ||
| 873 | case 0xb3: asus_map_key_clear(KEY_PROG3); break; | ||
| 874 | |||
| 783 | default: | 875 | default: |
| 784 | /* ASUS lazily declares 256 usages, ignore the rest, | 876 | /* ASUS lazily declares 256 usages, ignore the rest, |
| 785 | * as some make the keyboard appear as a pointer device. */ | 877 | * as some make the keyboard appear as a pointer device. */ |
| @@ -1126,6 +1218,9 @@ static const struct hid_device_id asus_devices[] = { · 340 unmodified lines | |||
| 1126 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, | 1218 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
| 1127 | USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD), | 1219 | USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD), |
| 1128 | QUIRK_USE_KBD_BACKLIGHT }, | 1220 | QUIRK_USE_KBD_BACKLIGHT }, |
| 1221 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, | ||
| 1222 | USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD), | ||
| 1223 | QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, | ||
| 1129 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, | 1224 | { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, |
| 1130 | USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD), | 1225 | USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD), |
| 1131 | QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, | 1226 | QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | * Copyright (c) 2017 Diego Elio Pettenò <flameeyes@flameeyes.eu> | 11 | * Copyright (c) 2017 Diego Elio Pettenò <flameeyes@flameeyes.eu> |
| 12 | * Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org> | 12 | * Copyright (c) 2017 Alex Manoussakis <amanou@gnu.org> |
| 13 | * Copyright (c) 2017 Tomasz Kramkowski <tk@the-tk.com> | 13 | * Copyright (c) 2017 Tomasz Kramkowski <tk@the-tk.com> |
| 14 | * Copyright (c) 2020 YOSHIOKA Takuma <lo48576@hard-wi.red> | ||
| 14 | */ | 15 | */ |
| 15 | 16 | ||
| 16 | /* | 17 | /* |
| @@ -29,25 +30,26 @@ · 12 unmodified lines | |||
| 29 | * report descriptor but it does not appear that these enable software to | 30 | * report descriptor but it does not appear that these enable software to |
| 30 | * control what the extra buttons map to. The only simple and straightforward | 31 | * control what the extra buttons map to. The only simple and straightforward |
| 31 | * solution seems to involve fixing up the report descriptor. | 32 | * solution seems to involve fixing up the report descriptor. |
| 32 | * | ||
| 33 | * Report descriptor format: | ||
| 34 | * Positions 13, 15, 21 and 31 store the button bit count, button usage minimum, | ||
| 35 | * button usage maximum and padding bit count respectively. | ||
| 36 | */ | 33 | */ |
| 37 | #define MOUSE_BUTTONS_MAX 8 | 34 | #define MOUSE_BUTTONS_MAX 8 |
| 38 | static void mouse_button_fixup(struct hid_device *hdev, | 35 | static void mouse_button_fixup(struct hid_device *hdev, |
| 39 | __u8 *rdesc, unsigned int rsize, | 36 | __u8 *rdesc, unsigned int rsize, |
| 37 | unsigned int button_bit_count, | ||
| 38 | unsigned int padding_bit, | ||
| 39 | unsigned int button_report_size, | ||
| 40 | unsigned int button_usage_maximum, | ||
| 40 | int nbuttons) | 41 | int nbuttons) |
| 41 | { | 42 | { |
| 42 | if (rsize < 32 || rdesc[12] != 0x95 || | 43 | if (rsize < 32 || rdesc[button_bit_count] != 0x95 || |
| 43 | rdesc[14] != 0x75 || rdesc[15] != 0x01 || | 44 | rdesc[button_report_size] != 0x75 || |
| 44 | rdesc[20] != 0x29 || rdesc[30] != 0x75) | 45 | rdesc[button_report_size + 1] != 0x01 || |
| 46 | rdesc[button_usage_maximum] != 0x29 || rdesc[padding_bit] != 0x75) | ||
| 45 | return; | 47 | return; |
| 46 | hid_info(hdev, "Fixing up Elecom mouse button count\n"); | 48 | hid_info(hdev, "Fixing up Elecom mouse button count\n"); |
| 47 | nbuttons = clamp(nbuttons, 0, MOUSE_BUTTONS_MAX); | 49 | nbuttons = clamp(nbuttons, 0, MOUSE_BUTTONS_MAX); |
| 48 | rdesc[13] = nbuttons; | 50 | rdesc[button_bit_count + 1] = nbuttons; |
| 49 | rdesc[21] = nbuttons; | 51 | rdesc[button_usage_maximum + 1] = nbuttons; |
| 50 | rdesc[31] = MOUSE_BUTTONS_MAX - nbuttons; | 52 | rdesc[padding_bit + 1] = MOUSE_BUTTONS_MAX - nbuttons; |
| 51 | } | 53 | } |
| 52 | 54 | ||
| 53 | static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, | 55 | 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, · 8 unmodified lines | |||
| 62 | rdesc[47] = 0x00; | 64 | rdesc[47] = 0x00; |
| 63 | } | 65 | } |
| 64 | break; | 66 | break; |
| 67 | case USB_DEVICE_ID_ELECOM_M_XGL20DLBK: | ||
| 68 | /* | ||
| 69 | * Report descriptor format: | ||
| 70 | * 20: button bit count | ||
| 71 | * 28: padding bit count | ||
| 72 | * 22: button report size | ||
| 73 | * 14: button usage maximum | ||
| 74 | */ | ||
| 75 | mouse_button_fixup(hdev, rdesc, *rsize, 20, 28, 22, 14, 8); | ||
| 76 | break; | ||
| 65 | case USB_DEVICE_ID_ELECOM_M_XT3URBK: | 77 | case USB_DEVICE_ID_ELECOM_M_XT3URBK: |
| 66 | case USB_DEVICE_ID_ELECOM_M_XT3DRBK: | 78 | case USB_DEVICE_ID_ELECOM_M_XT3DRBK: |
| 67 | case USB_DEVICE_ID_ELECOM_M_XT4DRBK: | 79 | case USB_DEVICE_ID_ELECOM_M_XT4DRBK: |
| 68 | mouse_button_fixup(hdev, rdesc, *rsize, 6); | 80 | /* |
| 81 | * Report descriptor format: | ||
| 82 | * 12: button bit count | ||
| 83 | * 30: padding bit count | ||
| 84 | * 14: button report size | ||
| 85 | * 20: button usage maximum | ||
| 86 | */ | ||
| 87 | mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 6); | ||
| 69 | break; | 88 | break; |
| 70 | case USB_DEVICE_ID_ELECOM_M_DT1URBK: | 89 | case USB_DEVICE_ID_ELECOM_M_DT1URBK: |
| 71 | case USB_DEVICE_ID_ELECOM_M_DT1DRBK: | 90 | case USB_DEVICE_ID_ELECOM_M_DT1DRBK: |
| 72 | case USB_DEVICE_ID_ELECOM_M_HT1URBK: | 91 | case USB_DEVICE_ID_ELECOM_M_HT1URBK: |
| 73 | case USB_DEVICE_ID_ELECOM_M_HT1DRBK: | 92 | case USB_DEVICE_ID_ELECOM_M_HT1DRBK: |
| 74 | mouse_button_fixup(hdev, rdesc, *rsize, 8); | 93 | /* |
| 94 | * Report descriptor format: | ||
| 95 | * 12: button bit count | ||
| 96 | * 30: padding bit count | ||
| 97 | * 14: button report size | ||
| 98 | * 20: button usage maximum | ||
| 99 | */ | ||
| 100 | mouse_button_fixup(hdev, rdesc, *rsize, 12, 30, 14, 20, 8); | ||
| 75 | break; | 101 | break; |
| 76 | } | 102 | } |
| 77 | return rdesc; | 103 | return rdesc; |
| @@ -79,6 +105,7 @@ static __u8 *elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, · 1 unmodified line | |||
| 79 | 105 | ||
| 80 | static const struct hid_device_id elecom_devices[] = { | 106 | static const struct hid_device_id elecom_devices[] = { |
| 81 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, | 107 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, |
| 108 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) }, | ||
| 82 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) }, | 109 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) }, |
| 83 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) }, | 110 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) }, |
| 84 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, | 111 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, |
| @@ -190,6 +190,7 @@ · 189 unmodified lines | |||
| 190 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854 | 190 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD1 0x1854 |
| 191 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837 | 191 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837 |
| 192 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822 | 192 | #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822 |
| 193 | #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866 | ||
| 193 | #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 | 194 | #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 |
| 194 | 195 | ||
| 195 | #define USB_VENDOR_ID_ATEN 0x0557 | 196 | #define USB_VENDOR_ID_ATEN 0x0557 |
| @@ -359,6 +360,7 @@ · 163 unmodified lines | |||
| 359 | #define USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR 0x1803 | 360 | #define USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR 0x1803 |
| 360 | #define USB_DEVICE_ID_DRAGONRISE_GAMECUBE1 0x1843 | 361 | #define USB_DEVICE_ID_DRAGONRISE_GAMECUBE1 0x1843 |
| 361 | #define USB_DEVICE_ID_DRAGONRISE_GAMECUBE2 0x1844 | 362 | #define USB_DEVICE_ID_DRAGONRISE_GAMECUBE2 0x1844 |
| 363 | #define USB_DEVICE_ID_DRAGONRISE_GAMECUBE3 0x1846 | ||
| 362 | 364 | ||
| 363 | #define USB_VENDOR_ID_DWAV 0x0eef | 365 | #define USB_VENDOR_ID_DWAV 0x0eef |
| 364 | #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 | 366 | #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 |
| @@ -390,6 +392,7 @@ · 25 unmodified lines | |||
| 390 | 392 | ||
| 391 | #define USB_VENDOR_ID_ELECOM 0x056e | 393 | #define USB_VENDOR_ID_ELECOM 0x056e |
| 392 | #define USB_DEVICE_ID_ELECOM_BM084 0x0061 | 394 | #define USB_DEVICE_ID_ELECOM_BM084 0x0061 |
| 395 | #define USB_DEVICE_ID_ELECOM_M_XGL20DLBK 0x00e6 | ||
| 393 | #define USB_DEVICE_ID_ELECOM_M_XT3URBK 0x00fb | 396 | #define USB_DEVICE_ID_ELECOM_M_XT3URBK 0x00fb |
| 394 | #define USB_DEVICE_ID_ELECOM_M_XT3DRBK 0x00fc | 397 | #define USB_DEVICE_ID_ELECOM_M_XT3DRBK 0x00fc |
| 395 | #define USB_DEVICE_ID_ELECOM_M_XT4DRBK 0x00fd | 398 | #define USB_DEVICE_ID_ELECOM_M_XT4DRBK 0x00fd |
| @@ -1074,6 +1077,9 @@ · 678 unmodified lines | |||
| 1074 | #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002 | 1077 | #define USB_DEVICE_ID_SONY_BUZZ_CONTROLLER 0x0002 |
| 1075 | #define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER 0x1000 | 1078 | #define USB_DEVICE_ID_SONY_WIRELESS_BUZZ_CONTROLLER 0x1000 |
| 1076 | 1079 | ||
| 1080 | #define USB_VENDOR_ID_SONY_GHLIVE 0x12ba | ||
| 1081 | #define USB_DEVICE_ID_SONY_PS3WIIU_GHLIVE_DONGLE 0x074b | ||
| 1082 | |||
| 1077 | #define USB_VENDOR_ID_SINO_LITE 0x1345 | 1083 | #define USB_VENDOR_ID_SINO_LITE 0x1345 |
| 1078 | #define USB_DEVICE_ID_SINO_LITE_CONTROLLER 0x3008 | 1084 | #define USB_DEVICE_ID_SINO_LITE_CONTROLLER 0x3008 |
| 1079 | 1085 | ||
| @@ -1133,6 +1139,7 @@ · 53 unmodified lines | |||
| 1133 | #define USB_DEVICE_ID_SYNAPTICS_DELL_K12A 0x2819 | 1139 | #define USB_DEVICE_ID_SYNAPTICS_DELL_K12A 0x2819 |
| 1134 | #define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012 0x2968 | 1140 | #define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012 0x2968 |
| 1135 | #define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710 | 1141 | #define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710 |
| 1142 | #define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002 0x73f4 | ||
| 1136 | #define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003 0x73f5 | 1143 | #define USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003 0x73f5 |
| 1137 | #define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5 0x81a7 | 1144 | #define USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5 0x81a7 |
| 1138 | 1145 | ||
| @@ -537,9 +537,12 @@ static void hidinput_update_battery(struct hid_device *dev, int value) · 536 unmodified lines | |||
| 537 | capacity = hidinput_scale_battery_capacity(dev, value); | 537 | capacity = hidinput_scale_battery_capacity(dev, value); |
| 538 | 538 | ||
| 539 | if (dev->battery_status != HID_BATTERY_REPORTED || | 539 | if (dev->battery_status != HID_BATTERY_REPORTED || |
| 540 | capacity != dev->battery_capacity) { | 540 | capacity != dev->battery_capacity || |
| 541 | ktime_after(ktime_get_coarse(), dev->battery_ratelimit_time)) { | ||
| 541 | dev->battery_capacity = capacity; | 542 | dev->battery_capacity = capacity; |
| 542 | dev->battery_status = HID_BATTERY_REPORTED; | 543 | dev->battery_status = HID_BATTERY_REPORTED; |
| 544 | dev->battery_ratelimit_time = | ||
| 545 | ktime_add_ms(ktime_get_coarse(), 30 * 1000); | ||
| 543 | power_supply_changed(dev->battery); | 546 | power_supply_changed(dev->battery); |
| 544 | } | 547 | } |
| 545 | } | 548 | } |
| @@ -746,6 +749,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel · 200 unmodified lines | |||
| 746 | field->flags |= HID_MAIN_ITEM_RELATIVE; | 749 | field->flags |= HID_MAIN_ITEM_RELATIVE; |
| 747 | break; | 750 | break; |
| 748 | } | 751 | } |
| 752 | goto unknown; | ||
| 749 | 753 | ||
| 750 | default: goto unknown; | 754 | default: goto unknown; |
| 751 | } | 755 | } |
| @@ -18,10 +18,16 @@ static __u8 *ite_report_fixup(struct hid_device *hdev, __u8 *rdesc, unsigned int · 17 unmodified lines | |||
| 18 | unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); | 18 | unsigned long quirks = (unsigned long)hid_get_drvdata(hdev); |
| 19 | 19 | ||
| 20 | if (quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) { | 20 | if (quirks & QUIRK_TOUCHPAD_ON_OFF_REPORT) { |
| 21 | /* For Acer Aspire Switch 10 SW5-012 keyboard-dock */ | ||
| 21 | if (*rsize == 188 && rdesc[162] == 0x81 && rdesc[163] == 0x02) { | 22 | if (*rsize == 188 && rdesc[162] == 0x81 && rdesc[163] == 0x02) { |
| 22 | hid_info(hdev, "Fixing up ITE keyboard report descriptor\n"); | 23 | hid_info(hdev, "Fixing up Acer Sw5-012 ITE keyboard report descriptor\n"); |
| 23 | rdesc[163] = HID_MAIN_ITEM_RELATIVE; | 24 | rdesc[163] = HID_MAIN_ITEM_RELATIVE; |
| 24 | } | 25 | } |
| 26 | /* For Acer One S1002 keyboard-dock */ | ||
| 27 | if (*rsize == 188 && rdesc[185] == 0x81 && rdesc[186] == 0x02) { | ||
| 28 | hid_info(hdev, "Fixing up Acer S1002 ITE keyboard report descriptor\n"); | ||
| 29 | rdesc[186] = HID_MAIN_ITEM_RELATIVE; | ||
| 30 | } | ||
| 25 | } | 31 | } |
| 26 | 32 | ||
| 27 | return rdesc; | 33 | return rdesc; |
| @@ -101,6 +107,11 @@ static const struct hid_device_id ite_devices[] = { · 73 unmodified lines | |||
| 101 | USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012), | 107 | USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5_012), |
| 102 | .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, | 108 | .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, |
| 103 | /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */ | 109 | /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */ |
| 110 | { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, | ||
| 111 | USB_VENDOR_ID_SYNAPTICS, | ||
| 112 | USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1002), | ||
| 113 | .driver_data = QUIRK_TOUCHPAD_ON_OFF_REPORT }, | ||
| 114 | /* ITE8910 USB kbd ctlr, with Synaptics touchpad connected to it. */ | ||
| 104 | { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, | 115 | { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, |
| 105 | USB_VENDOR_ID_SYNAPTICS, | 116 | USB_VENDOR_ID_SYNAPTICS, |
| 106 | USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003) }, | 117 | USB_DEVICE_ID_SYNAPTICS_ACER_ONE_S1003) }, |
| @@ -4048,6 +4048,8 @@ static const struct hid_device_id hidpp_devices[] = { · 4047 unmodified lines | |||
| 4048 | { /* MX5500 keyboard over Bluetooth */ | 4048 | { /* MX5500 keyboard over Bluetooth */ |
| 4049 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b), | 4049 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb30b), |
| 4050 | .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, | 4050 | .driver_data = HIDPP_QUIRK_HIDPP_CONSUMER_VENDOR_KEYS }, |
| 4051 | { /* M-RCQ142 V470 Cordless Laser Mouse over Bluetooth */ | ||
| 4052 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb008) }, | ||
| 4051 | { /* MX Master mouse over Bluetooth */ | 4053 | { /* MX Master mouse over Bluetooth */ |
| 4052 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb012), | 4054 | HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, 0xb012), |
| 4053 | .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, | 4055 | .driver_data = HIDPP_QUIRK_HI_RES_SCROLL_X2121 }, |
| @@ -153,6 +153,8 @@ static const struct hid_device_id mf_devices[] = { · 152 unmodified lines | |||
| 153 | .driver_data = HID_QUIRK_MULTI_INPUT }, | 153 | .driver_data = HID_QUIRK_MULTI_INPUT }, |
| 154 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2), | 154 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2), |
| 155 | .driver_data = 0 }, /* No quirk required */ | 155 | .driver_data = 0 }, /* No quirk required */ |
| 156 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3), | ||
| 157 | .driver_data = HID_QUIRK_MULTI_INPUT }, | ||
| 156 | { } | 158 | { } |
| 157 | }; | 159 | }; |
| 158 | MODULE_DEVICE_TABLE(hid, mf_devices); | 160 | MODULE_DEVICE_TABLE(hid, mf_devices); |
| @@ -72,6 +72,7 @@ static const struct hid_device_id hid_quirks[] = { · 71 unmodified lines | |||
| 72 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, | 72 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_REDRAGON_SEYMUR2), HID_QUIRK_INCREMENT_USAGE_ON_DUPLICATE }, |
| 73 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), HID_QUIRK_MULTI_INPUT }, | 73 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR), HID_QUIRK_MULTI_INPUT }, |
| 74 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), HID_QUIRK_MULTI_INPUT }, | 74 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1), HID_QUIRK_MULTI_INPUT }, |
| 75 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3), HID_QUIRK_MULTI_INPUT }, | ||
| 75 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT }, | 76 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_PS3), HID_QUIRK_MULTI_INPUT }, |
| 76 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU), HID_QUIRK_MULTI_INPUT }, | 77 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_WIIU), HID_QUIRK_MULTI_INPUT }, |
| 77 | { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER), HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET }, | 78 | { 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[] = { · 288 unmodified lines | |||
| 366 | #endif | 367 | #endif |
| 367 | #if IS_ENABLED(CONFIG_HID_ELECOM) | 368 | #if IS_ENABLED(CONFIG_HID_ELECOM) |
| 368 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, | 369 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, |
| 370 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XGL20DLBK) }, | ||
| 369 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) }, | 371 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3URBK) }, |
| 370 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) }, | 372 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT3DRBK) }, |
| 371 | { HID_USB_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_M_XT4DRBK) }, | 373 | { 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[] = { · 112 unmodified lines | |||
| 484 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR) }, | 486 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_DOLPHINBAR) }, |
| 485 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1) }, | 487 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE1) }, |
| 486 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2) }, | 488 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE2) }, |
| 489 | { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, USB_DEVICE_ID_DRAGONRISE_GAMECUBE3) }, | ||
| 487 | #endif | 490 | #endif |
| 488 | #if IS_ENABLED(CONFIG_HID_MICROSOFT) | 491 | #if IS_ENABLED(CONFIG_HID_MICROSOFT) |
| 489 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) }, | 492 | { HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) }, |
| @@ -11,6 +11,7 @@ · 10 unmodified lines | |||
| 11 | * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com> | 11 | * Copyright (c) 2013 Colin Leitner <colin.leitner@gmail.com> |
| 12 | * Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com> | 12 | * Copyright (c) 2014-2016 Frank Praznik <frank.praznik@gmail.com> |
| 13 | * Copyright (c) 2018 Todd Kelner | 13 | * Copyright (c) 2018 Todd Kelner |
| 14 | * Copyright (c) 2020 Pascal Giard <pascal.giard@etsmtl.ca> | ||
| 14 | */ | 15 | */ |
| 15 | 16 | ||
| 16 | /* | 17 | /* |
| @@ -35,6 +36,8 @@ · 18 unmodified lines | |||
| 35 | #include <linux/idr.h> | 36 | #include <linux/idr.h> |
| 36 | #include <linux/input/mt.h> | 37 | #include <linux/input/mt.h> |
| 37 | #include <linux/crc32.h> | 38 | #include <linux/crc32.h> |
| 39 | #include <linux/usb.h> | ||
| 40 | #include <linux/timer.h> | ||
| 38 | #include <asm/unaligned.h> | 41 | #include <asm/unaligned.h> |
| 39 | 42 | ||
| 40 | #include "hid-ids.h" | 43 | #include "hid-ids.h" |
| @@ -56,6 +59,7 @@ · 15 unmodified lines | |||
| 56 | #define NSG_MR5U_REMOTE_BT BIT(14) | 59 | #define NSG_MR5U_REMOTE_BT BIT(14) |
| 57 | #define NSG_MR7U_REMOTE_BT BIT(15) | 60 | #define NSG_MR7U_REMOTE_BT BIT(15) |
| 58 | #define SHANWAN_GAMEPAD BIT(16) | 61 | #define SHANWAN_GAMEPAD BIT(16) |
| 62 | #define GHL_GUITAR_PS3WIIU BIT(17) | ||
| 59 | 63 | ||
| 60 | #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) | 64 | #define SIXAXIS_CONTROLLER (SIXAXIS_CONTROLLER_USB | SIXAXIS_CONTROLLER_BT) |
| 61 | #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) | 65 | #define MOTION_CONTROLLER (MOTION_CONTROLLER_USB | MOTION_CONTROLLER_BT) |
| @@ -79,6 +83,17 @@ · 17 unmodified lines | |||
| 79 | #define NSG_MRXU_MAX_X 1667 | 83 | #define NSG_MRXU_MAX_X 1667 |
| 80 | #define NSG_MRXU_MAX_Y 1868 | 84 | #define NSG_MRXU_MAX_Y 1868 |
| 81 | 85 | ||
| 86 | #define GHL_GUITAR_POKE_INTERVAL 10 /* In seconds */ | ||
| 87 | #define GHL_GUITAR_TILT_USAGE 44 | ||
| 88 | |||
| 89 | /* Magic value and data taken from GHLtarUtility: | ||
| 90 | * https://github.com/ghlre/GHLtarUtility/blob/master/PS3Guitar.cs | ||
| 91 | * Note: The Wii U and PS3 dongles happen to share the same! | ||
| 92 | */ | ||
| 93 | static const u16 ghl_ps3wiiu_magic_value = 0x201; | ||
| 94 | static const char ghl_ps3wiiu_magic_data[] = { | ||
| 95 | 0x02, 0x08, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00 | ||
| 96 | }; | ||
| 82 | 97 | ||
| 83 | /* PS/3 Motion controller */ | 98 | /* PS/3 Motion controller */ |
| 84 | static u8 motion_rdesc[] = { | 99 | static u8 motion_rdesc[] = { |
| @@ -550,7 +565,9 @@ struct sony_sc { · 465 unmodified lines | |||
| 550 | struct power_supply_desc battery_desc; | 565 | struct power_supply_desc battery_desc; |
| 551 | int device_id; | 566 | int device_id; |
| 552 | unsigned fw_version; | 567 | unsigned fw_version; |
| 568 | bool fw_version_created; | ||
| 553 | unsigned hw_version; | 569 | unsigned hw_version; |
| 570 | bool hw_version_created; | ||
| 554 | u8 *output_report_dmabuf; | 571 | u8 *output_report_dmabuf; |
| 555 | 572 | ||
| 556 | #ifdef CONFIG_SONY_FF | 573 | #ifdef CONFIG_SONY_FF |
| @@ -562,9 +579,8 @@ struct sony_sc { · 5 unmodified lines | |||
| 562 | u8 hotplug_worker_initialized; | 579 | u8 hotplug_worker_initialized; |
| 563 | u8 state_worker_initialized; | 580 | u8 state_worker_initialized; |
| 564 | u8 defer_initialization; | 581 | u8 defer_initialization; |
| 565 | u8 cable_state; | ||
| 566 | u8 battery_charging; | ||
| 567 | u8 battery_capacity; | 582 | u8 battery_capacity; |
| 583 | int battery_status; | ||
| 568 | u8 led_state[MAX_LEDS]; | 584 | u8 led_state[MAX_LEDS]; |
| 569 | u8 led_delay_on[MAX_LEDS]; | 585 | u8 led_delay_on[MAX_LEDS]; |
| 570 | u8 led_delay_off[MAX_LEDS]; | 586 | u8 led_delay_off[MAX_LEDS]; |
| @@ -578,6 +594,10 @@ struct sony_sc { · 7 unmodified lines | |||
| 578 | enum ds4_dongle_state ds4_dongle_state; | 594 | enum ds4_dongle_state ds4_dongle_state; |
| 579 | /* DS4 calibration data */ | 595 | /* DS4 calibration data */ |
| 580 | struct ds4_calibration_data ds4_calib_data[6]; | 596 | struct ds4_calibration_data ds4_calib_data[6]; |
| 597 | /* GH Live */ | ||
| 598 | struct timer_list ghl_poke_timer; | ||
| 599 | struct usb_ctrlrequest *ghl_cr; | ||
| 600 | u8 *ghl_databuf; | ||
| 581 | }; | 601 | }; |
| 582 | 602 | ||
| 583 | static void sony_set_leds(struct sony_sc *sc); | 603 | static void sony_set_leds(struct sony_sc *sc); |
| @@ -601,6 +621,85 @@ static inline void sony_schedule_work(struct sony_sc *sc, · 17 unmodified lines | |||
| 601 | } | 621 | } |
| 602 | } | 622 | } |
| 603 | 623 | ||
| 624 | static void ghl_magic_poke_cb(struct urb *urb) | ||
| 625 | { | ||
| 626 | if (urb) { | ||
| 627 | /* Free sc->ghl_cr and sc->ghl_databuf allocated in | ||
| 628 | * ghl_magic_poke() | ||
| 629 | */ | ||
| 630 | kfree(urb->setup_packet); | ||
| 631 | kfree(urb->transfer_buffer); | ||
| 632 | } | ||
| 633 | } | ||
| 634 | |||
| 635 | static void ghl_magic_poke(struct timer_list *t) | ||
| 636 | { | ||
| 637 | struct sony_sc *sc = from_timer(sc, t, ghl_poke_timer); | ||
| 638 | |||
| 639 | int ret; | ||
| 640 | unsigned int pipe; | ||
| 641 | struct urb *urb; | ||
| 642 | struct usb_device *usbdev = to_usb_device(sc->hdev->dev.parent->parent); | ||
| 643 | const u16 poke_size = | ||
| 644 | ARRAY_SIZE(ghl_ps3wiiu_magic_data); | ||
| 645 | |||
| 646 | pipe = usb_sndctrlpipe(usbdev, 0); | ||
| 647 | |||
| 648 | if (!sc->ghl_cr) { | ||
| 649 | sc->ghl_cr = kzalloc(sizeof(*sc->ghl_cr), GFP_ATOMIC); | ||
| 650 | if (!sc->ghl_cr) | ||
| 651 | goto resched; | ||
| 652 | } | ||
| 653 | |||
| 654 | if (!sc->ghl_databuf) { | ||
| 655 | sc->ghl_databuf = kzalloc(poke_size, GFP_ATOMIC); | ||
| 656 | if (!sc->ghl_databuf) | ||
| 657 | goto resched; | ||
| 658 | } | ||
| 659 | |||
| 660 | urb = usb_alloc_urb(0, GFP_ATOMIC); | ||
| 661 | if (!urb) | ||
| 662 | goto resched; | ||
| 663 | |||
| 664 | sc->ghl_cr->bRequestType = | ||
| 665 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT; | ||
| 666 | sc->ghl_cr->bRequest = USB_REQ_SET_CONFIGURATION; | ||
| 667 | sc->ghl_cr->wValue = cpu_to_le16(ghl_ps3wiiu_magic_value); | ||
| 668 | sc->ghl_cr->wIndex = 0; | ||
| 669 | sc->ghl_cr->wLength = cpu_to_le16(poke_size); | ||
| 670 | memcpy(sc->ghl_databuf, ghl_ps3wiiu_magic_data, poke_size); | ||
| 671 | |||
| 672 | usb_fill_control_urb( | ||
| 673 | urb, usbdev, pipe, | ||
| 674 | (unsigned char *) sc->ghl_cr, sc->ghl_databuf, | ||
| 675 | poke_size, ghl_magic_poke_cb, NULL); | ||
| 676 | ret = usb_submit_urb(urb, GFP_ATOMIC); | ||
| 677 | if (ret < 0) { | ||
| 678 | kfree(sc->ghl_databuf); | ||
| 679 | kfree(sc->ghl_cr); | ||
| 680 | } | ||
| 681 | usb_free_urb(urb); | ||
| 682 | |||
| 683 | resched: | ||
| 684 | /* Reschedule for next time */ | ||
| 685 | mod_timer(&sc->ghl_poke_timer, jiffies + GHL_GUITAR_POKE_INTERVAL*HZ); | ||
| 686 | } | ||
| 687 | |||
| 688 | static int guitar_mapping(struct hid_device *hdev, struct hid_input *hi, | ||
| 689 | struct hid_field *field, struct hid_usage *usage, | ||
| 690 | unsigned long **bit, int *max) | ||
| 691 | { | ||
| 692 | if ((usage->hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR) { | ||
| 693 | unsigned int abs = usage->hid & HID_USAGE; | ||
| 694 | |||
| 695 | if (abs == GHL_GUITAR_TILT_USAGE) { | ||
| 696 | hid_map_usage_clear(hi, usage, bit, max, EV_ABS, ABS_RY); | ||
| 697 | return 1; | ||
| 698 | } | ||
| 699 | } | ||
| 700 | return 0; | ||
| 701 | } | ||
| 702 | |||
| 604 | static ssize_t ds4_show_poll_interval(struct device *dev, | 703 | static ssize_t ds4_show_poll_interval(struct device *dev, |
| 605 | struct device_attribute | 704 | struct device_attribute |
| 606 | *attr, char *buf) | 705 | *attr, char *buf) |
| @@ -892,7 +991,8 @@ static void sixaxis_parse_report(struct sony_sc *sc, u8 *rd, int size) · 285 unmodified lines | |||
| 892 | static const u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 }; | 991 | static const u8 sixaxis_battery_capacity[] = { 0, 1, 25, 50, 75, 100 }; |
| 893 | unsigned long flags; | 992 | unsigned long flags; |
| 894 | int offset; | 993 | int offset; |
| 895 | u8 cable_state, battery_capacity, battery_charging; | 994 | u8 battery_capacity; |
| 995 | int battery_status; | ||
| 896 | 996 | ||
| 897 | /* | 997 | /* |
| 898 | * The sixaxis is charging if the battery value is 0xee | 998 | * 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) · 5 unmodified lines | |||
| 904 | 1004 | ||
| 905 | if (rd[offset] >= 0xee) { | 1005 | if (rd[offset] >= 0xee) { |
| 906 | battery_capacity = 100; | 1006 | battery_capacity = 100; |
| 907 | battery_charging = !(rd[offset] & 0x01); | 1007 | battery_status = (rd[offset] & 0x01) ? POWER_SUPPLY_STATUS_FULL : POWER_SUPPLY_STATUS_CHARGING; |
| 908 | cable_state = 1; | ||
| 909 | } else { | 1008 | } else { |
| 910 | u8 index = rd[offset] <= 5 ? rd[offset] : 5; | 1009 | u8 index = rd[offset] <= 5 ? rd[offset] : 5; |
| 911 | battery_capacity = sixaxis_battery_capacity[index]; | 1010 | battery_capacity = sixaxis_battery_capacity[index]; |
| 912 | battery_charging = 0; | 1011 | battery_status = POWER_SUPPLY_STATUS_DISCHARGING; |
| 913 | cable_state = 0; | ||
| 914 | } | 1012 | } |
| 915 | 1013 | ||
| 916 | spin_lock_irqsave(&sc->lock, flags); | 1014 | spin_lock_irqsave(&sc->lock, flags); |
| 917 | sc->cable_state = cable_state; | ||
| 918 | sc->battery_capacity = battery_capacity; | 1015 | sc->battery_capacity = battery_capacity; |
| 919 | sc->battery_charging = battery_charging; | 1016 | sc->battery_status = battery_status; |
| 920 | spin_unlock_irqrestore(&sc->lock, flags); | 1017 | spin_unlock_irqrestore(&sc->lock, flags); |
| 921 | 1018 | ||
| 922 | if (sc->quirks & SIXAXIS_CONTROLLER) { | 1019 | if (sc->quirks & SIXAXIS_CONTROLLER) { |
| @@ -944,7 +1041,8 @@ static void dualshock4_parse_report(struct sony_sc *sc, u8 *rd, int size) · 21 unmodified lines | |||
| 944 | struct input_dev *input_dev = hidinput->input; | 1041 | struct input_dev *input_dev = hidinput->input; |
| 945 | unsigned long flags; | 1042 | unsigned long flags; |
| 946 | int n, m, offset, num_touch_data, max_touch_data; | 1043 | int n, m, offset, num_touch_data, max_touch_data; |
| 947 | u8 cable_state, battery_capacity, battery_charging; | 1044 | u8 cable_state, battery_capacity; |
| 1045 | int battery_status; | ||
| 948 | u16 timestamp; | 1046 | u16 timestamp; |
| 949 | 1047 | ||
| 950 | /* When using Bluetooth the header is 2 bytes longer, so skip these. */ | 1048 | /* 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) · 98 unmodified lines | |||
| 1049 | */ | 1147 | */ |
| 1050 | offset = data_offset + DS4_INPUT_REPORT_BATTERY_OFFSET; | 1148 | offset = data_offset + DS4_INPUT_REPORT_BATTERY_OFFSET; |
| 1051 | cable_state = (rd[offset] >> 4) & 0x01; | 1149 | cable_state = (rd[offset] >> 4) & 0x01; |
| 1052 | battery_capacity = rd[offset] & 0x0F; | ||
| 1053 | 1150 | ||
| 1054 | /* | 1151 | /* |
| 1055 | * When a USB power source is connected the battery level ranges from | 1152 | * Interpretation of the battery_capacity data depends on the cable state. |
| 1056 | * 0 to 10, and when running on battery power it ranges from 0 to 9. | 1153 | * When no cable is connected (bit4 is 0): |
| 1057 | * A battery level above 10 when plugged in means charge completed. | 1154 | * - 0:10: percentage in units of 10%. |
| 1155 | * When a cable is plugged in: | ||
| 1156 | * - 0-10: percentage in units of 10%. | ||
| 1157 | * - 11: battery is full | ||
| 1158 | * - 14: not charging due to Voltage or temperature error | ||
| 1159 | * - 15: charge error | ||
| 1058 | */ | 1160 | */ |
| 1059 | if (!cable_state || battery_capacity > 10) | 1161 | if (cable_state) { |
| 1060 | battery_charging = 0; | 1162 | u8 battery_data = rd[offset] & 0xf; |
| 1061 | else | 1163 | |
| 1062 | battery_charging = 1; | 1164 | if (battery_data < 10) { |
| 1165 | /* Take the mid-point for each battery capacity value, | ||
| 1166 | * because on the hardware side 0 = 0-9%, 1=10-19%, etc. | ||
| 1167 | * This matches official platform behavior, which does | ||
| 1168 | * the same. | ||
| 1169 | */ | ||
| 1170 | battery_capacity = battery_data * 10 + 5; | ||
| 1171 | battery_status = POWER_SUPPLY_STATUS_CHARGING; | ||
| 1172 | } else if (battery_data == 10) { | ||
| 1173 | battery_capacity = 100; | ||
| 1174 | battery_status = POWER_SUPPLY_STATUS_CHARGING; | ||
| 1175 | } else if (battery_data == 11) { | ||
| 1176 | battery_capacity = 100; | ||
| 1177 | battery_status = POWER_SUPPLY_STATUS_FULL; | ||
| 1178 | } else { /* 14, 15 and undefined values */ | ||
| 1179 | battery_capacity = 0; | ||
| 1180 | battery_status = POWER_SUPPLY_STATUS_UNKNOWN; | ||
| 1181 | } | ||
| 1182 | } else { | ||
| 1183 | u8 battery_data = rd[offset] & 0xf; | ||
| 1063 | 1184 | ||
| 1064 | if (!cable_state) | 1185 | if (battery_data < 10) |
| 1065 | battery_capacity++; | 1186 | battery_capacity = battery_data * 10 + 5; |
| 1066 | if (battery_capacity > 10) | 1187 | else /* 10 */ |
| 1067 | battery_capacity = 10; | 1188 | battery_capacity = 100; |
| 1068 | 1189 | ||
| 1069 | battery_capacity *= 10; | 1190 | battery_status = POWER_SUPPLY_STATUS_DISCHARGING; |
| 1191 | } | ||
| 1070 | 1192 | ||
| 1071 | spin_lock_irqsave(&sc->lock, flags); | 1193 | spin_lock_irqsave(&sc->lock, flags); |
| 1072 | sc->cable_state = cable_state; | ||
| 1073 | sc->battery_capacity = battery_capacity; | 1194 | sc->battery_capacity = battery_capacity; |
| 1074 | sc->battery_charging = battery_charging; | 1195 | sc->battery_status = battery_status; |
| 1075 | spin_unlock_irqrestore(&sc->lock, flags); | 1196 | spin_unlock_irqrestore(&sc->lock, flags); |
| 1076 | 1197 | ||
| 1077 | /* | 1198 | /* |
| @@ -1360,6 +1481,8 @@ static int sony_mapping(struct hid_device *hdev, struct hid_input *hi, · 282 unmodified lines | |||
| 1360 | if (sc->quirks & DUALSHOCK4_CONTROLLER) | 1481 | if (sc->quirks & DUALSHOCK4_CONTROLLER) |
| 1361 | return ds4_mapping(hdev, hi, field, usage, bit, max); | 1482 | return ds4_mapping(hdev, hi, field, usage, bit, max); |
| 1362 | 1483 | ||
| 1484 | if (sc->quirks & GHL_GUITAR_PS3WIIU) | ||
| 1485 | return guitar_mapping(hdev, hi, field, usage, bit, max); | ||
| 1363 | 1486 | ||
| 1364 | /* Let hid-core decide for the others */ | 1487 | /* Let hid-core decide for the others */ |
| 1365 | return 0; | 1488 | return 0; |
| @@ -1597,16 +1720,38 @@ static int dualshock4_get_calibration_data(struct sony_sc *sc) · 231 unmodified lines | |||
| 1597 | * of the controller, so that it sends input reports of type 0x11. | 1720 | * of the controller, so that it sends input reports of type 0x11. |
| 1598 | */ | 1721 | */ |
| 1599 | if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) { | 1722 | if (sc->quirks & (DUALSHOCK4_CONTROLLER_USB | DUALSHOCK4_DONGLE)) { |
| 1723 | int retries; | ||
| 1724 | |||
| 1600 | buf = kmalloc(DS4_FEATURE_REPORT_0x02_SIZE, GFP_KERNEL); | 1725 | buf = kmalloc(DS4_FEATURE_REPORT_0x02_SIZE, GFP_KERNEL); |
| 1601 | if (!buf) | 1726 | if (!buf) |
| 1602 | return -ENOMEM; | 1727 | return -ENOMEM; |
| 1603 | 1728 | ||
| 1604 | ret = hid_hw_raw_request(sc->hdev, 0x02, buf, | 1729 | /* We should normally receive the feature report data we asked |
| 1605 | DS4_FEATURE_REPORT_0x02_SIZE, | 1730 | * for, but hidraw applications such as Steam can issue feature |
| 1606 | HID_FEATURE_REPORT, | 1731 | * reports as well. In particular for Dongle reconnects, Steam |
| 1607 | HID_REQ_GET_REPORT); | 1732 | * and this function are competing resulting in often receiving |
| 1608 | if (ret < 0) | 1733 | * data for a different HID report, so retry a few times. |
| 1609 | goto err_stop; | 1734 | */ |
| 1735 | for (retries = 0; retries < 3; retries++) { | ||
| 1736 | ret = hid_hw_raw_request(sc->hdev, 0x02, buf, | ||
| 1737 | DS4_FEATURE_REPORT_0x02_SIZE, | ||
| 1738 | HID_FEATURE_REPORT, | ||
| 1739 | HID_REQ_GET_REPORT); | ||
| 1740 | if (ret < 0) | ||
| 1741 | goto err_stop; | ||
| 1742 | |||
| 1743 | if (buf[0] != 0x02) { | ||
| 1744 | if (retries < 2) { | ||
| 1745 | hid_warn(sc->hdev, "Retrying DualShock 4 get calibration report (0x02) request\n"); | ||
| 1746 | continue; | ||
| 1747 | } else { | ||
| 1748 | ret = -EILSEQ; | ||
| 1749 | goto err_stop; | ||
| 1750 | } | ||
| 1751 | } else { | ||
| 1752 | break; | ||
| 1753 | } | ||
| 1754 | } | ||
| 1610 | } else { | 1755 | } else { |
| 1611 | u8 bthdr = 0xA3; | 1756 | u8 bthdr = 0xA3; |
| 1612 | u32 crc; | 1757 | u32 crc; |
| @@ -2300,12 +2445,12 @@ static int sony_battery_get_property(struct power_supply *psy, · 687 unmodified lines | |||
| 2300 | struct sony_sc *sc = power_supply_get_drvdata(psy); | 2445 | struct sony_sc *sc = power_supply_get_drvdata(psy); |
| 2301 | unsigned long flags; | 2446 | unsigned long flags; |
| 2302 | int ret = 0; | 2447 | int ret = 0; |
| 2303 | u8 battery_charging, battery_capacity, cable_state; | 2448 | u8 battery_capacity; |
| 2449 | int battery_status; | ||
| 2304 | 2450 | ||
| 2305 | spin_lock_irqsave(&sc->lock, flags); | 2451 | spin_lock_irqsave(&sc->lock, flags); |
| 2306 | battery_charging = sc->battery_charging; | ||
| 2307 | battery_capacity = sc->battery_capacity; | 2452 | battery_capacity = sc->battery_capacity; |
| 2308 | cable_state = sc->cable_state; | 2453 | battery_status = sc->battery_status; |
| 2309 | spin_unlock_irqrestore(&sc->lock, flags); | 2454 | spin_unlock_irqrestore(&sc->lock, flags); |
| 2310 | 2455 | ||
| 2311 | switch (psp) { | 2456 | switch (psp) { |
| @@ -2319,13 +2464,7 @@ static int sony_battery_get_property(struct power_supply *psy, · 7 unmodified lines | |||
| 2319 | val->intval = battery_capacity; | 2464 | val->intval = battery_capacity; |
| 2320 | break; | 2465 | break; |
| 2321 | case POWER_SUPPLY_PROP_STATUS: | 2466 | case POWER_SUPPLY_PROP_STATUS: |
| 2322 | if (battery_charging) | 2467 | val->intval = battery_status; |
| 2323 | val->intval = POWER_SUPPLY_STATUS_CHARGING; | ||
| 2324 | else | ||
| 2325 | if (battery_capacity == 100 && cable_state) | ||
| 2326 | val->intval = POWER_SUPPLY_STATUS_FULL; | ||
| 2327 | else | ||
| 2328 | val->intval = POWER_SUPPLY_STATUS_DISCHARGING; | ||
| 2329 | break; | 2468 | break; |
| 2330 | default: | 2469 | default: |
| 2331 | ret = -EINVAL; | 2470 | ret = -EINVAL; |
| @@ -2723,19 +2862,17 @@ static int sony_input_configured(struct hid_device *hdev, · 391 unmodified lines | |||
| 2723 | 2862 | ||
| 2724 | ret = device_create_file(&sc->hdev->dev, &dev_attr_firmware_version); | 2863 | ret = device_create_file(&sc->hdev->dev, &dev_attr_firmware_version); |
| 2725 | if (ret) { | 2864 | if (ret) { |
| 2726 | /* Make zero for cleanup reasons of sysfs entries. */ | ||
| 2727 | sc->fw_version = 0; | ||
| 2728 | sc->hw_version = 0; | ||
| 2729 | hid_err(sc->hdev, "can't create sysfs firmware_version attribute err: %d\n", ret); | 2865 | hid_err(sc->hdev, "can't create sysfs firmware_version attribute err: %d\n", ret); |
| 2730 | goto err_stop; | 2866 | goto err_stop; |
| 2731 | } | 2867 | } |
| 2868 | sc->fw_version_created = true; | ||
| 2732 | 2869 | ||
| 2733 | ret = device_create_file(&sc->hdev->dev, &dev_attr_hardware_version); | 2870 | ret = device_create_file(&sc->hdev->dev, &dev_attr_hardware_version); |
| 2734 | if (ret) { | 2871 | if (ret) { |
| 2735 | sc->hw_version = 0; | ||
| 2736 | hid_err(sc->hdev, "can't create sysfs hardware_version attribute err: %d\n", ret); | 2872 | hid_err(sc->hdev, "can't create sysfs hardware_version attribute err: %d\n", ret); |
| 2737 | goto err_stop; | 2873 | goto err_stop; |
| 2738 | } | 2874 | } |
| 2875 | sc->hw_version_created = true; | ||
| 2739 | 2876 | ||
| 2740 | /* | 2877 | /* |
| 2741 | * The Dualshock 4 touchpad supports 2 touches and has a | 2878 | * The Dualshock 4 touchpad supports 2 touches and has a |
| @@ -2827,9 +2964,9 @@ err_stop: · 85 unmodified lines | |||
| 2827 | */ | 2964 | */ |
| 2828 | if (sc->ds4_bt_poll_interval) | 2965 | if (sc->ds4_bt_poll_interval) |
| 2829 | device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); | 2966 | device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); |
| 2830 | if (sc->fw_version) | 2967 | if (sc->fw_version_created) |
| 2831 | device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version); | 2968 | device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version); |
| 2832 | if (sc->hw_version) | 2969 | if (sc->hw_version_created) |
| 2833 | device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version); | 2970 | device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version); |
| 2834 | sony_cancel_work_sync(sc); | 2971 | sony_cancel_work_sync(sc); |
| 2835 | sony_remove_dev_list(sc); | 2972 | sony_remove_dev_list(sc); |
| @@ -2902,6 +3039,12 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id) · 66 unmodified lines | |||
| 2902 | return -ENODEV; | 3039 | return -ENODEV; |
| 2903 | } | 3040 | } |
| 2904 | 3041 | ||
| 3042 | if (sc->quirks & GHL_GUITAR_PS3WIIU) { | ||
| 3043 | timer_setup(&sc->ghl_poke_timer, ghl_magic_poke, 0); | ||
| 3044 | mod_timer(&sc->ghl_poke_timer, | ||
| 3045 | jiffies + GHL_GUITAR_POKE_INTERVAL*HZ); | ||
| 3046 | } | ||
| 3047 | |||
| 2905 | return ret; | 3048 | return ret; |
| 2906 | } | 3049 | } |
| 2907 | 3050 | ||
| @@ -2909,15 +3052,18 @@ static void sony_remove(struct hid_device *hdev) · 1 unmodified line | |||
| 2909 | { | 3052 | { |
| 2910 | struct sony_sc *sc = hid_get_drvdata(hdev); | 3053 | struct sony_sc *sc = hid_get_drvdata(hdev); |
| 2911 | 3054 | ||
| 3055 | if (sc->quirks & GHL_GUITAR_PS3WIIU) | ||
| 3056 | del_timer_sync(&sc->ghl_poke_timer); | ||
| 3057 | |||
| 2912 | hid_hw_close(hdev); | 3058 | hid_hw_close(hdev); |
| 2913 | 3059 | ||
| 2914 | if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) | 3060 | if (sc->quirks & DUALSHOCK4_CONTROLLER_BT) |
| 2915 | device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); | 3061 | device_remove_file(&sc->hdev->dev, &dev_attr_bt_poll_interval); |
| 2916 | 3062 | ||
| 2917 | if (sc->fw_version) | 3063 | if (sc->fw_version_created) |
| 2918 | device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version); | 3064 | device_remove_file(&sc->hdev->dev, &dev_attr_firmware_version); |
| 2919 | 3065 | ||
| 2920 | if (sc->hw_version) | 3066 | if (sc->hw_version_created) |
| 2921 | device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version); | 3067 | device_remove_file(&sc->hdev->dev, &dev_attr_hardware_version); |
| 2922 | 3068 | ||
| 2923 | sony_cancel_work_sync(sc); | 3069 | sony_cancel_work_sync(sc); |
| @@ -3020,6 +3166,9 @@ static const struct hid_device_id sony_devices[] = { · 96 unmodified lines | |||
| 3020 | /* SMK-Link NSG-MR7U Remote Control */ | 3166 | /* SMK-Link NSG-MR7U Remote Control */ |
| 3021 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE), | 3167 | { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SMK, USB_DEVICE_ID_SMK_NSG_MR7U_REMOTE), |
| 3022 | .driver_data = NSG_MR7U_REMOTE_BT }, | 3168 | .driver_data = NSG_MR7U_REMOTE_BT }, |
| 3169 | /* Guitar Hero Live PS3 and Wii U guitar dongles */ | ||
| 3170 | { HID_USB_DEVICE(USB_VENDOR_ID_SONY_GHLIVE, USB_DEVICE_ID_SONY_PS3WIIU_GHLIVE_DONGLE), | ||
| 3171 | .driver_data = GHL_GUITAR_PS3WIIU}, | ||
| 3023 | { } | 3172 | { } |
| 3024 | }; | 3173 | }; |
| 3025 | MODULE_DEVICE_TABLE(hid, sony_devices); | 3174 | MODULE_DEVICE_TABLE(hid, sony_devices); |
| @@ -170,7 +170,7 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t · 169 unmodified lines | |||
| 170 | /* | 170 | /* |
| 171 | * This function performs a Get_Report transfer over the control endpoint | 171 | * This function performs a Get_Report transfer over the control endpoint |
| 172 | * per section 7.2.1 of the HID specification, version 1.1. The first byte | 172 | * per section 7.2.1 of the HID specification, version 1.1. The first byte |
| 173 | * of buffer is the report number to request, or 0x0 if the defice does not | 173 | * of buffer is the report number to request, or 0x0 if the device does not |
| 174 | * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT | 174 | * use numbered reports. The report_type parameter can be HID_FEATURE_REPORT |
| 175 | * or HID_INPUT_REPORT. | 175 | * or HID_INPUT_REPORT. |
| 176 | */ | 176 | */ |
| @@ -428,6 +428,28 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd, · 251 unmodified lines | |||
| 428 | break; | 428 | break; |
| 429 | } | 429 | } |
| 430 | 430 | ||
| 431 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSINPUT(0))) { | ||
| 432 | int len = _IOC_SIZE(cmd); | ||
| 433 | ret = hidraw_send_report(file, user_arg, len, HID_INPUT_REPORT); | ||
| 434 | break; | ||
| 435 | } | ||
| 436 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGINPUT(0))) { | ||
| 437 | int len = _IOC_SIZE(cmd); | ||
| 438 | ret = hidraw_get_report(file, user_arg, len, HID_INPUT_REPORT); | ||
| 439 | break; | ||
| 440 | } | ||
| 441 | |||
| 442 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSOUTPUT(0))) { | ||
| 443 | int len = _IOC_SIZE(cmd); | ||
| 444 | ret = hidraw_send_report(file, user_arg, len, HID_OUTPUT_REPORT); | ||
| 445 | break; | ||
| 446 | } | ||
| 447 | if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGOUTPUT(0))) { | ||
| 448 | int len = _IOC_SIZE(cmd); | ||
| 449 | ret = hidraw_get_report(file, user_arg, len, HID_OUTPUT_REPORT); | ||
| 450 | break; | ||
| 451 | } | ||
| 452 | |||
| 431 | /* Begin Read-only ioctls. */ | 453 | /* Begin Read-only ioctls. */ |
| 432 | if (_IOC_DIR(cmd) != _IOC_READ) { | 454 | if (_IOC_DIR(cmd) != _IOC_READ) { |
| 433 | ret = -EINVAL; | 455 | ret = -EINVAL; |
| @@ -1106,8 +1106,11 @@ static int i2c_hid_probe(struct i2c_client *client, · 1105 unmodified lines | |||
| 1106 | } | 1106 | } |
| 1107 | 1107 | ||
| 1108 | ret = i2c_hid_fetch_hid_descriptor(ihid); | 1108 | ret = i2c_hid_fetch_hid_descriptor(ihid); |
| 1109 | if (ret < 0) | 1109 | if (ret < 0) { |
| 1110 | dev_err(&client->dev, | ||
| 1111 | "Failed to fetch the HID Descriptor\n"); | ||
| 1110 | goto err_regulator; | 1112 | goto err_regulator; |
| 1113 | } | ||
| 1111 | 1114 | ||
| 1112 | ret = i2c_hid_init_irq(client); | 1115 | ret = i2c_hid_init_irq(client); |
| 1113 | if (ret < 0) | 1116 | if (ret < 0) |
| @@ -405,6 +405,14 @@ static const struct dmi_system_id i2c_hid_dmi_desc_override_table[] = { · 404 unmodified lines | |||
| 405 | }, | 405 | }, |
| 406 | .driver_data = (void *)&sipodev_desc | 406 | .driver_data = (void *)&sipodev_desc |
| 407 | }, | 407 | }, |
| 408 | { | ||
| 409 | .ident = "Vero K147", | ||
| 410 | .matches = { | ||
| 411 | DMI_EXACT_MATCH(DMI_SYS_VENDOR, "VERO"), | ||
| 412 | DMI_EXACT_MATCH(DMI_PRODUCT_NAME, "K147"), | ||
| 413 | }, | ||
| 414 | .driver_data = (void *)&sipodev_desc | ||
| 415 | }, | ||
| 408 | { } /* Terminate list */ | 416 | { } /* Terminate list */ |
| 409 | }; | 417 | }; |
| 410 | 418 | ||
| @@ -211,10 +211,8 @@ int ishtp_hid_probe(unsigned int cur_hid_dev, · 210 unmodified lines | |||
| 211 | struct ishtp_hid_data *hid_data; | 211 | struct ishtp_hid_data *hid_data; |
| 212 | 212 | ||
| 213 | hid = hid_allocate_device(); | 213 | hid = hid_allocate_device(); |
| 214 | if (IS_ERR(hid)) { | 214 | if (IS_ERR(hid)) |
| 215 | rv = PTR_ERR(hid); | 215 | return PTR_ERR(hid); |
| 216 | return -ENOMEM; | ||
| 217 | } | ||
| 218 | 216 | ||
| 219 | hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL); | 217 | hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL); |
| 220 | if (!hid_data) { | 218 | if (!hid_data) { |
| @@ -438,6 +438,7 @@ static void hid_irq_out(struct urb *urb) · 437 unmodified lines | |||
| 438 | break; | 438 | break; |
| 439 | case -ESHUTDOWN: /* unplug */ | 439 | case -ESHUTDOWN: /* unplug */ |
| 440 | unplug = 1; | 440 | unplug = 1; |
| 441 | break; | ||
| 441 | case -EILSEQ: /* protocol error or unplug */ | 442 | case -EILSEQ: /* protocol error or unplug */ |
| 442 | case -EPROTO: /* protocol error or unplug */ | 443 | case -EPROTO: /* protocol error or unplug */ |
| 443 | case -ECONNRESET: /* unlink */ | 444 | case -ECONNRESET: /* unlink */ |
| @@ -489,6 +490,7 @@ static void hid_ctrl(struct urb *urb) · 45 unmodified lines | |||
| 489 | break; | 490 | break; |
| 490 | case -ESHUTDOWN: /* unplug */ | 491 | case -ESHUTDOWN: /* unplug */ |
| 491 | unplug = 1; | 492 | unplug = 1; |
| 493 | break; | ||
| 492 | case -EILSEQ: /* protocol error or unplug */ | 494 | case -EILSEQ: /* protocol error or unplug */ |
| 493 | case -EPROTO: /* protocol error or unplug */ | 495 | case -EPROTO: /* protocol error or unplug */ |
| 494 | case -ECONNRESET: /* unlink */ | 496 | case -ECONNRESET: /* unlink */ |
| @@ -1173,7 +1173,7 @@ static struct attribute *cintiq_led_attrs[] = { · 1172 unmodified lines | |||
| 1173 | NULL | 1173 | NULL |
| 1174 | }; | 1174 | }; |
| 1175 | 1175 | ||
| 1176 | static struct attribute_group cintiq_led_attr_group = { | 1176 | static const struct attribute_group cintiq_led_attr_group = { |
| 1177 | .name = "wacom_led", | 1177 | .name = "wacom_led", |
| 1178 | .attrs = cintiq_led_attrs, | 1178 | .attrs = cintiq_led_attrs, |
| 1179 | }; | 1179 | }; |
| @@ -1194,7 +1194,7 @@ static struct attribute *intuos4_led_attrs[] = { · 14 unmodified lines | |||
| 1194 | NULL | 1194 | NULL |
| 1195 | }; | 1195 | }; |
| 1196 | 1196 | ||
| 1197 | static struct attribute_group intuos4_led_attr_group = { | 1197 | static const struct attribute_group intuos4_led_attr_group = { |
| 1198 | .name = "wacom_led", | 1198 | .name = "wacom_led", |
| 1199 | .attrs = intuos4_led_attrs, | 1199 | .attrs = intuos4_led_attrs, |
| 1200 | }; | 1200 | }; |
| @@ -1205,7 +1205,7 @@ static struct attribute *intuos5_led_attrs[] = { · 4 unmodified lines | |||
| 1205 | NULL | 1205 | NULL |
| 1206 | }; | 1206 | }; |
| 1207 | 1207 | ||
| 1208 | static struct attribute_group intuos5_led_attr_group = { | 1208 | static const struct attribute_group intuos5_led_attr_group = { |
| 1209 | .name = "wacom_led", | 1209 | .name = "wacom_led", |
| 1210 | .attrs = intuos5_led_attrs, | 1210 | .attrs = intuos5_led_attrs, |
| 1211 | }; | 1211 | }; |
| @@ -1216,13 +1216,13 @@ static struct attribute *generic_led_attrs[] = { · 4 unmodified lines | |||
| 1216 | NULL | 1216 | NULL |
| 1217 | }; | 1217 | }; |
| 1218 | 1218 | ||
| 1219 | static struct attribute_group generic_led_attr_group = { | 1219 | static const struct attribute_group generic_led_attr_group = { |
| 1220 | .name = "wacom_led", | 1220 | .name = "wacom_led", |
| 1221 | .attrs = generic_led_attrs, | 1221 | .attrs = generic_led_attrs, |
| 1222 | }; | 1222 | }; |
| 1223 | 1223 | ||
| 1224 | struct wacom_sysfs_group_devres { | 1224 | struct wacom_sysfs_group_devres { |
| 1225 | struct attribute_group *group; | 1225 | const struct attribute_group *group; |
| 1226 | struct kobject *root; | 1226 | struct kobject *root; |
| 1227 | }; | 1227 | }; |
| 1228 | 1228 | ||
| @@ -1238,7 +1238,7 @@ static void wacom_devm_sysfs_group_release(struct device *dev, void *res) · 9 unmodified lines | |||
| 1238 | 1238 | ||
| 1239 | static int __wacom_devm_sysfs_create_group(struct wacom *wacom, | 1239 | static int __wacom_devm_sysfs_create_group(struct wacom *wacom, |
| 1240 | struct kobject *root, | 1240 | struct kobject *root, |
| 1241 | struct attribute_group *group) | 1241 | const struct attribute_group *group) |
| 1242 | { | 1242 | { |
| 1243 | struct wacom_sysfs_group_devres *devres; | 1243 | struct wacom_sysfs_group_devres *devres; |
| 1244 | int error; | 1244 | int error; |
| @@ -1264,7 +1264,7 @@ static int __wacom_devm_sysfs_create_group(struct wacom *wacom, · 19 unmodified lines | |||
| 1264 | } | 1264 | } |
| 1265 | 1265 | ||
| 1266 | static int wacom_devm_sysfs_create_group(struct wacom *wacom, | 1266 | static int wacom_devm_sysfs_create_group(struct wacom *wacom, |
| 1267 | struct attribute_group *group) | 1267 | const struct attribute_group *group) |
| 1268 | { | 1268 | { |
| 1269 | return __wacom_devm_sysfs_create_group(wacom, &wacom->hdev->dev.kobj, | 1269 | return __wacom_devm_sysfs_create_group(wacom, &wacom->hdev->dev.kobj, |
| 1270 | group); | 1270 | group); |
| @@ -1847,7 +1847,7 @@ static struct attribute *remote##SET_ID##_serial_attrs[] = { \ · 576 unmodified lines | |||
| 1847 | &remote##SET_ID##_mode_attr.attr, \ | 1847 | &remote##SET_ID##_mode_attr.attr, \ |
| 1848 | NULL \ | 1848 | NULL \ |
| 1849 | }; \ | 1849 | }; \ |
| 1850 | static struct attribute_group remote##SET_ID##_serial_group = { \ | 1850 | static const struct attribute_group remote##SET_ID##_serial_group = { \ |
| 1851 | .name = NULL, \ | 1851 | .name = NULL, \ |
| 1852 | .attrs = remote##SET_ID##_serial_attrs, \ | 1852 | .attrs = remote##SET_ID##_serial_attrs, \ |
| 1853 | } | 1853 | } |
| @@ -494,7 +494,7 @@ struct hid_report_enum { · 493 unmodified lines | |||
| 494 | }; | 494 | }; |
| 495 | 495 | ||
| 496 | #define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */ | 496 | #define HID_MIN_BUFFER_SIZE 64 /* make sure there is at least a packet size of space */ |
| 497 | #define HID_MAX_BUFFER_SIZE 8192 /* 8kb */ | 497 | #define HID_MAX_BUFFER_SIZE 16384 /* 16kb */ |
| 498 | #define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ | 498 | #define HID_CONTROL_FIFO_SIZE 256 /* to init devices with >100 reports */ |
| 499 | #define HID_OUTPUT_FIFO_SIZE 64 | 499 | #define HID_OUTPUT_FIFO_SIZE 64 |
| 500 | 500 | ||
| @@ -585,6 +585,7 @@ struct hid_device { /* device report descriptor */ · 84 unmodified lines | |||
| 585 | __s32 battery_report_id; | 585 | __s32 battery_report_id; |
| 586 | enum hid_battery_status battery_status; | 586 | enum hid_battery_status battery_status; |
| 587 | bool battery_avoid_query; | 587 | bool battery_avoid_query; |
| 588 | ktime_t battery_ratelimit_time; | ||
| 588 | #endif | 589 | #endif |
| 589 | 590 | ||
| 590 | unsigned long status; /* see STAT flags above */ | 591 | unsigned long status; /* see STAT flags above */ |
| @@ -40,6 +40,12 @@ struct hidraw_devinfo { · 39 unmodified lines | |||
| 40 | #define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len) | 40 | #define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len) |
| 41 | #define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len) | 41 | #define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len) |
| 42 | #define HIDIOCGRAWUNIQ(len) _IOC(_IOC_READ, 'H', 0x08, len) | 42 | #define HIDIOCGRAWUNIQ(len) _IOC(_IOC_READ, 'H', 0x08, len) |
| 43 | /* The first byte of SINPUT and GINPUT is the report number */ | ||
| 44 | #define HIDIOCSINPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x09, len) | ||
| 45 | #define HIDIOCGINPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0A, len) | ||
| 46 | /* The first byte of SOUTPUT and GOUTPUT is the report number */ | ||
| 47 | #define HIDIOCSOUTPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0B, len) | ||
| 48 | #define HIDIOCGOUTPUT(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x0C, len) | ||
| 43 | 49 | ||
| 44 | #define HIDRAW_FIRST_MINOR 0 | 50 | #define HIDRAW_FIRST_MINOR 0 |
| 45 | #define HIDRAW_MAX_DEVICES 64 | 51 | #define HIDRAW_MAX_DEVICES 64 |
| @@ -128,7 +128,7 @@ int main(int argc, char **argv) · 127 unmodified lines | |||
| 128 | perror("HIDIOCGFEATURE"); | 128 | perror("HIDIOCGFEATURE"); |
| 129 | } else { | 129 | } else { |
| 130 | printf("ioctl HIDIOCGFEATURE returned: %d\n", res); | 130 | printf("ioctl HIDIOCGFEATURE returned: %d\n", res); |
| 131 | printf("Report data (not containing the report number):\n\t"); | 131 | printf("Report data:\n\t"); |
| 132 | for (i = 0; i < res; i++) | 132 | for (i = 0; i < res; i++) |
| 133 | printf("%hhx ", buf[i]); | 133 | printf("%hhx ", buf[i]); |
| 134 | puts("\n"); | 134 | puts("\n"); |