18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright (c) 2013 Andrew Duggan <aduggan@synaptics.com> 48c2ecf20Sopenharmony_ci * Copyright (c) 2013 Synaptics Incorporated 58c2ecf20Sopenharmony_ci * Copyright (c) 2014 Benjamin Tissoires <benjamin.tissoires@gmail.com> 68c2ecf20Sopenharmony_ci * Copyright (c) 2014 Red Hat, Inc 78c2ecf20Sopenharmony_ci */ 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/kernel.h> 108c2ecf20Sopenharmony_ci#include <linux/hid.h> 118c2ecf20Sopenharmony_ci#include <linux/input.h> 128c2ecf20Sopenharmony_ci#include <linux/input/mt.h> 138c2ecf20Sopenharmony_ci#include <linux/irq.h> 148c2ecf20Sopenharmony_ci#include <linux/irqdomain.h> 158c2ecf20Sopenharmony_ci#include <linux/module.h> 168c2ecf20Sopenharmony_ci#include <linux/pm.h> 178c2ecf20Sopenharmony_ci#include <linux/slab.h> 188c2ecf20Sopenharmony_ci#include <linux/wait.h> 198c2ecf20Sopenharmony_ci#include <linux/sched.h> 208c2ecf20Sopenharmony_ci#include <linux/rmi.h> 218c2ecf20Sopenharmony_ci#include "hid-ids.h" 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci#define RMI_MOUSE_REPORT_ID 0x01 /* Mouse emulation Report */ 248c2ecf20Sopenharmony_ci#define RMI_WRITE_REPORT_ID 0x09 /* Output Report */ 258c2ecf20Sopenharmony_ci#define RMI_READ_ADDR_REPORT_ID 0x0a /* Output Report */ 268c2ecf20Sopenharmony_ci#define RMI_READ_DATA_REPORT_ID 0x0b /* Input Report */ 278c2ecf20Sopenharmony_ci#define RMI_ATTN_REPORT_ID 0x0c /* Input Report */ 288c2ecf20Sopenharmony_ci#define RMI_SET_RMI_MODE_REPORT_ID 0x0f /* Feature Report */ 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* flags */ 318c2ecf20Sopenharmony_ci#define RMI_READ_REQUEST_PENDING 0 328c2ecf20Sopenharmony_ci#define RMI_READ_DATA_PENDING 1 338c2ecf20Sopenharmony_ci#define RMI_STARTED 2 348c2ecf20Sopenharmony_ci 358c2ecf20Sopenharmony_ci/* device flags */ 368c2ecf20Sopenharmony_ci#define RMI_DEVICE BIT(0) 378c2ecf20Sopenharmony_ci#define RMI_DEVICE_HAS_PHYS_BUTTONS BIT(1) 388c2ecf20Sopenharmony_ci#define RMI_DEVICE_OUTPUT_SET_REPORT BIT(2) 398c2ecf20Sopenharmony_ci 408c2ecf20Sopenharmony_ci/* 418c2ecf20Sopenharmony_ci * retrieve the ctrl registers 428c2ecf20Sopenharmony_ci * the ctrl register has a size of 20 but a fw bug split it into 16 + 4, 438c2ecf20Sopenharmony_ci * and there is no way to know if the first 20 bytes are here or not. 448c2ecf20Sopenharmony_ci * We use only the first 12 bytes, so get only them. 458c2ecf20Sopenharmony_ci */ 468c2ecf20Sopenharmony_ci#define RMI_F11_CTRL_REG_COUNT 12 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cienum rmi_mode_type { 498c2ecf20Sopenharmony_ci RMI_MODE_OFF = 0, 508c2ecf20Sopenharmony_ci RMI_MODE_ATTN_REPORTS = 1, 518c2ecf20Sopenharmony_ci RMI_MODE_NO_PACKED_ATTN_REPORTS = 2, 528c2ecf20Sopenharmony_ci}; 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/** 558c2ecf20Sopenharmony_ci * struct rmi_data - stores information for hid communication 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * @page_mutex: Locks current page to avoid changing pages in unexpected ways. 588c2ecf20Sopenharmony_ci * @page: Keeps track of the current virtual page 598c2ecf20Sopenharmony_ci * @xport: transport device to be registered with the RMI4 core. 608c2ecf20Sopenharmony_ci * 618c2ecf20Sopenharmony_ci * @wait: Used for waiting for read data 628c2ecf20Sopenharmony_ci * 638c2ecf20Sopenharmony_ci * @writeReport: output buffer when writing RMI registers 648c2ecf20Sopenharmony_ci * @readReport: input buffer when reading RMI registers 658c2ecf20Sopenharmony_ci * 668c2ecf20Sopenharmony_ci * @input_report_size: size of an input report (advertised by HID) 678c2ecf20Sopenharmony_ci * @output_report_size: size of an output report (advertised by HID) 688c2ecf20Sopenharmony_ci * 698c2ecf20Sopenharmony_ci * @flags: flags for the current device (started, reading, etc...) 708c2ecf20Sopenharmony_ci * 718c2ecf20Sopenharmony_ci * @reset_work: worker which will be called in case of a mouse report 728c2ecf20Sopenharmony_ci * @hdev: pointer to the struct hid_device 738c2ecf20Sopenharmony_ci * 748c2ecf20Sopenharmony_ci * @device_flags: flags which describe the device 758c2ecf20Sopenharmony_ci * 768c2ecf20Sopenharmony_ci * @domain: the IRQ domain allocated for this RMI4 device 778c2ecf20Sopenharmony_ci * @rmi_irq: the irq that will be used to generate events to rmi-core 788c2ecf20Sopenharmony_ci */ 798c2ecf20Sopenharmony_cistruct rmi_data { 808c2ecf20Sopenharmony_ci struct mutex page_mutex; 818c2ecf20Sopenharmony_ci int page; 828c2ecf20Sopenharmony_ci struct rmi_transport_dev xport; 838c2ecf20Sopenharmony_ci 848c2ecf20Sopenharmony_ci wait_queue_head_t wait; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_ci u8 *writeReport; 878c2ecf20Sopenharmony_ci u8 *readReport; 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_ci u32 input_report_size; 908c2ecf20Sopenharmony_ci u32 output_report_size; 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_ci unsigned long flags; 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci struct work_struct reset_work; 958c2ecf20Sopenharmony_ci struct hid_device *hdev; 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_ci unsigned long device_flags; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci struct irq_domain *domain; 1008c2ecf20Sopenharmony_ci int rmi_irq; 1018c2ecf20Sopenharmony_ci}; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_ci#define RMI_PAGE(addr) (((addr) >> 8) & 0xff) 1048c2ecf20Sopenharmony_ci 1058c2ecf20Sopenharmony_cistatic int rmi_write_report(struct hid_device *hdev, u8 *report, int len); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci/** 1088c2ecf20Sopenharmony_ci * rmi_set_page - Set RMI page 1098c2ecf20Sopenharmony_ci * @hdev: The pointer to the hid_device struct 1108c2ecf20Sopenharmony_ci * @page: The new page address. 1118c2ecf20Sopenharmony_ci * 1128c2ecf20Sopenharmony_ci * RMI devices have 16-bit addressing, but some of the physical 1138c2ecf20Sopenharmony_ci * implementations (like SMBus) only have 8-bit addressing. So RMI implements 1148c2ecf20Sopenharmony_ci * a page address at 0xff of every page so we can reliable page addresses 1158c2ecf20Sopenharmony_ci * every 256 registers. 1168c2ecf20Sopenharmony_ci * 1178c2ecf20Sopenharmony_ci * The page_mutex lock must be held when this function is entered. 1188c2ecf20Sopenharmony_ci * 1198c2ecf20Sopenharmony_ci * Returns zero on success, non-zero on failure. 1208c2ecf20Sopenharmony_ci */ 1218c2ecf20Sopenharmony_cistatic int rmi_set_page(struct hid_device *hdev, u8 page) 1228c2ecf20Sopenharmony_ci{ 1238c2ecf20Sopenharmony_ci struct rmi_data *data = hid_get_drvdata(hdev); 1248c2ecf20Sopenharmony_ci int retval; 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci data->writeReport[0] = RMI_WRITE_REPORT_ID; 1278c2ecf20Sopenharmony_ci data->writeReport[1] = 1; 1288c2ecf20Sopenharmony_ci data->writeReport[2] = 0xFF; 1298c2ecf20Sopenharmony_ci data->writeReport[4] = page; 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci retval = rmi_write_report(hdev, data->writeReport, 1328c2ecf20Sopenharmony_ci data->output_report_size); 1338c2ecf20Sopenharmony_ci if (retval != data->output_report_size) { 1348c2ecf20Sopenharmony_ci dev_err(&hdev->dev, 1358c2ecf20Sopenharmony_ci "%s: set page failed: %d.", __func__, retval); 1368c2ecf20Sopenharmony_ci return retval; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci 1398c2ecf20Sopenharmony_ci data->page = page; 1408c2ecf20Sopenharmony_ci return 0; 1418c2ecf20Sopenharmony_ci} 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_cistatic int rmi_set_mode(struct hid_device *hdev, u8 mode) 1448c2ecf20Sopenharmony_ci{ 1458c2ecf20Sopenharmony_ci int ret; 1468c2ecf20Sopenharmony_ci const u8 txbuf[2] = {RMI_SET_RMI_MODE_REPORT_ID, mode}; 1478c2ecf20Sopenharmony_ci u8 *buf; 1488c2ecf20Sopenharmony_ci 1498c2ecf20Sopenharmony_ci buf = kmemdup(txbuf, sizeof(txbuf), GFP_KERNEL); 1508c2ecf20Sopenharmony_ci if (!buf) 1518c2ecf20Sopenharmony_ci return -ENOMEM; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci ret = hid_hw_raw_request(hdev, RMI_SET_RMI_MODE_REPORT_ID, buf, 1548c2ecf20Sopenharmony_ci sizeof(txbuf), HID_FEATURE_REPORT, HID_REQ_SET_REPORT); 1558c2ecf20Sopenharmony_ci kfree(buf); 1568c2ecf20Sopenharmony_ci if (ret < 0) { 1578c2ecf20Sopenharmony_ci dev_err(&hdev->dev, "unable to set rmi mode to %d (%d)\n", mode, 1588c2ecf20Sopenharmony_ci ret); 1598c2ecf20Sopenharmony_ci return ret; 1608c2ecf20Sopenharmony_ci } 1618c2ecf20Sopenharmony_ci 1628c2ecf20Sopenharmony_ci return 0; 1638c2ecf20Sopenharmony_ci} 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_cistatic int rmi_write_report(struct hid_device *hdev, u8 *report, int len) 1668c2ecf20Sopenharmony_ci{ 1678c2ecf20Sopenharmony_ci struct rmi_data *data = hid_get_drvdata(hdev); 1688c2ecf20Sopenharmony_ci int ret; 1698c2ecf20Sopenharmony_ci 1708c2ecf20Sopenharmony_ci if (data->device_flags & RMI_DEVICE_OUTPUT_SET_REPORT) { 1718c2ecf20Sopenharmony_ci /* 1728c2ecf20Sopenharmony_ci * Talk to device by using SET_REPORT requests instead. 1738c2ecf20Sopenharmony_ci */ 1748c2ecf20Sopenharmony_ci ret = hid_hw_raw_request(hdev, report[0], report, 1758c2ecf20Sopenharmony_ci len, HID_OUTPUT_REPORT, HID_REQ_SET_REPORT); 1768c2ecf20Sopenharmony_ci } else { 1778c2ecf20Sopenharmony_ci ret = hid_hw_output_report(hdev, (void *)report, len); 1788c2ecf20Sopenharmony_ci } 1798c2ecf20Sopenharmony_ci 1808c2ecf20Sopenharmony_ci if (ret < 0) { 1818c2ecf20Sopenharmony_ci dev_err(&hdev->dev, "failed to write hid report (%d)\n", ret); 1828c2ecf20Sopenharmony_ci return ret; 1838c2ecf20Sopenharmony_ci } 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_ci return ret; 1868c2ecf20Sopenharmony_ci} 1878c2ecf20Sopenharmony_ci 1888c2ecf20Sopenharmony_cistatic int rmi_hid_read_block(struct rmi_transport_dev *xport, u16 addr, 1898c2ecf20Sopenharmony_ci void *buf, size_t len) 1908c2ecf20Sopenharmony_ci{ 1918c2ecf20Sopenharmony_ci struct rmi_data *data = container_of(xport, struct rmi_data, xport); 1928c2ecf20Sopenharmony_ci struct hid_device *hdev = data->hdev; 1938c2ecf20Sopenharmony_ci int ret; 1948c2ecf20Sopenharmony_ci int bytes_read; 1958c2ecf20Sopenharmony_ci int bytes_needed; 1968c2ecf20Sopenharmony_ci int retries; 1978c2ecf20Sopenharmony_ci int read_input_count; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci mutex_lock(&data->page_mutex); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci if (RMI_PAGE(addr) != data->page) { 2028c2ecf20Sopenharmony_ci ret = rmi_set_page(hdev, RMI_PAGE(addr)); 2038c2ecf20Sopenharmony_ci if (ret < 0) 2048c2ecf20Sopenharmony_ci goto exit; 2058c2ecf20Sopenharmony_ci } 2068c2ecf20Sopenharmony_ci 2078c2ecf20Sopenharmony_ci for (retries = 5; retries > 0; retries--) { 2088c2ecf20Sopenharmony_ci data->writeReport[0] = RMI_READ_ADDR_REPORT_ID; 2098c2ecf20Sopenharmony_ci data->writeReport[1] = 0; /* old 1 byte read count */ 2108c2ecf20Sopenharmony_ci data->writeReport[2] = addr & 0xFF; 2118c2ecf20Sopenharmony_ci data->writeReport[3] = (addr >> 8) & 0xFF; 2128c2ecf20Sopenharmony_ci data->writeReport[4] = len & 0xFF; 2138c2ecf20Sopenharmony_ci data->writeReport[5] = (len >> 8) & 0xFF; 2148c2ecf20Sopenharmony_ci 2158c2ecf20Sopenharmony_ci set_bit(RMI_READ_REQUEST_PENDING, &data->flags); 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci ret = rmi_write_report(hdev, data->writeReport, 2188c2ecf20Sopenharmony_ci data->output_report_size); 2198c2ecf20Sopenharmony_ci if (ret != data->output_report_size) { 2208c2ecf20Sopenharmony_ci dev_err(&hdev->dev, 2218c2ecf20Sopenharmony_ci "failed to write request output report (%d)\n", 2228c2ecf20Sopenharmony_ci ret); 2238c2ecf20Sopenharmony_ci goto exit; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci bytes_read = 0; 2278c2ecf20Sopenharmony_ci bytes_needed = len; 2288c2ecf20Sopenharmony_ci while (bytes_read < len) { 2298c2ecf20Sopenharmony_ci if (!wait_event_timeout(data->wait, 2308c2ecf20Sopenharmony_ci test_bit(RMI_READ_DATA_PENDING, &data->flags), 2318c2ecf20Sopenharmony_ci msecs_to_jiffies(1000))) { 2328c2ecf20Sopenharmony_ci hid_warn(hdev, "%s: timeout elapsed\n", 2338c2ecf20Sopenharmony_ci __func__); 2348c2ecf20Sopenharmony_ci ret = -EAGAIN; 2358c2ecf20Sopenharmony_ci break; 2368c2ecf20Sopenharmony_ci } 2378c2ecf20Sopenharmony_ci 2388c2ecf20Sopenharmony_ci read_input_count = data->readReport[1]; 2398c2ecf20Sopenharmony_ci memcpy(buf + bytes_read, &data->readReport[2], 2408c2ecf20Sopenharmony_ci read_input_count < bytes_needed ? 2418c2ecf20Sopenharmony_ci read_input_count : bytes_needed); 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci bytes_read += read_input_count; 2448c2ecf20Sopenharmony_ci bytes_needed -= read_input_count; 2458c2ecf20Sopenharmony_ci clear_bit(RMI_READ_DATA_PENDING, &data->flags); 2468c2ecf20Sopenharmony_ci } 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (ret >= 0) { 2498c2ecf20Sopenharmony_ci ret = 0; 2508c2ecf20Sopenharmony_ci break; 2518c2ecf20Sopenharmony_ci } 2528c2ecf20Sopenharmony_ci } 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ciexit: 2558c2ecf20Sopenharmony_ci clear_bit(RMI_READ_REQUEST_PENDING, &data->flags); 2568c2ecf20Sopenharmony_ci mutex_unlock(&data->page_mutex); 2578c2ecf20Sopenharmony_ci return ret; 2588c2ecf20Sopenharmony_ci} 2598c2ecf20Sopenharmony_ci 2608c2ecf20Sopenharmony_cistatic int rmi_hid_write_block(struct rmi_transport_dev *xport, u16 addr, 2618c2ecf20Sopenharmony_ci const void *buf, size_t len) 2628c2ecf20Sopenharmony_ci{ 2638c2ecf20Sopenharmony_ci struct rmi_data *data = container_of(xport, struct rmi_data, xport); 2648c2ecf20Sopenharmony_ci struct hid_device *hdev = data->hdev; 2658c2ecf20Sopenharmony_ci int ret; 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci mutex_lock(&data->page_mutex); 2688c2ecf20Sopenharmony_ci 2698c2ecf20Sopenharmony_ci if (RMI_PAGE(addr) != data->page) { 2708c2ecf20Sopenharmony_ci ret = rmi_set_page(hdev, RMI_PAGE(addr)); 2718c2ecf20Sopenharmony_ci if (ret < 0) 2728c2ecf20Sopenharmony_ci goto exit; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci data->writeReport[0] = RMI_WRITE_REPORT_ID; 2768c2ecf20Sopenharmony_ci data->writeReport[1] = len; 2778c2ecf20Sopenharmony_ci data->writeReport[2] = addr & 0xFF; 2788c2ecf20Sopenharmony_ci data->writeReport[3] = (addr >> 8) & 0xFF; 2798c2ecf20Sopenharmony_ci memcpy(&data->writeReport[4], buf, len); 2808c2ecf20Sopenharmony_ci 2818c2ecf20Sopenharmony_ci ret = rmi_write_report(hdev, data->writeReport, 2828c2ecf20Sopenharmony_ci data->output_report_size); 2838c2ecf20Sopenharmony_ci if (ret < 0) { 2848c2ecf20Sopenharmony_ci dev_err(&hdev->dev, 2858c2ecf20Sopenharmony_ci "failed to write request output report (%d)\n", 2868c2ecf20Sopenharmony_ci ret); 2878c2ecf20Sopenharmony_ci goto exit; 2888c2ecf20Sopenharmony_ci } 2898c2ecf20Sopenharmony_ci ret = 0; 2908c2ecf20Sopenharmony_ci 2918c2ecf20Sopenharmony_ciexit: 2928c2ecf20Sopenharmony_ci mutex_unlock(&data->page_mutex); 2938c2ecf20Sopenharmony_ci return ret; 2948c2ecf20Sopenharmony_ci} 2958c2ecf20Sopenharmony_ci 2968c2ecf20Sopenharmony_cistatic int rmi_reset_attn_mode(struct hid_device *hdev) 2978c2ecf20Sopenharmony_ci{ 2988c2ecf20Sopenharmony_ci struct rmi_data *data = hid_get_drvdata(hdev); 2998c2ecf20Sopenharmony_ci struct rmi_device *rmi_dev = data->xport.rmi_dev; 3008c2ecf20Sopenharmony_ci int ret; 3018c2ecf20Sopenharmony_ci 3028c2ecf20Sopenharmony_ci ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); 3038c2ecf20Sopenharmony_ci if (ret) 3048c2ecf20Sopenharmony_ci return ret; 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_ci if (test_bit(RMI_STARTED, &data->flags)) 3078c2ecf20Sopenharmony_ci ret = rmi_dev->driver->reset_handler(rmi_dev); 3088c2ecf20Sopenharmony_ci 3098c2ecf20Sopenharmony_ci return ret; 3108c2ecf20Sopenharmony_ci} 3118c2ecf20Sopenharmony_ci 3128c2ecf20Sopenharmony_cistatic void rmi_reset_work(struct work_struct *work) 3138c2ecf20Sopenharmony_ci{ 3148c2ecf20Sopenharmony_ci struct rmi_data *hdata = container_of(work, struct rmi_data, 3158c2ecf20Sopenharmony_ci reset_work); 3168c2ecf20Sopenharmony_ci 3178c2ecf20Sopenharmony_ci /* switch the device to RMI if we receive a generic mouse report */ 3188c2ecf20Sopenharmony_ci rmi_reset_attn_mode(hdata->hdev); 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_cistatic int rmi_input_event(struct hid_device *hdev, u8 *data, int size) 3228c2ecf20Sopenharmony_ci{ 3238c2ecf20Sopenharmony_ci struct rmi_data *hdata = hid_get_drvdata(hdev); 3248c2ecf20Sopenharmony_ci struct rmi_device *rmi_dev = hdata->xport.rmi_dev; 3258c2ecf20Sopenharmony_ci unsigned long flags; 3268c2ecf20Sopenharmony_ci 3278c2ecf20Sopenharmony_ci if (!(test_bit(RMI_STARTED, &hdata->flags))) 3288c2ecf20Sopenharmony_ci return 0; 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci local_irq_save(flags); 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci rmi_set_attn_data(rmi_dev, data[1], &data[2], size - 2); 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci generic_handle_irq(hdata->rmi_irq); 3358c2ecf20Sopenharmony_ci 3368c2ecf20Sopenharmony_ci local_irq_restore(flags); 3378c2ecf20Sopenharmony_ci 3388c2ecf20Sopenharmony_ci return 1; 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_cistatic int rmi_read_data_event(struct hid_device *hdev, u8 *data, int size) 3428c2ecf20Sopenharmony_ci{ 3438c2ecf20Sopenharmony_ci struct rmi_data *hdata = hid_get_drvdata(hdev); 3448c2ecf20Sopenharmony_ci 3458c2ecf20Sopenharmony_ci if (!test_bit(RMI_READ_REQUEST_PENDING, &hdata->flags)) { 3468c2ecf20Sopenharmony_ci hid_dbg(hdev, "no read request pending\n"); 3478c2ecf20Sopenharmony_ci return 0; 3488c2ecf20Sopenharmony_ci } 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci memcpy(hdata->readReport, data, size < hdata->input_report_size ? 3518c2ecf20Sopenharmony_ci size : hdata->input_report_size); 3528c2ecf20Sopenharmony_ci set_bit(RMI_READ_DATA_PENDING, &hdata->flags); 3538c2ecf20Sopenharmony_ci wake_up(&hdata->wait); 3548c2ecf20Sopenharmony_ci 3558c2ecf20Sopenharmony_ci return 1; 3568c2ecf20Sopenharmony_ci} 3578c2ecf20Sopenharmony_ci 3588c2ecf20Sopenharmony_cistatic int rmi_check_sanity(struct hid_device *hdev, u8 *data, int size) 3598c2ecf20Sopenharmony_ci{ 3608c2ecf20Sopenharmony_ci int valid_size = size; 3618c2ecf20Sopenharmony_ci /* 3628c2ecf20Sopenharmony_ci * On the Dell XPS 13 9333, the bus sometimes get confused and fills 3638c2ecf20Sopenharmony_ci * the report with a sentinel value "ff". Synaptics told us that such 3648c2ecf20Sopenharmony_ci * behavior does not comes from the touchpad itself, so we filter out 3658c2ecf20Sopenharmony_ci * such reports here. 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ci 3688c2ecf20Sopenharmony_ci while ((data[valid_size - 1] == 0xff) && valid_size > 0) 3698c2ecf20Sopenharmony_ci valid_size--; 3708c2ecf20Sopenharmony_ci 3718c2ecf20Sopenharmony_ci return valid_size; 3728c2ecf20Sopenharmony_ci} 3738c2ecf20Sopenharmony_ci 3748c2ecf20Sopenharmony_cistatic int rmi_raw_event(struct hid_device *hdev, 3758c2ecf20Sopenharmony_ci struct hid_report *report, u8 *data, int size) 3768c2ecf20Sopenharmony_ci{ 3778c2ecf20Sopenharmony_ci struct rmi_data *hdata = hid_get_drvdata(hdev); 3788c2ecf20Sopenharmony_ci 3798c2ecf20Sopenharmony_ci if (!(hdata->device_flags & RMI_DEVICE)) 3808c2ecf20Sopenharmony_ci return 0; 3818c2ecf20Sopenharmony_ci 3828c2ecf20Sopenharmony_ci size = rmi_check_sanity(hdev, data, size); 3838c2ecf20Sopenharmony_ci if (size < 2) 3848c2ecf20Sopenharmony_ci return 0; 3858c2ecf20Sopenharmony_ci 3868c2ecf20Sopenharmony_ci switch (data[0]) { 3878c2ecf20Sopenharmony_ci case RMI_READ_DATA_REPORT_ID: 3888c2ecf20Sopenharmony_ci return rmi_read_data_event(hdev, data, size); 3898c2ecf20Sopenharmony_ci case RMI_ATTN_REPORT_ID: 3908c2ecf20Sopenharmony_ci return rmi_input_event(hdev, data, size); 3918c2ecf20Sopenharmony_ci default: 3928c2ecf20Sopenharmony_ci return 1; 3938c2ecf20Sopenharmony_ci } 3948c2ecf20Sopenharmony_ci 3958c2ecf20Sopenharmony_ci return 0; 3968c2ecf20Sopenharmony_ci} 3978c2ecf20Sopenharmony_ci 3988c2ecf20Sopenharmony_cistatic int rmi_event(struct hid_device *hdev, struct hid_field *field, 3998c2ecf20Sopenharmony_ci struct hid_usage *usage, __s32 value) 4008c2ecf20Sopenharmony_ci{ 4018c2ecf20Sopenharmony_ci struct rmi_data *data = hid_get_drvdata(hdev); 4028c2ecf20Sopenharmony_ci 4038c2ecf20Sopenharmony_ci if ((data->device_flags & RMI_DEVICE) && 4048c2ecf20Sopenharmony_ci (field->application == HID_GD_POINTER || 4058c2ecf20Sopenharmony_ci field->application == HID_GD_MOUSE)) { 4068c2ecf20Sopenharmony_ci if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) { 4078c2ecf20Sopenharmony_ci if ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON) 4088c2ecf20Sopenharmony_ci return 0; 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_ci if ((usage->hid == HID_GD_X || usage->hid == HID_GD_Y) 4118c2ecf20Sopenharmony_ci && !value) 4128c2ecf20Sopenharmony_ci return 1; 4138c2ecf20Sopenharmony_ci } 4148c2ecf20Sopenharmony_ci 4158c2ecf20Sopenharmony_ci schedule_work(&data->reset_work); 4168c2ecf20Sopenharmony_ci return 1; 4178c2ecf20Sopenharmony_ci } 4188c2ecf20Sopenharmony_ci 4198c2ecf20Sopenharmony_ci return 0; 4208c2ecf20Sopenharmony_ci} 4218c2ecf20Sopenharmony_ci 4228c2ecf20Sopenharmony_cistatic void rmi_report(struct hid_device *hid, struct hid_report *report) 4238c2ecf20Sopenharmony_ci{ 4248c2ecf20Sopenharmony_ci struct hid_field *field = report->field[0]; 4258c2ecf20Sopenharmony_ci 4268c2ecf20Sopenharmony_ci if (!(hid->claimed & HID_CLAIMED_INPUT)) 4278c2ecf20Sopenharmony_ci return; 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci switch (report->id) { 4308c2ecf20Sopenharmony_ci case RMI_READ_DATA_REPORT_ID: 4318c2ecf20Sopenharmony_ci case RMI_ATTN_REPORT_ID: 4328c2ecf20Sopenharmony_ci return; 4338c2ecf20Sopenharmony_ci } 4348c2ecf20Sopenharmony_ci 4358c2ecf20Sopenharmony_ci if (field && field->hidinput && field->hidinput->input) 4368c2ecf20Sopenharmony_ci input_sync(field->hidinput->input); 4378c2ecf20Sopenharmony_ci} 4388c2ecf20Sopenharmony_ci 4398c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4408c2ecf20Sopenharmony_cistatic int rmi_suspend(struct hid_device *hdev, pm_message_t message) 4418c2ecf20Sopenharmony_ci{ 4428c2ecf20Sopenharmony_ci struct rmi_data *data = hid_get_drvdata(hdev); 4438c2ecf20Sopenharmony_ci struct rmi_device *rmi_dev = data->xport.rmi_dev; 4448c2ecf20Sopenharmony_ci int ret; 4458c2ecf20Sopenharmony_ci 4468c2ecf20Sopenharmony_ci if (!(data->device_flags & RMI_DEVICE)) 4478c2ecf20Sopenharmony_ci return 0; 4488c2ecf20Sopenharmony_ci 4498c2ecf20Sopenharmony_ci ret = rmi_driver_suspend(rmi_dev, false); 4508c2ecf20Sopenharmony_ci if (ret) { 4518c2ecf20Sopenharmony_ci hid_warn(hdev, "Failed to suspend device: %d\n", ret); 4528c2ecf20Sopenharmony_ci return ret; 4538c2ecf20Sopenharmony_ci } 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int rmi_post_resume(struct hid_device *hdev) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct rmi_data *data = hid_get_drvdata(hdev); 4618c2ecf20Sopenharmony_ci struct rmi_device *rmi_dev = data->xport.rmi_dev; 4628c2ecf20Sopenharmony_ci int ret; 4638c2ecf20Sopenharmony_ci 4648c2ecf20Sopenharmony_ci if (!(data->device_flags & RMI_DEVICE)) 4658c2ecf20Sopenharmony_ci return 0; 4668c2ecf20Sopenharmony_ci 4678c2ecf20Sopenharmony_ci /* Make sure the HID device is ready to receive events */ 4688c2ecf20Sopenharmony_ci ret = hid_hw_open(hdev); 4698c2ecf20Sopenharmony_ci if (ret) 4708c2ecf20Sopenharmony_ci return ret; 4718c2ecf20Sopenharmony_ci 4728c2ecf20Sopenharmony_ci ret = rmi_reset_attn_mode(hdev); 4738c2ecf20Sopenharmony_ci if (ret) 4748c2ecf20Sopenharmony_ci goto out; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci ret = rmi_driver_resume(rmi_dev, false); 4778c2ecf20Sopenharmony_ci if (ret) { 4788c2ecf20Sopenharmony_ci hid_warn(hdev, "Failed to resume device: %d\n", ret); 4798c2ecf20Sopenharmony_ci goto out; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ciout: 4838c2ecf20Sopenharmony_ci hid_hw_close(hdev); 4848c2ecf20Sopenharmony_ci return ret; 4858c2ecf20Sopenharmony_ci} 4868c2ecf20Sopenharmony_ci#endif /* CONFIG_PM */ 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_cistatic int rmi_hid_reset(struct rmi_transport_dev *xport, u16 reset_addr) 4898c2ecf20Sopenharmony_ci{ 4908c2ecf20Sopenharmony_ci struct rmi_data *data = container_of(xport, struct rmi_data, xport); 4918c2ecf20Sopenharmony_ci struct hid_device *hdev = data->hdev; 4928c2ecf20Sopenharmony_ci 4938c2ecf20Sopenharmony_ci return rmi_reset_attn_mode(hdev); 4948c2ecf20Sopenharmony_ci} 4958c2ecf20Sopenharmony_ci 4968c2ecf20Sopenharmony_cistatic int rmi_input_configured(struct hid_device *hdev, struct hid_input *hi) 4978c2ecf20Sopenharmony_ci{ 4988c2ecf20Sopenharmony_ci struct rmi_data *data = hid_get_drvdata(hdev); 4998c2ecf20Sopenharmony_ci struct input_dev *input = hi->input; 5008c2ecf20Sopenharmony_ci int ret = 0; 5018c2ecf20Sopenharmony_ci 5028c2ecf20Sopenharmony_ci if (!(data->device_flags & RMI_DEVICE)) 5038c2ecf20Sopenharmony_ci return 0; 5048c2ecf20Sopenharmony_ci 5058c2ecf20Sopenharmony_ci data->xport.input = input; 5068c2ecf20Sopenharmony_ci 5078c2ecf20Sopenharmony_ci hid_dbg(hdev, "Opening low level driver\n"); 5088c2ecf20Sopenharmony_ci ret = hid_hw_open(hdev); 5098c2ecf20Sopenharmony_ci if (ret) 5108c2ecf20Sopenharmony_ci return ret; 5118c2ecf20Sopenharmony_ci 5128c2ecf20Sopenharmony_ci /* Allow incoming hid reports */ 5138c2ecf20Sopenharmony_ci hid_device_io_start(hdev); 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci ret = rmi_set_mode(hdev, RMI_MODE_ATTN_REPORTS); 5168c2ecf20Sopenharmony_ci if (ret < 0) { 5178c2ecf20Sopenharmony_ci dev_err(&hdev->dev, "failed to set rmi mode\n"); 5188c2ecf20Sopenharmony_ci goto exit; 5198c2ecf20Sopenharmony_ci } 5208c2ecf20Sopenharmony_ci 5218c2ecf20Sopenharmony_ci ret = rmi_set_page(hdev, 0); 5228c2ecf20Sopenharmony_ci if (ret < 0) { 5238c2ecf20Sopenharmony_ci dev_err(&hdev->dev, "failed to set page select to 0.\n"); 5248c2ecf20Sopenharmony_ci goto exit; 5258c2ecf20Sopenharmony_ci } 5268c2ecf20Sopenharmony_ci 5278c2ecf20Sopenharmony_ci ret = rmi_register_transport_device(&data->xport); 5288c2ecf20Sopenharmony_ci if (ret < 0) { 5298c2ecf20Sopenharmony_ci dev_err(&hdev->dev, "failed to register transport driver\n"); 5308c2ecf20Sopenharmony_ci goto exit; 5318c2ecf20Sopenharmony_ci } 5328c2ecf20Sopenharmony_ci 5338c2ecf20Sopenharmony_ci set_bit(RMI_STARTED, &data->flags); 5348c2ecf20Sopenharmony_ci 5358c2ecf20Sopenharmony_ciexit: 5368c2ecf20Sopenharmony_ci hid_device_io_stop(hdev); 5378c2ecf20Sopenharmony_ci hid_hw_close(hdev); 5388c2ecf20Sopenharmony_ci return ret; 5398c2ecf20Sopenharmony_ci} 5408c2ecf20Sopenharmony_ci 5418c2ecf20Sopenharmony_cistatic int rmi_input_mapping(struct hid_device *hdev, 5428c2ecf20Sopenharmony_ci struct hid_input *hi, struct hid_field *field, 5438c2ecf20Sopenharmony_ci struct hid_usage *usage, unsigned long **bit, int *max) 5448c2ecf20Sopenharmony_ci{ 5458c2ecf20Sopenharmony_ci struct rmi_data *data = hid_get_drvdata(hdev); 5468c2ecf20Sopenharmony_ci 5478c2ecf20Sopenharmony_ci /* 5488c2ecf20Sopenharmony_ci * we want to make HID ignore the advertised HID collection 5498c2ecf20Sopenharmony_ci * for RMI deivces 5508c2ecf20Sopenharmony_ci */ 5518c2ecf20Sopenharmony_ci if (data->device_flags & RMI_DEVICE) { 5528c2ecf20Sopenharmony_ci if ((data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) && 5538c2ecf20Sopenharmony_ci ((usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)) 5548c2ecf20Sopenharmony_ci return 0; 5558c2ecf20Sopenharmony_ci 5568c2ecf20Sopenharmony_ci return -1; 5578c2ecf20Sopenharmony_ci } 5588c2ecf20Sopenharmony_ci 5598c2ecf20Sopenharmony_ci return 0; 5608c2ecf20Sopenharmony_ci} 5618c2ecf20Sopenharmony_ci 5628c2ecf20Sopenharmony_cistatic int rmi_check_valid_report_id(struct hid_device *hdev, unsigned type, 5638c2ecf20Sopenharmony_ci unsigned id, struct hid_report **report) 5648c2ecf20Sopenharmony_ci{ 5658c2ecf20Sopenharmony_ci int i; 5668c2ecf20Sopenharmony_ci 5678c2ecf20Sopenharmony_ci *report = hdev->report_enum[type].report_id_hash[id]; 5688c2ecf20Sopenharmony_ci if (*report) { 5698c2ecf20Sopenharmony_ci for (i = 0; i < (*report)->maxfield; i++) { 5708c2ecf20Sopenharmony_ci unsigned app = (*report)->field[i]->application; 5718c2ecf20Sopenharmony_ci if ((app & HID_USAGE_PAGE) >= HID_UP_MSVENDOR) 5728c2ecf20Sopenharmony_ci return 1; 5738c2ecf20Sopenharmony_ci } 5748c2ecf20Sopenharmony_ci } 5758c2ecf20Sopenharmony_ci 5768c2ecf20Sopenharmony_ci return 0; 5778c2ecf20Sopenharmony_ci} 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_cistatic struct rmi_device_platform_data rmi_hid_pdata = { 5808c2ecf20Sopenharmony_ci .sensor_pdata = { 5818c2ecf20Sopenharmony_ci .sensor_type = rmi_sensor_touchpad, 5828c2ecf20Sopenharmony_ci .axis_align.flip_y = true, 5838c2ecf20Sopenharmony_ci .dribble = RMI_REG_STATE_ON, 5848c2ecf20Sopenharmony_ci .palm_detect = RMI_REG_STATE_OFF, 5858c2ecf20Sopenharmony_ci }, 5868c2ecf20Sopenharmony_ci}; 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_cistatic const struct rmi_transport_ops hid_rmi_ops = { 5898c2ecf20Sopenharmony_ci .write_block = rmi_hid_write_block, 5908c2ecf20Sopenharmony_ci .read_block = rmi_hid_read_block, 5918c2ecf20Sopenharmony_ci .reset = rmi_hid_reset, 5928c2ecf20Sopenharmony_ci}; 5938c2ecf20Sopenharmony_ci 5948c2ecf20Sopenharmony_cistatic void rmi_irq_teardown(void *data) 5958c2ecf20Sopenharmony_ci{ 5968c2ecf20Sopenharmony_ci struct rmi_data *hdata = data; 5978c2ecf20Sopenharmony_ci struct irq_domain *domain = hdata->domain; 5988c2ecf20Sopenharmony_ci 5998c2ecf20Sopenharmony_ci if (!domain) 6008c2ecf20Sopenharmony_ci return; 6018c2ecf20Sopenharmony_ci 6028c2ecf20Sopenharmony_ci irq_dispose_mapping(irq_find_mapping(domain, 0)); 6038c2ecf20Sopenharmony_ci 6048c2ecf20Sopenharmony_ci irq_domain_remove(domain); 6058c2ecf20Sopenharmony_ci hdata->domain = NULL; 6068c2ecf20Sopenharmony_ci hdata->rmi_irq = 0; 6078c2ecf20Sopenharmony_ci} 6088c2ecf20Sopenharmony_ci 6098c2ecf20Sopenharmony_cistatic int rmi_irq_map(struct irq_domain *h, unsigned int virq, 6108c2ecf20Sopenharmony_ci irq_hw_number_t hw_irq_num) 6118c2ecf20Sopenharmony_ci{ 6128c2ecf20Sopenharmony_ci irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq); 6138c2ecf20Sopenharmony_ci 6148c2ecf20Sopenharmony_ci return 0; 6158c2ecf20Sopenharmony_ci} 6168c2ecf20Sopenharmony_ci 6178c2ecf20Sopenharmony_cistatic const struct irq_domain_ops rmi_irq_ops = { 6188c2ecf20Sopenharmony_ci .map = rmi_irq_map, 6198c2ecf20Sopenharmony_ci}; 6208c2ecf20Sopenharmony_ci 6218c2ecf20Sopenharmony_cistatic int rmi_setup_irq_domain(struct hid_device *hdev) 6228c2ecf20Sopenharmony_ci{ 6238c2ecf20Sopenharmony_ci struct rmi_data *hdata = hid_get_drvdata(hdev); 6248c2ecf20Sopenharmony_ci int ret; 6258c2ecf20Sopenharmony_ci 6268c2ecf20Sopenharmony_ci hdata->domain = irq_domain_create_linear(hdev->dev.fwnode, 1, 6278c2ecf20Sopenharmony_ci &rmi_irq_ops, hdata); 6288c2ecf20Sopenharmony_ci if (!hdata->domain) 6298c2ecf20Sopenharmony_ci return -ENOMEM; 6308c2ecf20Sopenharmony_ci 6318c2ecf20Sopenharmony_ci ret = devm_add_action_or_reset(&hdev->dev, &rmi_irq_teardown, hdata); 6328c2ecf20Sopenharmony_ci if (ret) 6338c2ecf20Sopenharmony_ci return ret; 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci hdata->rmi_irq = irq_create_mapping(hdata->domain, 0); 6368c2ecf20Sopenharmony_ci if (hdata->rmi_irq <= 0) { 6378c2ecf20Sopenharmony_ci hid_err(hdev, "Can't allocate an IRQ\n"); 6388c2ecf20Sopenharmony_ci return hdata->rmi_irq < 0 ? hdata->rmi_irq : -ENXIO; 6398c2ecf20Sopenharmony_ci } 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci return 0; 6428c2ecf20Sopenharmony_ci} 6438c2ecf20Sopenharmony_ci 6448c2ecf20Sopenharmony_cistatic int rmi_probe(struct hid_device *hdev, const struct hid_device_id *id) 6458c2ecf20Sopenharmony_ci{ 6468c2ecf20Sopenharmony_ci struct rmi_data *data = NULL; 6478c2ecf20Sopenharmony_ci int ret; 6488c2ecf20Sopenharmony_ci size_t alloc_size; 6498c2ecf20Sopenharmony_ci struct hid_report *input_report; 6508c2ecf20Sopenharmony_ci struct hid_report *output_report; 6518c2ecf20Sopenharmony_ci struct hid_report *feature_report; 6528c2ecf20Sopenharmony_ci 6538c2ecf20Sopenharmony_ci data = devm_kzalloc(&hdev->dev, sizeof(struct rmi_data), GFP_KERNEL); 6548c2ecf20Sopenharmony_ci if (!data) 6558c2ecf20Sopenharmony_ci return -ENOMEM; 6568c2ecf20Sopenharmony_ci 6578c2ecf20Sopenharmony_ci INIT_WORK(&data->reset_work, rmi_reset_work); 6588c2ecf20Sopenharmony_ci data->hdev = hdev; 6598c2ecf20Sopenharmony_ci 6608c2ecf20Sopenharmony_ci hid_set_drvdata(hdev, data); 6618c2ecf20Sopenharmony_ci 6628c2ecf20Sopenharmony_ci hdev->quirks |= HID_QUIRK_NO_INIT_REPORTS; 6638c2ecf20Sopenharmony_ci hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC; 6648c2ecf20Sopenharmony_ci 6658c2ecf20Sopenharmony_ci ret = hid_parse(hdev); 6668c2ecf20Sopenharmony_ci if (ret) { 6678c2ecf20Sopenharmony_ci hid_err(hdev, "parse failed\n"); 6688c2ecf20Sopenharmony_ci return ret; 6698c2ecf20Sopenharmony_ci } 6708c2ecf20Sopenharmony_ci 6718c2ecf20Sopenharmony_ci if (id->driver_data) 6728c2ecf20Sopenharmony_ci data->device_flags = id->driver_data; 6738c2ecf20Sopenharmony_ci 6748c2ecf20Sopenharmony_ci /* 6758c2ecf20Sopenharmony_ci * Check for the RMI specific report ids. If they are misisng 6768c2ecf20Sopenharmony_ci * simply return and let the events be processed by hid-input 6778c2ecf20Sopenharmony_ci */ 6788c2ecf20Sopenharmony_ci if (!rmi_check_valid_report_id(hdev, HID_FEATURE_REPORT, 6798c2ecf20Sopenharmony_ci RMI_SET_RMI_MODE_REPORT_ID, &feature_report)) { 6808c2ecf20Sopenharmony_ci hid_dbg(hdev, "device does not have set mode feature report\n"); 6818c2ecf20Sopenharmony_ci goto start; 6828c2ecf20Sopenharmony_ci } 6838c2ecf20Sopenharmony_ci 6848c2ecf20Sopenharmony_ci if (!rmi_check_valid_report_id(hdev, HID_INPUT_REPORT, 6858c2ecf20Sopenharmony_ci RMI_ATTN_REPORT_ID, &input_report)) { 6868c2ecf20Sopenharmony_ci hid_dbg(hdev, "device does not have attention input report\n"); 6878c2ecf20Sopenharmony_ci goto start; 6888c2ecf20Sopenharmony_ci } 6898c2ecf20Sopenharmony_ci 6908c2ecf20Sopenharmony_ci data->input_report_size = hid_report_len(input_report); 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci if (!rmi_check_valid_report_id(hdev, HID_OUTPUT_REPORT, 6938c2ecf20Sopenharmony_ci RMI_WRITE_REPORT_ID, &output_report)) { 6948c2ecf20Sopenharmony_ci hid_dbg(hdev, 6958c2ecf20Sopenharmony_ci "device does not have rmi write output report\n"); 6968c2ecf20Sopenharmony_ci goto start; 6978c2ecf20Sopenharmony_ci } 6988c2ecf20Sopenharmony_ci 6998c2ecf20Sopenharmony_ci data->output_report_size = hid_report_len(output_report); 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci data->device_flags |= RMI_DEVICE; 7028c2ecf20Sopenharmony_ci alloc_size = data->output_report_size + data->input_report_size; 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL); 7058c2ecf20Sopenharmony_ci if (!data->writeReport) { 7068c2ecf20Sopenharmony_ci hid_err(hdev, "failed to allocate buffer for HID reports\n"); 7078c2ecf20Sopenharmony_ci return -ENOMEM; 7088c2ecf20Sopenharmony_ci } 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci data->readReport = data->writeReport + data->output_report_size; 7118c2ecf20Sopenharmony_ci 7128c2ecf20Sopenharmony_ci init_waitqueue_head(&data->wait); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci mutex_init(&data->page_mutex); 7158c2ecf20Sopenharmony_ci 7168c2ecf20Sopenharmony_ci ret = rmi_setup_irq_domain(hdev); 7178c2ecf20Sopenharmony_ci if (ret) { 7188c2ecf20Sopenharmony_ci hid_err(hdev, "failed to allocate IRQ domain\n"); 7198c2ecf20Sopenharmony_ci return ret; 7208c2ecf20Sopenharmony_ci } 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci if (data->device_flags & RMI_DEVICE_HAS_PHYS_BUTTONS) 7238c2ecf20Sopenharmony_ci rmi_hid_pdata.gpio_data.disable = true; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci data->xport.dev = hdev->dev.parent; 7268c2ecf20Sopenharmony_ci data->xport.pdata = rmi_hid_pdata; 7278c2ecf20Sopenharmony_ci data->xport.pdata.irq = data->rmi_irq; 7288c2ecf20Sopenharmony_ci data->xport.proto_name = "hid"; 7298c2ecf20Sopenharmony_ci data->xport.ops = &hid_rmi_ops; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_cistart: 7328c2ecf20Sopenharmony_ci ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT); 7338c2ecf20Sopenharmony_ci if (ret) { 7348c2ecf20Sopenharmony_ci hid_err(hdev, "hw start failed\n"); 7358c2ecf20Sopenharmony_ci return ret; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci 7388c2ecf20Sopenharmony_ci return 0; 7398c2ecf20Sopenharmony_ci} 7408c2ecf20Sopenharmony_ci 7418c2ecf20Sopenharmony_cistatic void rmi_remove(struct hid_device *hdev) 7428c2ecf20Sopenharmony_ci{ 7438c2ecf20Sopenharmony_ci struct rmi_data *hdata = hid_get_drvdata(hdev); 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci if ((hdata->device_flags & RMI_DEVICE) 7468c2ecf20Sopenharmony_ci && test_bit(RMI_STARTED, &hdata->flags)) { 7478c2ecf20Sopenharmony_ci clear_bit(RMI_STARTED, &hdata->flags); 7488c2ecf20Sopenharmony_ci cancel_work_sync(&hdata->reset_work); 7498c2ecf20Sopenharmony_ci rmi_unregister_transport_device(&hdata->xport); 7508c2ecf20Sopenharmony_ci } 7518c2ecf20Sopenharmony_ci 7528c2ecf20Sopenharmony_ci hid_hw_stop(hdev); 7538c2ecf20Sopenharmony_ci} 7548c2ecf20Sopenharmony_ci 7558c2ecf20Sopenharmony_cistatic const struct hid_device_id rmi_id[] = { 7568c2ecf20Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_RAZER, USB_DEVICE_ID_RAZER_BLADE_14), 7578c2ecf20Sopenharmony_ci .driver_data = RMI_DEVICE_HAS_PHYS_BUTTONS }, 7588c2ecf20Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_X1_COVER) }, 7598c2ecf20Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_PRIMAX, USB_DEVICE_ID_PRIMAX_REZEL) }, 7608c2ecf20Sopenharmony_ci { HID_USB_DEVICE(USB_VENDOR_ID_SYNAPTICS, USB_DEVICE_ID_SYNAPTICS_ACER_SWITCH5), 7618c2ecf20Sopenharmony_ci .driver_data = RMI_DEVICE_OUTPUT_SET_REPORT }, 7628c2ecf20Sopenharmony_ci { HID_DEVICE(HID_BUS_ANY, HID_GROUP_RMI, HID_ANY_ID, HID_ANY_ID) }, 7638c2ecf20Sopenharmony_ci { } 7648c2ecf20Sopenharmony_ci}; 7658c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(hid, rmi_id); 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_cistatic struct hid_driver rmi_driver = { 7688c2ecf20Sopenharmony_ci .name = "hid-rmi", 7698c2ecf20Sopenharmony_ci .id_table = rmi_id, 7708c2ecf20Sopenharmony_ci .probe = rmi_probe, 7718c2ecf20Sopenharmony_ci .remove = rmi_remove, 7728c2ecf20Sopenharmony_ci .event = rmi_event, 7738c2ecf20Sopenharmony_ci .raw_event = rmi_raw_event, 7748c2ecf20Sopenharmony_ci .report = rmi_report, 7758c2ecf20Sopenharmony_ci .input_mapping = rmi_input_mapping, 7768c2ecf20Sopenharmony_ci .input_configured = rmi_input_configured, 7778c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 7788c2ecf20Sopenharmony_ci .suspend = rmi_suspend, 7798c2ecf20Sopenharmony_ci .resume = rmi_post_resume, 7808c2ecf20Sopenharmony_ci .reset_resume = rmi_post_resume, 7818c2ecf20Sopenharmony_ci#endif 7828c2ecf20Sopenharmony_ci}; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cimodule_hid_driver(rmi_driver); 7858c2ecf20Sopenharmony_ci 7868c2ecf20Sopenharmony_ciMODULE_AUTHOR("Andrew Duggan <aduggan@synaptics.com>"); 7878c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RMI HID driver"); 7888c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 789