ishtp-hid.c (6523B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * ISHTP-HID glue driver. 4 * 5 * Copyright (c) 2012-2016, Intel Corporation. 6 */ 7 8#include <linux/hid.h> 9#include <linux/intel-ish-client-if.h> 10#include <uapi/linux/input.h> 11#include "ishtp-hid.h" 12 13/** 14 * ishtp_hid_parse() - hid-core .parse() callback 15 * @hid: hid device instance 16 * 17 * This function gets called during call to hid_add_device 18 * 19 * Return: 0 on success and non zero on error 20 */ 21static int ishtp_hid_parse(struct hid_device *hid) 22{ 23 struct ishtp_hid_data *hid_data = hid->driver_data; 24 struct ishtp_cl_data *client_data = hid_data->client_data; 25 int rv; 26 27 rv = hid_parse_report(hid, client_data->report_descr[hid_data->index], 28 client_data->report_descr_size[hid_data->index]); 29 if (rv) 30 return rv; 31 32 return 0; 33} 34 35/* Empty callbacks with success return code */ 36static int ishtp_hid_start(struct hid_device *hid) 37{ 38 return 0; 39} 40 41static void ishtp_hid_stop(struct hid_device *hid) 42{ 43} 44 45static int ishtp_hid_open(struct hid_device *hid) 46{ 47 return 0; 48} 49 50static void ishtp_hid_close(struct hid_device *hid) 51{ 52} 53 54static int ishtp_raw_request(struct hid_device *hid, unsigned char reportnum, 55 __u8 *buf, size_t len, unsigned char rtype, 56 int reqtype) 57{ 58 struct ishtp_hid_data *hid_data = hid->driver_data; 59 char *ishtp_buf = NULL; 60 size_t ishtp_buf_len; 61 unsigned int header_size = sizeof(struct hostif_msg); 62 63 if (rtype == HID_OUTPUT_REPORT) 64 return -EINVAL; 65 66 hid_data->request_done = false; 67 switch (reqtype) { 68 case HID_REQ_GET_REPORT: 69 hid_data->raw_buf = buf; 70 hid_data->raw_buf_size = len; 71 hid_data->raw_get_req = true; 72 73 hid_ishtp_get_report(hid, reportnum, rtype); 74 break; 75 case HID_REQ_SET_REPORT: 76 /* 77 * Spare 7 bytes for 64b accesses through 78 * get/put_unaligned_le64() 79 */ 80 ishtp_buf_len = len + header_size; 81 ishtp_buf = kzalloc(ishtp_buf_len + 7, GFP_KERNEL); 82 if (!ishtp_buf) 83 return -ENOMEM; 84 85 memcpy(ishtp_buf + header_size, buf, len); 86 hid_ishtp_set_feature(hid, ishtp_buf, ishtp_buf_len, reportnum); 87 kfree(ishtp_buf); 88 break; 89 } 90 91 hid_hw_wait(hid); 92 93 return len; 94} 95 96/** 97 * ishtp_hid_request() - hid-core .request() callback 98 * @hid: hid device instance 99 * @rep: pointer to hid_report 100 * @reqtype: type of req. [GET|SET]_REPORT 101 * 102 * This function is used to set/get feaure/input report. 103 */ 104static void ishtp_hid_request(struct hid_device *hid, struct hid_report *rep, 105 int reqtype) 106{ 107 struct ishtp_hid_data *hid_data = hid->driver_data; 108 /* the specific report length, just HID part of it */ 109 unsigned int len = ((rep->size - 1) >> 3) + 1 + (rep->id > 0); 110 char *buf; 111 unsigned int header_size = sizeof(struct hostif_msg); 112 113 len += header_size; 114 115 hid_data->request_done = false; 116 switch (reqtype) { 117 case HID_REQ_GET_REPORT: 118 hid_data->raw_get_req = false; 119 hid_ishtp_get_report(hid, rep->id, rep->type); 120 break; 121 case HID_REQ_SET_REPORT: 122 /* 123 * Spare 7 bytes for 64b accesses through 124 * get/put_unaligned_le64() 125 */ 126 buf = kzalloc(len + 7, GFP_KERNEL); 127 if (!buf) 128 return; 129 130 hid_output_report(rep, buf + header_size); 131 hid_ishtp_set_feature(hid, buf, len, rep->id); 132 kfree(buf); 133 break; 134 } 135} 136 137/** 138 * ishtp_wait_for_response() - hid-core .wait() callback 139 * @hid: hid device instance 140 * 141 * This function is used to wait after get feaure/input report. 142 * 143 * Return: 0 on success and non zero on error 144 */ 145static int ishtp_wait_for_response(struct hid_device *hid) 146{ 147 struct ishtp_hid_data *hid_data = hid->driver_data; 148 int rv; 149 150 hid_ishtp_trace(client_data, "%s hid %p\n", __func__, hid); 151 152 rv = ishtp_hid_link_ready_wait(hid_data->client_data); 153 if (rv) 154 return rv; 155 156 if (!hid_data->request_done) 157 wait_event_interruptible_timeout(hid_data->hid_wait, 158 hid_data->request_done, 3 * HZ); 159 160 if (!hid_data->request_done) { 161 hid_err(hid, 162 "timeout waiting for response from ISHTP device\n"); 163 return -ETIMEDOUT; 164 } 165 hid_ishtp_trace(client_data, "%s hid %p done\n", __func__, hid); 166 167 hid_data->request_done = false; 168 169 return 0; 170} 171 172/** 173 * ishtp_hid_wakeup() - Wakeup caller 174 * @hid: hid device instance 175 * 176 * This function will wakeup caller waiting for Get/Set feature report 177 */ 178void ishtp_hid_wakeup(struct hid_device *hid) 179{ 180 struct ishtp_hid_data *hid_data = hid->driver_data; 181 182 hid_data->request_done = true; 183 wake_up_interruptible(&hid_data->hid_wait); 184} 185 186static struct hid_ll_driver ishtp_hid_ll_driver = { 187 .parse = ishtp_hid_parse, 188 .start = ishtp_hid_start, 189 .stop = ishtp_hid_stop, 190 .open = ishtp_hid_open, 191 .close = ishtp_hid_close, 192 .request = ishtp_hid_request, 193 .wait = ishtp_wait_for_response, 194 .raw_request = ishtp_raw_request 195}; 196 197/** 198 * ishtp_hid_probe() - hid register ll driver 199 * @cur_hid_dev: Index of hid device calling to register 200 * @client_data: Client data pointer 201 * 202 * This function is used to allocate and add HID device. 203 * 204 * Return: 0 on success, non zero on error 205 */ 206int ishtp_hid_probe(unsigned int cur_hid_dev, 207 struct ishtp_cl_data *client_data) 208{ 209 int rv; 210 struct hid_device *hid; 211 struct ishtp_hid_data *hid_data; 212 213 hid = hid_allocate_device(); 214 if (IS_ERR(hid)) 215 return PTR_ERR(hid); 216 217 hid_data = kzalloc(sizeof(*hid_data), GFP_KERNEL); 218 if (!hid_data) { 219 rv = -ENOMEM; 220 goto err_hid_data; 221 } 222 223 hid_data->index = cur_hid_dev; 224 hid_data->client_data = client_data; 225 init_waitqueue_head(&hid_data->hid_wait); 226 227 hid->driver_data = hid_data; 228 229 client_data->hid_sensor_hubs[cur_hid_dev] = hid; 230 231 hid->ll_driver = &ishtp_hid_ll_driver; 232 hid->bus = BUS_INTEL_ISHTP; 233 hid->dev.parent = ishtp_device(client_data->cl_device); 234 235 hid->version = le16_to_cpu(ISH_HID_VERSION); 236 hid->vendor = le16_to_cpu(client_data->hid_devices[cur_hid_dev].vid); 237 hid->product = le16_to_cpu(client_data->hid_devices[cur_hid_dev].pid); 238 snprintf(hid->name, sizeof(hid->name), "%s %04X:%04X", "hid-ishtp", 239 hid->vendor, hid->product); 240 241 rv = hid_add_device(hid); 242 if (rv) 243 goto err_hid_device; 244 245 hid_ishtp_trace(client_data, "%s allocated hid %p\n", __func__, hid); 246 247 return 0; 248 249err_hid_device: 250 kfree(hid_data); 251err_hid_data: 252 hid_destroy_device(hid); 253 return rv; 254} 255 256/** 257 * ishtp_hid_remove() - Remove registered hid device 258 * @client_data: client data pointer 259 * 260 * This function is used to destroy allocatd HID device. 261 */ 262void ishtp_hid_remove(struct ishtp_cl_data *client_data) 263{ 264 int i; 265 266 for (i = 0; i < client_data->num_hid_devices; ++i) { 267 if (client_data->hid_sensor_hubs[i]) { 268 kfree(client_data->hid_sensor_hubs[i]->driver_data); 269 hid_destroy_device(client_data->hid_sensor_hubs[i]); 270 client_data->hid_sensor_hubs[i] = NULL; 271 } 272 } 273}