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
);
124 static int st_nci_hci_dm_get_data(struct nfc_dev
*dev
, void *data
,
128 struct sk_buff
*msg
, *skb
;
129 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
131 r
= nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
, ST_NCI_HCI_DM_GETDATA
,
132 data
, data_len
, &skb
);
136 msg
= nfc_vendor_cmd_alloc_reply_skb(dev
, ST_NCI_VENDOR_OUI
,
137 HCI_DM_GET_DATA
, skb
->len
);
143 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, skb
->len
, skb
->data
)) {
149 r
= nfc_vendor_cmd_reply(msg
);
157 static int st_nci_hci_dm_fwupd_start(struct nfc_dev
*dev
, void *data
,
161 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
163 dev
->fw_download_in_progress
= true;
164 r
= nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
165 ST_NCI_HCI_DM_FWUPD_START
, data
, data_len
, NULL
);
167 dev
->fw_download_in_progress
= false;
172 static int st_nci_hci_dm_fwupd_end(struct nfc_dev
*dev
, void *data
,
175 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
177 return nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
178 ST_NCI_HCI_DM_FWUPD_STOP
, data
, data_len
, NULL
);
181 static int st_nci_hci_dm_direct_load(struct nfc_dev
*dev
, void *data
,
184 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
186 if (dev
->fw_download_in_progress
) {
187 dev
->fw_download_in_progress
= false;
188 return nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
189 ST_NCI_HCI_DM_LOAD
, data
, data_len
, NULL
);
194 static int st_nci_hci_dm_reset(struct nfc_dev
*dev
, void *data
,
197 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
199 nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
200 ST_NCI_HCI_DM_RESET
, data
, data_len
, NULL
);
206 static int st_nci_hci_get_param(struct nfc_dev
*dev
, void *data
,
210 struct sk_buff
*msg
, *skb
;
211 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
212 struct get_param_data
*param
= (struct get_param_data
*)data
;
214 if (data_len
< sizeof(struct get_param_data
))
217 r
= nci_hci_get_param(ndev
, param
->gate
, param
->data
, &skb
);
221 msg
= nfc_vendor_cmd_alloc_reply_skb(dev
, ST_NCI_VENDOR_OUI
,
222 HCI_GET_PARAM
, skb
->len
);
228 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, skb
->len
, skb
->data
)) {
234 r
= nfc_vendor_cmd_reply(msg
);
242 static int st_nci_hci_dm_field_generator(struct nfc_dev
*dev
, void *data
,
245 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
247 return nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
248 ST_NCI_HCI_DM_FIELD_GENERATOR
, data
, data_len
, NULL
);
251 static int st_nci_hci_dm_vdc_measurement_value(struct nfc_dev
*dev
, void *data
,
255 struct sk_buff
*msg
, *skb
;
256 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
261 r
= nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
262 ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE
,
263 data
, data_len
, &skb
);
267 msg
= nfc_vendor_cmd_alloc_reply_skb(dev
, ST_NCI_VENDOR_OUI
,
268 HCI_DM_VDC_MEASUREMENT_VALUE
, skb
->len
);
274 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, skb
->len
, skb
->data
)) {
280 r
= nfc_vendor_cmd_reply(msg
);
288 static int st_nci_hci_dm_vdc_value_comparison(struct nfc_dev
*dev
, void *data
,
292 struct sk_buff
*msg
, *skb
;
293 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
298 r
= nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
299 ST_NCI_HCI_DM_VDC_VALUE_COMPARISON
,
300 data
, data_len
, &skb
);
304 msg
= nfc_vendor_cmd_alloc_reply_skb(dev
, ST_NCI_VENDOR_OUI
,
305 HCI_DM_VDC_VALUE_COMPARISON
, skb
->len
);
311 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, skb
->len
, skb
->data
)) {
317 r
= nfc_vendor_cmd_reply(msg
);
325 static int st_nci_loopback(struct nfc_dev
*dev
, void *data
,
329 struct sk_buff
*msg
, *skb
;
330 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
335 r
= nci_nfcc_loopback(ndev
, data
, data_len
, &skb
);
339 msg
= nfc_vendor_cmd_alloc_reply_skb(dev
, ST_NCI_VENDOR_OUI
,
346 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, skb
->len
, skb
->data
)) {
352 r
= nfc_vendor_cmd_reply(msg
);
358 static int st_nci_manufacturer_specific(struct nfc_dev
*dev
, void *data
,
362 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
364 msg
= nfc_vendor_cmd_alloc_reply_skb(dev
, ST_NCI_VENDOR_OUI
,
365 MANUFACTURER_SPECIFIC
,
366 sizeof(ndev
->manufact_specific_info
));
370 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, sizeof(ndev
->manufact_specific_info
),
371 &ndev
->manufact_specific_info
)) {
376 return nfc_vendor_cmd_reply(msg
);
379 static struct nfc_vendor_cmd st_nci_vendor_cmds
[] = {
381 .vendor_id
= ST_NCI_VENDOR_OUI
,
382 .subcmd
= FACTORY_MODE
,
383 .doit
= st_nci_factory_mode
,
386 .vendor_id
= ST_NCI_VENDOR_OUI
,
387 .subcmd
= HCI_CLEAR_ALL_PIPES
,
388 .doit
= st_nci_hci_clear_all_pipes
,
391 .vendor_id
= ST_NCI_VENDOR_OUI
,
392 .subcmd
= HCI_DM_PUT_DATA
,
393 .doit
= st_nci_hci_dm_put_data
,
396 .vendor_id
= ST_NCI_VENDOR_OUI
,
397 .subcmd
= HCI_DM_UPDATE_AID
,
398 .doit
= st_nci_hci_dm_update_aid
,
401 .vendor_id
= ST_NCI_VENDOR_OUI
,
402 .subcmd
= HCI_DM_GET_INFO
,
403 .doit
= st_nci_hci_dm_get_info
,
406 .vendor_id
= ST_NCI_VENDOR_OUI
,
407 .subcmd
= HCI_DM_GET_DATA
,
408 .doit
= st_nci_hci_dm_get_data
,
411 .vendor_id
= ST_NCI_VENDOR_OUI
,
412 .subcmd
= HCI_DM_DIRECT_LOAD
,
413 .doit
= st_nci_hci_dm_direct_load
,
416 .vendor_id
= ST_NCI_VENDOR_OUI
,
417 .subcmd
= HCI_DM_RESET
,
418 .doit
= st_nci_hci_dm_reset
,
421 .vendor_id
= ST_NCI_VENDOR_OUI
,
422 .subcmd
= HCI_GET_PARAM
,
423 .doit
= st_nci_hci_get_param
,
426 .vendor_id
= ST_NCI_VENDOR_OUI
,
427 .subcmd
= HCI_DM_FIELD_GENERATOR
,
428 .doit
= st_nci_hci_dm_field_generator
,
431 .vendor_id
= ST_NCI_VENDOR_OUI
,
432 .subcmd
= HCI_DM_FWUPD_START
,
433 .doit
= st_nci_hci_dm_fwupd_start
,
436 .vendor_id
= ST_NCI_VENDOR_OUI
,
437 .subcmd
= HCI_DM_FWUPD_END
,
438 .doit
= st_nci_hci_dm_fwupd_end
,
441 .vendor_id
= ST_NCI_VENDOR_OUI
,
443 .doit
= st_nci_loopback
,
446 .vendor_id
= ST_NCI_VENDOR_OUI
,
447 .subcmd
= HCI_DM_VDC_MEASUREMENT_VALUE
,
448 .doit
= st_nci_hci_dm_vdc_measurement_value
,
451 .vendor_id
= ST_NCI_VENDOR_OUI
,
452 .subcmd
= HCI_DM_VDC_VALUE_COMPARISON
,
453 .doit
= st_nci_hci_dm_vdc_value_comparison
,
456 .vendor_id
= ST_NCI_VENDOR_OUI
,
457 .subcmd
= MANUFACTURER_SPECIFIC
,
458 .doit
= st_nci_manufacturer_specific
,
462 int st_nci_vendor_cmds_init(struct nci_dev
*ndev
)
464 return nfc_set_vendor_cmds(ndev
->nfc_dev
, st_nci_vendor_cmds
,
465 sizeof(st_nci_vendor_cmds
));
467 EXPORT_SYMBOL(st_nci_vendor_cmds_init
);