vendor_cmds.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * Proprietary commands extension for STMicroelectronics NFC Chip
  3. *
  4. * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
  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 that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, see <http://www.gnu.org/licenses/>.
  17. */
  18. #include <net/genetlink.h>
  19. #include <linux/module.h>
  20. #include <linux/nfc.h>
  21. #include <net/nfc/hci.h>
  22. #include <net/nfc/llc.h>
  23. #include "st21nfca.h"
  24. #define ST21NFCA_HCI_DM_GETDATA 0x10
  25. #define ST21NFCA_HCI_DM_PUTDATA 0x11
  26. #define ST21NFCA_HCI_DM_LOAD 0x12
  27. #define ST21NFCA_HCI_DM_GETINFO 0x13
  28. #define ST21NFCA_HCI_DM_UPDATE_AID 0x20
  29. #define ST21NFCA_HCI_DM_RESET 0x3e
  30. #define ST21NFCA_HCI_DM_FIELD_GENERATOR 0x32
  31. #define ST21NFCA_FACTORY_MODE_ON 1
  32. #define ST21NFCA_FACTORY_MODE_OFF 0
  33. #define ST21NFCA_EVT_POST_DATA 0x02
  34. struct get_param_data {
  35. u8 gate;
  36. u8 data;
  37. } __packed;
  38. static int st21nfca_factory_mode(struct nfc_dev *dev, void *data,
  39. size_t data_len)
  40. {
  41. struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  42. if (data_len != 1)
  43. return -EINVAL;
  44. pr_debug("factory mode: %x\n", ((u8 *)data)[0]);
  45. switch (((u8 *)data)[0]) {
  46. case ST21NFCA_FACTORY_MODE_ON:
  47. test_and_set_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
  48. break;
  49. case ST21NFCA_FACTORY_MODE_OFF:
  50. clear_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
  51. break;
  52. default:
  53. return -EINVAL;
  54. }
  55. return 0;
  56. }
  57. static int st21nfca_hci_clear_all_pipes(struct nfc_dev *dev, void *data,
  58. size_t data_len)
  59. {
  60. struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  61. return nfc_hci_disconnect_all_gates(hdev);
  62. }
  63. static int st21nfca_hci_dm_put_data(struct nfc_dev *dev, void *data,
  64. size_t data_len)
  65. {
  66. struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  67. return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
  68. ST21NFCA_HCI_DM_PUTDATA, data,
  69. data_len, NULL);
  70. }
  71. static int st21nfca_hci_dm_update_aid(struct nfc_dev *dev, void *data,
  72. size_t data_len)
  73. {
  74. struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  75. return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
  76. ST21NFCA_HCI_DM_UPDATE_AID, data, data_len, NULL);
  77. }
  78. static int st21nfca_hci_dm_get_info(struct nfc_dev *dev, void *data,
  79. size_t data_len)
  80. {
  81. int r;
  82. struct sk_buff *msg, *skb;
  83. struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  84. r = nfc_hci_send_cmd(hdev,
  85. ST21NFCA_DEVICE_MGNT_GATE,
  86. ST21NFCA_HCI_DM_GETINFO,
  87. data, data_len, &skb);
  88. if (r)
  89. goto exit;
  90. msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
  91. HCI_DM_GET_INFO, skb->len);
  92. if (!msg) {
  93. r = -ENOMEM;
  94. goto free_skb;
  95. }
  96. if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
  97. kfree_skb(msg);
  98. r = -ENOBUFS;
  99. goto free_skb;
  100. }
  101. r = nfc_vendor_cmd_reply(msg);
  102. free_skb:
  103. kfree_skb(skb);
  104. exit:
  105. return r;
  106. }
  107. static int st21nfca_hci_dm_get_data(struct nfc_dev *dev, void *data,
  108. size_t data_len)
  109. {
  110. int r;
  111. struct sk_buff *msg, *skb;
  112. struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  113. r = nfc_hci_send_cmd(hdev,
  114. ST21NFCA_DEVICE_MGNT_GATE,
  115. ST21NFCA_HCI_DM_GETDATA,
  116. data, data_len, &skb);
  117. if (r)
  118. goto exit;
  119. msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
  120. HCI_DM_GET_DATA, skb->len);
  121. if (!msg) {
  122. r = -ENOMEM;
  123. goto free_skb;
  124. }
  125. if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
  126. kfree_skb(msg);
  127. r = -ENOBUFS;
  128. goto free_skb;
  129. }
  130. r = nfc_vendor_cmd_reply(msg);
  131. free_skb:
  132. kfree_skb(skb);
  133. exit:
  134. return r;
  135. }
  136. static int st21nfca_hci_dm_load(struct nfc_dev *dev, void *data,
  137. size_t data_len)
  138. {
  139. struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  140. return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
  141. ST21NFCA_HCI_DM_LOAD, data, data_len, NULL);
  142. }
  143. static int st21nfca_hci_dm_reset(struct nfc_dev *dev, void *data,
  144. size_t data_len)
  145. {
  146. int r;
  147. struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  148. r = nfc_hci_send_cmd_async(hdev, ST21NFCA_DEVICE_MGNT_GATE,
  149. ST21NFCA_HCI_DM_RESET, data, data_len, NULL, NULL);
  150. if (r < 0)
  151. return r;
  152. r = nfc_llc_stop(hdev->llc);
  153. if (r < 0)
  154. return r;
  155. return nfc_llc_start(hdev->llc);
  156. }
  157. static int st21nfca_hci_get_param(struct nfc_dev *dev, void *data,
  158. size_t data_len)
  159. {
  160. int r;
  161. struct sk_buff *msg, *skb;
  162. struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  163. struct get_param_data *param = (struct get_param_data *)data;
  164. if (data_len < sizeof(struct get_param_data))
  165. return -EPROTO;
  166. r = nfc_hci_get_param(hdev, param->gate, param->data, &skb);
  167. if (r)
  168. goto exit;
  169. msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
  170. HCI_GET_PARAM, skb->len);
  171. if (!msg) {
  172. r = -ENOMEM;
  173. goto free_skb;
  174. }
  175. if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
  176. kfree_skb(msg);
  177. r = -ENOBUFS;
  178. goto free_skb;
  179. }
  180. r = nfc_vendor_cmd_reply(msg);
  181. free_skb:
  182. kfree_skb(skb);
  183. exit:
  184. return r;
  185. }
  186. static int st21nfca_hci_dm_field_generator(struct nfc_dev *dev, void *data,
  187. size_t data_len)
  188. {
  189. struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  190. return nfc_hci_send_cmd(hdev,
  191. ST21NFCA_DEVICE_MGNT_GATE,
  192. ST21NFCA_HCI_DM_FIELD_GENERATOR,
  193. data, data_len, NULL);
  194. }
  195. int st21nfca_hci_loopback_event_received(struct nfc_hci_dev *hdev, u8 event,
  196. struct sk_buff *skb)
  197. {
  198. struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
  199. switch (event) {
  200. case ST21NFCA_EVT_POST_DATA:
  201. info->vendor_info.rx_skb = skb;
  202. break;
  203. default:
  204. nfc_err(&hdev->ndev->dev, "Unexpected event on loopback gate\n");
  205. }
  206. complete(&info->vendor_info.req_completion);
  207. return 0;
  208. }
  209. EXPORT_SYMBOL(st21nfca_hci_loopback_event_received);
  210. static int st21nfca_hci_loopback(struct nfc_dev *dev, void *data,
  211. size_t data_len)
  212. {
  213. int r;
  214. struct sk_buff *msg;
  215. struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
  216. struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
  217. if (data_len <= 0)
  218. return -EPROTO;
  219. reinit_completion(&info->vendor_info.req_completion);
  220. info->vendor_info.rx_skb = NULL;
  221. r = nfc_hci_send_event(hdev, NFC_HCI_LOOPBACK_GATE,
  222. ST21NFCA_EVT_POST_DATA, data, data_len);
  223. if (r < 0) {
  224. r = -EPROTO;
  225. goto exit;
  226. }
  227. wait_for_completion_interruptible(&info->vendor_info.req_completion);
  228. if (!info->vendor_info.rx_skb ||
  229. info->vendor_info.rx_skb->len != data_len) {
  230. r = -EPROTO;
  231. goto exit;
  232. }
  233. msg = nfc_vendor_cmd_alloc_reply_skb(hdev->ndev,
  234. ST21NFCA_VENDOR_OUI,
  235. HCI_LOOPBACK,
  236. info->vendor_info.rx_skb->len);
  237. if (!msg) {
  238. r = -ENOMEM;
  239. goto free_skb;
  240. }
  241. if (nla_put(msg, NFC_ATTR_VENDOR_DATA, info->vendor_info.rx_skb->len,
  242. info->vendor_info.rx_skb->data)) {
  243. kfree_skb(msg);
  244. r = -ENOBUFS;
  245. goto free_skb;
  246. }
  247. r = nfc_vendor_cmd_reply(msg);
  248. free_skb:
  249. kfree_skb(info->vendor_info.rx_skb);
  250. exit:
  251. return r;
  252. }
  253. static struct nfc_vendor_cmd st21nfca_vendor_cmds[] = {
  254. {
  255. .vendor_id = ST21NFCA_VENDOR_OUI,
  256. .subcmd = FACTORY_MODE,
  257. .doit = st21nfca_factory_mode,
  258. },
  259. {
  260. .vendor_id = ST21NFCA_VENDOR_OUI,
  261. .subcmd = HCI_CLEAR_ALL_PIPES,
  262. .doit = st21nfca_hci_clear_all_pipes,
  263. },
  264. {
  265. .vendor_id = ST21NFCA_VENDOR_OUI,
  266. .subcmd = HCI_DM_PUT_DATA,
  267. .doit = st21nfca_hci_dm_put_data,
  268. },
  269. {
  270. .vendor_id = ST21NFCA_VENDOR_OUI,
  271. .subcmd = HCI_DM_UPDATE_AID,
  272. .doit = st21nfca_hci_dm_update_aid,
  273. },
  274. {
  275. .vendor_id = ST21NFCA_VENDOR_OUI,
  276. .subcmd = HCI_DM_GET_INFO,
  277. .doit = st21nfca_hci_dm_get_info,
  278. },
  279. {
  280. .vendor_id = ST21NFCA_VENDOR_OUI,
  281. .subcmd = HCI_DM_GET_DATA,
  282. .doit = st21nfca_hci_dm_get_data,
  283. },
  284. {
  285. .vendor_id = ST21NFCA_VENDOR_OUI,
  286. .subcmd = HCI_DM_LOAD,
  287. .doit = st21nfca_hci_dm_load,
  288. },
  289. {
  290. .vendor_id = ST21NFCA_VENDOR_OUI,
  291. .subcmd = HCI_DM_RESET,
  292. .doit = st21nfca_hci_dm_reset,
  293. },
  294. {
  295. .vendor_id = ST21NFCA_VENDOR_OUI,
  296. .subcmd = HCI_GET_PARAM,
  297. .doit = st21nfca_hci_get_param,
  298. },
  299. {
  300. .vendor_id = ST21NFCA_VENDOR_OUI,
  301. .subcmd = HCI_DM_FIELD_GENERATOR,
  302. .doit = st21nfca_hci_dm_field_generator,
  303. },
  304. {
  305. .vendor_id = ST21NFCA_VENDOR_OUI,
  306. .subcmd = HCI_LOOPBACK,
  307. .doit = st21nfca_hci_loopback,
  308. },
  309. };
  310. int st21nfca_vendor_cmds_init(struct nfc_hci_dev *hdev)
  311. {
  312. struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
  313. init_completion(&info->vendor_info.req_completion);
  314. return nfc_set_vendor_cmds(hdev->ndev, st21nfca_vendor_cmds,
  315. sizeof(st21nfca_vendor_cmds));
  316. }
  317. EXPORT_SYMBOL(st21nfca_vendor_cmds_init);