hal-hidhost.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  1. // SPDX-License-Identifier: Apache-2.0
  2. /*
  3. * Copyright (C) 2013 Intel Corporation
  4. *
  5. */
  6. #include <stdbool.h>
  7. #include <stddef.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10. #include "hal-log.h"
  11. #include "hal.h"
  12. #include "hal-msg.h"
  13. #include "ipc-common.h"
  14. #include "hal-ipc.h"
  15. static const bthh_callbacks_t *cbacks;
  16. static bool interface_ready(void)
  17. {
  18. return cbacks != NULL;
  19. }
  20. static void handle_conn_state(void *buf, uint16_t len, int fd)
  21. {
  22. struct hal_ev_hidhost_conn_state *ev = buf;
  23. if (cbacks->connection_state_cb)
  24. cbacks->connection_state_cb((bt_bdaddr_t *) ev->bdaddr,
  25. ev->state);
  26. }
  27. static void handle_info(void *buf, uint16_t len, int fd)
  28. {
  29. struct hal_ev_hidhost_info *ev = buf;
  30. bthh_hid_info_t info;
  31. info.attr_mask = ev->attr;
  32. info.sub_class = ev->subclass;
  33. info.app_id = ev->app_id;
  34. info.vendor_id = ev->vendor;
  35. info.product_id = ev->product;
  36. info.version = ev->version;
  37. info.ctry_code = ev->country;
  38. info.dl_len = ev->descr_len;
  39. memcpy(info.dsc_list, ev->descr, info.dl_len);
  40. if (cbacks->hid_info_cb)
  41. cbacks->hid_info_cb((bt_bdaddr_t *) ev->bdaddr, info);
  42. }
  43. static void handle_proto_mode(void *buf, uint16_t len, int fd)
  44. {
  45. struct hal_ev_hidhost_proto_mode *ev = buf;
  46. if (cbacks->protocol_mode_cb)
  47. cbacks->protocol_mode_cb((bt_bdaddr_t *) ev->bdaddr,
  48. ev->status, ev->mode);
  49. }
  50. static void handle_idle_time(void *buf, uint16_t len, int fd)
  51. {
  52. struct hal_ev_hidhost_idle_time *ev = buf;
  53. if (cbacks->idle_time_cb)
  54. cbacks->idle_time_cb((bt_bdaddr_t *) ev->bdaddr, ev->status,
  55. ev->idle_rate);
  56. }
  57. static void handle_get_report(void *buf, uint16_t len, int fd)
  58. {
  59. struct hal_ev_hidhost_get_report *ev = buf;
  60. if (len != sizeof(*ev) + ev->len) {
  61. error("invalid get report event, aborting");
  62. exit(EXIT_FAILURE);
  63. }
  64. if (cbacks->get_report_cb)
  65. cbacks->get_report_cb((bt_bdaddr_t *) ev->bdaddr, ev->status,
  66. ev->data, ev->len);
  67. }
  68. static void handle_virtual_unplug(void *buf, uint16_t len, int fd)
  69. {
  70. struct hal_ev_hidhost_virtual_unplug *ev = buf;
  71. if (cbacks->virtual_unplug_cb)
  72. cbacks->virtual_unplug_cb((bt_bdaddr_t *) ev->bdaddr,
  73. ev->status);
  74. }
  75. static void handle_handshake(void *buf, uint16_t len, int fd)
  76. {
  77. #if ANDROID_VERSION >= PLATFORM_VER(5, 0, 0)
  78. struct hal_ev_hidhost_handshake *ev = buf;
  79. if (cbacks->handshake_cb)
  80. cbacks->handshake_cb((bt_bdaddr_t *) ev->bdaddr, ev->status);
  81. #endif
  82. }
  83. /*
  84. * handlers will be called from notification thread context,
  85. * index in table equals to 'opcode - HAL_MINIMUM_EVENT'
  86. */
  87. static const struct hal_ipc_handler ev_handlers[] = {
  88. /* HAL_EV_HIDHOST_CONN_STATE */
  89. { handle_conn_state, false, sizeof(struct hal_ev_hidhost_conn_state) },
  90. /* HAL_EV_HIDHOST_INFO */
  91. { handle_info, false, sizeof(struct hal_ev_hidhost_info) },
  92. /* HAL_EV_HIDHOST_PROTO_MODE */
  93. { handle_proto_mode, false, sizeof(struct hal_ev_hidhost_proto_mode) },
  94. /* HAL_EV_HIDHOST_IDLE_TIME */
  95. { handle_idle_time, false, sizeof(struct hal_ev_hidhost_idle_time) },
  96. /* HAL_EV_HIDHOST_GET_REPORT */
  97. { handle_get_report, true, sizeof(struct hal_ev_hidhost_get_report) },
  98. /* HAL_EV_HIDHOST_VIRTUAL_UNPLUG */
  99. { handle_virtual_unplug, false,
  100. sizeof(struct hal_ev_hidhost_virtual_unplug) },
  101. { handle_handshake, false, sizeof(struct hal_ev_hidhost_handshake) },
  102. };
  103. static bt_status_t hidhost_connect(bt_bdaddr_t *bd_addr)
  104. {
  105. struct hal_cmd_hidhost_connect cmd;
  106. DBG("");
  107. if (!interface_ready())
  108. return BT_STATUS_NOT_READY;
  109. if (!bd_addr)
  110. return BT_STATUS_PARM_INVALID;
  111. memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
  112. return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_OP_HIDHOST_CONNECT,
  113. sizeof(cmd), &cmd, NULL, NULL, NULL);
  114. }
  115. static bt_status_t disconnect(bt_bdaddr_t *bd_addr)
  116. {
  117. struct hal_cmd_hidhost_disconnect cmd;
  118. DBG("");
  119. if (!interface_ready())
  120. return BT_STATUS_NOT_READY;
  121. if (!bd_addr)
  122. return BT_STATUS_PARM_INVALID;
  123. memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
  124. return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_OP_HIDHOST_DISCONNECT,
  125. sizeof(cmd), &cmd, NULL, NULL, NULL);
  126. }
  127. static bt_status_t virtual_unplug(bt_bdaddr_t *bd_addr)
  128. {
  129. struct hal_cmd_hidhost_virtual_unplug cmd;
  130. DBG("");
  131. if (!interface_ready())
  132. return BT_STATUS_NOT_READY;
  133. if (!bd_addr)
  134. return BT_STATUS_PARM_INVALID;
  135. memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
  136. return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST,
  137. HAL_OP_HIDHOST_VIRTUAL_UNPLUG,
  138. sizeof(cmd), &cmd, NULL, NULL, NULL);
  139. }
  140. static bt_status_t set_info(bt_bdaddr_t *bd_addr, bthh_hid_info_t hid_info)
  141. {
  142. struct hal_cmd_hidhost_set_info cmd;
  143. DBG("");
  144. if (!interface_ready())
  145. return BT_STATUS_NOT_READY;
  146. if (!bd_addr)
  147. return BT_STATUS_PARM_INVALID;
  148. memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
  149. cmd.attr = hid_info.attr_mask;
  150. cmd.subclass = hid_info.sub_class;
  151. cmd.app_id = hid_info.app_id;
  152. cmd.vendor = hid_info.vendor_id;
  153. cmd.product = hid_info.product_id;
  154. cmd.country = hid_info.ctry_code;
  155. cmd.descr_len = hid_info.dl_len;
  156. memcpy(cmd.descr, hid_info.dsc_list, cmd.descr_len);
  157. return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_OP_HIDHOST_SET_INFO,
  158. sizeof(cmd), &cmd, NULL, NULL, NULL);
  159. }
  160. static bt_status_t get_protocol(bt_bdaddr_t *bd_addr,
  161. bthh_protocol_mode_t protocol_mode)
  162. {
  163. struct hal_cmd_hidhost_get_protocol cmd;
  164. DBG("");
  165. if (!interface_ready())
  166. return BT_STATUS_NOT_READY;
  167. if (!bd_addr)
  168. return BT_STATUS_PARM_INVALID;
  169. memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
  170. /* type match IPC type */
  171. cmd.mode = protocol_mode;
  172. return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST,
  173. HAL_OP_HIDHOST_GET_PROTOCOL,
  174. sizeof(cmd), &cmd, NULL, NULL, NULL);
  175. }
  176. static bt_status_t set_protocol(bt_bdaddr_t *bd_addr,
  177. bthh_protocol_mode_t protocol_mode)
  178. {
  179. struct hal_cmd_hidhost_set_protocol cmd;
  180. DBG("");
  181. if (!interface_ready())
  182. return BT_STATUS_NOT_READY;
  183. if (!bd_addr)
  184. return BT_STATUS_PARM_INVALID;
  185. memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
  186. /* type match IPC type */
  187. cmd.mode = protocol_mode;
  188. return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST,
  189. HAL_OP_HIDHOST_SET_PROTOCOL,
  190. sizeof(cmd), &cmd, NULL, NULL, NULL);
  191. }
  192. static bt_status_t get_report(bt_bdaddr_t *bd_addr,
  193. bthh_report_type_t report_type,
  194. uint8_t report_id,
  195. int buffer_size)
  196. {
  197. struct hal_cmd_hidhost_get_report cmd;
  198. DBG("");
  199. if (!interface_ready())
  200. return BT_STATUS_NOT_READY;
  201. if (!bd_addr)
  202. return BT_STATUS_PARM_INVALID;
  203. memcpy(cmd.bdaddr, bd_addr, sizeof(cmd.bdaddr));
  204. cmd.id = report_id;
  205. cmd.buf_size = buffer_size;
  206. /* type match IPC type */
  207. cmd.type = report_type;
  208. return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_OP_HIDHOST_GET_REPORT,
  209. sizeof(cmd), &cmd, NULL, NULL, NULL);
  210. }
  211. static bt_status_t set_report(bt_bdaddr_t *bd_addr,
  212. bthh_report_type_t report_type,
  213. char *report)
  214. {
  215. uint8_t buf[IPC_MTU];
  216. struct hal_cmd_hidhost_set_report *cmd = (void *) buf;
  217. DBG("");
  218. if (!interface_ready())
  219. return BT_STATUS_NOT_READY;
  220. if (!bd_addr || !report)
  221. return BT_STATUS_PARM_INVALID;
  222. memcpy(cmd->bdaddr, bd_addr, sizeof(cmd->bdaddr));
  223. cmd->len = strlen(report);
  224. memcpy(cmd->data, report, cmd->len);
  225. /* type match IPC type */
  226. cmd->type = report_type;
  227. return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_OP_HIDHOST_SET_REPORT,
  228. sizeof(*cmd) + cmd->len, buf, NULL, NULL, NULL);
  229. }
  230. static bt_status_t send_data(bt_bdaddr_t *bd_addr, char *data)
  231. {
  232. uint8_t buf[IPC_MTU];
  233. struct hal_cmd_hidhost_send_data *cmd = (void *) buf;
  234. DBG("");
  235. if (!interface_ready())
  236. return BT_STATUS_NOT_READY;
  237. if (!bd_addr || !data)
  238. return BT_STATUS_PARM_INVALID;
  239. memcpy(cmd->bdaddr, bd_addr, sizeof(cmd->bdaddr));
  240. cmd->len = strlen(data);
  241. memcpy(cmd->data, data, cmd->len);
  242. return hal_ipc_cmd(HAL_SERVICE_ID_HIDHOST, HAL_OP_HIDHOST_SEND_DATA,
  243. sizeof(*cmd) + cmd->len, buf, NULL, NULL, NULL);
  244. }
  245. static bt_status_t init(bthh_callbacks_t *callbacks)
  246. {
  247. struct hal_cmd_register_module cmd;
  248. int ret;
  249. DBG("");
  250. if (interface_ready())
  251. return BT_STATUS_DONE;
  252. /* store reference to user callbacks */
  253. cbacks = callbacks;
  254. hal_ipc_register(HAL_SERVICE_ID_HIDHOST, ev_handlers,
  255. sizeof(ev_handlers)/sizeof(ev_handlers[0]));
  256. cmd.service_id = HAL_SERVICE_ID_HIDHOST;
  257. cmd.mode = HAL_MODE_DEFAULT;
  258. cmd.max_clients = 1;
  259. ret = hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_REGISTER_MODULE,
  260. sizeof(cmd), &cmd, NULL, NULL, NULL);
  261. if (ret != BT_STATUS_SUCCESS) {
  262. cbacks = NULL;
  263. hal_ipc_unregister(HAL_SERVICE_ID_HIDHOST);
  264. }
  265. return ret;
  266. }
  267. static void cleanup(void)
  268. {
  269. struct hal_cmd_unregister_module cmd;
  270. DBG("");
  271. if (!interface_ready())
  272. return;
  273. cmd.service_id = HAL_SERVICE_ID_HIDHOST;
  274. hal_ipc_cmd(HAL_SERVICE_ID_CORE, HAL_OP_UNREGISTER_MODULE,
  275. sizeof(cmd), &cmd, NULL, NULL, NULL);
  276. hal_ipc_unregister(HAL_SERVICE_ID_HIDHOST);
  277. cbacks = NULL;
  278. }
  279. static bthh_interface_t hidhost_if = {
  280. .size = sizeof(hidhost_if),
  281. .init = init,
  282. .connect = hidhost_connect,
  283. .disconnect = disconnect,
  284. .virtual_unplug = virtual_unplug,
  285. .set_info = set_info,
  286. .get_protocol = get_protocol,
  287. .set_protocol = set_protocol,
  288. .get_report = get_report,
  289. .set_report = set_report,
  290. .send_data = send_data,
  291. .cleanup = cleanup
  292. };
  293. bthh_interface_t *bt_get_hidhost_interface(void)
  294. {
  295. return &hidhost_if;
  296. }