Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'for-linus-2022080201' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid

Pull HID updates from Jiri Kosina:

- support for AMD SOCs using SFH1.1 memory access (Basavaraj Natikar)

- XP-PEN Deco L support (José Expósito)

- support for Elan eKTH6915 touchscreens (Douglas Anderson)

- other small assorted fixes and device ID additions

* tag 'for-linus-2022080201' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (39 commits)
HID: amd_sfh: Handle condition of "no sensors"
HID: amd_sfh: Fix implicit declaration error on i386
HID: apple: Add "GANSS" to the non-Apple list
HID: alps: Declare U1_UNICORN_LEGACY support
HID: wacom: Force pen out of prox if no events have been received in a while
HID: nintendo: Add missing array termination
HID: lg-g15: Fix comment typo
HID: amd_sfh: Implement SFH1.1 functionality
HID: amd_sfh: Move interrupt handling to common interface
HID: amd_sfh: Move amd_sfh_work to common interface
HID: amd_sfh: Move global functions to static
HID: amd_sfh: Add remove operation in amd_mp2_ops
HID: amd_sfh: Add PM operations in amd_mp2_ops
HID: amd_sfh: Add descriptor operations in amd_mp2_ops
HID: amd_sfh: Move request_list variable to client data
HID: amd_sfh: Move request_list struct to header file
HID: amd_sfh: Move common macros and structures
HID: amd_sfh: Add NULL check for hid device
HID: core: remove unneeded assignment in hid_process_report()
ID: intel-ish-hid: hid-client: drop unexpected word "the" in the comments
...

+2065 -207
+65
Documentation/devicetree/bindings/input/elan,ekth6915.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/input/elan,ekth6915.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Elan eKTH6915 touchscreen controller 8 + 9 + maintainers: 10 + - Douglas Anderson <dianders@chromium.org> 11 + 12 + description: 13 + Supports the Elan eKTH6915 touchscreen controller. 14 + This touchscreen controller uses the i2c-hid protocol with a reset GPIO. 15 + 16 + properties: 17 + compatible: 18 + items: 19 + - const: elan,ekth6915 20 + 21 + reg: 22 + const: 0x10 23 + 24 + interrupts: 25 + maxItems: 1 26 + 27 + reset-gpios: 28 + description: Reset GPIO; not all touchscreens using eKTH6915 hook this up. 29 + 30 + vcc33-supply: 31 + description: The 3.3V supply to the touchscreen. 32 + 33 + vccio-supply: 34 + description: 35 + The IO supply to the touchscreen. Need not be specified if this is the 36 + same as the 3.3V supply. 37 + 38 + required: 39 + - compatible 40 + - reg 41 + - interrupts 42 + - vcc33-supply 43 + 44 + additionalProperties: false 45 + 46 + examples: 47 + - | 48 + #include <dt-bindings/gpio/gpio.h> 49 + #include <dt-bindings/interrupt-controller/irq.h> 50 + 51 + i2c { 52 + #address-cells = <1>; 53 + #size-cells = <0>; 54 + 55 + ap_ts: touchscreen@10 { 56 + compatible = "elan,ekth6915"; 57 + reg = <0x10>; 58 + 59 + interrupt-parent = <&tlmm>; 60 + interrupts = <9 IRQ_TYPE_LEVEL_LOW>; 61 + 62 + reset-gpios = <&tlmm 8 GPIO_ACTIVE_LOW>; 63 + vcc33-supply = <&pp3300_ts>; 64 + }; 65 + };
+5
drivers/hid/.kunitconfig
··· 1 + CONFIG_KUNIT=y 2 + CONFIG_USB=y 3 + CONFIG_USB_HID=y 4 + CONFIG_HID_UCLOGIC=y 5 + CONFIG_HID_KUNIT_TEST=y
+16
drivers/hid/Kconfig
··· 1306 1306 To compile this driver as a module, choose M here: the module 1307 1307 will be called hid-mcp2221.ko. 1308 1308 1309 + config HID_KUNIT_TEST 1310 + bool "KUnit tests for HID" if !KUNIT_ALL_TESTS 1311 + depends on KUNIT=y 1312 + depends on HID_UCLOGIC 1313 + default KUNIT_ALL_TESTS 1314 + help 1315 + This builds unit tests for HID. This option is not useful for 1316 + distributions or general kernels, but only for kernel 1317 + developers working on HID and associated drivers. 1318 + 1319 + For more information on KUnit and unit tests in general, 1320 + please refer to the KUnit documentation in 1321 + Documentation/dev-tools/kunit/. 1322 + 1323 + If in doubt, say "N". 1324 + 1309 1325 endmenu 1310 1326 1311 1327 endif # HID
+3
drivers/hid/Makefile
··· 144 144 obj-$(CONFIG_HID_SENSOR_HUB) += hid-sensor-hub.o 145 145 obj-$(CONFIG_HID_SENSOR_CUSTOM_SENSOR) += hid-sensor-custom.o 146 146 147 + obj-$(CONFIG_HID_KUNIT_TEST) += hid-uclogic-rdesc.o \ 148 + hid-uclogic-rdesc-test.o 149 + 147 150 obj-$(CONFIG_USB_HID) += usbhid/ 148 151 obj-$(CONFIG_USB_MOUSE) += usbhid/ 149 152 obj-$(CONFIG_USB_KBD) += usbhid/
+3
drivers/hid/amd-sfh-hid/Makefile
··· 9 9 amd_sfh-objs += amd_sfh_client.o 10 10 amd_sfh-objs += amd_sfh_pcie.o 11 11 amd_sfh-objs += hid_descriptor/amd_sfh_hid_desc.o 12 + amd_sfh-objs += sfh1_1/amd_sfh_init.o 13 + amd_sfh-objs += sfh1_1/amd_sfh_interface.o 14 + amd_sfh-objs += sfh1_1/amd_sfh_desc.o 12 15 13 16 ccflags-y += -I $(srctree)/$(src)/
+85 -32
drivers/hid/amd-sfh-hid/amd_sfh_client.c
··· 18 18 #include "amd_sfh_pcie.h" 19 19 #include "amd_sfh_hid.h" 20 20 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 21 void amd_sfh_set_report(struct hid_device *hid, int report_id, 34 22 int report_type) 35 23 { ··· 38 50 { 39 51 struct amdtp_hid_data *hid_data = hid->driver_data; 40 52 struct amdtp_cl_data *cli_data = hid_data->cli_data; 53 + struct request_list *req_list = &cli_data->req_list; 41 54 int i; 42 55 43 56 for (i = 0; i < cli_data->num_hid_devices; i++) { ··· 55 66 new->report_id = report_id; 56 67 cli_data->report_id[i] = report_id; 57 68 cli_data->request_done[i] = false; 58 - list_add(&new->list, &req_list.list); 69 + list_add(&new->list, &req_list->list); 59 70 break; 60 71 } 61 72 } ··· 63 74 return 0; 64 75 } 65 76 66 - static void amd_sfh_work(struct work_struct *work) 77 + void amd_sfh_work(struct work_struct *work) 67 78 { 68 79 struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work.work); 80 + struct request_list *req_list = &cli_data->req_list; 69 81 struct amd_input_data *in_data = cli_data->in_data; 70 82 struct request_list *req_node; 71 83 u8 current_index, sensor_index; 84 + struct amd_mp2_ops *mp2_ops; 85 + struct amd_mp2_dev *mp2; 72 86 u8 report_id, node_type; 73 87 u8 report_size = 0; 74 88 75 - req_node = list_last_entry(&req_list.list, struct request_list, list); 89 + req_node = list_last_entry(&req_list->list, struct request_list, list); 76 90 list_del(&req_node->list); 77 91 current_index = req_node->current_index; 78 92 sensor_index = req_node->sensor_idx; ··· 83 91 node_type = req_node->report_type; 84 92 kfree(req_node); 85 93 94 + mp2 = container_of(in_data, struct amd_mp2_dev, in_data); 95 + mp2_ops = mp2->mp2_ops; 86 96 if (node_type == HID_FEATURE_REPORT) { 87 - report_size = get_feature_report(sensor_index, report_id, 88 - cli_data->feature_report[current_index]); 97 + report_size = mp2_ops->get_feat_rep(sensor_index, report_id, 98 + cli_data->feature_report[current_index]); 89 99 if (report_size) 90 100 hid_input_report(cli_data->hid_sensor_hubs[current_index], 91 101 cli_data->report_type[current_index], ··· 96 102 pr_err("AMDSFH: Invalid report size\n"); 97 103 98 104 } else if (node_type == HID_INPUT_REPORT) { 99 - report_size = get_input_report(current_index, sensor_index, report_id, in_data); 105 + report_size = mp2_ops->get_in_rep(current_index, sensor_index, report_id, in_data); 100 106 if (report_size) 101 107 hid_input_report(cli_data->hid_sensor_hubs[current_index], 102 108 cli_data->report_type[current_index], ··· 109 115 amdtp_hid_wakeup(cli_data->hid_sensor_hubs[current_index]); 110 116 } 111 117 112 - static void amd_sfh_work_buffer(struct work_struct *work) 118 + void amd_sfh_work_buffer(struct work_struct *work) 113 119 { 114 120 struct amdtp_cl_data *cli_data = container_of(work, struct amdtp_cl_data, work_buffer.work); 115 121 struct amd_input_data *in_data = cli_data->in_data; 122 + struct amd_mp2_dev *mp2; 116 123 u8 report_size; 117 124 int i; 118 125 119 126 for (i = 0; i < cli_data->num_hid_devices; i++) { 120 127 if (cli_data->sensor_sts[i] == SENSOR_ENABLED) { 121 - report_size = get_input_report 122 - (i, cli_data->sensor_idx[i], cli_data->report_id[i], in_data); 128 + mp2 = container_of(in_data, struct amd_mp2_dev, in_data); 129 + report_size = mp2->mp2_ops->get_in_rep(i, cli_data->sensor_idx[i], 130 + cli_data->report_id[i], in_data); 123 131 hid_input_report(cli_data->hid_sensor_hubs[i], HID_INPUT_REPORT, 124 132 in_data->input_report[i], report_size, 0); 125 133 } ··· 129 133 schedule_delayed_work(&cli_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); 130 134 } 131 135 132 - u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts) 136 + static u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts) 133 137 { 134 138 if (mp2->mp2_ops->response) 135 139 sensor_sts = mp2->mp2_ops->response(mp2, sid, sensor_sts); ··· 137 141 return sensor_sts; 138 142 } 139 143 140 - const char *get_sensor_name(int idx) 144 + static const char *get_sensor_name(int idx) 141 145 { 142 146 switch (idx) { 143 147 case accel_idx: ··· 155 159 } 156 160 } 157 161 162 + static void amd_sfh_resume(struct amd_mp2_dev *mp2) 163 + { 164 + struct amdtp_cl_data *cl_data = mp2->cl_data; 165 + struct amd_mp2_sensor_info info; 166 + int i, status; 167 + 168 + for (i = 0; i < cl_data->num_hid_devices; i++) { 169 + if (cl_data->sensor_sts[i] == SENSOR_DISABLED) { 170 + info.period = AMD_SFH_IDLE_LOOP; 171 + info.sensor_idx = cl_data->sensor_idx[i]; 172 + info.dma_address = cl_data->sensor_dma_addr[i]; 173 + mp2->mp2_ops->start(mp2, info); 174 + status = amd_sfh_wait_for_response 175 + (mp2, cl_data->sensor_idx[i], SENSOR_ENABLED); 176 + if (status == SENSOR_ENABLED) 177 + cl_data->sensor_sts[i] = SENSOR_ENABLED; 178 + dev_dbg(&mp2->pdev->dev, "resume sid 0x%x (%s) status 0x%x\n", 179 + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 180 + cl_data->sensor_sts[i]); 181 + } 182 + } 183 + 184 + schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); 185 + amd_sfh_clear_intr(mp2); 186 + } 187 + 188 + static void amd_sfh_suspend(struct amd_mp2_dev *mp2) 189 + { 190 + struct amdtp_cl_data *cl_data = mp2->cl_data; 191 + int i, status; 192 + 193 + for (i = 0; i < cl_data->num_hid_devices; i++) { 194 + if (cl_data->sensor_idx[i] != HPD_IDX && 195 + cl_data->sensor_sts[i] == SENSOR_ENABLED) { 196 + mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]); 197 + status = amd_sfh_wait_for_response 198 + (mp2, cl_data->sensor_idx[i], SENSOR_DISABLED); 199 + if (status != SENSOR_ENABLED) 200 + cl_data->sensor_sts[i] = SENSOR_DISABLED; 201 + dev_dbg(&mp2->pdev->dev, "suspend sid 0x%x (%s) status 0x%x\n", 202 + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 203 + cl_data->sensor_sts[i]); 204 + } 205 + } 206 + 207 + cancel_delayed_work_sync(&cl_data->work_buffer); 208 + amd_sfh_clear_intr(mp2); 209 + } 210 + 158 211 int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata) 159 212 { 160 213 struct amd_input_data *in_data = &privdata->in_data; 161 214 struct amdtp_cl_data *cl_data = privdata->cl_data; 215 + struct amd_mp2_ops *mp2_ops = privdata->mp2_ops; 162 216 struct amd_mp2_sensor_info info; 217 + struct request_list *req_list; 163 218 struct device *dev; 164 219 u32 feature_report_size; 165 220 u32 input_report_size; 166 221 int rc, i, status; 167 222 u8 cl_idx; 168 223 224 + req_list = &cl_data->req_list; 169 225 dev = &privdata->pdev->dev; 226 + amd_sfh_set_desc_ops(mp2_ops); 227 + 228 + mp2_ops->suspend = amd_sfh_suspend; 229 + mp2_ops->resume = amd_sfh_resume; 170 230 171 231 cl_data->num_hid_devices = amd_mp2_get_sensor_num(privdata, &cl_data->sensor_idx[0]); 232 + if (cl_data->num_hid_devices == 0) 233 + return -ENODEV; 172 234 173 235 INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work); 174 236 INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer); 175 - INIT_LIST_HEAD(&req_list.list); 237 + INIT_LIST_HEAD(&req_list->list); 176 238 cl_data->in_data = in_data; 177 239 178 240 for (i = 0; i < cl_data->num_hid_devices; i++) { ··· 241 187 cl_data->sensor_requested_cnt[i] = 0; 242 188 cl_data->cur_hid_dev = i; 243 189 cl_idx = cl_data->sensor_idx[i]; 244 - cl_data->report_descr_sz[i] = get_descr_sz(cl_idx, descr_size); 190 + cl_data->report_descr_sz[i] = mp2_ops->get_desc_sz(cl_idx, descr_size); 245 191 if (!cl_data->report_descr_sz[i]) { 246 192 rc = -EINVAL; 247 193 goto cleanup; 248 194 } 249 - feature_report_size = get_descr_sz(cl_idx, feature_size); 195 + feature_report_size = mp2_ops->get_desc_sz(cl_idx, feature_size); 250 196 if (!feature_report_size) { 251 197 rc = -EINVAL; 252 198 goto cleanup; 253 199 } 254 - input_report_size = get_descr_sz(cl_idx, input_size); 200 + input_report_size = mp2_ops->get_desc_sz(cl_idx, input_size); 255 201 if (!input_report_size) { 256 202 rc = -EINVAL; 257 203 goto cleanup; ··· 276 222 rc = -ENOMEM; 277 223 goto cleanup; 278 224 } 279 - rc = get_report_descriptor(cl_idx, cl_data->report_descr[i]); 225 + rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]); 280 226 if (rc) 281 227 return rc; 282 - privdata->mp2_ops->start(privdata, info); 228 + mp2_ops->start(privdata, info); 283 229 status = amd_sfh_wait_for_response 284 230 (privdata, cl_data->sensor_idx[i], SENSOR_ENABLED); 285 231 if (status == SENSOR_ENABLED) { 286 232 cl_data->sensor_sts[i] = SENSOR_ENABLED; 287 233 rc = amdtp_hid_probe(cl_data->cur_hid_dev, cl_data); 288 234 if (rc) { 289 - privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]); 235 + mp2_ops->stop(privdata, cl_data->sensor_idx[i]); 290 236 status = amd_sfh_wait_for_response 291 237 (privdata, cl_data->sensor_idx[i], SENSOR_DISABLED); 292 238 if (status != SENSOR_ENABLED) ··· 302 248 cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 303 249 cl_data->sensor_sts[i]); 304 250 } 305 - if (privdata->mp2_ops->discovery_status && 306 - privdata->mp2_ops->discovery_status(privdata) == 0) { 251 + if (mp2_ops->discovery_status && mp2_ops->discovery_status(privdata) == 0) { 307 252 amd_sfh_hid_client_deinit(privdata); 308 253 for (i = 0; i < cl_data->num_hid_devices; i++) { 309 254 devm_kfree(dev, cl_data->feature_report[i]);
+76
drivers/hid/amd-sfh-hid/amd_sfh_common.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * AMD MP2 common macros and structures 4 + * 5 + * Copyright (c) 2022, Advanced Micro Devices, Inc. 6 + * All Rights Reserved. 7 + * 8 + * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com> 9 + */ 10 + #ifndef AMD_SFH_COMMON_H 11 + #define AMD_SFH_COMMON_H 12 + 13 + #include <linux/pci.h> 14 + #include "amd_sfh_hid.h" 15 + 16 + #define PCI_DEVICE_ID_AMD_MP2 0x15E4 17 + #define PCI_DEVICE_ID_AMD_MP2_1_1 0x164A 18 + 19 + #define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4)) 20 + #define AMD_P2C_MSG(regno) (0x10680 + ((regno) * 4)) 21 + 22 + #define SENSOR_ENABLED 4 23 + #define SENSOR_DISABLED 5 24 + 25 + #define AMD_SFH_IDLE_LOOP 200 26 + 27 + enum cmd_id { 28 + NO_OP, 29 + ENABLE_SENSOR, 30 + DISABLE_SENSOR, 31 + STOP_ALL_SENSORS = 8, 32 + }; 33 + 34 + struct amd_mp2_sensor_info { 35 + u8 sensor_idx; 36 + u32 period; 37 + dma_addr_t dma_address; 38 + }; 39 + 40 + struct amd_mp2_dev { 41 + struct pci_dev *pdev; 42 + struct amdtp_cl_data *cl_data; 43 + void __iomem *mmio; 44 + void __iomem *vsbase; 45 + const struct amd_sfh1_1_ops *sfh1_1_ops; 46 + struct amd_mp2_ops *mp2_ops; 47 + struct amd_input_data in_data; 48 + /* mp2 active control status */ 49 + u32 mp2_acs; 50 + }; 51 + 52 + struct amd_mp2_ops { 53 + void (*start)(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info); 54 + void (*stop)(struct amd_mp2_dev *privdata, u16 sensor_idx); 55 + void (*stop_all)(struct amd_mp2_dev *privdata); 56 + int (*response)(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts); 57 + void (*clear_intr)(struct amd_mp2_dev *privdata); 58 + int (*init_intr)(struct amd_mp2_dev *privdata); 59 + int (*discovery_status)(struct amd_mp2_dev *privdata); 60 + void (*suspend)(struct amd_mp2_dev *mp2); 61 + void (*resume)(struct amd_mp2_dev *mp2); 62 + void (*remove)(void *privdata); 63 + int (*get_rep_desc)(int sensor_idx, u8 rep_desc[]); 64 + u32 (*get_desc_sz)(int sensor_idx, int descriptor_name); 65 + u8 (*get_feat_rep)(int sensor_idx, int report_id, u8 *feature_report); 66 + u8 (*get_in_rep)(u8 current_index, int sensor_idx, int report_id, 67 + struct amd_input_data *in_data); 68 + }; 69 + 70 + void amd_sfh_work(struct work_struct *work); 71 + void amd_sfh_work_buffer(struct work_struct *work); 72 + void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata); 73 + int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata); 74 + void amd_sfh_clear_intr(struct amd_mp2_dev *privdata); 75 + int amd_sfh_irq_init(struct amd_mp2_dev *privdata); 76 + #endif
+8 -4
drivers/hid/amd-sfh-hid/amd_sfh_hid.c
··· 101 101 102 102 void amdtp_hid_wakeup(struct hid_device *hid) 103 103 { 104 - struct amdtp_hid_data *hid_data = hid->driver_data; 105 - struct amdtp_cl_data *cli_data = hid_data->cli_data; 104 + struct amdtp_hid_data *hid_data; 105 + struct amdtp_cl_data *cli_data; 106 106 107 - cli_data->request_done[cli_data->cur_hid_dev] = true; 108 - wake_up_interruptible(&hid_data->hid_wait); 107 + if (hid) { 108 + hid_data = hid->driver_data; 109 + cli_data = hid_data->cli_data; 110 + cli_data->request_done[cli_data->cur_hid_dev] = true; 111 + wake_up_interruptible(&hid_data->hid_wait); 112 + } 109 113 } 110 114 111 115 static struct hid_ll_driver amdtp_hid_ll_driver = {
+10 -2
drivers/hid/amd-sfh-hid/amd_sfh_hid.h
··· 15 15 #define AMD_SFH_HID_VENDOR 0x1022 16 16 #define AMD_SFH_HID_PRODUCT 0x0001 17 17 18 + struct request_list { 19 + struct hid_device *hid; 20 + struct list_head list; 21 + u8 report_id; 22 + u8 sensor_idx; 23 + u8 report_type; 24 + u8 current_index; 25 + }; 26 + 18 27 struct amd_input_data { 19 28 u32 *sensor_virt_addr[MAX_HID_DEVICES]; 20 29 u8 *input_report[MAX_HID_DEVICES]; ··· 52 43 struct amd_input_data *in_data; 53 44 struct delayed_work work; 54 45 struct delayed_work work_buffer; 46 + struct request_list req_list; 55 47 }; 56 48 57 49 /** ··· 79 69 int amd_sfh_get_report(struct hid_device *hid, int report_id, int report_type); 80 70 void amd_sfh_set_report(struct hid_device *hid, int report_id, int report_type); 81 71 void amdtp_hid_wakeup(struct hid_device *hid); 82 - u8 get_input_report(u8 current_index, int sensor_idx, int report_id, 83 - struct amd_input_data *in_data); 84 72 #endif
+28 -50
drivers/hid/amd-sfh-hid/amd_sfh_pcie.c
··· 19 19 #include <linux/slab.h> 20 20 21 21 #include "amd_sfh_pcie.h" 22 + #include "sfh1_1/amd_sfh_init.h" 22 23 23 24 #define DRIVER_NAME "pcie_mp2_amd" 24 25 #define DRIVER_DESC "AMD(R) PCIe MP2 Communication Driver" ··· 93 92 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); 94 93 } 95 94 96 - static void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata) 95 + void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata) 97 96 { 98 97 if (readl(privdata->mmio + AMD_P2C_MSG(4))) { 99 98 writel(0, privdata->mmio + AMD_P2C_MSG(4)); ··· 101 100 } 102 101 } 103 102 104 - static void amd_sfh_clear_intr(struct amd_mp2_dev *privdata) 103 + void amd_sfh_clear_intr(struct amd_mp2_dev *privdata) 105 104 { 106 105 if (privdata->mp2_ops->clear_intr) 107 106 privdata->mp2_ops->clear_intr(privdata); ··· 114 113 return IRQ_HANDLED; 115 114 } 116 115 117 - static int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata) 116 + int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata) 118 117 { 119 118 int rc; 120 119 ··· 137 136 SENSOR_DISCOVERY_STATUS_MASK) >> SENSOR_DISCOVERY_STATUS_SHIFT; 138 137 } 139 138 140 - void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) 139 + static void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) 141 140 { 142 141 union sfh_cmd_param cmd_param; 143 142 union sfh_cmd_base cmd_base; ··· 158 157 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); 159 158 } 160 159 161 - void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx) 160 + static void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx) 162 161 { 163 162 union sfh_cmd_base cmd_base; 164 163 ··· 172 171 writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); 173 172 } 174 173 175 - void amd_stop_all_sensors(struct amd_mp2_dev *privdata) 174 + static void amd_stop_all_sensors(struct amd_mp2_dev *privdata) 176 175 { 177 176 union sfh_cmd_base cmd_base; 178 177 ··· 245 244 amd_sfh_clear_intr(mp2); 246 245 } 247 246 248 - static const struct amd_mp2_ops amd_sfh_ops_v2 = { 247 + static struct amd_mp2_ops amd_sfh_ops_v2 = { 249 248 .start = amd_start_sensor_v2, 250 249 .stop = amd_stop_sensor_v2, 251 250 .stop_all = amd_stop_all_sensor_v2, ··· 253 252 .clear_intr = amd_sfh_clear_intr_v2, 254 253 .init_intr = amd_sfh_irq_init_v2, 255 254 .discovery_status = amd_sfh_dis_sts_v2, 255 + .remove = amd_mp2_pci_remove, 256 256 }; 257 257 258 - static const struct amd_mp2_ops amd_sfh_ops = { 258 + static struct amd_mp2_ops amd_sfh_ops = { 259 259 .start = amd_start_sensor, 260 260 .stop = amd_stop_sensor, 261 261 .stop_all = amd_stop_all_sensors, 262 + .remove = amd_mp2_pci_remove, 262 263 }; 263 264 264 265 static void mp2_select_ops(struct amd_mp2_dev *privdata) ··· 280 277 } 281 278 } 282 279 283 - static int amd_sfh_irq_init(struct amd_mp2_dev *privdata) 280 + int amd_sfh_irq_init(struct amd_mp2_dev *privdata) 284 281 { 285 282 if (privdata->mp2_ops->init_intr) 286 283 return privdata->mp2_ops->init_intr(privdata); ··· 319 316 if (!privdata->cl_data) 320 317 return -ENOMEM; 321 318 319 + privdata->sfh1_1_ops = (const struct amd_sfh1_1_ops *)id->driver_data; 320 + if (privdata->sfh1_1_ops) { 321 + rc = privdata->sfh1_1_ops->init(privdata); 322 + if (rc) 323 + return rc; 324 + goto init_done; 325 + } 326 + 322 327 mp2_select_ops(privdata); 323 328 324 329 rc = amd_sfh_irq_init(privdata); ··· 338 327 rc = amd_sfh_hid_client_init(privdata); 339 328 if (rc) { 340 329 amd_sfh_clear_intr(privdata); 341 - dev_err(&pdev->dev, "amd_sfh_hid_client_init failed\n"); 330 + if (rc != -EOPNOTSUPP) 331 + dev_err(&pdev->dev, "amd_sfh_hid_client_init failed\n"); 342 332 return rc; 343 333 } 344 334 335 + init_done: 345 336 amd_sfh_clear_intr(privdata); 346 337 347 - return devm_add_action_or_reset(&pdev->dev, amd_mp2_pci_remove, privdata); 338 + return devm_add_action_or_reset(&pdev->dev, privdata->mp2_ops->remove, privdata); 348 339 } 349 340 350 341 static int __maybe_unused amd_mp2_pci_resume(struct device *dev) 351 342 { 352 343 struct amd_mp2_dev *mp2 = dev_get_drvdata(dev); 353 - struct amdtp_cl_data *cl_data = mp2->cl_data; 354 - struct amd_mp2_sensor_info info; 355 - int i, status; 356 344 357 - for (i = 0; i < cl_data->num_hid_devices; i++) { 358 - if (cl_data->sensor_sts[i] == SENSOR_DISABLED) { 359 - info.period = AMD_SFH_IDLE_LOOP; 360 - info.sensor_idx = cl_data->sensor_idx[i]; 361 - info.dma_address = cl_data->sensor_dma_addr[i]; 362 - mp2->mp2_ops->start(mp2, info); 363 - status = amd_sfh_wait_for_response 364 - (mp2, cl_data->sensor_idx[i], SENSOR_ENABLED); 365 - if (status == SENSOR_ENABLED) 366 - cl_data->sensor_sts[i] = SENSOR_ENABLED; 367 - dev_dbg(dev, "suspend sid 0x%x (%s) status 0x%x\n", 368 - cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 369 - cl_data->sensor_sts[i]); 370 - } 371 - } 372 - 373 - schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); 374 - amd_sfh_clear_intr(mp2); 345 + mp2->mp2_ops->resume(mp2); 375 346 376 347 return 0; 377 348 } ··· 361 368 static int __maybe_unused amd_mp2_pci_suspend(struct device *dev) 362 369 { 363 370 struct amd_mp2_dev *mp2 = dev_get_drvdata(dev); 364 - struct amdtp_cl_data *cl_data = mp2->cl_data; 365 - int i, status; 366 371 367 - for (i = 0; i < cl_data->num_hid_devices; i++) { 368 - if (cl_data->sensor_idx[i] != HPD_IDX && 369 - cl_data->sensor_sts[i] == SENSOR_ENABLED) { 370 - mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]); 371 - status = amd_sfh_wait_for_response 372 - (mp2, cl_data->sensor_idx[i], SENSOR_DISABLED); 373 - if (status != SENSOR_ENABLED) 374 - cl_data->sensor_sts[i] = SENSOR_DISABLED; 375 - dev_dbg(dev, "suspend sid 0x%x (%s) status 0x%x\n", 376 - cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 377 - cl_data->sensor_sts[i]); 378 - } 379 - } 380 - 381 - cancel_delayed_work_sync(&cl_data->work_buffer); 382 - amd_sfh_clear_intr(mp2); 372 + mp2->mp2_ops->suspend(mp2); 383 373 384 374 return 0; 385 375 } ··· 372 396 373 397 static const struct pci_device_id amd_mp2_pci_tbl[] = { 374 398 { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2) }, 399 + { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_MP2_1_1), 400 + .driver_data = (kernel_ulong_t)&sfh1_1_ops }, 375 401 { } 376 402 }; 377 403 MODULE_DEVICE_TABLE(pci, amd_mp2_pci_tbl);
+2 -48
drivers/hid/amd-sfh-hid/amd_sfh_pcie.h
··· 10 10 #ifndef PCIE_MP2_AMD_H 11 11 #define PCIE_MP2_AMD_H 12 12 13 - #include <linux/pci.h> 14 - #include "amd_sfh_hid.h" 15 - 16 - #define PCI_DEVICE_ID_AMD_MP2 0x15E4 17 - 18 - #define ENABLE_SENSOR 1 19 - #define DISABLE_SENSOR 2 20 - #define STOP_ALL_SENSORS 8 13 + #include "amd_sfh_common.h" 21 14 22 15 /* MP2 C2P Message Registers */ 23 16 #define AMD_C2P_MSG0 0x10500 24 17 #define AMD_C2P_MSG1 0x10504 25 18 #define AMD_C2P_MSG2 0x10508 26 19 27 - #define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4)) 28 - #define AMD_P2C_MSG(regno) (0x10680 + ((regno) * 4)) 29 - 30 20 /* MP2 P2C Message Registers */ 31 21 #define AMD_P2C_MSG3 0x1068C /* Supported Sensors info */ 32 22 33 23 #define V2_STATUS 0x2 34 24 35 - #define SENSOR_ENABLED 4 36 - #define SENSOR_DISABLED 5 37 - 38 25 #define HPD_IDX 16 39 - 40 - #define AMD_SFH_IDLE_LOOP 200 41 26 42 27 #define SENSOR_DISCOVERY_STATUS_MASK GENMASK(5, 3) 43 28 #define SENSOR_DISCOVERY_STATUS_SHIFT 3 ··· 81 96 als_idx = 19 82 97 }; 83 98 84 - struct amd_mp2_dev { 85 - struct pci_dev *pdev; 86 - struct amdtp_cl_data *cl_data; 87 - void __iomem *mmio; 88 - const struct amd_mp2_ops *mp2_ops; 89 - struct amd_input_data in_data; 90 - /* mp2 active control status */ 91 - u32 mp2_acs; 92 - }; 93 - 94 - struct amd_mp2_sensor_info { 95 - u8 sensor_idx; 96 - u32 period; 97 - dma_addr_t dma_address; 98 - }; 99 - 100 99 enum mem_use_type { 101 100 USE_DRAM, 102 101 USE_C2P_REG, ··· 98 129 }; 99 130 }; 100 131 101 - void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info); 102 - void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx); 103 - void amd_stop_all_sensors(struct amd_mp2_dev *privdata); 104 132 int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id); 105 133 int amd_sfh_hid_client_init(struct amd_mp2_dev *privdata); 106 134 int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata); 107 - u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts); 108 - void amd_mp2_suspend(struct amd_mp2_dev *mp2); 109 - void amd_mp2_resume(struct amd_mp2_dev *mp2); 110 - const char *get_sensor_name(int idx); 135 + void amd_sfh_set_desc_ops(struct amd_mp2_ops *mp2_ops); 111 136 112 - struct amd_mp2_ops { 113 - void (*start)(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info); 114 - void (*stop)(struct amd_mp2_dev *privdata, u16 sensor_idx); 115 - void (*stop_all)(struct amd_mp2_dev *privdata); 116 - int (*response)(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts); 117 - void (*clear_intr)(struct amd_mp2_dev *privdata); 118 - int (*init_intr)(struct amd_mp2_dev *privdata); 119 - int (*discovery_status)(struct amd_mp2_dev *privdata); 120 - }; 121 137 #endif
+13 -4
drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.c
··· 29 29 #define HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM 0x04 30 30 #define ILLUMINANCE_MASK GENMASK(14, 0) 31 31 32 - int get_report_descriptor(int sensor_idx, u8 *rep_desc) 32 + static int get_report_descriptor(int sensor_idx, u8 *rep_desc) 33 33 { 34 34 switch (sensor_idx) { 35 35 case accel_idx: /* accel */ ··· 63 63 return 0; 64 64 } 65 65 66 - u32 get_descr_sz(int sensor_idx, int descriptor_name) 66 + static u32 get_descr_sz(int sensor_idx, int descriptor_name) 67 67 { 68 68 switch (sensor_idx) { 69 69 case accel_idx: ··· 133 133 common->report_interval = HID_DEFAULT_REPORT_INTERVAL; 134 134 } 135 135 136 - u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report) 136 + static u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report) 137 137 { 138 138 struct accel3_feature_report acc_feature; 139 139 struct gyro_feature_report gyro_feature; ··· 200 200 common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM; 201 201 } 202 202 203 - u8 get_input_report(u8 current_index, int sensor_idx, int report_id, struct amd_input_data *in_data) 203 + static u8 get_input_report(u8 current_index, int sensor_idx, int report_id, 204 + struct amd_input_data *in_data) 204 205 { 205 206 struct amd_mp2_dev *privdata = container_of(in_data, struct amd_mp2_dev, in_data); 206 207 u32 *sensor_virt_addr = in_data->sensor_virt_addr[current_index]; ··· 267 266 break; 268 267 } 269 268 return report_size; 269 + } 270 + 271 + void amd_sfh_set_desc_ops(struct amd_mp2_ops *mp2_ops) 272 + { 273 + mp2_ops->get_rep_desc = get_report_descriptor; 274 + mp2_ops->get_feat_rep = get_feature_report; 275 + mp2_ops->get_in_rep = get_input_report; 276 + mp2_ops->get_desc_sz = get_descr_sz; 270 277 }
-3
drivers/hid/amd-sfh-hid/hid_descriptor/amd_sfh_hid_desc.h
··· 111 111 u8 human_presence; 112 112 } __packed; 113 113 114 - int get_report_descriptor(int sensor_idx, u8 rep_desc[]); 115 - u32 get_descr_sz(int sensor_idx, int descriptor_name); 116 - u8 get_feature_report(int sensor_idx, int report_id, u8 *feature_report); 117 114 #endif
+300
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_desc.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * AMD MP2 1.1 descriptor interfaces 4 + * 5 + * Copyright (c) 2022, Advanced Micro Devices, Inc. 6 + * All Rights Reserved. 7 + * 8 + * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com> 9 + */ 10 + 11 + #include <linux/hid-sensor-ids.h> 12 + 13 + #include "amd_sfh_interface.h" 14 + #include "../hid_descriptor/amd_sfh_hid_desc.h" 15 + #include "../hid_descriptor/amd_sfh_hid_report_desc.h" 16 + 17 + #define SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM 0x41 18 + #define 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 + static int get_report_desc(int sensor_idx, u8 *rep_desc) 30 + { 31 + switch (sensor_idx) { 32 + case ACCEL_IDX: /* accelerometer */ 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: /* gyroscope */ 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 + case HPD_IDX: /* HPD sensor */ 53 + memset(rep_desc, 0, sizeof(hpd_report_descriptor)); 54 + memcpy(rep_desc, hpd_report_descriptor, 55 + sizeof(hpd_report_descriptor)); 56 + break; 57 + } 58 + return 0; 59 + } 60 + 61 + static void get_common_features(struct common_feature_property *common, int report_id) 62 + { 63 + common->report_id = report_id; 64 + common->connection_type = HID_USAGE_SENSOR_PROPERTY_CONNECTION_TYPE_PC_INTEGRATED_ENUM; 65 + common->report_state = SENSOR_PROP_REPORTING_STATE_ALL_EVENTS_ENUM; 66 + common->power_state = SENSOR_PROP_POWER_STATE_D0_FULL_POWER_ENUM; 67 + common->sensor_state = HID_USAGE_SENSOR_STATE_INITIALIZING_ENUM; 68 + common->report_interval = HID_DEFAULT_REPORT_INTERVAL; 69 + } 70 + 71 + static u8 get_feature_rep(int sensor_idx, int report_id, u8 *feature_report) 72 + { 73 + struct magno_feature_report magno_feature; 74 + struct accel3_feature_report acc_feature; 75 + struct gyro_feature_report gyro_feature; 76 + struct hpd_feature_report hpd_feature; 77 + struct als_feature_report als_feature; 78 + u8 report_size = 0; 79 + 80 + if (!feature_report) 81 + return report_size; 82 + 83 + switch (sensor_idx) { 84 + case ACCEL_IDX: /* accelerometer */ 85 + get_common_features(&acc_feature.common_property, report_id); 86 + acc_feature.accel_change_sesnitivity = HID_DEFAULT_SENSITIVITY; 87 + acc_feature.accel_sensitivity_min = HID_DEFAULT_MIN_VALUE; 88 + acc_feature.accel_sensitivity_max = HID_DEFAULT_MAX_VALUE; 89 + memcpy(feature_report, &acc_feature, sizeof(acc_feature)); 90 + report_size = sizeof(acc_feature); 91 + break; 92 + case GYRO_IDX: /* gyroscope */ 93 + get_common_features(&gyro_feature.common_property, report_id); 94 + gyro_feature.gyro_change_sesnitivity = HID_DEFAULT_SENSITIVITY; 95 + gyro_feature.gyro_sensitivity_min = HID_DEFAULT_MIN_VALUE; 96 + gyro_feature.gyro_sensitivity_max = HID_DEFAULT_MAX_VALUE; 97 + memcpy(feature_report, &gyro_feature, sizeof(gyro_feature)); 98 + report_size = sizeof(gyro_feature); 99 + break; 100 + case MAG_IDX: /* magnetometer */ 101 + get_common_features(&magno_feature.common_property, report_id); 102 + magno_feature.magno_headingchange_sensitivity = HID_DEFAULT_SENSITIVITY; 103 + magno_feature.heading_min = HID_DEFAULT_MIN_VALUE; 104 + magno_feature.heading_max = HID_DEFAULT_MAX_VALUE; 105 + magno_feature.flux_change_sensitivity = HID_DEFAULT_MIN_VALUE; 106 + magno_feature.flux_min = HID_DEFAULT_MIN_VALUE; 107 + magno_feature.flux_max = HID_DEFAULT_MAX_VALUE; 108 + memcpy(feature_report, &magno_feature, sizeof(magno_feature)); 109 + report_size = sizeof(magno_feature); 110 + break; 111 + case ALS_IDX: /* ambient light sensor */ 112 + get_common_features(&als_feature.common_property, report_id); 113 + als_feature.als_change_sesnitivity = HID_DEFAULT_SENSITIVITY; 114 + als_feature.als_sensitivity_min = HID_DEFAULT_MIN_VALUE; 115 + als_feature.als_sensitivity_max = HID_DEFAULT_MAX_VALUE; 116 + memcpy(feature_report, &als_feature, sizeof(als_feature)); 117 + report_size = sizeof(als_feature); 118 + break; 119 + case HPD_IDX: /* human presence detection sensor */ 120 + get_common_features(&hpd_feature.common_property, report_id); 121 + memcpy(feature_report, &hpd_feature, sizeof(hpd_feature)); 122 + report_size = sizeof(hpd_feature); 123 + break; 124 + } 125 + return report_size; 126 + } 127 + 128 + static void get_common_inputs(struct common_input_property *common, int report_id) 129 + { 130 + common->report_id = report_id; 131 + common->sensor_state = HID_USAGE_SENSOR_STATE_READY_ENUM; 132 + common->event_type = HID_USAGE_SENSOR_EVENT_DATA_UPDATED_ENUM; 133 + } 134 + 135 + static int float_to_int(u32 float32) 136 + { 137 + int fraction, shift, mantissa, sign, exp, zeropre; 138 + 139 + mantissa = float32 & GENMASK(22, 0); 140 + sign = (float32 & BIT(31)) ? -1 : 1; 141 + exp = (float32 & ~BIT(31)) >> 23; 142 + 143 + if (!exp && !mantissa) 144 + return 0; 145 + 146 + exp -= 127; 147 + if (exp < 0) { 148 + exp = -exp; 149 + zeropre = (((BIT(23) + mantissa) * 100) >> 23) >> exp; 150 + return zeropre >= 50 ? sign : 0; 151 + } 152 + 153 + shift = 23 - exp; 154 + float32 = BIT(exp) + (mantissa >> shift); 155 + fraction = mantissa & GENMASK(shift - 1, 0); 156 + 157 + return (((fraction * 100) >> shift) >= 50) ? sign * (float32 + 1) : sign * float32; 158 + } 159 + 160 + static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id, 161 + struct amd_input_data *in_data) 162 + { 163 + struct amd_mp2_dev *mp2 = container_of(in_data, struct amd_mp2_dev, in_data); 164 + u8 *input_report = in_data->input_report[current_index]; 165 + struct magno_input_report magno_input; 166 + struct accel3_input_report acc_input; 167 + struct gyro_input_report gyro_input; 168 + struct als_input_report als_input; 169 + struct hpd_input_report hpd_input; 170 + struct sfh_accel_data accel_data; 171 + struct sfh_gyro_data gyro_data; 172 + struct sfh_mag_data mag_data; 173 + struct sfh_als_data als_data; 174 + struct hpd_status hpdstatus; 175 + void __iomem *sensoraddr; 176 + u8 report_size = 0; 177 + 178 + if (!input_report) 179 + return report_size; 180 + 181 + switch (sensor_idx) { 182 + case ACCEL_IDX: /* accelerometer */ 183 + sensoraddr = mp2->vsbase + (ACCEL_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) + 184 + OFFSET_SENSOR_DATA_DEFAULT; 185 + memcpy_fromio(&accel_data, sensoraddr, sizeof(struct sfh_accel_data)); 186 + get_common_inputs(&acc_input.common_property, report_id); 187 + acc_input.in_accel_x_value = float_to_int(accel_data.acceldata.x) / 100; 188 + acc_input.in_accel_y_value = float_to_int(accel_data.acceldata.y) / 100; 189 + acc_input.in_accel_z_value = float_to_int(accel_data.acceldata.z) / 100; 190 + memcpy(input_report, &acc_input, sizeof(acc_input)); 191 + report_size = sizeof(acc_input); 192 + break; 193 + case GYRO_IDX: /* gyroscope */ 194 + sensoraddr = mp2->vsbase + (GYRO_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) + 195 + OFFSET_SENSOR_DATA_DEFAULT; 196 + memcpy_fromio(&gyro_data, sensoraddr, sizeof(struct sfh_gyro_data)); 197 + get_common_inputs(&gyro_input.common_property, report_id); 198 + gyro_input.in_angel_x_value = float_to_int(gyro_data.gyrodata.x) / 1000; 199 + gyro_input.in_angel_y_value = float_to_int(gyro_data.gyrodata.y) / 1000; 200 + gyro_input.in_angel_z_value = float_to_int(gyro_data.gyrodata.z) / 1000; 201 + memcpy(input_report, &gyro_input, sizeof(gyro_input)); 202 + report_size = sizeof(gyro_input); 203 + break; 204 + case MAG_IDX: /* magnetometer */ 205 + sensoraddr = mp2->vsbase + (MAG_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) + 206 + OFFSET_SENSOR_DATA_DEFAULT; 207 + memcpy_fromio(&mag_data, sensoraddr, sizeof(struct sfh_mag_data)); 208 + get_common_inputs(&magno_input.common_property, report_id); 209 + magno_input.in_magno_x = float_to_int(mag_data.magdata.x) / 100; 210 + magno_input.in_magno_y = float_to_int(mag_data.magdata.y) / 100; 211 + magno_input.in_magno_z = float_to_int(mag_data.magdata.z) / 100; 212 + magno_input.in_magno_accuracy = mag_data.accuracy / 100; 213 + memcpy(input_report, &magno_input, sizeof(magno_input)); 214 + report_size = sizeof(magno_input); 215 + break; 216 + case ALS_IDX: 217 + sensoraddr = mp2->vsbase + (ALS_IDX * SENSOR_DATA_MEM_SIZE_DEFAULT) + 218 + OFFSET_SENSOR_DATA_DEFAULT; 219 + memcpy_fromio(&als_data, sensoraddr, sizeof(struct sfh_als_data)); 220 + get_common_inputs(&als_input.common_property, report_id); 221 + als_input.illuminance_value = als_data.lux; 222 + report_size = sizeof(als_input); 223 + memcpy(input_report, &als_input, sizeof(als_input)); 224 + break; 225 + case HPD_IDX: 226 + get_common_inputs(&hpd_input.common_property, report_id); 227 + hpdstatus.val = readl(mp2->mmio + AMD_C2P_MSG(4)); 228 + hpd_input.human_presence = hpdstatus.shpd.presence; 229 + report_size = sizeof(hpd_input); 230 + memcpy(input_report, &hpd_input, sizeof(hpd_input)); 231 + break; 232 + } 233 + return report_size; 234 + } 235 + 236 + static u32 get_desc_size(int sensor_idx, int descriptor_name) 237 + { 238 + switch (sensor_idx) { 239 + case ACCEL_IDX: 240 + switch (descriptor_name) { 241 + case descr_size: 242 + return sizeof(accel3_report_descriptor); 243 + case input_size: 244 + return sizeof(struct accel3_input_report); 245 + case feature_size: 246 + return sizeof(struct accel3_feature_report); 247 + } 248 + break; 249 + case GYRO_IDX: 250 + switch (descriptor_name) { 251 + case descr_size: 252 + return sizeof(gyro3_report_descriptor); 253 + case input_size: 254 + return sizeof(struct gyro_input_report); 255 + case feature_size: 256 + return sizeof(struct gyro_feature_report); 257 + } 258 + break; 259 + case MAG_IDX: 260 + switch (descriptor_name) { 261 + case descr_size: 262 + return sizeof(comp3_report_descriptor); 263 + case input_size: 264 + return sizeof(struct magno_input_report); 265 + case feature_size: 266 + return sizeof(struct magno_feature_report); 267 + } 268 + break; 269 + case ALS_IDX: 270 + switch (descriptor_name) { 271 + case descr_size: 272 + return sizeof(als_report_descriptor); 273 + case input_size: 274 + return sizeof(struct als_input_report); 275 + case feature_size: 276 + return sizeof(struct als_feature_report); 277 + } 278 + break; 279 + case HPD_IDX: 280 + switch (descriptor_name) { 281 + case descr_size: 282 + return sizeof(hpd_report_descriptor); 283 + case input_size: 284 + return sizeof(struct hpd_input_report); 285 + case feature_size: 286 + return sizeof(struct hpd_feature_report); 287 + } 288 + break; 289 + } 290 + 291 + return 0; 292 + } 293 + 294 + void amd_sfh1_1_set_desc_ops(struct amd_mp2_ops *mp2_ops) 295 + { 296 + mp2_ops->get_rep_desc = get_report_desc; 297 + mp2_ops->get_feat_rep = get_feature_rep; 298 + mp2_ops->get_desc_sz = get_desc_size; 299 + mp2_ops->get_in_rep = get_input_rep; 300 + }
+324
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * AMD MP2 1.1 communication driver 4 + * 5 + * Copyright (c) 2022, Advanced Micro Devices, Inc. 6 + * All Rights Reserved. 7 + * 8 + * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com> 9 + */ 10 + 11 + #include <linux/delay.h> 12 + #include <linux/hid.h> 13 + 14 + #include "amd_sfh_init.h" 15 + #include "amd_sfh_interface.h" 16 + #include "../hid_descriptor/amd_sfh_hid_desc.h" 17 + 18 + static int amd_sfh_get_sensor_num(struct amd_mp2_dev *mp2, u8 *sensor_id) 19 + { 20 + struct sfh_sensor_list *slist; 21 + struct sfh_base_info binfo; 22 + int num_of_sensors = 0; 23 + int i; 24 + 25 + memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info)); 26 + slist = &binfo.sbase.s_list; 27 + 28 + for (i = 0; i < MAX_IDX; i++) { 29 + switch (i) { 30 + case ACCEL_IDX: 31 + case GYRO_IDX: 32 + case MAG_IDX: 33 + case ALS_IDX: 34 + case HPD_IDX: 35 + if (BIT(i) & slist->sl.sensors) 36 + sensor_id[num_of_sensors++] = i; 37 + break; 38 + } 39 + } 40 + 41 + return num_of_sensors; 42 + } 43 + 44 + static u32 amd_sfh_wait_for_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id) 45 + { 46 + if (mp2->mp2_ops->response) 47 + return mp2->mp2_ops->response(mp2, sid, cmd_id); 48 + 49 + return 0; 50 + } 51 + 52 + static const char *get_sensor_name(int idx) 53 + { 54 + switch (idx) { 55 + case ACCEL_IDX: 56 + return "accelerometer"; 57 + case GYRO_IDX: 58 + return "gyroscope"; 59 + case MAG_IDX: 60 + return "magnetometer"; 61 + case ALS_IDX: 62 + return "ALS"; 63 + case HPD_IDX: 64 + return "HPD"; 65 + default: 66 + return "unknown sensor type"; 67 + } 68 + } 69 + 70 + static int amd_sfh_hid_client_deinit(struct amd_mp2_dev *privdata) 71 + { 72 + struct amdtp_cl_data *cl_data = privdata->cl_data; 73 + int i, status; 74 + 75 + for (i = 0; i < cl_data->num_hid_devices; i++) { 76 + if (cl_data->sensor_sts[i] == SENSOR_ENABLED) { 77 + privdata->mp2_ops->stop(privdata, cl_data->sensor_idx[i]); 78 + status = amd_sfh_wait_for_response 79 + (privdata, cl_data->sensor_idx[i], DISABLE_SENSOR); 80 + if (status == 0) 81 + cl_data->sensor_sts[i] = SENSOR_DISABLED; 82 + dev_dbg(&privdata->pdev->dev, "stopping sid 0x%x (%s) status 0x%x\n", 83 + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 84 + cl_data->sensor_sts[i]); 85 + } 86 + } 87 + 88 + cancel_delayed_work_sync(&cl_data->work); 89 + cancel_delayed_work_sync(&cl_data->work_buffer); 90 + amdtp_hid_remove(cl_data); 91 + 92 + return 0; 93 + } 94 + 95 + static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata) 96 + { 97 + struct amd_input_data *in_data = &privdata->in_data; 98 + struct amdtp_cl_data *cl_data = privdata->cl_data; 99 + struct amd_mp2_ops *mp2_ops = privdata->mp2_ops; 100 + struct amd_mp2_sensor_info info; 101 + struct request_list *req_list; 102 + u32 feature_report_size; 103 + u32 input_report_size; 104 + struct device *dev; 105 + int rc, i, status; 106 + u8 cl_idx; 107 + 108 + req_list = &cl_data->req_list; 109 + dev = &privdata->pdev->dev; 110 + amd_sfh1_1_set_desc_ops(mp2_ops); 111 + 112 + cl_data->num_hid_devices = amd_sfh_get_sensor_num(privdata, &cl_data->sensor_idx[0]); 113 + 114 + INIT_DELAYED_WORK(&cl_data->work, amd_sfh_work); 115 + INIT_DELAYED_WORK(&cl_data->work_buffer, amd_sfh_work_buffer); 116 + INIT_LIST_HEAD(&req_list->list); 117 + cl_data->in_data = in_data; 118 + 119 + for (i = 0; i < cl_data->num_hid_devices; i++) { 120 + cl_data->sensor_sts[i] = SENSOR_DISABLED; 121 + cl_data->sensor_requested_cnt[i] = 0; 122 + cl_data->cur_hid_dev = i; 123 + cl_idx = cl_data->sensor_idx[i]; 124 + 125 + cl_data->report_descr_sz[i] = mp2_ops->get_desc_sz(cl_idx, descr_size); 126 + if (!cl_data->report_descr_sz[i]) { 127 + rc = -EINVAL; 128 + goto cleanup; 129 + } 130 + feature_report_size = mp2_ops->get_desc_sz(cl_idx, feature_size); 131 + if (!feature_report_size) { 132 + rc = -EINVAL; 133 + goto cleanup; 134 + } 135 + input_report_size = mp2_ops->get_desc_sz(cl_idx, input_size); 136 + if (!input_report_size) { 137 + rc = -EINVAL; 138 + goto cleanup; 139 + } 140 + cl_data->feature_report[i] = devm_kzalloc(dev, feature_report_size, GFP_KERNEL); 141 + if (!cl_data->feature_report[i]) { 142 + rc = -ENOMEM; 143 + goto cleanup; 144 + } 145 + in_data->input_report[i] = devm_kzalloc(dev, input_report_size, GFP_KERNEL); 146 + if (!in_data->input_report[i]) { 147 + rc = -ENOMEM; 148 + goto cleanup; 149 + } 150 + 151 + info.sensor_idx = cl_idx; 152 + 153 + cl_data->report_descr[i] = 154 + devm_kzalloc(dev, cl_data->report_descr_sz[i], GFP_KERNEL); 155 + if (!cl_data->report_descr[i]) { 156 + rc = -ENOMEM; 157 + goto cleanup; 158 + } 159 + rc = mp2_ops->get_rep_desc(cl_idx, cl_data->report_descr[i]); 160 + if (rc) 161 + return rc; 162 + 163 + writel(0, privdata->mmio + AMD_P2C_MSG(0)); 164 + mp2_ops->start(privdata, info); 165 + status = amd_sfh_wait_for_response 166 + (privdata, cl_data->sensor_idx[i], ENABLE_SENSOR); 167 + 168 + status = (status == 0) ? SENSOR_ENABLED : SENSOR_DISABLED; 169 + 170 + if (status == SENSOR_ENABLED) { 171 + cl_data->sensor_sts[i] = SENSOR_ENABLED; 172 + rc = amdtp_hid_probe(i, cl_data); 173 + if (rc) { 174 + mp2_ops->stop(privdata, cl_data->sensor_idx[i]); 175 + status = amd_sfh_wait_for_response 176 + (privdata, cl_data->sensor_idx[i], DISABLE_SENSOR); 177 + if (status == 0) 178 + status = SENSOR_DISABLED; 179 + if (status != SENSOR_ENABLED) 180 + cl_data->sensor_sts[i] = SENSOR_DISABLED; 181 + dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n", 182 + cl_data->sensor_idx[i], 183 + get_sensor_name(cl_data->sensor_idx[i]), 184 + cl_data->sensor_sts[i]); 185 + goto cleanup; 186 + } 187 + } 188 + dev_dbg(dev, "sid 0x%x (%s) status 0x%x\n", 189 + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 190 + cl_data->sensor_sts[i]); 191 + } 192 + 193 + schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); 194 + return 0; 195 + 196 + cleanup: 197 + amd_sfh_hid_client_deinit(privdata); 198 + for (i = 0; i < cl_data->num_hid_devices; i++) { 199 + devm_kfree(dev, cl_data->feature_report[i]); 200 + devm_kfree(dev, in_data->input_report[i]); 201 + devm_kfree(dev, cl_data->report_descr[i]); 202 + } 203 + return rc; 204 + } 205 + 206 + static void amd_sfh_resume(struct amd_mp2_dev *mp2) 207 + { 208 + struct amdtp_cl_data *cl_data = mp2->cl_data; 209 + struct amd_mp2_sensor_info info; 210 + int i, status; 211 + 212 + for (i = 0; i < cl_data->num_hid_devices; i++) { 213 + if (cl_data->sensor_sts[i] == SENSOR_DISABLED) { 214 + info.sensor_idx = cl_data->sensor_idx[i]; 215 + mp2->mp2_ops->start(mp2, info); 216 + status = amd_sfh_wait_for_response 217 + (mp2, cl_data->sensor_idx[i], ENABLE_SENSOR); 218 + if (status == 0) 219 + status = SENSOR_ENABLED; 220 + if (status == SENSOR_ENABLED) 221 + cl_data->sensor_sts[i] = SENSOR_ENABLED; 222 + dev_dbg(&mp2->pdev->dev, "resume sid 0x%x (%s) status 0x%x\n", 223 + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 224 + cl_data->sensor_sts[i]); 225 + } 226 + } 227 + 228 + schedule_delayed_work(&cl_data->work_buffer, msecs_to_jiffies(AMD_SFH_IDLE_LOOP)); 229 + amd_sfh_clear_intr(mp2); 230 + } 231 + 232 + static void amd_sfh_suspend(struct amd_mp2_dev *mp2) 233 + { 234 + struct amdtp_cl_data *cl_data = mp2->cl_data; 235 + int i, status; 236 + 237 + for (i = 0; i < cl_data->num_hid_devices; i++) { 238 + if (cl_data->sensor_idx[i] != HPD_IDX && 239 + cl_data->sensor_sts[i] == SENSOR_ENABLED) { 240 + mp2->mp2_ops->stop(mp2, cl_data->sensor_idx[i]); 241 + status = amd_sfh_wait_for_response 242 + (mp2, cl_data->sensor_idx[i], DISABLE_SENSOR); 243 + if (status == 0) 244 + status = SENSOR_DISABLED; 245 + if (status != SENSOR_ENABLED) 246 + cl_data->sensor_sts[i] = SENSOR_DISABLED; 247 + dev_dbg(&mp2->pdev->dev, "suspend sid 0x%x (%s) status 0x%x\n", 248 + cl_data->sensor_idx[i], get_sensor_name(cl_data->sensor_idx[i]), 249 + cl_data->sensor_sts[i]); 250 + } 251 + } 252 + 253 + cancel_delayed_work_sync(&cl_data->work_buffer); 254 + amd_sfh_clear_intr(mp2); 255 + } 256 + 257 + static void amd_mp2_pci_remove(void *privdata) 258 + { 259 + struct amd_mp2_dev *mp2 = privdata; 260 + 261 + amd_sfh_hid_client_deinit(privdata); 262 + mp2->mp2_ops->stop_all(mp2); 263 + pci_intx(mp2->pdev, false); 264 + amd_sfh_clear_intr(mp2); 265 + } 266 + 267 + static void amd_sfh_set_ops(struct amd_mp2_dev *mp2) 268 + { 269 + struct amd_mp2_ops *mp2_ops; 270 + 271 + sfh_interface_init(mp2); 272 + mp2_ops = mp2->mp2_ops; 273 + mp2_ops->clear_intr = amd_sfh_clear_intr_v2, 274 + mp2_ops->init_intr = amd_sfh_irq_init_v2, 275 + mp2_ops->suspend = amd_sfh_suspend; 276 + mp2_ops->resume = amd_sfh_resume; 277 + mp2_ops->remove = amd_mp2_pci_remove; 278 + } 279 + 280 + int amd_sfh1_1_init(struct amd_mp2_dev *mp2) 281 + { 282 + u32 phy_base = readl(mp2->mmio + AMD_C2P_MSG(22)); 283 + struct device *dev = &mp2->pdev->dev; 284 + struct sfh_base_info binfo; 285 + int rc; 286 + 287 + phy_base <<= 21; 288 + if (!devm_request_mem_region(dev, phy_base, 128 * 1024, "amd_sfh")) { 289 + dev_err(dev, "can't reserve mmio registers\n"); 290 + return -ENOMEM; 291 + } 292 + 293 + mp2->vsbase = devm_ioremap(dev, phy_base, 128 * 1024); 294 + if (!mp2->vsbase) { 295 + dev_err(dev, "failed to remap vsbase\n"); 296 + return -ENOMEM; 297 + } 298 + 299 + /* Before accessing give time for SFH firmware for processing configuration */ 300 + msleep(5000); 301 + 302 + memcpy_fromio(&binfo, mp2->vsbase, sizeof(struct sfh_base_info)); 303 + if (binfo.sbase.fw_info.fw_ver == 0 || binfo.sbase.s_list.sl.sensors == 0) { 304 + dev_err(dev, "failed to get sensors\n"); 305 + return -EOPNOTSUPP; 306 + } 307 + dev_dbg(dev, "firmware version 0x%x\n", binfo.sbase.fw_info.fw_ver); 308 + 309 + amd_sfh_set_ops(mp2); 310 + 311 + rc = amd_sfh_irq_init(mp2); 312 + if (rc) { 313 + dev_err(dev, "amd_sfh_irq_init failed\n"); 314 + return rc; 315 + } 316 + 317 + rc = amd_sfh1_1_hid_client_init(mp2); 318 + if (rc) { 319 + dev_err(dev, "amd_sfh1_1_hid_client_init failed\n"); 320 + return rc; 321 + } 322 + 323 + return rc; 324 + }
+26
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_init.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * AMD MP2 1.1 initialization structures 4 + * 5 + * Copyright (c) 2022, Advanced Micro Devices, Inc. 6 + * All Rights Reserved. 7 + * 8 + * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com> 9 + */ 10 + 11 + #ifndef AMD_SFH_INIT_H 12 + #define AMD_SFH_INIT_H 13 + 14 + #include "../amd_sfh_common.h" 15 + 16 + struct amd_sfh1_1_ops { 17 + int (*init)(struct amd_mp2_dev *mp2); 18 + }; 19 + 20 + int amd_sfh1_1_init(struct amd_mp2_dev *mp2); 21 + 22 + static const struct amd_sfh1_1_ops __maybe_unused sfh1_1_ops = { 23 + .init = amd_sfh1_1_init, 24 + }; 25 + 26 + #endif
+75
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-or-later 2 + /* 3 + * AMD MP2 1.1 communication interfaces 4 + * 5 + * Copyright (c) 2022, Advanced Micro Devices, Inc. 6 + * All Rights Reserved. 7 + * 8 + * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com> 9 + */ 10 + #include <linux/io-64-nonatomic-lo-hi.h> 11 + #include <linux/iopoll.h> 12 + 13 + #include "amd_sfh_interface.h" 14 + 15 + static int amd_sfh_wait_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id) 16 + { 17 + struct sfh_cmd_response cmd_resp; 18 + 19 + /* Get response with status within a max of 1600 ms timeout */ 20 + if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG(0), cmd_resp.resp, 21 + (cmd_resp.response.response == 0 && 22 + cmd_resp.response.cmd_id == cmd_id && (sid == 0xff || 23 + cmd_resp.response.sensor_id == sid)), 500, 1600000)) 24 + return cmd_resp.response.response; 25 + 26 + return -1; 27 + } 28 + 29 + static void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) 30 + { 31 + struct sfh_cmd_base cmd_base; 32 + 33 + cmd_base.ul = 0; 34 + cmd_base.cmd.cmd_id = ENABLE_SENSOR; 35 + cmd_base.cmd.intr_disable = 0; 36 + cmd_base.cmd.sensor_id = info.sensor_idx; 37 + 38 + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG(0)); 39 + } 40 + 41 + static void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx) 42 + { 43 + struct sfh_cmd_base cmd_base; 44 + 45 + cmd_base.ul = 0; 46 + cmd_base.cmd.cmd_id = DISABLE_SENSOR; 47 + cmd_base.cmd.intr_disable = 0; 48 + cmd_base.cmd.sensor_id = sensor_idx; 49 + 50 + writeq(0x0, privdata->mmio + AMD_C2P_MSG(1)); 51 + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG(0)); 52 + } 53 + 54 + static void amd_stop_all_sensor(struct amd_mp2_dev *privdata) 55 + { 56 + struct sfh_cmd_base cmd_base; 57 + 58 + cmd_base.ul = 0; 59 + cmd_base.cmd.cmd_id = STOP_ALL_SENSORS; 60 + cmd_base.cmd.intr_disable = 0; 61 + 62 + writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG(0)); 63 + } 64 + 65 + static struct amd_mp2_ops amd_sfh_ops = { 66 + .start = amd_start_sensor, 67 + .stop = amd_stop_sensor, 68 + .stop_all = amd_stop_all_sensor, 69 + .response = amd_sfh_wait_response, 70 + }; 71 + 72 + void sfh_interface_init(struct amd_mp2_dev *mp2) 73 + { 74 + mp2->mp2_ops = &amd_sfh_ops; 75 + }
+154
drivers/hid/amd-sfh-hid/sfh1_1/amd_sfh_interface.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-or-later */ 2 + /* 3 + * AMD MP2 1.1 communication interfaces 4 + * 5 + * Copyright (c) 2022, Advanced Micro Devices, Inc. 6 + * All Rights Reserved. 7 + * 8 + * Author: Basavaraj Natikar <Basavaraj.Natikar@amd.com> 9 + */ 10 + 11 + #ifndef AMD_SFH_INTERFACE_H 12 + #define AMD_SFH_INTERFACE_H 13 + 14 + #include "../amd_sfh_common.h" 15 + 16 + #define SENSOR_DATA_MEM_SIZE_DEFAULT 256 17 + #define TOTAL_STATIC_MEM_DEFAULT 1024 18 + #define OFFSET_SFH_INFO_BASE_DEFAULT 0 19 + #define OFFSET_SENSOR_DATA_DEFAULT (OFFSET_SFH_INFO_BASE_DEFAULT + \ 20 + TOTAL_STATIC_MEM_DEFAULT) 21 + enum sensor_index { 22 + ACCEL_IDX, 23 + GYRO_IDX, 24 + MAG_IDX, 25 + ALS_IDX = 4, 26 + HPD_IDX = 5, 27 + MAX_IDX = 15, 28 + }; 29 + 30 + struct sfh_cmd_base { 31 + union { 32 + u32 ul; 33 + struct { 34 + u32 sensor_id : 4; 35 + u32 cmd_id : 4; 36 + u32 sub_cmd_id : 6; 37 + u32 length : 12; 38 + u32 rsvd : 5; 39 + u32 intr_disable : 1; 40 + } cmd; 41 + }; 42 + }; 43 + 44 + struct sfh_cmd_response { 45 + union { 46 + u32 resp; 47 + struct { 48 + u32 response : 8; 49 + u32 sensor_id : 4; 50 + u32 cmd_id : 4; 51 + u32 sub_cmd : 6; 52 + u32 rsvd2 : 10; 53 + } response; 54 + }; 55 + }; 56 + 57 + struct sfh_platform_info { 58 + union { 59 + u32 pi; 60 + struct { 61 + u32 cust_id : 16; 62 + u32 plat_id : 6; 63 + u32 interface_id : 4; 64 + u32 rsvd : 6; 65 + } pinfo; 66 + }; 67 + }; 68 + 69 + struct sfh_firmware_info { 70 + union { 71 + u32 fw_ver; 72 + struct { 73 + u32 minor_rev : 8; 74 + u32 major_rev : 8; 75 + u32 minor_ver : 8; 76 + u32 major_ver : 8; 77 + } fver; 78 + }; 79 + }; 80 + 81 + struct sfh_sensor_list { 82 + union { 83 + u32 slist; 84 + struct { 85 + u32 sensors : 16; 86 + u32 rsvd : 16; 87 + } sl; 88 + }; 89 + }; 90 + 91 + struct sfh_base_info { 92 + union { 93 + u32 sfh_base[24]; 94 + struct { 95 + struct sfh_platform_info plat_info; 96 + struct sfh_firmware_info fw_info; 97 + struct sfh_sensor_list s_list; 98 + } sbase; 99 + }; 100 + }; 101 + 102 + struct sfh_common_data { 103 + u64 timestamp; 104 + u32 intr_cnt; 105 + u32 featvalid : 16; 106 + u32 rsvd : 13; 107 + u32 sensor_state : 3; 108 + }; 109 + 110 + struct sfh_float32 { 111 + u32 x; 112 + u32 y; 113 + u32 z; 114 + }; 115 + 116 + struct sfh_accel_data { 117 + struct sfh_common_data commondata; 118 + struct sfh_float32 acceldata; 119 + u32 accelstatus; 120 + }; 121 + 122 + struct sfh_gyro_data { 123 + struct sfh_common_data commondata; 124 + struct sfh_float32 gyrodata; 125 + u32 result; 126 + }; 127 + 128 + struct sfh_mag_data { 129 + struct sfh_common_data commondata; 130 + struct sfh_float32 magdata; 131 + u32 accuracy; 132 + }; 133 + 134 + struct sfh_als_data { 135 + struct sfh_common_data commondata; 136 + u16 lux; 137 + }; 138 + 139 + struct hpd_status { 140 + union { 141 + struct { 142 + u32 distance : 16; 143 + u32 probablity : 8; 144 + u32 presence : 2; 145 + u32 rsvd : 5; 146 + u32 state : 1; 147 + } shpd; 148 + u32 val; 149 + }; 150 + }; 151 + 152 + void sfh_interface_init(struct amd_mp2_dev *mp2); 153 + void amd_sfh1_1_set_desc_ops(struct amd_mp2_ops *mp2_ops); 154 + #endif
+2
drivers/hid/hid-alps.c
··· 831 831 { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, 832 832 USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1) }, 833 833 { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, 834 + USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_UNICORN_LEGACY) }, 835 + { HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY, 834 836 USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_T4_BTNLESS) }, 835 837 { } 836 838 };
+30 -5
drivers/hid/hid-apple.c
··· 36 36 #define APPLE_NUMLOCK_EMULATION BIT(8) 37 37 #define APPLE_RDESC_BATTERY BIT(9) 38 38 #define APPLE_BACKLIGHT_CTL BIT(10) 39 - #define APPLE_IS_KEYCHRON BIT(11) 39 + #define APPLE_IS_NON_APPLE BIT(11) 40 40 41 41 #define APPLE_FLAG_FKEY 0x01 42 42 ··· 64 64 MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. " 65 65 "(For people who want to keep PC keyboard muscle memory. " 66 66 "[0] = as-is, Mac layout, 1 = swapped, PC layout)"); 67 + 68 + struct apple_non_apple_keyboard { 69 + char *name; 70 + }; 67 71 68 72 struct apple_sc_backlight { 69 73 struct led_classdev cdev; ··· 317 313 { } 318 314 }; 319 315 316 + static const struct apple_non_apple_keyboard non_apple_keyboards[] = { 317 + { "SONiX USB DEVICE" }, 318 + { "Keychron" }, 319 + { "AONE" }, 320 + { "GANSS" } 321 + }; 322 + 323 + static bool apple_is_non_apple_keyboard(struct hid_device *hdev) 324 + { 325 + int i; 326 + 327 + for (i = 0; i < ARRAY_SIZE(non_apple_keyboards); i++) { 328 + char *non_apple = non_apple_keyboards[i].name; 329 + 330 + if (strncmp(hdev->name, non_apple, strlen(non_apple)) == 0) 331 + return true; 332 + } 333 + 334 + return false; 335 + } 336 + 320 337 static inline void apple_setup_key_translation(struct input_dev *input, 321 338 const struct apple_key_translation *table) 322 339 { ··· 388 363 } 389 364 390 365 if (fnmode == 3) { 391 - real_fnmode = (asc->quirks & APPLE_IS_KEYCHRON) ? 2 : 1; 366 + real_fnmode = (asc->quirks & APPLE_IS_NON_APPLE) ? 2 : 1; 392 367 } else { 393 368 real_fnmode = fnmode; 394 369 } ··· 694 669 asc->quirks &= ~APPLE_HAS_FN; 695 670 } 696 671 697 - if (strncmp(hdev->name, "Keychron", 8) == 0) { 698 - hid_info(hdev, "Keychron keyboard detected; function keys will default to fnmode=2 behavior\n"); 699 - asc->quirks |= APPLE_IS_KEYCHRON; 672 + if (apple_is_non_apple_keyboard(hdev)) { 673 + hid_info(hdev, "Non-apple keyboard detected; function keys will default to fnmode=2 behavior\n"); 674 + asc->quirks |= APPLE_IS_NON_APPLE; 700 675 } 701 676 702 677 return 0;
+1 -1
drivers/hid/hid-core.c
··· 1662 1662 1663 1663 /* first retrieve all incoming values in data */ 1664 1664 for (a = 0; a < report->maxfield; a++) 1665 - hid_input_fetch_field(hid, field = report->field[a], data); 1665 + hid_input_fetch_field(hid, report->field[a], data); 1666 1666 1667 1667 if (!list_empty(&report->field_entry_list)) { 1668 1668 /* INPUT_REPORT, we have a priority list of fields */
+5
drivers/hid/hid-cp2112.c
··· 790 790 data->word = le16_to_cpup((__le16 *)buf); 791 791 break; 792 792 case I2C_SMBUS_I2C_BLOCK_DATA: 793 + if (read_length > I2C_SMBUS_BLOCK_MAX) { 794 + ret = -EINVAL; 795 + goto power_normal; 796 + } 797 + 793 798 memcpy(data->block + 1, buf, read_length); 794 799 break; 795 800 case I2C_SMBUS_BLOCK_DATA:
+2
drivers/hid/hid-ids.h
··· 413 413 #define USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN 0x2544 414 414 #define USB_DEVICE_ID_ASUS_UX550_TOUCHSCREEN 0x2706 415 415 #define I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN 0x261A 416 + #define I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN 0x2A1C 416 417 417 418 #define USB_VENDOR_ID_ELECOM 0x056e 418 419 #define USB_DEVICE_ID_ELECOM_BM084 0x0061 ··· 1279 1278 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G540 0x0075 1280 1279 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_G640 0x0094 1281 1280 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01 0x0042 1281 + #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L 0x0935 1282 1282 #define USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06 0x0078 1283 1283 #define USB_DEVICE_ID_UGEE_TABLET_G5 0x0074 1284 1284 #define USB_DEVICE_ID_UGEE_TABLET_EX07S 0x0071
+2
drivers/hid/hid-input.c
··· 381 381 HID_BATTERY_QUIRK_IGNORE }, 382 382 { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO_TOUCHSCREEN), 383 383 HID_BATTERY_QUIRK_IGNORE }, 384 + { HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_SURFACE_GO2_TOUCHSCREEN), 385 + HID_BATTERY_QUIRK_IGNORE }, 384 386 {} 385 387 }; 386 388
+1 -1
drivers/hid/hid-lg-g15.c
··· 766 766 767 767 /* 768 768 * Some models have multiple interfaces, we want the interface with 769 - * with the f000.0000 application input report. 769 + * the f000.0000 application input report. 770 770 */ 771 771 rep_enum = &hdev->report_enum[HID_INPUT_REPORT]; 772 772 list_for_each_entry(rep, &rep_enum->report_list, list) {
+1 -1
drivers/hid/hid-logitech-hidpp.c
··· 1694 1694 val->strval = hidpp->hid_dev->uniq; 1695 1695 break; 1696 1696 case POWER_SUPPLY_PROP_VOLTAGE_NOW: 1697 - /* hardware reports voltage in in mV. sysfs expects uV */ 1697 + /* hardware reports voltage in mV. sysfs expects uV */ 1698 1698 val->intval = hidpp->battery.voltage * 1000; 1699 1699 break; 1700 1700 case POWER_SUPPLY_PROP_CHARGE_TYPE:
+3
drivers/hid/hid-mcp2221.c
··· 385 385 data_len = 7; 386 386 break; 387 387 default: 388 + if (len > I2C_SMBUS_BLOCK_MAX) 389 + return -EINVAL; 390 + 388 391 memcpy(&mcp->txbuf[5], buf, len); 389 392 data_len = len + 5; 390 393 }
+12 -1
drivers/hid/hid-multitouch.c
··· 194 194 #define MT_CLS_WIN_8_FORCE_MULTI_INPUT 0x0015 195 195 #define MT_CLS_WIN_8_DISABLE_WAKEUP 0x0016 196 196 #define MT_CLS_WIN_8_NO_STICKY_FINGERS 0x0017 197 + #define MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU 0x0018 197 198 198 199 /* vendor specific classes */ 199 200 #define MT_CLS_3M 0x0101 ··· 286 285 MT_QUIRK_STICKY_FINGERS | 287 286 MT_QUIRK_WIN8_PTP_BUTTONS | 288 287 MT_QUIRK_FORCE_MULTI_INPUT, 288 + .export_all_inputs = true }, 289 + { .name = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU, 290 + .quirks = MT_QUIRK_IGNORE_DUPLICATES | 291 + MT_QUIRK_HOVERING | 292 + MT_QUIRK_CONTACT_CNT_ACCURATE | 293 + MT_QUIRK_STICKY_FINGERS | 294 + MT_QUIRK_WIN8_PTP_BUTTONS | 295 + MT_QUIRK_FORCE_MULTI_INPUT | 296 + MT_QUIRK_NOT_SEEN_MEANS_UP, 289 297 .export_all_inputs = true }, 290 298 { .name = MT_CLS_WIN_8_DISABLE_WAKEUP, 291 299 .quirks = MT_QUIRK_ALWAYS_VALID | ··· 793 783 case HID_DG_CONFIDENCE: 794 784 if ((cls->name == MT_CLS_WIN_8 || 795 785 cls->name == MT_CLS_WIN_8_FORCE_MULTI_INPUT || 786 + cls->name == MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU || 796 787 cls->name == MT_CLS_WIN_8_DISABLE_WAKEUP) && 797 788 (field->application == HID_DG_TOUCHPAD || 798 789 field->application == HID_DG_TOUCHSCREEN)) ··· 2046 2035 USB_DEVICE_ID_LENOVO_X1_TAB3) }, 2047 2036 2048 2037 /* Lenovo X12 TAB Gen 1 */ 2049 - { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT, 2038 + { .driver_data = MT_CLS_WIN_8_FORCE_MULTI_INPUT_NSMU, 2050 2039 HID_DEVICE(BUS_USB, HID_GROUP_MULTITOUCH_WIN_8, 2051 2040 USB_VENDOR_ID_LENOVO, 2052 2041 USB_DEVICE_ID_LENOVO_X12_TAB) },
+4 -2
drivers/hid/hid-nintendo.c
··· 292 292 }; 293 293 static const u16 JC_RUMBLE_DFLT_LOW_FREQ = 160; 294 294 static const u16 JC_RUMBLE_DFLT_HIGH_FREQ = 320; 295 + static const unsigned short JC_RUMBLE_ZERO_AMP_PKT_CNT = 5; 295 296 #endif /* IS_ENABLED(CONFIG_NINTENDO_FF) */ 296 297 static const u16 JC_RUMBLE_PERIOD_MS = 50; 297 298 ··· 402 401 #define JC_MAX_RESP_SIZE (sizeof(struct joycon_input_report) + 35) 403 402 #define JC_RUMBLE_DATA_SIZE 8 404 403 #define JC_RUMBLE_QUEUE_SIZE 8 405 - 406 - static const unsigned short JC_RUMBLE_ZERO_AMP_PKT_CNT = 5; 407 404 408 405 static const char * const joycon_player_led_names[] = { 409 406 LED_FUNCTION_PLAYER1, ··· 1585 1586 /* We report joy-con d-pad inputs as buttons and pro controller as a hat. */ 1586 1587 static const unsigned int joycon_dpad_inputs_jc[] = { 1587 1588 BTN_DPAD_UP, BTN_DPAD_DOWN, BTN_DPAD_LEFT, BTN_DPAD_RIGHT, 1589 + 0 /* 0 signals end of array */ 1588 1590 }; 1589 1591 1590 1592 static int joycon_input_create(struct joycon_ctlr *ctlr) ··· 1634 1634 ctlr->input->id.version = hdev->version; 1635 1635 ctlr->input->uniq = ctlr->mac_addr_str; 1636 1636 ctlr->input->name = name; 1637 + ctlr->input->phys = hdev->phys; 1637 1638 input_set_drvdata(ctlr->input, ctlr); 1638 1639 1639 1640 /* set up sticks and buttons */ ··· 1714 1713 ctlr->imu_input->id.version = hdev->version; 1715 1714 ctlr->imu_input->uniq = ctlr->mac_addr_str; 1716 1715 ctlr->imu_input->name = imu_name; 1716 + ctlr->imu_input->phys = hdev->phys; 1717 1717 input_set_drvdata(ctlr->imu_input, ctlr); 1718 1718 1719 1719 /* configure imu axes */
+2
drivers/hid/hid-uclogic-core.c
··· 522 522 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, 523 523 USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO01) }, 524 524 { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, 525 + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) }, 526 + { HID_USB_DEVICE(USB_VENDOR_ID_UGEE, 525 527 USB_DEVICE_ID_UGEE_XPPEN_TABLET_STAR06) }, 526 528 { } 527 529 };
+213 -12
drivers/hid/hid-uclogic-params.c
··· 23 23 /** 24 24 * uclogic_params_pen_inrange_to_str() - Convert a pen in-range reporting type 25 25 * to a string. 26 - * 27 26 * @inrange: The in-range reporting type to convert. 28 27 * 29 - * Returns: 30 - * The string representing the type, or NULL if the type is unknown. 28 + * Return: 29 + * * The string representing the type, or 30 + * * %NULL if the type is unknown. 31 31 */ 32 32 static const char *uclogic_params_pen_inrange_to_str( 33 33 enum uclogic_params_pen_inrange inrange) ··· 45 45 } 46 46 47 47 /** 48 - * Dump tablet interface pen parameters with hid_dbg(), indented with one tab. 49 - * 48 + * uclogic_params_pen_hid_dbg() - Dump tablet interface pen parameters 50 49 * @hdev: The HID device the pen parameters describe. 51 50 * @pen: The pen parameters to dump. 51 + * 52 + * Dump tablet interface pen parameters with hid_dbg(). The dump is indented 53 + * with a tab. 52 54 */ 53 55 static void uclogic_params_pen_hid_dbg(const struct hid_device *hdev, 54 56 const struct uclogic_params_pen *pen) ··· 79 77 } 80 78 81 79 /** 82 - * Dump tablet interface frame parameters with hid_dbg(), indented with two 83 - * tabs. 84 - * 80 + * uclogic_params_frame_hid_dbg() - Dump tablet interface frame parameters 85 81 * @hdev: The HID device the pen parameters describe. 86 82 * @frame: The frame parameters to dump. 83 + * 84 + * Dump tablet interface frame parameters with hid_dbg(). The dump is 85 + * indented with two tabs. 87 86 */ 88 87 static void uclogic_params_frame_hid_dbg( 89 88 const struct hid_device *hdev, ··· 105 102 } 106 103 107 104 /** 108 - * Dump tablet interface parameters with hid_dbg(). 109 - * 105 + * uclogic_params_hid_dbg() - Dump tablet interface parameters 110 106 * @hdev: The HID device the parameters describe. 111 107 * @params: The parameters to dump. 108 + * 109 + * Dump tablet interface parameters with hid_dbg(). 112 110 */ 113 111 void uclogic_params_hid_dbg(const struct hid_device *hdev, 114 112 const struct uclogic_params *params) ··· 238 234 const int len = 12; 239 235 s32 resolution; 240 236 /* Pen report descriptor template parameters */ 241 - s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM]; 237 + s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; 242 238 __u8 *desc_ptr = NULL; 243 239 244 240 /* Check arguments */ ··· 383 379 size_t i; 384 380 s32 resolution; 385 381 /* Pen report descriptor template parameters */ 386 - s32 desc_params[UCLOGIC_RDESC_PEN_PH_ID_NUM]; 382 + s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; 387 383 __u8 *desc_ptr = NULL; 388 384 389 385 /* Check arguments */ ··· 1007 1003 } 1008 1004 1009 1005 /** 1006 + * uclogic_probe_interface() - some tablets, like the Parblo A610 PLUS V2 or 1007 + * the XP-PEN Deco Mini 7, need to be initialized by sending them magic data. 1008 + * 1009 + * @hdev: The HID device of the tablet interface to initialize and get 1010 + * parameters from. Cannot be NULL. 1011 + * @magic_arr: The magic data that should be sent to probe the interface. 1012 + * Cannot be NULL. 1013 + * @magic_size: Size of the magic data. 1014 + * @endpoint: Endpoint where the magic data should be sent. 1015 + * 1016 + * Returns: 1017 + * Zero, if successful. A negative errno code on error. 1018 + */ 1019 + static int uclogic_probe_interface(struct hid_device *hdev, u8 *magic_arr, 1020 + int magic_size, int endpoint) 1021 + { 1022 + struct usb_device *udev; 1023 + unsigned int pipe = 0; 1024 + int sent; 1025 + u8 *buf = NULL; 1026 + int rc = 0; 1027 + 1028 + if (!hdev || !magic_arr) { 1029 + rc = -EINVAL; 1030 + goto cleanup; 1031 + } 1032 + 1033 + buf = kmemdup(magic_arr, magic_size, GFP_KERNEL); 1034 + if (!buf) { 1035 + rc = -ENOMEM; 1036 + goto cleanup; 1037 + } 1038 + 1039 + udev = hid_to_usb_dev(hdev); 1040 + pipe = usb_sndintpipe(udev, endpoint); 1041 + 1042 + rc = usb_interrupt_msg(udev, pipe, buf, magic_size, &sent, 1000); 1043 + if (rc || sent != magic_size) { 1044 + hid_err(hdev, "Interface probing failed: %d\n", rc); 1045 + rc = -1; 1046 + goto cleanup; 1047 + } 1048 + 1049 + rc = 0; 1050 + cleanup: 1051 + kfree(buf); 1052 + return rc; 1053 + } 1054 + 1055 + /** 1056 + * uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by 1057 + * discovering their parameters. 1058 + * 1059 + * These tables, internally designed as v2 to differentiate them from older 1060 + * models, expect a payload of magic data in orther to be switched to the fully 1061 + * functional mode and expose their parameters in a similar way to the 1062 + * information present in uclogic_params_pen_init_v1() but with some 1063 + * differences. 1064 + * 1065 + * @params: Parameters to fill in (to be cleaned with 1066 + * uclogic_params_cleanup()). Not modified in case of error. 1067 + * Cannot be NULL. 1068 + * @hdev: The HID device of the tablet interface to initialize and get 1069 + * parameters from. Cannot be NULL. 1070 + * 1071 + * Returns: 1072 + * Zero, if successful. A negative errno code on error. 1073 + */ 1074 + static int uclogic_params_ugee_v2_init(struct uclogic_params *params, 1075 + struct hid_device *hdev) 1076 + { 1077 + int rc = 0; 1078 + struct usb_interface *iface; 1079 + __u8 bInterfaceNumber; 1080 + const int str_desc_len = 12; 1081 + __u8 *str_desc = NULL; 1082 + __u8 *rdesc_pen = NULL; 1083 + __u8 *rdesc_frame = NULL; 1084 + s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM]; 1085 + s32 resolution; 1086 + __u8 magic_arr[] = { 1087 + 0x02, 0xb0, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 1088 + }; 1089 + /* The resulting parameters (noop) */ 1090 + struct uclogic_params p = {0, }; 1091 + 1092 + if (!params || !hdev) { 1093 + rc = -EINVAL; 1094 + goto cleanup; 1095 + } 1096 + 1097 + iface = to_usb_interface(hdev->dev.parent); 1098 + bInterfaceNumber = iface->cur_altsetting->desc.bInterfaceNumber; 1099 + if (bInterfaceNumber != 2) { 1100 + uclogic_params_init_invalid(&p); 1101 + goto output; 1102 + } 1103 + 1104 + /* 1105 + * Initialize the interface by sending magic data. 1106 + * The specific data was discovered by sniffing the Windows driver 1107 + * traffic. 1108 + */ 1109 + rc = uclogic_probe_interface(hdev, magic_arr, sizeof(magic_arr), 0x03); 1110 + if (rc) { 1111 + uclogic_params_init_invalid(&p); 1112 + goto output; 1113 + } 1114 + 1115 + /* 1116 + * Read the string descriptor containing pen and frame parameters. 1117 + * The specific string descriptor and data were discovered by sniffing 1118 + * the Windows driver traffic. 1119 + */ 1120 + rc = uclogic_params_get_str_desc(&str_desc, hdev, 100, str_desc_len); 1121 + if (rc != str_desc_len) { 1122 + hid_err(hdev, "failed retrieving pen and frame parameters: %d\n", rc); 1123 + uclogic_params_init_invalid(&p); 1124 + goto output; 1125 + } 1126 + 1127 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 1128 + get_unaligned_le16(str_desc + 2); 1129 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 1130 + get_unaligned_le16(str_desc + 4); 1131 + desc_params[UCLOGIC_RDESC_FRAME_PH_ID_UM] = str_desc[6]; 1132 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 1133 + get_unaligned_le16(str_desc + 8); 1134 + resolution = get_unaligned_le16(str_desc + 10); 1135 + if (resolution == 0) { 1136 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0; 1137 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0; 1138 + } else { 1139 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 1140 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_X_LM] * 1000 / 1141 + resolution; 1142 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 1143 + desc_params[UCLOGIC_RDESC_PEN_PH_ID_Y_LM] * 1000 / 1144 + resolution; 1145 + } 1146 + kfree(str_desc); 1147 + str_desc = NULL; 1148 + 1149 + /* Initialize the pen interface */ 1150 + rdesc_pen = uclogic_rdesc_template_apply( 1151 + uclogic_rdesc_ugee_v2_pen_template_arr, 1152 + uclogic_rdesc_ugee_v2_pen_template_size, 1153 + desc_params, ARRAY_SIZE(desc_params)); 1154 + if (!rdesc_pen) { 1155 + rc = -ENOMEM; 1156 + goto cleanup; 1157 + } 1158 + 1159 + p.pen.desc_ptr = rdesc_pen; 1160 + p.pen.desc_size = uclogic_rdesc_ugee_v2_pen_template_size; 1161 + p.pen.id = 0x02; 1162 + p.pen.subreport_list[0].value = 0xf0; 1163 + p.pen.subreport_list[0].id = UCLOGIC_RDESC_V1_FRAME_ID; 1164 + 1165 + /* Initialize the frame interface */ 1166 + rdesc_frame = uclogic_rdesc_template_apply( 1167 + uclogic_rdesc_ugee_v2_frame_btn_template_arr, 1168 + uclogic_rdesc_ugee_v2_frame_btn_template_size, 1169 + desc_params, ARRAY_SIZE(desc_params)); 1170 + if (!rdesc_frame) { 1171 + rc = -ENOMEM; 1172 + goto cleanup; 1173 + } 1174 + 1175 + rc = uclogic_params_frame_init_with_desc(&p.frame_list[0], 1176 + rdesc_frame, 1177 + uclogic_rdesc_ugee_v2_frame_btn_template_size, 1178 + UCLOGIC_RDESC_V1_FRAME_ID); 1179 + kfree(rdesc_frame); 1180 + if (rc) { 1181 + uclogic_params_init_invalid(&p); 1182 + goto output; 1183 + } 1184 + 1185 + output: 1186 + /* Output parameters */ 1187 + memcpy(params, &p, sizeof(*params)); 1188 + memset(&p, 0, sizeof(p)); 1189 + rc = 0; 1190 + cleanup: 1191 + kfree(str_desc); 1192 + uclogic_params_cleanup(&p); 1193 + return rc; 1194 + } 1195 + 1196 + /** 1010 1197 * uclogic_params_init() - initialize a tablet interface and discover its 1011 1198 * parameters. 1012 1199 * ··· 1431 1236 } else { 1432 1237 uclogic_params_init_invalid(&p); 1433 1238 } 1239 + break; 1240 + case VID_PID(USB_VENDOR_ID_UGEE, 1241 + USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L): 1242 + rc = uclogic_params_ugee_v2_init(&p, hdev); 1243 + if (rc != 0) 1244 + goto cleanup; 1434 1245 break; 1435 1246 case VID_PID(USB_VENDOR_ID_TRUST, 1436 1247 USB_DEVICE_ID_TRUST_PANORA_TABLET):
+219
drivers/hid/hid-uclogic-rdesc-test.c
··· 1 + // SPDX-License-Identifier: GPL-2.0+ 2 + 3 + /* 4 + * HID driver for UC-Logic devices not fully compliant with HID standard 5 + * 6 + * Copyright (c) 2022 José Expósito <jose.exposito89@gmail.com> 7 + */ 8 + 9 + #include <kunit/test.h> 10 + #include "./hid-uclogic-rdesc.h" 11 + 12 + struct uclogic_template_case { 13 + const char *name; 14 + const __u8 *template; 15 + size_t template_size; 16 + const s32 *param_list; 17 + size_t param_num; 18 + const __u8 *expected; 19 + }; 20 + 21 + static const s32 params_pen_all[UCLOGIC_RDESC_PH_ID_NUM] = { 22 + [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xAA, 23 + [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0xBB, 24 + [UCLOGIC_RDESC_PEN_PH_ID_Y_LM] = 0xCC, 25 + [UCLOGIC_RDESC_PEN_PH_ID_Y_PM] = 0xDD, 26 + [UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM] = 0xEE, 27 + }; 28 + 29 + static const s32 params_pen_some[] = { 30 + [UCLOGIC_RDESC_PEN_PH_ID_X_LM] = 0xAA, 31 + [UCLOGIC_RDESC_PEN_PH_ID_X_PM] = 0xBB, 32 + }; 33 + 34 + static const s32 params_frame_all[UCLOGIC_RDESC_PH_ID_NUM] = { 35 + [UCLOGIC_RDESC_FRAME_PH_ID_UM] = 0xFF, 36 + }; 37 + 38 + static const __u8 template_empty[] = { }; 39 + static const __u8 template_small[] = { 0x00 }; 40 + static const __u8 template_no_ph[] = { 0xAA, 0xFE, 0xAA, 0xED, 0x1D }; 41 + 42 + static const __u8 template_pen_ph_end[] = { 43 + 0xAA, 0xBB, UCLOGIC_RDESC_PEN_PH_HEAD 44 + }; 45 + 46 + static const __u8 template_btn_ph_end[] = { 47 + 0xAA, 0xBB, UCLOGIC_RDESC_FRAME_PH_BTN_HEAD 48 + }; 49 + 50 + static const __u8 template_pen_all_params[] = { 51 + UCLOGIC_RDESC_PEN_PH(X_LM), 52 + 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), 53 + 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), 54 + UCLOGIC_RDESC_PEN_PH(Y_PM), 55 + 0x00, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), 56 + }; 57 + 58 + static const __u8 expected_pen_all_params[] = { 59 + 0xAA, 0x00, 0x00, 0x00, 60 + 0x47, 0xBB, 0x00, 0x00, 0x00, 61 + 0x27, 0xCC, 0x00, 0x00, 0x00, 62 + 0xDD, 0x00, 0x00, 0x00, 63 + 0x00, 0xEE, 0x00, 0x00, 0x00, 64 + }; 65 + 66 + static const __u8 template_frame_all_params[] = { 67 + 0x01, 0x02, 68 + UCLOGIC_RDESC_FRAME_PH_BTN, 69 + 0x99, 70 + }; 71 + 72 + static const __u8 expected_frame_all_params[] = { 73 + 0x01, 0x02, 74 + 0x2A, 0xFF, 0x00, 75 + 0x99, 76 + }; 77 + 78 + static const __u8 template_pen_some_params[] = { 79 + 0x01, 0x02, 80 + UCLOGIC_RDESC_PEN_PH(X_LM), 81 + 0x03, UCLOGIC_RDESC_PEN_PH(X_PM), 82 + 0x04, 0x05, 83 + }; 84 + 85 + static const __u8 expected_pen_some_params[] = { 86 + 0x01, 0x02, 87 + 0xAA, 0x00, 0x00, 0x00, 88 + 0x03, 0xBB, 0x00, 0x00, 0x00, 89 + 0x04, 0x05, 90 + }; 91 + 92 + static const __u8 template_params_none[] = { 93 + 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), 94 + UCLOGIC_RDESC_PEN_PH(Y_PM), 95 + 0x00, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), 96 + }; 97 + 98 + static struct uclogic_template_case uclogic_template_cases[] = { 99 + { 100 + .name = "Empty template", 101 + .template = template_empty, 102 + .template_size = sizeof(template_empty), 103 + .param_list = params_pen_all, 104 + .param_num = ARRAY_SIZE(params_pen_all), 105 + .expected = template_empty, 106 + }, 107 + { 108 + .name = "Template smaller than the placeholder", 109 + .template = template_small, 110 + .template_size = sizeof(template_small), 111 + .param_list = params_pen_all, 112 + .param_num = ARRAY_SIZE(params_pen_all), 113 + .expected = template_small, 114 + }, 115 + { 116 + .name = "No placeholder", 117 + .template = template_no_ph, 118 + .template_size = sizeof(template_no_ph), 119 + .param_list = params_pen_all, 120 + .param_num = ARRAY_SIZE(params_pen_all), 121 + .expected = template_no_ph, 122 + }, 123 + { 124 + .name = "Pen placeholder at the end, without ID", 125 + .template = template_pen_ph_end, 126 + .template_size = sizeof(template_pen_ph_end), 127 + .param_list = params_pen_all, 128 + .param_num = ARRAY_SIZE(params_pen_all), 129 + .expected = template_pen_ph_end, 130 + }, 131 + { 132 + .name = "Frame button placeholder at the end, without ID", 133 + .template = template_btn_ph_end, 134 + .template_size = sizeof(template_btn_ph_end), 135 + .param_list = params_frame_all, 136 + .param_num = ARRAY_SIZE(params_frame_all), 137 + .expected = template_btn_ph_end, 138 + }, 139 + { 140 + .name = "All params present in the pen template", 141 + .template = template_pen_all_params, 142 + .template_size = sizeof(template_pen_all_params), 143 + .param_list = params_pen_all, 144 + .param_num = ARRAY_SIZE(params_pen_all), 145 + .expected = expected_pen_all_params, 146 + }, 147 + { 148 + .name = "All params present in the frame template", 149 + .template = template_frame_all_params, 150 + .template_size = sizeof(template_frame_all_params), 151 + .param_list = params_frame_all, 152 + .param_num = ARRAY_SIZE(params_frame_all), 153 + .expected = expected_frame_all_params, 154 + }, 155 + { 156 + .name = "Some params present in the pen template (complete param list)", 157 + .template = template_pen_some_params, 158 + .template_size = sizeof(template_pen_some_params), 159 + .param_list = params_pen_all, 160 + .param_num = ARRAY_SIZE(params_pen_all), 161 + .expected = expected_pen_some_params, 162 + }, 163 + { 164 + .name = "Some params present in the pen template (incomplete param list)", 165 + .template = template_pen_some_params, 166 + .template_size = sizeof(template_pen_some_params), 167 + .param_list = params_pen_some, 168 + .param_num = ARRAY_SIZE(params_pen_some), 169 + .expected = expected_pen_some_params, 170 + }, 171 + { 172 + .name = "No params present in the template", 173 + .template = template_params_none, 174 + .template_size = sizeof(template_params_none), 175 + .param_list = params_pen_some, 176 + .param_num = ARRAY_SIZE(params_pen_some), 177 + .expected = template_params_none, 178 + }, 179 + }; 180 + 181 + static void uclogic_template_case_desc(struct uclogic_template_case *t, 182 + char *desc) 183 + { 184 + strscpy(desc, t->name, KUNIT_PARAM_DESC_SIZE); 185 + } 186 + 187 + KUNIT_ARRAY_PARAM(uclogic_template, uclogic_template_cases, 188 + uclogic_template_case_desc); 189 + 190 + static void uclogic_template_test(struct kunit *test) 191 + { 192 + __u8 *res; 193 + const struct uclogic_template_case *params = test->param_value; 194 + 195 + res = uclogic_rdesc_template_apply(params->template, 196 + params->template_size, 197 + params->param_list, 198 + params->param_num); 199 + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, res); 200 + KUNIT_EXPECT_EQ(test, 0, 201 + memcmp(res, params->expected, params->template_size)); 202 + kfree(res); 203 + } 204 + 205 + static struct kunit_case hid_uclogic_rdesc_test_cases[] = { 206 + KUNIT_CASE_PARAM(uclogic_template_test, uclogic_template_gen_params), 207 + {} 208 + }; 209 + 210 + static struct kunit_suite hid_uclogic_rdesc_test_suite = { 211 + .name = "hid-uclogic-rdesc-test", 212 + .test_cases = hid_uclogic_rdesc_test_cases, 213 + }; 214 + 215 + kunit_test_suite(hid_uclogic_rdesc_test_suite); 216 + 217 + MODULE_DESCRIPTION("KUnit tests for the UC-Logic driver"); 218 + MODULE_LICENSE("GPL"); 219 + MODULE_AUTHOR("José Expósito <jose.exposito89@gmail.com>");
+117 -7
drivers/hid/hid-uclogic-rdesc.c
··· 859 859 const size_t uclogic_rdesc_v2_frame_dial_size = 860 860 sizeof(uclogic_rdesc_v2_frame_dial_arr); 861 861 862 + /* Fixed report descriptor template for UGEE v2 pen reports */ 863 + const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[] = { 864 + 0x05, 0x0d, /* Usage Page (Digitizers), */ 865 + 0x09, 0x01, /* Usage (Digitizer), */ 866 + 0xa1, 0x01, /* Collection (Application), */ 867 + 0x85, 0x02, /* Report ID (2), */ 868 + 0x09, 0x20, /* Usage (Stylus), */ 869 + 0xa1, 0x00, /* Collection (Physical), */ 870 + 0x09, 0x42, /* Usage (Tip Switch), */ 871 + 0x09, 0x44, /* Usage (Barrel Switch), */ 872 + 0x09, 0x46, /* Usage (Tablet Pick), */ 873 + 0x75, 0x01, /* Report Size (1), */ 874 + 0x95, 0x03, /* Report Count (3), */ 875 + 0x14, /* Logical Minimum (0), */ 876 + 0x25, 0x01, /* Logical Maximum (1), */ 877 + 0x81, 0x02, /* Input (Variable), */ 878 + 0x95, 0x02, /* Report Count (2), */ 879 + 0x81, 0x03, /* Input (Constant, Variable), */ 880 + 0x09, 0x32, /* Usage (In Range), */ 881 + 0x95, 0x01, /* Report Count (1), */ 882 + 0x81, 0x02, /* Input (Variable), */ 883 + 0x95, 0x02, /* Report Count (2), */ 884 + 0x81, 0x03, /* Input (Constant, Variable), */ 885 + 0x75, 0x10, /* Report Size (16), */ 886 + 0x95, 0x01, /* Report Count (1), */ 887 + 0x35, 0x00, /* Physical Minimum (0), */ 888 + 0xa4, /* Push, */ 889 + 0x05, 0x01, /* Usage Page (Desktop), */ 890 + 0x09, 0x30, /* Usage (X), */ 891 + 0x65, 0x13, /* Unit (Inch), */ 892 + 0x55, 0x0d, /* Unit Exponent (-3), */ 893 + 0x27, UCLOGIC_RDESC_PEN_PH(X_LM), 894 + /* Logical Maximum (PLACEHOLDER), */ 895 + 0x47, UCLOGIC_RDESC_PEN_PH(X_PM), 896 + /* Physical Maximum (PLACEHOLDER), */ 897 + 0x81, 0x02, /* Input (Variable), */ 898 + 0x09, 0x31, /* Usage (Y), */ 899 + 0x27, UCLOGIC_RDESC_PEN_PH(Y_LM), 900 + /* Logical Maximum (PLACEHOLDER), */ 901 + 0x47, UCLOGIC_RDESC_PEN_PH(Y_PM), 902 + /* Physical Maximum (PLACEHOLDER), */ 903 + 0x81, 0x02, /* Input (Variable), */ 904 + 0xb4, /* Pop, */ 905 + 0x09, 0x30, /* Usage (Tip Pressure), */ 906 + 0x45, 0x00, /* Physical Maximum (0), */ 907 + 0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM), 908 + /* Logical Maximum (PLACEHOLDER), */ 909 + 0x75, 0x0D, /* Report Size (13), */ 910 + 0x95, 0x01, /* Report Count (1), */ 911 + 0x81, 0x02, /* Input (Variable), */ 912 + 0x75, 0x01, /* Report Size (1), */ 913 + 0x95, 0x03, /* Report Count (3), */ 914 + 0x81, 0x01, /* Input (Constant), */ 915 + 0x09, 0x3d, /* Usage (X Tilt), */ 916 + 0x35, 0xC3, /* Physical Minimum (-61), */ 917 + 0x45, 0x3C, /* Physical Maximum (60), */ 918 + 0x15, 0xC3, /* Logical Minimum (-61), */ 919 + 0x25, 0x3C, /* Logical Maximum (60), */ 920 + 0x75, 0x08, /* Report Size (8), */ 921 + 0x95, 0x01, /* Report Count (1), */ 922 + 0x81, 0x02, /* Input (Variable), */ 923 + 0x09, 0x3e, /* Usage (Y Tilt), */ 924 + 0x35, 0xC3, /* Physical Minimum (-61), */ 925 + 0x45, 0x3C, /* Physical Maximum (60), */ 926 + 0x15, 0xC3, /* Logical Minimum (-61), */ 927 + 0x25, 0x3C, /* Logical Maximum (60), */ 928 + 0x81, 0x02, /* Input (Variable), */ 929 + 0xc0, /* End Collection, */ 930 + 0xc0, /* End Collection */ 931 + }; 932 + const size_t uclogic_rdesc_ugee_v2_pen_template_size = 933 + sizeof(uclogic_rdesc_ugee_v2_pen_template_arr); 934 + 935 + /* Fixed report descriptor template for UGEE v2 frame reports (buttons only) */ 936 + const __u8 uclogic_rdesc_ugee_v2_frame_btn_template_arr[] = { 937 + 0x05, 0x01, /* Usage Page (Desktop), */ 938 + 0x09, 0x07, /* Usage (Keypad), */ 939 + 0xA1, 0x01, /* Collection (Application), */ 940 + 0x85, UCLOGIC_RDESC_V1_FRAME_ID, 941 + /* Report ID, */ 942 + 0x05, 0x0D, /* Usage Page (Digitizer), */ 943 + 0x09, 0x39, /* Usage (Tablet Function Keys), */ 944 + 0xA0, /* Collection (Physical), */ 945 + 0x75, 0x01, /* Report Size (1), */ 946 + 0x95, 0x08, /* Report Count (8), */ 947 + 0x81, 0x01, /* Input (Constant), */ 948 + 0x05, 0x09, /* Usage Page (Button), */ 949 + 0x19, 0x01, /* Usage Minimum (01h), */ 950 + UCLOGIC_RDESC_FRAME_PH_BTN, 951 + /* Usage Maximum (PLACEHOLDER), */ 952 + 0x95, 0x0A, /* Report Count (10), */ 953 + 0x14, /* Logical Minimum (0), */ 954 + 0x25, 0x01, /* Logical Maximum (1), */ 955 + 0x81, 0x02, /* Input (Variable), */ 956 + 0x95, 0x46, /* Report Count (70), */ 957 + 0x81, 0x01, /* Input (Constant), */ 958 + 0xC0, /* End Collection, */ 959 + 0xC0 /* End Collection */ 960 + }; 961 + const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size = 962 + sizeof(uclogic_rdesc_ugee_v2_frame_btn_template_arr); 963 + 862 964 /* Fixed report descriptor for Ugee EX07 frame */ 863 965 const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = { 864 966 0x05, 0x01, /* Usage Page (Desktop), */ ··· 1081 979 * uclogic_rdesc_template_apply() - apply report descriptor parameters to a 1082 980 * report descriptor template, creating a report descriptor. Copies the 1083 981 * template over to the new report descriptor and replaces every occurrence of 1084 - * UCLOGIC_RDESC_PH_HEAD, followed by an index byte, with the value from the 982 + * the template placeholders, followed by an index byte, with the value from the 1085 983 * parameter list at that index. 1086 984 * 1087 985 * @template_ptr: Pointer to the template buffer. ··· 1098 996 const s32 *param_list, 1099 997 size_t param_num) 1100 998 { 1101 - static const __u8 head[] = {UCLOGIC_RDESC_PH_HEAD}; 999 + static const __u8 btn_head[] = {UCLOGIC_RDESC_FRAME_PH_BTN_HEAD}; 1000 + static const __u8 pen_head[] = {UCLOGIC_RDESC_PEN_PH_HEAD}; 1102 1001 __u8 *rdesc_ptr; 1103 1002 __u8 *p; 1104 1003 s32 v; ··· 1108 1005 if (rdesc_ptr == NULL) 1109 1006 return NULL; 1110 1007 1111 - for (p = rdesc_ptr; p + sizeof(head) < rdesc_ptr + template_size;) { 1112 - if (memcmp(p, head, sizeof(head)) == 0 && 1113 - p[sizeof(head)] < param_num) { 1114 - v = param_list[p[sizeof(head)]]; 1008 + for (p = rdesc_ptr; p + sizeof(btn_head) < rdesc_ptr + template_size;) { 1009 + if (p + sizeof(pen_head) < rdesc_ptr + template_size && 1010 + memcmp(p, pen_head, sizeof(pen_head)) == 0 && 1011 + p[sizeof(pen_head)] < param_num) { 1012 + v = param_list[p[sizeof(pen_head)]]; 1115 1013 put_unaligned(cpu_to_le32(v), (s32 *)p); 1116 - p += sizeof(head) + 1; 1014 + p += sizeof(pen_head) + 1; 1015 + } else if (memcmp(p, btn_head, sizeof(btn_head)) == 0 && 1016 + p[sizeof(btn_head)] < param_num) { 1017 + v = param_list[p[sizeof(btn_head)]]; 1018 + put_unaligned((__u8)0x2A, p); /* Usage Maximum */ 1019 + put_unaligned_le16((__force u16)cpu_to_le16(v), p + 1); 1020 + p += sizeof(btn_head) + 1; 1117 1021 } else { 1118 1022 p++; 1119 1023 }
+19 -5
drivers/hid/hid-uclogic-rdesc.h
··· 81 81 extern const size_t uclogic_rdesc_twha60_fixed1_size; 82 82 83 83 /* Report descriptor template placeholder head */ 84 - #define UCLOGIC_RDESC_PH_HEAD 0xFE, 0xED, 0x1D 84 + #define UCLOGIC_RDESC_PEN_PH_HEAD 0xFE, 0xED, 0x1D 85 + #define UCLOGIC_RDESC_FRAME_PH_BTN_HEAD 0xFE, 0xED 85 86 86 87 /* Apply report descriptor parameters to a report descriptor template */ 87 88 extern __u8 *uclogic_rdesc_template_apply(const __u8 *template_ptr, ··· 90 89 const s32 *param_list, 91 90 size_t param_num); 92 91 93 - /* Pen report descriptor template placeholder IDs */ 94 - enum uclogic_rdesc_pen_ph_id { 92 + /* Report descriptor template placeholder IDs */ 93 + enum uclogic_rdesc_ph_id { 95 94 UCLOGIC_RDESC_PEN_PH_ID_X_LM, 96 95 UCLOGIC_RDESC_PEN_PH_ID_X_PM, 97 96 UCLOGIC_RDESC_PEN_PH_ID_Y_LM, 98 97 UCLOGIC_RDESC_PEN_PH_ID_Y_PM, 99 98 UCLOGIC_RDESC_PEN_PH_ID_PRESSURE_LM, 100 - UCLOGIC_RDESC_PEN_PH_ID_NUM 99 + UCLOGIC_RDESC_FRAME_PH_ID_UM, 100 + UCLOGIC_RDESC_PH_ID_NUM 101 101 }; 102 102 103 103 /* Report descriptor pen template placeholder */ 104 104 #define UCLOGIC_RDESC_PEN_PH(_ID) \ 105 - UCLOGIC_RDESC_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID 105 + UCLOGIC_RDESC_PEN_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID 106 + 107 + /* Report descriptor frame buttons template placeholder */ 108 + #define UCLOGIC_RDESC_FRAME_PH_BTN \ 109 + UCLOGIC_RDESC_FRAME_PH_BTN_HEAD, UCLOGIC_RDESC_FRAME_PH_ID_UM 106 110 107 111 /* Report ID for v1 pen reports */ 108 112 #define UCLOGIC_RDESC_V1_PEN_ID 0x07 ··· 160 154 161 155 /* Device ID byte offset in v2 frame dial reports */ 162 156 #define UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE 0x4 157 + 158 + /* Fixed report descriptor template for UGEE v2 pen reports */ 159 + extern const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[]; 160 + extern const size_t uclogic_rdesc_ugee_v2_pen_template_size; 161 + 162 + /* Fixed report descriptor template for UGEE v2 frame reports (buttons only) */ 163 + extern const __u8 uclogic_rdesc_ugee_v2_frame_btn_template_arr[]; 164 + extern const size_t uclogic_rdesc_ugee_v2_frame_btn_template_size; 163 165 164 166 /* Fixed report descriptor for Ugee EX07 frame */ 165 167 extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[];
+15
drivers/hid/i2c-hid/Kconfig
··· 32 32 will be called i2c-hid-of. It will also build/depend on the 33 33 module i2c-hid. 34 34 35 + config I2C_HID_OF_ELAN 36 + tristate "Driver for Elan hid-i2c based devices on OF systems" 37 + default n 38 + depends on I2C && INPUT && OF 39 + help 40 + Say Y here if you want support for Elan i2c devices that use 41 + the i2c-hid protocol on Open Firmware (Device Tree)-based 42 + systems. 43 + 44 + If unsure, say N. 45 + 46 + This support is also available as a module. If so, the module 47 + will be called i2c-hid-of-elan. It will also build/depend on 48 + the module i2c-hid. 49 + 35 50 config I2C_HID_OF_GOODIX 36 51 tristate "Driver for Goodix hid-i2c based devices on OF systems" 37 52 default n
+1
drivers/hid/i2c-hid/Makefile
··· 10 10 11 11 obj-$(CONFIG_I2C_HID_ACPI) += i2c-hid-acpi.o 12 12 obj-$(CONFIG_I2C_HID_OF) += i2c-hid-of.o 13 + obj-$(CONFIG_I2C_HID_OF_ELAN) += i2c-hid-of-elan.o 13 14 obj-$(CONFIG_I2C_HID_OF_GOODIX) += i2c-hid-of-goodix.o
+130
drivers/hid/i2c-hid/i2c-hid-of-elan.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Driver for Elan touchscreens that use the i2c-hid protocol. 4 + * 5 + * Copyright 2020 Google LLC 6 + */ 7 + 8 + #include <linux/delay.h> 9 + #include <linux/device.h> 10 + #include <linux/gpio/consumer.h> 11 + #include <linux/i2c.h> 12 + #include <linux/kernel.h> 13 + #include <linux/module.h> 14 + #include <linux/of.h> 15 + #include <linux/pm.h> 16 + #include <linux/regulator/consumer.h> 17 + 18 + #include "i2c-hid.h" 19 + 20 + struct elan_i2c_hid_chip_data { 21 + unsigned int post_gpio_reset_delay_ms; 22 + unsigned int post_power_delay_ms; 23 + u16 hid_descriptor_address; 24 + }; 25 + 26 + struct i2c_hid_of_elan { 27 + struct i2chid_ops ops; 28 + 29 + struct regulator *vcc33; 30 + struct regulator *vccio; 31 + struct gpio_desc *reset_gpio; 32 + const struct elan_i2c_hid_chip_data *chip_data; 33 + }; 34 + 35 + static int elan_i2c_hid_power_up(struct i2chid_ops *ops) 36 + { 37 + struct i2c_hid_of_elan *ihid_elan = 38 + container_of(ops, struct i2c_hid_of_elan, ops); 39 + int ret; 40 + 41 + ret = regulator_enable(ihid_elan->vcc33); 42 + if (ret) 43 + return ret; 44 + 45 + ret = regulator_enable(ihid_elan->vccio); 46 + if (ret) { 47 + regulator_disable(ihid_elan->vcc33); 48 + return ret; 49 + } 50 + 51 + if (ihid_elan->chip_data->post_power_delay_ms) 52 + msleep(ihid_elan->chip_data->post_power_delay_ms); 53 + 54 + gpiod_set_value_cansleep(ihid_elan->reset_gpio, 0); 55 + if (ihid_elan->chip_data->post_gpio_reset_delay_ms) 56 + msleep(ihid_elan->chip_data->post_gpio_reset_delay_ms); 57 + 58 + return 0; 59 + } 60 + 61 + static void elan_i2c_hid_power_down(struct i2chid_ops *ops) 62 + { 63 + struct i2c_hid_of_elan *ihid_elan = 64 + container_of(ops, struct i2c_hid_of_elan, ops); 65 + 66 + gpiod_set_value_cansleep(ihid_elan->reset_gpio, 1); 67 + regulator_disable(ihid_elan->vccio); 68 + regulator_disable(ihid_elan->vcc33); 69 + } 70 + 71 + static int i2c_hid_of_elan_probe(struct i2c_client *client, 72 + const struct i2c_device_id *id) 73 + { 74 + struct i2c_hid_of_elan *ihid_elan; 75 + 76 + ihid_elan = devm_kzalloc(&client->dev, sizeof(*ihid_elan), GFP_KERNEL); 77 + if (!ihid_elan) 78 + return -ENOMEM; 79 + 80 + ihid_elan->ops.power_up = elan_i2c_hid_power_up; 81 + ihid_elan->ops.power_down = elan_i2c_hid_power_down; 82 + 83 + /* Start out with reset asserted */ 84 + ihid_elan->reset_gpio = 85 + devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_HIGH); 86 + if (IS_ERR(ihid_elan->reset_gpio)) 87 + return PTR_ERR(ihid_elan->reset_gpio); 88 + 89 + ihid_elan->vccio = devm_regulator_get(&client->dev, "vccio"); 90 + if (IS_ERR(ihid_elan->vccio)) 91 + return PTR_ERR(ihid_elan->vccio); 92 + 93 + ihid_elan->vcc33 = devm_regulator_get(&client->dev, "vcc33"); 94 + if (IS_ERR(ihid_elan->vcc33)) 95 + return PTR_ERR(ihid_elan->vcc33); 96 + 97 + ihid_elan->chip_data = device_get_match_data(&client->dev); 98 + 99 + return i2c_hid_core_probe(client, &ihid_elan->ops, 100 + ihid_elan->chip_data->hid_descriptor_address, 0); 101 + } 102 + 103 + static const struct elan_i2c_hid_chip_data elan_ekth6915_chip_data = { 104 + .post_power_delay_ms = 1, 105 + .post_gpio_reset_delay_ms = 300, 106 + .hid_descriptor_address = 0x0001, 107 + }; 108 + 109 + static const struct of_device_id elan_i2c_hid_of_match[] = { 110 + { .compatible = "elan,ekth6915", .data = &elan_ekth6915_chip_data }, 111 + { } 112 + }; 113 + MODULE_DEVICE_TABLE(of, elan_i2c_hid_of_match); 114 + 115 + static struct i2c_driver elan_i2c_hid_ts_driver = { 116 + .driver = { 117 + .name = "i2c_hid_of_elan", 118 + .pm = &i2c_hid_core_pm, 119 + .probe_type = PROBE_PREFER_ASYNCHRONOUS, 120 + .of_match_table = of_match_ptr(elan_i2c_hid_of_match), 121 + }, 122 + .probe = i2c_hid_of_elan_probe, 123 + .remove = i2c_hid_core_remove, 124 + .shutdown = i2c_hid_core_shutdown, 125 + }; 126 + module_i2c_driver(elan_i2c_hid_ts_driver); 127 + 128 + MODULE_AUTHOR("Douglas Anderson <dianders@chromium.org>"); 129 + MODULE_DESCRIPTION("Elan i2c-hid touchscreen driver"); 130 + MODULE_LICENSE("GPL");
+1 -1
drivers/hid/intel-ish-hid/ipc/ipc.c
··· 578 578 static unsigned long prev_sync; 579 579 uint64_t usec; 580 580 581 - if (prev_sync && jiffies - prev_sync < 20 * HZ) 581 + if (prev_sync && time_before(jiffies, prev_sync + 20 * HZ)) 582 582 return; 583 583 584 584 prev_sync = jiffies;
+1 -1
drivers/hid/intel-ish-hid/ishtp-hid-client.c
··· 328 328 329 329 /** 330 330 * ish_cl_event_cb() - bus driver callback for incoming message/packet 331 - * @device: Pointer to the the ishtp client device for which this message 331 + * @device: Pointer to the ishtp client device for which this message 332 332 * is targeted 333 333 * 334 334 * Remove the packet from the list and process the message by calling
+3
drivers/hid/wacom.h
··· 91 91 #include <linux/leds.h> 92 92 #include <linux/usb/input.h> 93 93 #include <linux/power_supply.h> 94 + #include <linux/timer.h> 94 95 #include <asm/unaligned.h> 95 96 96 97 /* ··· 168 167 struct delayed_work init_work; 169 168 struct wacom_remote *remote; 170 169 struct work_struct mode_change_work; 170 + struct timer_list idleprox_timer; 171 171 bool generic_has_leds; 172 172 struct wacom_leds { 173 173 struct wacom_group_leds *groups; ··· 241 239 struct wacom_led *wacom_led_next(struct wacom *wacom, struct wacom_led *cur); 242 240 int wacom_equivalent_usage(int usage); 243 241 int wacom_initialize_leds(struct wacom *wacom); 242 + void wacom_idleprox_timeout(struct timer_list *list); 244 243 #endif
+3 -1
drivers/hid/wacom_sys.c
··· 2121 2121 2122 2122 error = wacom_setup_pad_input_capabilities(pad_input_dev, wacom_wac); 2123 2123 if (error) { 2124 - /* no pad in use on this interface */ 2124 + /* no pad events using this interface */ 2125 2125 input_free_device(pad_input_dev); 2126 2126 wacom_wac->pad_input = NULL; 2127 2127 pad_input_dev = NULL; ··· 2781 2781 INIT_WORK(&wacom->battery_work, wacom_battery_work); 2782 2782 INIT_WORK(&wacom->remote_work, wacom_remote_work); 2783 2783 INIT_WORK(&wacom->mode_change_work, wacom_mode_change_work); 2784 + timer_setup(&wacom->idleprox_timer, &wacom_idleprox_timeout, TIMER_DEFERRABLE); 2784 2785 2785 2786 /* ask for the report descriptor to be loaded by HID */ 2786 2787 error = hid_parse(hdev); ··· 2822 2821 cancel_work_sync(&wacom->battery_work); 2823 2822 cancel_work_sync(&wacom->remote_work); 2824 2823 cancel_work_sync(&wacom->mode_change_work); 2824 + del_timer_sync(&wacom->idleprox_timer); 2825 2825 if (hdev->bus == BUS_BLUETOOTH) 2826 2826 device_remove_file(&hdev->dev, &dev_attr_speed); 2827 2827
+85 -26
drivers/hid/wacom_wac.c
··· 11 11 #include "wacom_wac.h" 12 12 #include "wacom.h" 13 13 #include <linux/input/mt.h> 14 + #include <linux/jiffies.h> 14 15 15 16 /* resolution for penabled devices */ 16 17 #define WACOM_PL_RES 20 ··· 42 41 43 42 static void wacom_update_led(struct wacom *wacom, int button_count, int mask, 44 43 int group); 44 + 45 + static void wacom_force_proxout(struct wacom_wac *wacom_wac) 46 + { 47 + struct input_dev *input = wacom_wac->pen_input; 48 + 49 + wacom_wac->shared->stylus_in_proximity = 0; 50 + 51 + input_report_key(input, BTN_TOUCH, 0); 52 + input_report_key(input, BTN_STYLUS, 0); 53 + input_report_key(input, BTN_STYLUS2, 0); 54 + input_report_key(input, BTN_STYLUS3, 0); 55 + input_report_key(input, wacom_wac->tool[0], 0); 56 + if (wacom_wac->serial[0]) { 57 + input_report_abs(input, ABS_MISC, 0); 58 + } 59 + input_report_abs(input, ABS_PRESSURE, 0); 60 + 61 + wacom_wac->tool[0] = 0; 62 + wacom_wac->id[0] = 0; 63 + wacom_wac->serial[0] = 0; 64 + 65 + input_sync(input); 66 + } 67 + 68 + void wacom_idleprox_timeout(struct timer_list *list) 69 + { 70 + struct wacom *wacom = from_timer(wacom, list, idleprox_timer); 71 + struct wacom_wac *wacom_wac = &wacom->wacom_wac; 72 + 73 + if (!wacom_wac->hid_data.sense_state) { 74 + return; 75 + } 76 + 77 + hid_warn(wacom->hdev, "%s: tool appears to be hung in-prox. forcing it out.\n", __func__); 78 + wacom_force_proxout(wacom_wac); 79 + } 80 + 45 81 /* 46 82 * Percent of battery capacity for Graphire. 47 83 * 8th value means AC online and show 100% capacity. ··· 676 638 return (tool_id & ~0xFFF) << 4 | (tool_id & 0xFFF); 677 639 } 678 640 641 + static bool wacom_is_art_pen(int tool_id) 642 + { 643 + bool is_art_pen = false; 644 + 645 + switch (tool_id) { 646 + case 0x885: /* Intuos3 Marker Pen */ 647 + case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */ 648 + case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */ 649 + is_art_pen = true; 650 + break; 651 + } 652 + return is_art_pen; 653 + } 654 + 679 655 static int wacom_intuos_get_tool_type(int tool_id) 680 656 { 681 - int tool_type; 657 + int tool_type = BTN_TOOL_PEN; 658 + 659 + if (wacom_is_art_pen(tool_id)) 660 + return tool_type; 682 661 683 662 switch (tool_id) { 684 663 case 0x812: /* Inking pen */ ··· 710 655 case 0x852: 711 656 case 0x823: /* Intuos3 Grip Pen */ 712 657 case 0x813: /* Intuos3 Classic Pen */ 713 - case 0x885: /* Intuos3 Marker Pen */ 714 658 case 0x802: /* Intuos4/5 13HD/24HD General Pen */ 715 - case 0x804: /* Intuos4/5 13HD/24HD Marker Pen */ 716 659 case 0x8e2: /* IntuosHT2 pen */ 717 660 case 0x022: 718 - case 0x10804: /* Intuos4/5 13HD/24HD Art Pen */ 719 661 case 0x10842: /* MobileStudio Pro Pro Pen slim */ 720 662 case 0x14802: /* Intuos4/5 13HD/24HD Classic Pen */ 721 663 case 0x16802: /* Cintiq 13HD Pro Pen */ ··· 769 717 case 0x902: /* Intuos4/5 13HD/24HD Airbrush */ 770 718 case 0x10902: /* Intuos4/5 13HD/24HD Airbrush */ 771 719 tool_type = BTN_TOOL_AIRBRUSH; 772 - break; 773 - 774 - default: /* Unknown tool */ 775 - tool_type = BTN_TOOL_PEN; 776 720 break; 777 721 } 778 722 return tool_type; ··· 2057 2009 wacom_wac->has_mute_touch_switch = true; 2058 2010 usage->type = EV_SW; 2059 2011 usage->code = SW_MUTE_DEVICE; 2060 - features->device_type |= WACOM_DEVICETYPE_PAD; 2061 2012 break; 2062 2013 case WACOM_HID_WD_TOUCHSTRIP: 2063 2014 wacom_map_usage(input, usage, field, EV_ABS, ABS_RX, 0); ··· 2136 2089 wacom_wac->hid_data.inrange_state |= value; 2137 2090 } 2138 2091 2092 + /* Process touch switch state first since it is reported through touch interface, 2093 + * which is indepentent of pad interface. In the case when there are no other pad 2094 + * events, the pad interface will not even be created. 2095 + */ 2096 + if ((equivalent_usage == WACOM_HID_WD_MUTE_DEVICE) || 2097 + (equivalent_usage == WACOM_HID_WD_TOUCHONOFF)) { 2098 + if (wacom_wac->shared->touch_input) { 2099 + bool *is_touch_on = &wacom_wac->shared->is_touch_on; 2100 + 2101 + if (equivalent_usage == WACOM_HID_WD_MUTE_DEVICE && value) 2102 + *is_touch_on = !(*is_touch_on); 2103 + else if (equivalent_usage == WACOM_HID_WD_TOUCHONOFF) 2104 + *is_touch_on = value; 2105 + 2106 + input_report_switch(wacom_wac->shared->touch_input, 2107 + SW_MUTE_DEVICE, !(*is_touch_on)); 2108 + input_sync(wacom_wac->shared->touch_input); 2109 + } 2110 + return; 2111 + } 2112 + 2113 + if (!input) 2114 + return; 2115 + 2139 2116 switch (equivalent_usage) { 2140 2117 case WACOM_HID_WD_TOUCHRING: 2141 2118 /* ··· 2193 2122 case WACOM_HID_WD_TOUCHRINGSTATUS: 2194 2123 if (!value) 2195 2124 input_event(input, usage->type, usage->code, 0); 2196 - break; 2197 - 2198 - case WACOM_HID_WD_MUTE_DEVICE: 2199 - case WACOM_HID_WD_TOUCHONOFF: 2200 - if (wacom_wac->shared->touch_input) { 2201 - bool *is_touch_on = &wacom_wac->shared->is_touch_on; 2202 - 2203 - if (equivalent_usage == WACOM_HID_WD_MUTE_DEVICE && value) 2204 - *is_touch_on = !(*is_touch_on); 2205 - else if (equivalent_usage == WACOM_HID_WD_TOUCHONOFF) 2206 - *is_touch_on = value; 2207 - 2208 - input_report_switch(wacom_wac->shared->touch_input, 2209 - SW_MUTE_DEVICE, !(*is_touch_on)); 2210 - input_sync(wacom_wac->shared->touch_input); 2211 - } 2212 2125 break; 2213 2126 2214 2127 case WACOM_HID_WD_MODE_CHANGE: ··· 2367 2312 value = field->logical_maximum - value; 2368 2313 break; 2369 2314 case HID_DG_INRANGE: 2315 + mod_timer(&wacom->idleprox_timer, jiffies + msecs_to_jiffies(100)); 2370 2316 wacom_wac->hid_data.inrange_state = value; 2371 2317 if (!(features->quirks & WACOM_QUIRK_SENSE)) 2372 2318 wacom_wac->hid_data.sense_state = value; ··· 2392 2336 } 2393 2337 return; 2394 2338 case HID_DG_TWIST: 2339 + /* don't modify the value if the pen doesn't support the feature */ 2340 + if (!wacom_is_art_pen(wacom_wac->id[0])) return; 2341 + 2395 2342 /* 2396 2343 * Userspace expects pen twist to have its zero point when 2397 2344 * the buttons/finger is on the tablet's left. HID values ··· 2881 2822 /* usage tests must precede field tests */ 2882 2823 if (WACOM_BATTERY_USAGE(usage)) 2883 2824 wacom_wac_battery_event(hdev, field, usage, value); 2884 - else if (WACOM_PAD_FIELD(field) && wacom->wacom_wac.pad_input) 2825 + else if (WACOM_PAD_FIELD(field)) 2885 2826 wacom_wac_pad_event(hdev, field, usage, value); 2886 2827 else if (WACOM_PEN_FIELD(field) && wacom->wacom_wac.pen_input) 2887 2828 wacom_wac_pen_event(hdev, field, usage, value);