Linux 4.16.11
[linux/fpc-iii.git] / drivers / nfc / st21nfca / vendor_cmds.c
blobab765e5478c018884090b2b5bcfdc511c2732436
1 /*
2 * Proprietary commands extension for STMicroelectronics NFC Chip
4 * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
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.
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.
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/>.
19 #include <net/genetlink.h>
20 #include <linux/module.h>
21 #include <linux/nfc.h>
22 #include <net/nfc/hci.h>
23 #include <net/nfc/llc.h>
25 #include "st21nfca.h"
27 #define ST21NFCA_HCI_DM_GETDATA 0x10
28 #define ST21NFCA_HCI_DM_PUTDATA 0x11
29 #define ST21NFCA_HCI_DM_LOAD 0x12
30 #define ST21NFCA_HCI_DM_GETINFO 0x13
31 #define ST21NFCA_HCI_DM_UPDATE_AID 0x20
32 #define ST21NFCA_HCI_DM_RESET 0x3e
34 #define ST21NFCA_HCI_DM_FIELD_GENERATOR 0x32
36 #define ST21NFCA_FACTORY_MODE_ON 1
37 #define ST21NFCA_FACTORY_MODE_OFF 0
39 #define ST21NFCA_EVT_POST_DATA 0x02
41 struct get_param_data {
42 u8 gate;
43 u8 data;
44 } __packed;
46 static int st21nfca_factory_mode(struct nfc_dev *dev, void *data,
47 size_t data_len)
49 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
51 if (data_len != 1)
52 return -EINVAL;
54 pr_debug("factory mode: %x\n", ((u8 *)data)[0]);
56 switch (((u8 *)data)[0]) {
57 case ST21NFCA_FACTORY_MODE_ON:
58 test_and_set_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
59 break;
60 case ST21NFCA_FACTORY_MODE_OFF:
61 clear_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
62 break;
63 default:
64 return -EINVAL;
67 return 0;
70 static int st21nfca_hci_clear_all_pipes(struct nfc_dev *dev, void *data,
71 size_t data_len)
73 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
75 return nfc_hci_disconnect_all_gates(hdev);
78 static int st21nfca_hci_dm_put_data(struct nfc_dev *dev, void *data,
79 size_t data_len)
81 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
83 return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
84 ST21NFCA_HCI_DM_PUTDATA, data,
85 data_len, NULL);
88 static int st21nfca_hci_dm_update_aid(struct nfc_dev *dev, void *data,
89 size_t data_len)
91 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
93 return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
94 ST21NFCA_HCI_DM_UPDATE_AID, data, data_len, NULL);
97 static int st21nfca_hci_dm_get_info(struct nfc_dev *dev, void *data,
98 size_t data_len)
100 int r;
101 struct sk_buff *msg, *skb;
102 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
104 r = nfc_hci_send_cmd(hdev,
105 ST21NFCA_DEVICE_MGNT_GATE,
106 ST21NFCA_HCI_DM_GETINFO,
107 data, data_len, &skb);
108 if (r)
109 goto exit;
111 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
112 HCI_DM_GET_INFO, skb->len);
113 if (!msg) {
114 r = -ENOMEM;
115 goto free_skb;
118 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
119 kfree_skb(msg);
120 r = -ENOBUFS;
121 goto free_skb;
124 r = nfc_vendor_cmd_reply(msg);
126 free_skb:
127 kfree_skb(skb);
128 exit:
129 return r;
132 static int st21nfca_hci_dm_get_data(struct nfc_dev *dev, void *data,
133 size_t data_len)
135 int r;
136 struct sk_buff *msg, *skb;
137 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
139 r = nfc_hci_send_cmd(hdev,
140 ST21NFCA_DEVICE_MGNT_GATE,
141 ST21NFCA_HCI_DM_GETDATA,
142 data, data_len, &skb);
143 if (r)
144 goto exit;
146 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
147 HCI_DM_GET_DATA, skb->len);
148 if (!msg) {
149 r = -ENOMEM;
150 goto free_skb;
153 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
154 kfree_skb(msg);
155 r = -ENOBUFS;
156 goto free_skb;
159 r = nfc_vendor_cmd_reply(msg);
161 free_skb:
162 kfree_skb(skb);
163 exit:
164 return r;
167 static int st21nfca_hci_dm_load(struct nfc_dev *dev, void *data,
168 size_t data_len)
170 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
172 return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
173 ST21NFCA_HCI_DM_LOAD, data, data_len, NULL);
176 static int st21nfca_hci_dm_reset(struct nfc_dev *dev, void *data,
177 size_t data_len)
179 int r;
180 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
182 r = nfc_hci_send_cmd_async(hdev, ST21NFCA_DEVICE_MGNT_GATE,
183 ST21NFCA_HCI_DM_RESET, data, data_len, NULL, NULL);
184 if (r < 0)
185 return r;
187 r = nfc_llc_stop(hdev->llc);
188 if (r < 0)
189 return r;
191 return nfc_llc_start(hdev->llc);
194 static int st21nfca_hci_get_param(struct nfc_dev *dev, void *data,
195 size_t data_len)
197 int r;
198 struct sk_buff *msg, *skb;
199 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
200 struct get_param_data *param = (struct get_param_data *)data;
202 if (data_len < sizeof(struct get_param_data))
203 return -EPROTO;
205 r = nfc_hci_get_param(hdev, param->gate, param->data, &skb);
206 if (r)
207 goto exit;
209 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
210 HCI_GET_PARAM, skb->len);
211 if (!msg) {
212 r = -ENOMEM;
213 goto free_skb;
216 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
217 kfree_skb(msg);
218 r = -ENOBUFS;
219 goto free_skb;
222 r = nfc_vendor_cmd_reply(msg);
224 free_skb:
225 kfree_skb(skb);
226 exit:
227 return r;
230 static int st21nfca_hci_dm_field_generator(struct nfc_dev *dev, void *data,
231 size_t data_len)
233 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
235 return nfc_hci_send_cmd(hdev,
236 ST21NFCA_DEVICE_MGNT_GATE,
237 ST21NFCA_HCI_DM_FIELD_GENERATOR,
238 data, data_len, NULL);
241 int st21nfca_hci_loopback_event_received(struct nfc_hci_dev *hdev, u8 event,
242 struct sk_buff *skb)
244 struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
246 switch (event) {
247 case ST21NFCA_EVT_POST_DATA:
248 info->vendor_info.rx_skb = skb;
249 break;
250 default:
251 nfc_err(&hdev->ndev->dev, "Unexpected event on loopback gate\n");
253 complete(&info->vendor_info.req_completion);
254 return 0;
256 EXPORT_SYMBOL(st21nfca_hci_loopback_event_received);
258 static int st21nfca_hci_loopback(struct nfc_dev *dev, void *data,
259 size_t data_len)
261 int r;
262 struct sk_buff *msg;
263 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
264 struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
266 if (data_len <= 0)
267 return -EPROTO;
269 reinit_completion(&info->vendor_info.req_completion);
270 info->vendor_info.rx_skb = NULL;
272 r = nfc_hci_send_event(hdev, NFC_HCI_LOOPBACK_GATE,
273 ST21NFCA_EVT_POST_DATA, data, data_len);
274 if (r < 0) {
275 r = -EPROTO;
276 goto exit;
279 wait_for_completion_interruptible(&info->vendor_info.req_completion);
280 if (!info->vendor_info.rx_skb ||
281 info->vendor_info.rx_skb->len != data_len) {
282 r = -EPROTO;
283 goto exit;
286 msg = nfc_vendor_cmd_alloc_reply_skb(hdev->ndev,
287 ST21NFCA_VENDOR_OUI,
288 HCI_LOOPBACK,
289 info->vendor_info.rx_skb->len);
290 if (!msg) {
291 r = -ENOMEM;
292 goto free_skb;
295 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, info->vendor_info.rx_skb->len,
296 info->vendor_info.rx_skb->data)) {
297 kfree_skb(msg);
298 r = -ENOBUFS;
299 goto free_skb;
302 r = nfc_vendor_cmd_reply(msg);
303 free_skb:
304 kfree_skb(info->vendor_info.rx_skb);
305 exit:
306 return r;
309 static struct nfc_vendor_cmd st21nfca_vendor_cmds[] = {
311 .vendor_id = ST21NFCA_VENDOR_OUI,
312 .subcmd = FACTORY_MODE,
313 .doit = st21nfca_factory_mode,
316 .vendor_id = ST21NFCA_VENDOR_OUI,
317 .subcmd = HCI_CLEAR_ALL_PIPES,
318 .doit = st21nfca_hci_clear_all_pipes,
321 .vendor_id = ST21NFCA_VENDOR_OUI,
322 .subcmd = HCI_DM_PUT_DATA,
323 .doit = st21nfca_hci_dm_put_data,
326 .vendor_id = ST21NFCA_VENDOR_OUI,
327 .subcmd = HCI_DM_UPDATE_AID,
328 .doit = st21nfca_hci_dm_update_aid,
331 .vendor_id = ST21NFCA_VENDOR_OUI,
332 .subcmd = HCI_DM_GET_INFO,
333 .doit = st21nfca_hci_dm_get_info,
336 .vendor_id = ST21NFCA_VENDOR_OUI,
337 .subcmd = HCI_DM_GET_DATA,
338 .doit = st21nfca_hci_dm_get_data,
341 .vendor_id = ST21NFCA_VENDOR_OUI,
342 .subcmd = HCI_DM_LOAD,
343 .doit = st21nfca_hci_dm_load,
346 .vendor_id = ST21NFCA_VENDOR_OUI,
347 .subcmd = HCI_DM_RESET,
348 .doit = st21nfca_hci_dm_reset,
351 .vendor_id = ST21NFCA_VENDOR_OUI,
352 .subcmd = HCI_GET_PARAM,
353 .doit = st21nfca_hci_get_param,
356 .vendor_id = ST21NFCA_VENDOR_OUI,
357 .subcmd = HCI_DM_FIELD_GENERATOR,
358 .doit = st21nfca_hci_dm_field_generator,
361 .vendor_id = ST21NFCA_VENDOR_OUI,
362 .subcmd = HCI_LOOPBACK,
363 .doit = st21nfca_hci_loopback,
367 int st21nfca_vendor_cmds_init(struct nfc_hci_dev *hdev)
369 struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
371 init_completion(&info->vendor_info.req_completion);
372 return nfc_set_vendor_cmds(hdev->ndev, st21nfca_vendor_cmds,
373 sizeof(st21nfca_vendor_cmds));
375 EXPORT_SYMBOL(st21nfca_vendor_cmds_init);