2 * Proprietary commands extension for STMicroelectronics NFC NCI 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 <linux/delay.h>
23 #include <net/nfc/nci_core.h>
27 #define ST_NCI_HCI_DM_GETDATA 0x10
28 #define ST_NCI_HCI_DM_PUTDATA 0x11
29 #define ST_NCI_HCI_DM_LOAD 0x12
30 #define ST_NCI_HCI_DM_GETINFO 0x13
31 #define ST_NCI_HCI_DM_FWUPD_START 0x14
32 #define ST_NCI_HCI_DM_FWUPD_STOP 0x15
33 #define ST_NCI_HCI_DM_UPDATE_AID 0x20
34 #define ST_NCI_HCI_DM_RESET 0x3e
36 #define ST_NCI_HCI_DM_FIELD_GENERATOR 0x32
37 #define ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE 0x33
38 #define ST_NCI_HCI_DM_VDC_VALUE_COMPARISON 0x34
40 #define ST_NCI_FACTORY_MODE_ON 1
41 #define ST_NCI_FACTORY_MODE_OFF 0
43 #define ST_NCI_EVT_POST_DATA 0x02
45 struct get_param_data
{
50 static int st_nci_factory_mode(struct nfc_dev
*dev
, void *data
,
53 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
54 struct st_nci_info
*info
= nci_get_drvdata(ndev
);
59 pr_debug("factory mode: %x\n", ((u8
*)data
)[0]);
61 switch (((u8
*)data
)[0]) {
62 case ST_NCI_FACTORY_MODE_ON
:
63 test_and_set_bit(ST_NCI_FACTORY_MODE
, &info
->flags
);
65 case ST_NCI_FACTORY_MODE_OFF
:
66 clear_bit(ST_NCI_FACTORY_MODE
, &info
->flags
);
75 static int st_nci_hci_clear_all_pipes(struct nfc_dev
*dev
, void *data
,
78 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
80 return nci_hci_clear_all_pipes(ndev
);
83 static int st_nci_hci_dm_put_data(struct nfc_dev
*dev
, void *data
,
86 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
88 return nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
89 ST_NCI_HCI_DM_PUTDATA
, data
,
93 static int st_nci_hci_dm_update_aid(struct nfc_dev
*dev
, void *data
,
96 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
98 return nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
99 ST_NCI_HCI_DM_UPDATE_AID
, data
, data_len
, NULL
);
102 static int st_nci_hci_dm_get_info(struct nfc_dev
*dev
, void *data
,
106 struct sk_buff
*msg
, *skb
;
107 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
109 r
= nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
, ST_NCI_HCI_DM_GETINFO
,
110 data
, data_len
, &skb
);
114 msg
= nfc_vendor_cmd_alloc_reply_skb(dev
, ST_NCI_VENDOR_OUI
,
115 HCI_DM_GET_INFO
, skb
->len
);
121 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, skb
->len
, skb
->data
)) {
127 r
= nfc_vendor_cmd_reply(msg
);
135 static int st_nci_hci_dm_get_data(struct nfc_dev
*dev
, void *data
,
139 struct sk_buff
*msg
, *skb
;
140 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
142 r
= nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
, ST_NCI_HCI_DM_GETDATA
,
143 data
, data_len
, &skb
);
147 msg
= nfc_vendor_cmd_alloc_reply_skb(dev
, ST_NCI_VENDOR_OUI
,
148 HCI_DM_GET_DATA
, skb
->len
);
154 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, skb
->len
, skb
->data
)) {
160 r
= nfc_vendor_cmd_reply(msg
);
168 static int st_nci_hci_dm_fwupd_start(struct nfc_dev
*dev
, void *data
,
172 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
174 dev
->fw_download_in_progress
= true;
175 r
= nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
176 ST_NCI_HCI_DM_FWUPD_START
, data
, data_len
, NULL
);
178 dev
->fw_download_in_progress
= false;
183 static int st_nci_hci_dm_fwupd_end(struct nfc_dev
*dev
, void *data
,
186 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
188 return nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
189 ST_NCI_HCI_DM_FWUPD_STOP
, data
, data_len
, NULL
);
192 static int st_nci_hci_dm_direct_load(struct nfc_dev
*dev
, void *data
,
195 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
197 if (dev
->fw_download_in_progress
) {
198 dev
->fw_download_in_progress
= false;
199 return nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
200 ST_NCI_HCI_DM_LOAD
, data
, data_len
, NULL
);
205 static int st_nci_hci_dm_reset(struct nfc_dev
*dev
, void *data
,
208 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
210 nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
211 ST_NCI_HCI_DM_RESET
, data
, data_len
, NULL
);
217 static int st_nci_hci_get_param(struct nfc_dev
*dev
, void *data
,
221 struct sk_buff
*msg
, *skb
;
222 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
223 struct get_param_data
*param
= (struct get_param_data
*)data
;
225 if (data_len
< sizeof(struct get_param_data
))
228 r
= nci_hci_get_param(ndev
, param
->gate
, param
->data
, &skb
);
232 msg
= nfc_vendor_cmd_alloc_reply_skb(dev
, ST_NCI_VENDOR_OUI
,
233 HCI_GET_PARAM
, skb
->len
);
239 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, skb
->len
, skb
->data
)) {
245 r
= nfc_vendor_cmd_reply(msg
);
253 static int st_nci_hci_dm_field_generator(struct nfc_dev
*dev
, void *data
,
256 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
258 return nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
259 ST_NCI_HCI_DM_FIELD_GENERATOR
, data
, data_len
, NULL
);
262 static int st_nci_hci_dm_vdc_measurement_value(struct nfc_dev
*dev
, void *data
,
266 struct sk_buff
*msg
, *skb
;
267 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
272 r
= nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
273 ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE
,
274 data
, data_len
, &skb
);
278 msg
= nfc_vendor_cmd_alloc_reply_skb(dev
, ST_NCI_VENDOR_OUI
,
279 HCI_DM_VDC_MEASUREMENT_VALUE
, skb
->len
);
285 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, skb
->len
, skb
->data
)) {
291 r
= nfc_vendor_cmd_reply(msg
);
299 static int st_nci_hci_dm_vdc_value_comparison(struct nfc_dev
*dev
, void *data
,
303 struct sk_buff
*msg
, *skb
;
304 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
309 r
= nci_hci_send_cmd(ndev
, ST_NCI_DEVICE_MGNT_GATE
,
310 ST_NCI_HCI_DM_VDC_VALUE_COMPARISON
,
311 data
, data_len
, &skb
);
315 msg
= nfc_vendor_cmd_alloc_reply_skb(dev
, ST_NCI_VENDOR_OUI
,
316 HCI_DM_VDC_VALUE_COMPARISON
, skb
->len
);
322 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, skb
->len
, skb
->data
)) {
328 r
= nfc_vendor_cmd_reply(msg
);
336 void st_nci_hci_loopback_event_received(struct nci_dev
*ndev
, u8 event
,
339 struct st_nci_info
*info
= nci_get_drvdata(ndev
);
342 case ST_NCI_EVT_POST_DATA
:
343 info
->vendor_info
.rx_skb
= skb
;
346 nfc_err(&ndev
->nfc_dev
->dev
, "Unexpected event on loopback gate\n");
348 complete(&info
->vendor_info
.req_completion
);
350 EXPORT_SYMBOL(st_nci_hci_loopback_event_received
);
352 static int st_nci_hci_loopback(struct nfc_dev
*dev
, void *data
,
357 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
358 struct st_nci_info
*info
= nci_get_drvdata(ndev
);
363 reinit_completion(&info
->vendor_info
.req_completion
);
364 info
->vendor_info
.rx_skb
= NULL
;
366 r
= nci_hci_send_event(ndev
, NCI_HCI_LOOPBACK_GATE
,
367 ST_NCI_EVT_POST_DATA
, data
, data_len
);
373 wait_for_completion_interruptible(&info
->vendor_info
.req_completion
);
375 if (!info
->vendor_info
.rx_skb
||
376 info
->vendor_info
.rx_skb
->len
!= data_len
) {
381 msg
= nfc_vendor_cmd_alloc_reply_skb(ndev
->nfc_dev
,
384 info
->vendor_info
.rx_skb
->len
);
390 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, info
->vendor_info
.rx_skb
->len
,
391 info
->vendor_info
.rx_skb
->data
)) {
397 r
= nfc_vendor_cmd_reply(msg
);
399 kfree_skb(info
->vendor_info
.rx_skb
);
404 static int st_nci_manufacturer_specific(struct nfc_dev
*dev
, void *data
,
408 struct nci_dev
*ndev
= nfc_get_drvdata(dev
);
410 msg
= nfc_vendor_cmd_alloc_reply_skb(dev
, ST_NCI_VENDOR_OUI
,
411 MANUFACTURER_SPECIFIC
,
412 sizeof(ndev
->manufact_specific_info
));
416 if (nla_put(msg
, NFC_ATTR_VENDOR_DATA
, sizeof(ndev
->manufact_specific_info
),
417 &ndev
->manufact_specific_info
)) {
422 return nfc_vendor_cmd_reply(msg
);
425 static struct nfc_vendor_cmd st_nci_vendor_cmds
[] = {
427 .vendor_id
= ST_NCI_VENDOR_OUI
,
428 .subcmd
= FACTORY_MODE
,
429 .doit
= st_nci_factory_mode
,
432 .vendor_id
= ST_NCI_VENDOR_OUI
,
433 .subcmd
= HCI_CLEAR_ALL_PIPES
,
434 .doit
= st_nci_hci_clear_all_pipes
,
437 .vendor_id
= ST_NCI_VENDOR_OUI
,
438 .subcmd
= HCI_DM_PUT_DATA
,
439 .doit
= st_nci_hci_dm_put_data
,
442 .vendor_id
= ST_NCI_VENDOR_OUI
,
443 .subcmd
= HCI_DM_UPDATE_AID
,
444 .doit
= st_nci_hci_dm_update_aid
,
447 .vendor_id
= ST_NCI_VENDOR_OUI
,
448 .subcmd
= HCI_DM_GET_INFO
,
449 .doit
= st_nci_hci_dm_get_info
,
452 .vendor_id
= ST_NCI_VENDOR_OUI
,
453 .subcmd
= HCI_DM_GET_DATA
,
454 .doit
= st_nci_hci_dm_get_data
,
457 .vendor_id
= ST_NCI_VENDOR_OUI
,
458 .subcmd
= HCI_DM_DIRECT_LOAD
,
459 .doit
= st_nci_hci_dm_direct_load
,
462 .vendor_id
= ST_NCI_VENDOR_OUI
,
463 .subcmd
= HCI_DM_RESET
,
464 .doit
= st_nci_hci_dm_reset
,
467 .vendor_id
= ST_NCI_VENDOR_OUI
,
468 .subcmd
= HCI_GET_PARAM
,
469 .doit
= st_nci_hci_get_param
,
472 .vendor_id
= ST_NCI_VENDOR_OUI
,
473 .subcmd
= HCI_DM_FIELD_GENERATOR
,
474 .doit
= st_nci_hci_dm_field_generator
,
477 .vendor_id
= ST_NCI_VENDOR_OUI
,
478 .subcmd
= HCI_DM_FWUPD_START
,
479 .doit
= st_nci_hci_dm_fwupd_start
,
482 .vendor_id
= ST_NCI_VENDOR_OUI
,
483 .subcmd
= HCI_DM_FWUPD_END
,
484 .doit
= st_nci_hci_dm_fwupd_end
,
487 .vendor_id
= ST_NCI_VENDOR_OUI
,
488 .subcmd
= HCI_LOOPBACK
,
489 .doit
= st_nci_hci_loopback
,
492 .vendor_id
= ST_NCI_VENDOR_OUI
,
493 .subcmd
= HCI_DM_VDC_MEASUREMENT_VALUE
,
494 .doit
= st_nci_hci_dm_vdc_measurement_value
,
497 .vendor_id
= ST_NCI_VENDOR_OUI
,
498 .subcmd
= HCI_DM_VDC_VALUE_COMPARISON
,
499 .doit
= st_nci_hci_dm_vdc_value_comparison
,
502 .vendor_id
= ST_NCI_VENDOR_OUI
,
503 .subcmd
= MANUFACTURER_SPECIFIC
,
504 .doit
= st_nci_manufacturer_specific
,
508 int st_nci_vendor_cmds_init(struct nci_dev
*ndev
)
510 struct st_nci_info
*info
= nci_get_drvdata(ndev
);
512 init_completion(&info
->vendor_info
.req_completion
);
513 return nfc_set_vendor_cmds(ndev
->nfc_dev
, st_nci_vendor_cmds
,
514 sizeof(st_nci_vendor_cmds
));
516 EXPORT_SYMBOL(st_nci_vendor_cmds_init
);