1 // SPDX-License-Identifier: GPL-2.0-only
3 * Proprietary commands extension for STMicroelectronics NFC NCI Chip
5 * Copyright (C) 2014-2015 STMicroelectronics SAS. All rights reserved.
8 #include <net/genetlink.h>
9 #include <linux/module.h>
10 #include <linux/nfc.h>
11 #include <linux/delay.h>
12 #include <net/nfc/nci_core.h>
16 #define ST_NCI_HCI_DM_GETDATA 0x10
17 #define ST_NCI_HCI_DM_PUTDATA 0x11
18 #define ST_NCI_HCI_DM_LOAD 0x12
19 #define ST_NCI_HCI_DM_GETINFO 0x13
20 #define ST_NCI_HCI_DM_FWUPD_START 0x14
21 #define ST_NCI_HCI_DM_FWUPD_STOP 0x15
22 #define ST_NCI_HCI_DM_UPDATE_AID 0x20
23 #define ST_NCI_HCI_DM_RESET 0x3e
25 #define ST_NCI_HCI_DM_FIELD_GENERATOR 0x32
26 #define ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE 0x33
27 #define ST_NCI_HCI_DM_VDC_VALUE_COMPARISON 0x34
29 #define ST_NCI_FACTORY_MODE_ON 1
30 #define ST_NCI_FACTORY_MODE_OFF 0
32 #define ST_NCI_EVT_POST_DATA 0x02
34 struct get_param_data {
39 static int st_nci_factory_mode(struct nfc_dev *dev, void *data,
42 struct nci_dev *ndev = nfc_get_drvdata(dev);
43 struct st_nci_info *info = nci_get_drvdata(ndev);
48 pr_debug("factory mode: %x\n", ((u8 *)data)[0]);
50 switch (((u8 *)data)[0]) {
51 case ST_NCI_FACTORY_MODE_ON:
52 test_and_set_bit(ST_NCI_FACTORY_MODE, &info->flags);
54 case ST_NCI_FACTORY_MODE_OFF:
55 clear_bit(ST_NCI_FACTORY_MODE, &info->flags);
64 static int st_nci_hci_clear_all_pipes(struct nfc_dev *dev, void *data,
67 struct nci_dev *ndev = nfc_get_drvdata(dev);
69 return nci_hci_clear_all_pipes(ndev);
72 static int st_nci_hci_dm_put_data(struct nfc_dev *dev, void *data,
75 struct nci_dev *ndev = nfc_get_drvdata(dev);
77 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
78 ST_NCI_HCI_DM_PUTDATA, data,
82 static int st_nci_hci_dm_update_aid(struct nfc_dev *dev, void *data,
85 struct nci_dev *ndev = nfc_get_drvdata(dev);
87 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
88 ST_NCI_HCI_DM_UPDATE_AID, data, data_len, NULL);
91 static int st_nci_hci_dm_get_info(struct nfc_dev *dev, void *data,
95 struct sk_buff *msg, *skb;
96 struct nci_dev *ndev = nfc_get_drvdata(dev);
98 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETINFO,
99 data, data_len, &skb);
103 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
104 HCI_DM_GET_INFO, skb->len);
110 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
116 r = nfc_vendor_cmd_reply(msg);
123 static int st_nci_hci_dm_get_data(struct nfc_dev *dev, void *data,
127 struct sk_buff *msg, *skb;
128 struct nci_dev *ndev = nfc_get_drvdata(dev);
130 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETDATA,
131 data, data_len, &skb);
135 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
136 HCI_DM_GET_DATA, skb->len);
142 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
148 r = nfc_vendor_cmd_reply(msg);
155 static int st_nci_hci_dm_fwupd_start(struct nfc_dev *dev, void *data,
159 struct nci_dev *ndev = nfc_get_drvdata(dev);
161 dev->fw_download_in_progress = true;
162 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
163 ST_NCI_HCI_DM_FWUPD_START, data, data_len, NULL);
165 dev->fw_download_in_progress = false;
170 static int st_nci_hci_dm_fwupd_end(struct nfc_dev *dev, void *data,
173 struct nci_dev *ndev = nfc_get_drvdata(dev);
175 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
176 ST_NCI_HCI_DM_FWUPD_STOP, data, data_len, NULL);
179 static int st_nci_hci_dm_direct_load(struct nfc_dev *dev, void *data,
182 struct nci_dev *ndev = nfc_get_drvdata(dev);
184 if (dev->fw_download_in_progress) {
185 dev->fw_download_in_progress = false;
186 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
187 ST_NCI_HCI_DM_LOAD, data, data_len, NULL);
192 static int st_nci_hci_dm_reset(struct nfc_dev *dev, void *data,
195 struct nci_dev *ndev = nfc_get_drvdata(dev);
197 nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
198 ST_NCI_HCI_DM_RESET, data, data_len, NULL);
204 static int st_nci_hci_get_param(struct nfc_dev *dev, void *data,
208 struct sk_buff *msg, *skb;
209 struct nci_dev *ndev = nfc_get_drvdata(dev);
210 struct get_param_data *param = (struct get_param_data *)data;
212 if (data_len < sizeof(struct get_param_data))
215 r = nci_hci_get_param(ndev, param->gate, param->data, &skb);
219 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
220 HCI_GET_PARAM, skb->len);
226 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
232 r = nfc_vendor_cmd_reply(msg);
239 static int st_nci_hci_dm_field_generator(struct nfc_dev *dev, void *data,
242 struct nci_dev *ndev = nfc_get_drvdata(dev);
244 return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
245 ST_NCI_HCI_DM_FIELD_GENERATOR, data, data_len, NULL);
248 static int st_nci_hci_dm_vdc_measurement_value(struct nfc_dev *dev, void *data,
252 struct sk_buff *msg, *skb;
253 struct nci_dev *ndev = nfc_get_drvdata(dev);
258 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
259 ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE,
260 data, data_len, &skb);
264 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
265 HCI_DM_VDC_MEASUREMENT_VALUE, skb->len);
271 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
277 r = nfc_vendor_cmd_reply(msg);
284 static int st_nci_hci_dm_vdc_value_comparison(struct nfc_dev *dev, void *data,
288 struct sk_buff *msg, *skb;
289 struct nci_dev *ndev = nfc_get_drvdata(dev);
294 r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
295 ST_NCI_HCI_DM_VDC_VALUE_COMPARISON,
296 data, data_len, &skb);
300 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
301 HCI_DM_VDC_VALUE_COMPARISON, skb->len);
307 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
313 r = nfc_vendor_cmd_reply(msg);
320 static int st_nci_loopback(struct nfc_dev *dev, void *data,
324 struct sk_buff *msg, *skb;
325 struct nci_dev *ndev = nfc_get_drvdata(dev);
330 r = nci_nfcc_loopback(ndev, data, data_len, &skb);
334 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
341 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
347 r = nfc_vendor_cmd_reply(msg);
353 static int st_nci_manufacturer_specific(struct nfc_dev *dev, void *data,
357 struct nci_dev *ndev = nfc_get_drvdata(dev);
359 msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
360 MANUFACTURER_SPECIFIC,
361 sizeof(ndev->manufact_specific_info));
365 if (nla_put(msg, NFC_ATTR_VENDOR_DATA, sizeof(ndev->manufact_specific_info),
366 &ndev->manufact_specific_info)) {
371 return nfc_vendor_cmd_reply(msg);
374 static const struct nfc_vendor_cmd st_nci_vendor_cmds[] = {
376 .vendor_id = ST_NCI_VENDOR_OUI,
377 .subcmd = FACTORY_MODE,
378 .doit = st_nci_factory_mode,
381 .vendor_id = ST_NCI_VENDOR_OUI,
382 .subcmd = HCI_CLEAR_ALL_PIPES,
383 .doit = st_nci_hci_clear_all_pipes,
386 .vendor_id = ST_NCI_VENDOR_OUI,
387 .subcmd = HCI_DM_PUT_DATA,
388 .doit = st_nci_hci_dm_put_data,
391 .vendor_id = ST_NCI_VENDOR_OUI,
392 .subcmd = HCI_DM_UPDATE_AID,
393 .doit = st_nci_hci_dm_update_aid,
396 .vendor_id = ST_NCI_VENDOR_OUI,
397 .subcmd = HCI_DM_GET_INFO,
398 .doit = st_nci_hci_dm_get_info,
401 .vendor_id = ST_NCI_VENDOR_OUI,
402 .subcmd = HCI_DM_GET_DATA,
403 .doit = st_nci_hci_dm_get_data,
406 .vendor_id = ST_NCI_VENDOR_OUI,
407 .subcmd = HCI_DM_DIRECT_LOAD,
408 .doit = st_nci_hci_dm_direct_load,
411 .vendor_id = ST_NCI_VENDOR_OUI,
412 .subcmd = HCI_DM_RESET,
413 .doit = st_nci_hci_dm_reset,
416 .vendor_id = ST_NCI_VENDOR_OUI,
417 .subcmd = HCI_GET_PARAM,
418 .doit = st_nci_hci_get_param,
421 .vendor_id = ST_NCI_VENDOR_OUI,
422 .subcmd = HCI_DM_FIELD_GENERATOR,
423 .doit = st_nci_hci_dm_field_generator,
426 .vendor_id = ST_NCI_VENDOR_OUI,
427 .subcmd = HCI_DM_FWUPD_START,
428 .doit = st_nci_hci_dm_fwupd_start,
431 .vendor_id = ST_NCI_VENDOR_OUI,
432 .subcmd = HCI_DM_FWUPD_END,
433 .doit = st_nci_hci_dm_fwupd_end,
436 .vendor_id = ST_NCI_VENDOR_OUI,
438 .doit = st_nci_loopback,
441 .vendor_id = ST_NCI_VENDOR_OUI,
442 .subcmd = HCI_DM_VDC_MEASUREMENT_VALUE,
443 .doit = st_nci_hci_dm_vdc_measurement_value,
446 .vendor_id = ST_NCI_VENDOR_OUI,
447 .subcmd = HCI_DM_VDC_VALUE_COMPARISON,
448 .doit = st_nci_hci_dm_vdc_value_comparison,
451 .vendor_id = ST_NCI_VENDOR_OUI,
452 .subcmd = MANUFACTURER_SPECIFIC,
453 .doit = st_nci_manufacturer_specific,
457 int st_nci_vendor_cmds_init(struct nci_dev *ndev)
459 return nci_set_vendor_cmds(ndev, st_nci_vendor_cmds,
460 sizeof(st_nci_vendor_cmds));
462 EXPORT_SYMBOL(st_nci_vendor_cmds_init);