146fe7771SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
215d17170SChristophe Ricard /*
315d17170SChristophe Ricard  * Proprietary commands extension for STMicroelectronics NFC Chip
415d17170SChristophe Ricard  *
515d17170SChristophe Ricard  * Copyright (C) 2014-2015  STMicroelectronics SAS. All rights reserved.
615d17170SChristophe Ricard  */
715d17170SChristophe Ricard 
815d17170SChristophe Ricard #include <net/genetlink.h>
915d17170SChristophe Ricard #include <linux/module.h>
1015d17170SChristophe Ricard #include <linux/nfc.h>
1115d17170SChristophe Ricard #include <net/nfc/hci.h>
1215d17170SChristophe Ricard #include <net/nfc/llc.h>
1315d17170SChristophe Ricard 
1415d17170SChristophe Ricard #include "st21nfca.h"
1515d17170SChristophe Ricard 
1615d17170SChristophe Ricard #define ST21NFCA_HCI_DM_GETDATA			0x10
1715d17170SChristophe Ricard #define ST21NFCA_HCI_DM_PUTDATA			0x11
1815d17170SChristophe Ricard #define ST21NFCA_HCI_DM_LOAD			0x12
1915d17170SChristophe Ricard #define ST21NFCA_HCI_DM_GETINFO			0x13
2015d17170SChristophe Ricard #define ST21NFCA_HCI_DM_UPDATE_AID		0x20
2115d17170SChristophe Ricard #define ST21NFCA_HCI_DM_RESET			0x3e
2215d17170SChristophe Ricard 
2315d17170SChristophe Ricard #define ST21NFCA_HCI_DM_FIELD_GENERATOR		0x32
2415d17170SChristophe Ricard 
2515d17170SChristophe Ricard #define ST21NFCA_FACTORY_MODE_ON		1
2615d17170SChristophe Ricard #define ST21NFCA_FACTORY_MODE_OFF		0
2715d17170SChristophe Ricard 
2815d17170SChristophe Ricard #define ST21NFCA_EVT_POST_DATA			0x02
2915d17170SChristophe Ricard 
3015d17170SChristophe Ricard struct get_param_data {
3115d17170SChristophe Ricard 	u8 gate;
3215d17170SChristophe Ricard 	u8 data;
3315d17170SChristophe Ricard } __packed;
3415d17170SChristophe Ricard 
st21nfca_factory_mode(struct nfc_dev * dev,void * data,size_t data_len)3515d17170SChristophe Ricard static int st21nfca_factory_mode(struct nfc_dev *dev, void *data,
3615d17170SChristophe Ricard 			       size_t data_len)
3715d17170SChristophe Ricard {
3815d17170SChristophe Ricard 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
3915d17170SChristophe Ricard 
4015d17170SChristophe Ricard 	if (data_len != 1)
4115d17170SChristophe Ricard 		return -EINVAL;
4215d17170SChristophe Ricard 
4315d17170SChristophe Ricard 	pr_debug("factory mode: %x\n", ((u8 *)data)[0]);
4415d17170SChristophe Ricard 
4515d17170SChristophe Ricard 	switch (((u8 *)data)[0]) {
4615d17170SChristophe Ricard 	case ST21NFCA_FACTORY_MODE_ON:
4715d17170SChristophe Ricard 		test_and_set_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
4815d17170SChristophe Ricard 	break;
4915d17170SChristophe Ricard 	case ST21NFCA_FACTORY_MODE_OFF:
5015d17170SChristophe Ricard 		clear_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
5115d17170SChristophe Ricard 	break;
5215d17170SChristophe Ricard 	default:
5315d17170SChristophe Ricard 		return -EINVAL;
5415d17170SChristophe Ricard 	}
5515d17170SChristophe Ricard 
5615d17170SChristophe Ricard 	return 0;
5715d17170SChristophe Ricard }
5815d17170SChristophe Ricard 
st21nfca_hci_clear_all_pipes(struct nfc_dev * dev,void * data,size_t data_len)5915d17170SChristophe Ricard static int st21nfca_hci_clear_all_pipes(struct nfc_dev *dev, void *data,
6015d17170SChristophe Ricard 				      size_t data_len)
6115d17170SChristophe Ricard {
6215d17170SChristophe Ricard 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
6315d17170SChristophe Ricard 
6415d17170SChristophe Ricard 	return nfc_hci_disconnect_all_gates(hdev);
6515d17170SChristophe Ricard }
6615d17170SChristophe Ricard 
st21nfca_hci_dm_put_data(struct nfc_dev * dev,void * data,size_t data_len)6715d17170SChristophe Ricard static int st21nfca_hci_dm_put_data(struct nfc_dev *dev, void *data,
6815d17170SChristophe Ricard 				  size_t data_len)
6915d17170SChristophe Ricard {
7015d17170SChristophe Ricard 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
7115d17170SChristophe Ricard 
7215d17170SChristophe Ricard 	return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
7315d17170SChristophe Ricard 				ST21NFCA_HCI_DM_PUTDATA, data,
7415d17170SChristophe Ricard 				data_len, NULL);
7515d17170SChristophe Ricard }
7615d17170SChristophe Ricard 
st21nfca_hci_dm_update_aid(struct nfc_dev * dev,void * data,size_t data_len)7715d17170SChristophe Ricard static int st21nfca_hci_dm_update_aid(struct nfc_dev *dev, void *data,
7815d17170SChristophe Ricard 				    size_t data_len)
7915d17170SChristophe Ricard {
8015d17170SChristophe Ricard 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
8115d17170SChristophe Ricard 
8215d17170SChristophe Ricard 	return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
8315d17170SChristophe Ricard 			ST21NFCA_HCI_DM_UPDATE_AID, data, data_len, NULL);
8415d17170SChristophe Ricard }
8515d17170SChristophe Ricard 
st21nfca_hci_dm_get_info(struct nfc_dev * dev,void * data,size_t data_len)8615d17170SChristophe Ricard static int st21nfca_hci_dm_get_info(struct nfc_dev *dev, void *data,
8715d17170SChristophe Ricard 				    size_t data_len)
8815d17170SChristophe Ricard {
8915d17170SChristophe Ricard 	int r;
9015d17170SChristophe Ricard 	struct sk_buff *msg, *skb;
9115d17170SChristophe Ricard 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
9215d17170SChristophe Ricard 
9315d17170SChristophe Ricard 	r = nfc_hci_send_cmd(hdev,
9415d17170SChristophe Ricard 			     ST21NFCA_DEVICE_MGNT_GATE,
9515d17170SChristophe Ricard 			     ST21NFCA_HCI_DM_GETINFO,
9615d17170SChristophe Ricard 			     data, data_len, &skb);
9715d17170SChristophe Ricard 	if (r)
9815d17170SChristophe Ricard 		goto exit;
9915d17170SChristophe Ricard 
10015d17170SChristophe Ricard 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
10115d17170SChristophe Ricard 					     HCI_DM_GET_INFO, skb->len);
10215d17170SChristophe Ricard 	if (!msg) {
10315d17170SChristophe Ricard 		r = -ENOMEM;
10415d17170SChristophe Ricard 		goto free_skb;
10515d17170SChristophe Ricard 	}
10615d17170SChristophe Ricard 
10715d17170SChristophe Ricard 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
10815d17170SChristophe Ricard 		kfree_skb(msg);
10915d17170SChristophe Ricard 		r = -ENOBUFS;
11015d17170SChristophe Ricard 		goto free_skb;
11115d17170SChristophe Ricard 	}
11215d17170SChristophe Ricard 
11315d17170SChristophe Ricard 	r = nfc_vendor_cmd_reply(msg);
11415d17170SChristophe Ricard 
11515d17170SChristophe Ricard free_skb:
11615d17170SChristophe Ricard 	kfree_skb(skb);
11715d17170SChristophe Ricard exit:
11815d17170SChristophe Ricard 	return r;
11915d17170SChristophe Ricard }
12015d17170SChristophe Ricard 
st21nfca_hci_dm_get_data(struct nfc_dev * dev,void * data,size_t data_len)12115d17170SChristophe Ricard static int st21nfca_hci_dm_get_data(struct nfc_dev *dev, void *data,
12215d17170SChristophe Ricard 				    size_t data_len)
12315d17170SChristophe Ricard {
12415d17170SChristophe Ricard 	int r;
12515d17170SChristophe Ricard 	struct sk_buff *msg, *skb;
12615d17170SChristophe Ricard 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
12715d17170SChristophe Ricard 
12815d17170SChristophe Ricard 	r = nfc_hci_send_cmd(hdev,
12915d17170SChristophe Ricard 			     ST21NFCA_DEVICE_MGNT_GATE,
13015d17170SChristophe Ricard 			     ST21NFCA_HCI_DM_GETDATA,
13115d17170SChristophe Ricard 			     data, data_len, &skb);
13215d17170SChristophe Ricard 	if (r)
13315d17170SChristophe Ricard 		goto exit;
13415d17170SChristophe Ricard 
13515d17170SChristophe Ricard 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
13615d17170SChristophe Ricard 					     HCI_DM_GET_DATA, skb->len);
13715d17170SChristophe Ricard 	if (!msg) {
13815d17170SChristophe Ricard 		r = -ENOMEM;
13915d17170SChristophe Ricard 		goto free_skb;
14015d17170SChristophe Ricard 	}
14115d17170SChristophe Ricard 
14215d17170SChristophe Ricard 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
14315d17170SChristophe Ricard 		kfree_skb(msg);
14415d17170SChristophe Ricard 		r = -ENOBUFS;
14515d17170SChristophe Ricard 		goto free_skb;
14615d17170SChristophe Ricard 	}
14715d17170SChristophe Ricard 
14815d17170SChristophe Ricard 	r = nfc_vendor_cmd_reply(msg);
14915d17170SChristophe Ricard 
15015d17170SChristophe Ricard free_skb:
15115d17170SChristophe Ricard 	kfree_skb(skb);
15215d17170SChristophe Ricard exit:
15315d17170SChristophe Ricard 	return r;
15415d17170SChristophe Ricard }
15515d17170SChristophe Ricard 
st21nfca_hci_dm_load(struct nfc_dev * dev,void * data,size_t data_len)15615d17170SChristophe Ricard static int st21nfca_hci_dm_load(struct nfc_dev *dev, void *data,
15715d17170SChristophe Ricard 				size_t data_len)
15815d17170SChristophe Ricard {
15915d17170SChristophe Ricard 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
16015d17170SChristophe Ricard 
16115d17170SChristophe Ricard 	return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
16215d17170SChristophe Ricard 				ST21NFCA_HCI_DM_LOAD, data, data_len, NULL);
16315d17170SChristophe Ricard }
16415d17170SChristophe Ricard 
st21nfca_hci_dm_reset(struct nfc_dev * dev,void * data,size_t data_len)16515d17170SChristophe Ricard static int st21nfca_hci_dm_reset(struct nfc_dev *dev, void *data,
16615d17170SChristophe Ricard 				 size_t data_len)
16715d17170SChristophe Ricard {
16815d17170SChristophe Ricard 	int r;
16915d17170SChristophe Ricard 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
17015d17170SChristophe Ricard 
17115d17170SChristophe Ricard 	r = nfc_hci_send_cmd_async(hdev, ST21NFCA_DEVICE_MGNT_GATE,
17215d17170SChristophe Ricard 			ST21NFCA_HCI_DM_RESET, data, data_len, NULL, NULL);
17315d17170SChristophe Ricard 	if (r < 0)
17415d17170SChristophe Ricard 		return r;
17515d17170SChristophe Ricard 
17615d17170SChristophe Ricard 	r = nfc_llc_stop(hdev->llc);
17715d17170SChristophe Ricard 	if (r < 0)
17815d17170SChristophe Ricard 		return r;
17915d17170SChristophe Ricard 
18015d17170SChristophe Ricard 	return nfc_llc_start(hdev->llc);
18115d17170SChristophe Ricard }
18215d17170SChristophe Ricard 
st21nfca_hci_get_param(struct nfc_dev * dev,void * data,size_t data_len)18315d17170SChristophe Ricard static int st21nfca_hci_get_param(struct nfc_dev *dev, void *data,
18415d17170SChristophe Ricard 				  size_t data_len)
18515d17170SChristophe Ricard {
18615d17170SChristophe Ricard 	int r;
18715d17170SChristophe Ricard 	struct sk_buff *msg, *skb;
18815d17170SChristophe Ricard 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
18915d17170SChristophe Ricard 	struct get_param_data *param = (struct get_param_data *)data;
19015d17170SChristophe Ricard 
19115d17170SChristophe Ricard 	if (data_len < sizeof(struct get_param_data))
19215d17170SChristophe Ricard 		return -EPROTO;
19315d17170SChristophe Ricard 
19415d17170SChristophe Ricard 	r = nfc_hci_get_param(hdev, param->gate, param->data, &skb);
19515d17170SChristophe Ricard 	if (r)
19615d17170SChristophe Ricard 		goto exit;
19715d17170SChristophe Ricard 
19815d17170SChristophe Ricard 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
19915d17170SChristophe Ricard 					     HCI_GET_PARAM, skb->len);
20015d17170SChristophe Ricard 	if (!msg) {
20115d17170SChristophe Ricard 		r = -ENOMEM;
20215d17170SChristophe Ricard 		goto free_skb;
20315d17170SChristophe Ricard 	}
20415d17170SChristophe Ricard 
20515d17170SChristophe Ricard 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
20615d17170SChristophe Ricard 		kfree_skb(msg);
20715d17170SChristophe Ricard 		r = -ENOBUFS;
20815d17170SChristophe Ricard 		goto free_skb;
20915d17170SChristophe Ricard 	}
21015d17170SChristophe Ricard 
21115d17170SChristophe Ricard 	r = nfc_vendor_cmd_reply(msg);
21215d17170SChristophe Ricard 
21315d17170SChristophe Ricard free_skb:
21415d17170SChristophe Ricard 	kfree_skb(skb);
21515d17170SChristophe Ricard exit:
21615d17170SChristophe Ricard 	return r;
21715d17170SChristophe Ricard }
21815d17170SChristophe Ricard 
st21nfca_hci_dm_field_generator(struct nfc_dev * dev,void * data,size_t data_len)21915d17170SChristophe Ricard static int st21nfca_hci_dm_field_generator(struct nfc_dev *dev, void *data,
22015d17170SChristophe Ricard 					   size_t data_len)
22115d17170SChristophe Ricard {
22215d17170SChristophe Ricard 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
22315d17170SChristophe Ricard 
22415d17170SChristophe Ricard 	return nfc_hci_send_cmd(hdev,
22515d17170SChristophe Ricard 				ST21NFCA_DEVICE_MGNT_GATE,
22615d17170SChristophe Ricard 				ST21NFCA_HCI_DM_FIELD_GENERATOR,
22715d17170SChristophe Ricard 				data, data_len, NULL);
22815d17170SChristophe Ricard }
22915d17170SChristophe Ricard 
st21nfca_hci_loopback_event_received(struct nfc_hci_dev * hdev,u8 event,struct sk_buff * skb)23015d17170SChristophe Ricard int st21nfca_hci_loopback_event_received(struct nfc_hci_dev *hdev, u8 event,
23115d17170SChristophe Ricard 					 struct sk_buff *skb)
23215d17170SChristophe Ricard {
23315d17170SChristophe Ricard 	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
23415d17170SChristophe Ricard 
23515d17170SChristophe Ricard 	switch (event) {
23615d17170SChristophe Ricard 	case ST21NFCA_EVT_POST_DATA:
23715d17170SChristophe Ricard 		info->vendor_info.rx_skb = skb;
23815d17170SChristophe Ricard 	break;
23915d17170SChristophe Ricard 	default:
24015d17170SChristophe Ricard 		nfc_err(&hdev->ndev->dev, "Unexpected event on loopback gate\n");
24115d17170SChristophe Ricard 	}
24215d17170SChristophe Ricard 	complete(&info->vendor_info.req_completion);
24315d17170SChristophe Ricard 	return 0;
24415d17170SChristophe Ricard }
24515d17170SChristophe Ricard EXPORT_SYMBOL(st21nfca_hci_loopback_event_received);
24615d17170SChristophe Ricard 
st21nfca_hci_loopback(struct nfc_dev * dev,void * data,size_t data_len)24715d17170SChristophe Ricard static int st21nfca_hci_loopback(struct nfc_dev *dev, void *data,
24815d17170SChristophe Ricard 				 size_t data_len)
24915d17170SChristophe Ricard {
25015d17170SChristophe Ricard 	int r;
25115d17170SChristophe Ricard 	struct sk_buff *msg;
25215d17170SChristophe Ricard 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
25315d17170SChristophe Ricard 	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
25415d17170SChristophe Ricard 
25515d17170SChristophe Ricard 	if (data_len <= 0)
25615d17170SChristophe Ricard 		return -EPROTO;
25715d17170SChristophe Ricard 
25815d17170SChristophe Ricard 	reinit_completion(&info->vendor_info.req_completion);
25915d17170SChristophe Ricard 	info->vendor_info.rx_skb = NULL;
26015d17170SChristophe Ricard 
26115d17170SChristophe Ricard 	r = nfc_hci_send_event(hdev, NFC_HCI_LOOPBACK_GATE,
26215d17170SChristophe Ricard 			       ST21NFCA_EVT_POST_DATA, data, data_len);
26315d17170SChristophe Ricard 	if (r < 0) {
26415d17170SChristophe Ricard 		r = -EPROTO;
26515d17170SChristophe Ricard 		goto exit;
26615d17170SChristophe Ricard 	}
26715d17170SChristophe Ricard 
26815d17170SChristophe Ricard 	wait_for_completion_interruptible(&info->vendor_info.req_completion);
26915d17170SChristophe Ricard 	if (!info->vendor_info.rx_skb ||
27015d17170SChristophe Ricard 	    info->vendor_info.rx_skb->len != data_len) {
27115d17170SChristophe Ricard 		r = -EPROTO;
27215d17170SChristophe Ricard 		goto exit;
27315d17170SChristophe Ricard 	}
27415d17170SChristophe Ricard 
27515d17170SChristophe Ricard 	msg = nfc_vendor_cmd_alloc_reply_skb(hdev->ndev,
27615d17170SChristophe Ricard 					ST21NFCA_VENDOR_OUI,
27715d17170SChristophe Ricard 					HCI_LOOPBACK,
27815d17170SChristophe Ricard 					info->vendor_info.rx_skb->len);
27915d17170SChristophe Ricard 	if (!msg) {
28015d17170SChristophe Ricard 		r = -ENOMEM;
28115d17170SChristophe Ricard 		goto free_skb;
28215d17170SChristophe Ricard 	}
28315d17170SChristophe Ricard 
28415d17170SChristophe Ricard 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, info->vendor_info.rx_skb->len,
28515d17170SChristophe Ricard 		    info->vendor_info.rx_skb->data)) {
28615d17170SChristophe Ricard 		kfree_skb(msg);
28715d17170SChristophe Ricard 		r = -ENOBUFS;
28815d17170SChristophe Ricard 		goto free_skb;
28915d17170SChristophe Ricard 	}
29015d17170SChristophe Ricard 
29115d17170SChristophe Ricard 	r = nfc_vendor_cmd_reply(msg);
29215d17170SChristophe Ricard free_skb:
29315d17170SChristophe Ricard 	kfree_skb(info->vendor_info.rx_skb);
29415d17170SChristophe Ricard exit:
29515d17170SChristophe Ricard 	return r;
29615d17170SChristophe Ricard }
29715d17170SChristophe Ricard 
29815944ad2SKrzysztof Kozlowski static const struct nfc_vendor_cmd st21nfca_vendor_cmds[] = {
29915d17170SChristophe Ricard 	{
30015d17170SChristophe Ricard 		.vendor_id = ST21NFCA_VENDOR_OUI,
30115d17170SChristophe Ricard 		.subcmd = FACTORY_MODE,
30215d17170SChristophe Ricard 		.doit = st21nfca_factory_mode,
30315d17170SChristophe Ricard 	},
30415d17170SChristophe Ricard 	{
30515d17170SChristophe Ricard 		.vendor_id = ST21NFCA_VENDOR_OUI,
30615d17170SChristophe Ricard 		.subcmd = HCI_CLEAR_ALL_PIPES,
30715d17170SChristophe Ricard 		.doit = st21nfca_hci_clear_all_pipes,
30815d17170SChristophe Ricard 	},
30915d17170SChristophe Ricard 	{
31015d17170SChristophe Ricard 		.vendor_id = ST21NFCA_VENDOR_OUI,
31115d17170SChristophe Ricard 		.subcmd = HCI_DM_PUT_DATA,
31215d17170SChristophe Ricard 		.doit = st21nfca_hci_dm_put_data,
31315d17170SChristophe Ricard 	},
31415d17170SChristophe Ricard 	{
31515d17170SChristophe Ricard 		.vendor_id = ST21NFCA_VENDOR_OUI,
31615d17170SChristophe Ricard 		.subcmd = HCI_DM_UPDATE_AID,
31715d17170SChristophe Ricard 		.doit = st21nfca_hci_dm_update_aid,
31815d17170SChristophe Ricard 	},
31915d17170SChristophe Ricard 	{
32015d17170SChristophe Ricard 		.vendor_id = ST21NFCA_VENDOR_OUI,
32115d17170SChristophe Ricard 		.subcmd = HCI_DM_GET_INFO,
32215d17170SChristophe Ricard 		.doit = st21nfca_hci_dm_get_info,
32315d17170SChristophe Ricard 	},
32415d17170SChristophe Ricard 	{
32515d17170SChristophe Ricard 		.vendor_id = ST21NFCA_VENDOR_OUI,
32615d17170SChristophe Ricard 		.subcmd = HCI_DM_GET_DATA,
32715d17170SChristophe Ricard 		.doit = st21nfca_hci_dm_get_data,
32815d17170SChristophe Ricard 	},
32915d17170SChristophe Ricard 	{
33015d17170SChristophe Ricard 		.vendor_id = ST21NFCA_VENDOR_OUI,
33115d17170SChristophe Ricard 		.subcmd = HCI_DM_LOAD,
33215d17170SChristophe Ricard 		.doit = st21nfca_hci_dm_load,
33315d17170SChristophe Ricard 	},
33415d17170SChristophe Ricard 	{
33515d17170SChristophe Ricard 		.vendor_id = ST21NFCA_VENDOR_OUI,
33615d17170SChristophe Ricard 		.subcmd = HCI_DM_RESET,
33715d17170SChristophe Ricard 		.doit = st21nfca_hci_dm_reset,
33815d17170SChristophe Ricard 	},
33915d17170SChristophe Ricard 	{
34015d17170SChristophe Ricard 		.vendor_id = ST21NFCA_VENDOR_OUI,
34115d17170SChristophe Ricard 		.subcmd = HCI_GET_PARAM,
34215d17170SChristophe Ricard 		.doit = st21nfca_hci_get_param,
34315d17170SChristophe Ricard 	},
34415d17170SChristophe Ricard 	{
34515d17170SChristophe Ricard 		.vendor_id = ST21NFCA_VENDOR_OUI,
34615d17170SChristophe Ricard 		.subcmd = HCI_DM_FIELD_GENERATOR,
34715d17170SChristophe Ricard 		.doit = st21nfca_hci_dm_field_generator,
34815d17170SChristophe Ricard 	},
34915d17170SChristophe Ricard 	{
35015d17170SChristophe Ricard 		.vendor_id = ST21NFCA_VENDOR_OUI,
35115d17170SChristophe Ricard 		.subcmd = HCI_LOOPBACK,
35215d17170SChristophe Ricard 		.doit = st21nfca_hci_loopback,
35315d17170SChristophe Ricard 	},
35415d17170SChristophe Ricard };
35515d17170SChristophe Ricard 
st21nfca_vendor_cmds_init(struct nfc_hci_dev * hdev)35615d17170SChristophe Ricard int st21nfca_vendor_cmds_init(struct nfc_hci_dev *hdev)
35715d17170SChristophe Ricard {
35815d17170SChristophe Ricard 	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
35915d17170SChristophe Ricard 
36015d17170SChristophe Ricard 	init_completion(&info->vendor_info.req_completion);
361*f7bfd110SJakub Kicinski 	return nfc_hci_set_vendor_cmds(hdev, st21nfca_vendor_cmds,
36215d17170SChristophe Ricard 				       sizeof(st21nfca_vendor_cmds));
36315d17170SChristophe Ricard }
36415d17170SChristophe Ricard EXPORT_SYMBOL(st21nfca_vendor_cmds_init);
365