ishtp-hid.c 6.4 KB

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