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>
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 {
46 static int st21nfca_factory_mode(struct nfc_dev *dev, void *data,
49 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
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);
60 case ST21NFCA_FACTORY_MODE_OFF:
61 clear_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
70 static int st21nfca_hci_clear_all_pipes(struct nfc_dev *dev, void *data,
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,
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,
88 static int st21nfca_hci_dm_update_aid(struct nfc_dev *dev, void *data,
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,
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);
111 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
112 HCI_DM_GET_INFO, skb->len);
118 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
124 r = nfc_vendor_cmd_reply(msg);
132 static int st21nfca_hci_dm_get_data(struct nfc_dev *dev, void *data,
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);
146 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
147 HCI_DM_GET_DATA, skb->len);
153 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
159 r = nfc_vendor_cmd_reply(msg);
167 static int st21nfca_hci_dm_load(struct nfc_dev *dev, void *data,
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,
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);
187 r = nfc_llc_stop(hdev->llc);
191 return nfc_llc_start(hdev->llc);
194 static int st21nfca_hci_get_param(struct nfc_dev *dev, void *data,
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))
205 r = nfc_hci_get_param(hdev, param->gate, param->data, &skb);
209 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
210 HCI_GET_PARAM, skb->len);
216 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
222 r = nfc_vendor_cmd_reply(msg);
230 static int st21nfca_hci_dm_field_generator(struct nfc_dev *dev, void *data,
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,
244 struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
247 case ST21NFCA_EVT_POST_DATA:
248 info->vendor_info.rx_skb = skb;
251 nfc_err(&hdev->ndev->dev, "Unexpected event on loopback gate\n");
253 complete(&info->vendor_info.req_completion);
256 EXPORT_SYMBOL(st21nfca_hci_loopback_event_received);
258 static int st21nfca_hci_loopback(struct nfc_dev *dev, void *data,
263 struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
264 struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
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);
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) {
286 msg = nfc_vendor_cmd_alloc_reply_skb(hdev->ndev,
289 info->vendor_info.rx_skb->len);
295 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, info->vendor_info.rx_skb->len,
296 info->vendor_info.rx_skb->data)) {
302 r = nfc_vendor_cmd_reply(msg);
304 kfree_skb(info->vendor_info.rx_skb);
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);