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