xref: /openbmc/linux/drivers/nfc/st-nci/vendor_cmds.c (revision f7bfd110)
146fe7771SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2b1fa4dc4SChristophe Ricard /*
3b1fa4dc4SChristophe Ricard  * Proprietary commands extension for STMicroelectronics NFC NCI Chip
4b1fa4dc4SChristophe Ricard  *
5b1fa4dc4SChristophe Ricard  * Copyright (C) 2014-2015  STMicroelectronics SAS. All rights reserved.
6b1fa4dc4SChristophe Ricard  */
7b1fa4dc4SChristophe Ricard 
8b1fa4dc4SChristophe Ricard #include <net/genetlink.h>
9b1fa4dc4SChristophe Ricard #include <linux/module.h>
10b1fa4dc4SChristophe Ricard #include <linux/nfc.h>
11b1fa4dc4SChristophe Ricard #include <linux/delay.h>
12b1fa4dc4SChristophe Ricard #include <net/nfc/nci_core.h>
13b1fa4dc4SChristophe Ricard 
14b1fa4dc4SChristophe Ricard #include "st-nci.h"
15b1fa4dc4SChristophe Ricard 
16b1fa4dc4SChristophe Ricard #define ST_NCI_HCI_DM_GETDATA			0x10
17b1fa4dc4SChristophe Ricard #define ST_NCI_HCI_DM_PUTDATA			0x11
18b1fa4dc4SChristophe Ricard #define ST_NCI_HCI_DM_LOAD			0x12
19b1fa4dc4SChristophe Ricard #define ST_NCI_HCI_DM_GETINFO			0x13
20b1fa4dc4SChristophe Ricard #define ST_NCI_HCI_DM_FWUPD_START		0x14
21b1fa4dc4SChristophe Ricard #define ST_NCI_HCI_DM_FWUPD_STOP		0x15
22b1fa4dc4SChristophe Ricard #define ST_NCI_HCI_DM_UPDATE_AID		0x20
23b1fa4dc4SChristophe Ricard #define ST_NCI_HCI_DM_RESET			0x3e
24b1fa4dc4SChristophe Ricard 
25b1fa4dc4SChristophe Ricard #define ST_NCI_HCI_DM_FIELD_GENERATOR		0x32
26b1fa4dc4SChristophe Ricard #define ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE	0x33
27b1fa4dc4SChristophe Ricard #define ST_NCI_HCI_DM_VDC_VALUE_COMPARISON	0x34
28b1fa4dc4SChristophe Ricard 
29b1fa4dc4SChristophe Ricard #define ST_NCI_FACTORY_MODE_ON			1
30b1fa4dc4SChristophe Ricard #define ST_NCI_FACTORY_MODE_OFF			0
31b1fa4dc4SChristophe Ricard 
32b1fa4dc4SChristophe Ricard #define ST_NCI_EVT_POST_DATA			0x02
33b1fa4dc4SChristophe Ricard 
34b1fa4dc4SChristophe Ricard struct get_param_data {
35b1fa4dc4SChristophe Ricard 	u8 gate;
36b1fa4dc4SChristophe Ricard 	u8 data;
37b1fa4dc4SChristophe Ricard } __packed;
38b1fa4dc4SChristophe Ricard 
st_nci_factory_mode(struct nfc_dev * dev,void * data,size_t data_len)39b1fa4dc4SChristophe Ricard static int st_nci_factory_mode(struct nfc_dev *dev, void *data,
40b1fa4dc4SChristophe Ricard 			       size_t data_len)
41b1fa4dc4SChristophe Ricard {
42b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
43b1fa4dc4SChristophe Ricard 	struct st_nci_info *info = nci_get_drvdata(ndev);
44b1fa4dc4SChristophe Ricard 
45b1fa4dc4SChristophe Ricard 	if (data_len != 1)
46b1fa4dc4SChristophe Ricard 		return -EINVAL;
47b1fa4dc4SChristophe Ricard 
48b1fa4dc4SChristophe Ricard 	pr_debug("factory mode: %x\n", ((u8 *)data)[0]);
49b1fa4dc4SChristophe Ricard 
50b1fa4dc4SChristophe Ricard 	switch (((u8 *)data)[0]) {
51b1fa4dc4SChristophe Ricard 	case ST_NCI_FACTORY_MODE_ON:
52b1fa4dc4SChristophe Ricard 		test_and_set_bit(ST_NCI_FACTORY_MODE, &info->flags);
53b1fa4dc4SChristophe Ricard 	break;
54b1fa4dc4SChristophe Ricard 	case ST_NCI_FACTORY_MODE_OFF:
55b1fa4dc4SChristophe Ricard 		clear_bit(ST_NCI_FACTORY_MODE, &info->flags);
56b1fa4dc4SChristophe Ricard 	break;
57b1fa4dc4SChristophe Ricard 	default:
58b1fa4dc4SChristophe Ricard 		return -EINVAL;
59b1fa4dc4SChristophe Ricard 	}
60b1fa4dc4SChristophe Ricard 
61b1fa4dc4SChristophe Ricard 	return 0;
62b1fa4dc4SChristophe Ricard }
63b1fa4dc4SChristophe Ricard 
st_nci_hci_clear_all_pipes(struct nfc_dev * dev,void * data,size_t data_len)64b1fa4dc4SChristophe Ricard static int st_nci_hci_clear_all_pipes(struct nfc_dev *dev, void *data,
65b1fa4dc4SChristophe Ricard 				      size_t data_len)
66b1fa4dc4SChristophe Ricard {
67b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
68b1fa4dc4SChristophe Ricard 
69b1fa4dc4SChristophe Ricard 	return nci_hci_clear_all_pipes(ndev);
70b1fa4dc4SChristophe Ricard }
71b1fa4dc4SChristophe Ricard 
st_nci_hci_dm_put_data(struct nfc_dev * dev,void * data,size_t data_len)72b1fa4dc4SChristophe Ricard static int st_nci_hci_dm_put_data(struct nfc_dev *dev, void *data,
73b1fa4dc4SChristophe Ricard 				  size_t data_len)
74b1fa4dc4SChristophe Ricard {
75b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
76b1fa4dc4SChristophe Ricard 
77b1fa4dc4SChristophe Ricard 	return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
78b1fa4dc4SChristophe Ricard 				ST_NCI_HCI_DM_PUTDATA, data,
79b1fa4dc4SChristophe Ricard 				data_len, NULL);
80b1fa4dc4SChristophe Ricard }
81b1fa4dc4SChristophe Ricard 
st_nci_hci_dm_update_aid(struct nfc_dev * dev,void * data,size_t data_len)82b1fa4dc4SChristophe Ricard static int st_nci_hci_dm_update_aid(struct nfc_dev *dev, void *data,
83b1fa4dc4SChristophe Ricard 				    size_t data_len)
84b1fa4dc4SChristophe Ricard {
85b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
86b1fa4dc4SChristophe Ricard 
87b1fa4dc4SChristophe Ricard 	return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
88b1fa4dc4SChristophe Ricard 			ST_NCI_HCI_DM_UPDATE_AID, data, data_len, NULL);
89b1fa4dc4SChristophe Ricard }
90b1fa4dc4SChristophe Ricard 
st_nci_hci_dm_get_info(struct nfc_dev * dev,void * data,size_t data_len)91b1fa4dc4SChristophe Ricard static int st_nci_hci_dm_get_info(struct nfc_dev *dev, void *data,
92b1fa4dc4SChristophe Ricard 				  size_t data_len)
93b1fa4dc4SChristophe Ricard {
94b1fa4dc4SChristophe Ricard 	int r;
95b1fa4dc4SChristophe Ricard 	struct sk_buff *msg, *skb;
96b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
97b1fa4dc4SChristophe Ricard 
98b1fa4dc4SChristophe Ricard 	r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETINFO,
99b1fa4dc4SChristophe Ricard 			     data, data_len, &skb);
100b1fa4dc4SChristophe Ricard 	if (r)
101c7a551b2Swengjianfeng 		return r;
102b1fa4dc4SChristophe Ricard 
103b1fa4dc4SChristophe Ricard 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
104b1fa4dc4SChristophe Ricard 					     HCI_DM_GET_INFO, skb->len);
105b1fa4dc4SChristophe Ricard 	if (!msg) {
106b1fa4dc4SChristophe Ricard 		r = -ENOMEM;
107b1fa4dc4SChristophe Ricard 		goto free_skb;
108b1fa4dc4SChristophe Ricard 	}
109b1fa4dc4SChristophe Ricard 
110b1fa4dc4SChristophe Ricard 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
111b1fa4dc4SChristophe Ricard 		kfree_skb(msg);
112b1fa4dc4SChristophe Ricard 		r = -ENOBUFS;
113b1fa4dc4SChristophe Ricard 		goto free_skb;
114b1fa4dc4SChristophe Ricard 	}
115b1fa4dc4SChristophe Ricard 
116b1fa4dc4SChristophe Ricard 	r = nfc_vendor_cmd_reply(msg);
117b1fa4dc4SChristophe Ricard 
118b1fa4dc4SChristophe Ricard free_skb:
119b1fa4dc4SChristophe Ricard 	kfree_skb(skb);
120b1fa4dc4SChristophe Ricard 	return r;
121b1fa4dc4SChristophe Ricard }
122b1fa4dc4SChristophe Ricard 
st_nci_hci_dm_get_data(struct nfc_dev * dev,void * data,size_t data_len)123b1fa4dc4SChristophe Ricard static int st_nci_hci_dm_get_data(struct nfc_dev *dev, void *data,
124b1fa4dc4SChristophe Ricard 				  size_t data_len)
125b1fa4dc4SChristophe Ricard {
126b1fa4dc4SChristophe Ricard 	int r;
127b1fa4dc4SChristophe Ricard 	struct sk_buff *msg, *skb;
128b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
129b1fa4dc4SChristophe Ricard 
130b1fa4dc4SChristophe Ricard 	r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE, ST_NCI_HCI_DM_GETDATA,
131b1fa4dc4SChristophe Ricard 			     data, data_len, &skb);
132b1fa4dc4SChristophe Ricard 	if (r)
133c7a551b2Swengjianfeng 		return r;
134b1fa4dc4SChristophe Ricard 
135b1fa4dc4SChristophe Ricard 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
136b1fa4dc4SChristophe Ricard 					     HCI_DM_GET_DATA, skb->len);
137b1fa4dc4SChristophe Ricard 	if (!msg) {
138b1fa4dc4SChristophe Ricard 		r = -ENOMEM;
139b1fa4dc4SChristophe Ricard 		goto free_skb;
140b1fa4dc4SChristophe Ricard 	}
141b1fa4dc4SChristophe Ricard 
142b1fa4dc4SChristophe Ricard 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
143b1fa4dc4SChristophe Ricard 		kfree_skb(msg);
144b1fa4dc4SChristophe Ricard 		r = -ENOBUFS;
145b1fa4dc4SChristophe Ricard 		goto free_skb;
146b1fa4dc4SChristophe Ricard 	}
147b1fa4dc4SChristophe Ricard 
148b1fa4dc4SChristophe Ricard 	r = nfc_vendor_cmd_reply(msg);
149b1fa4dc4SChristophe Ricard 
150b1fa4dc4SChristophe Ricard free_skb:
151b1fa4dc4SChristophe Ricard 	kfree_skb(skb);
152b1fa4dc4SChristophe Ricard 	return r;
153b1fa4dc4SChristophe Ricard }
154b1fa4dc4SChristophe Ricard 
st_nci_hci_dm_fwupd_start(struct nfc_dev * dev,void * data,size_t data_len)155b1fa4dc4SChristophe Ricard static int st_nci_hci_dm_fwupd_start(struct nfc_dev *dev, void *data,
156b1fa4dc4SChristophe Ricard 				     size_t data_len)
157b1fa4dc4SChristophe Ricard {
158b1fa4dc4SChristophe Ricard 	int r;
159b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
160b1fa4dc4SChristophe Ricard 
161b1fa4dc4SChristophe Ricard 	dev->fw_download_in_progress = true;
162b1fa4dc4SChristophe Ricard 	r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
163b1fa4dc4SChristophe Ricard 			ST_NCI_HCI_DM_FWUPD_START, data, data_len, NULL);
164b1fa4dc4SChristophe Ricard 	if (r)
165b1fa4dc4SChristophe Ricard 		dev->fw_download_in_progress = false;
166b1fa4dc4SChristophe Ricard 
167b1fa4dc4SChristophe Ricard 	return r;
168b1fa4dc4SChristophe Ricard }
169b1fa4dc4SChristophe Ricard 
st_nci_hci_dm_fwupd_end(struct nfc_dev * dev,void * data,size_t data_len)170b1fa4dc4SChristophe Ricard static int st_nci_hci_dm_fwupd_end(struct nfc_dev *dev, void *data,
171b1fa4dc4SChristophe Ricard 				   size_t data_len)
172b1fa4dc4SChristophe Ricard {
173b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
174b1fa4dc4SChristophe Ricard 
175b1fa4dc4SChristophe Ricard 	return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
176b1fa4dc4SChristophe Ricard 			ST_NCI_HCI_DM_FWUPD_STOP, data, data_len, NULL);
177b1fa4dc4SChristophe Ricard }
178b1fa4dc4SChristophe Ricard 
st_nci_hci_dm_direct_load(struct nfc_dev * dev,void * data,size_t data_len)179b1fa4dc4SChristophe Ricard static int st_nci_hci_dm_direct_load(struct nfc_dev *dev, void *data,
180b1fa4dc4SChristophe Ricard 				     size_t data_len)
181b1fa4dc4SChristophe Ricard {
182b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
183b1fa4dc4SChristophe Ricard 
184b1fa4dc4SChristophe Ricard 	if (dev->fw_download_in_progress) {
185b1fa4dc4SChristophe Ricard 		dev->fw_download_in_progress = false;
186b1fa4dc4SChristophe Ricard 		return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
187b1fa4dc4SChristophe Ricard 				ST_NCI_HCI_DM_LOAD, data, data_len, NULL);
188b1fa4dc4SChristophe Ricard 	}
189b1fa4dc4SChristophe Ricard 	return -EPROTO;
190b1fa4dc4SChristophe Ricard }
191b1fa4dc4SChristophe Ricard 
st_nci_hci_dm_reset(struct nfc_dev * dev,void * data,size_t data_len)192b1fa4dc4SChristophe Ricard static int st_nci_hci_dm_reset(struct nfc_dev *dev, void *data,
193b1fa4dc4SChristophe Ricard 			       size_t data_len)
194b1fa4dc4SChristophe Ricard {
195b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
196b1fa4dc4SChristophe Ricard 
197b1fa4dc4SChristophe Ricard 	nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
198b1fa4dc4SChristophe Ricard 			ST_NCI_HCI_DM_RESET, data, data_len, NULL);
199b1fa4dc4SChristophe Ricard 	msleep(200);
200b1fa4dc4SChristophe Ricard 
201b1fa4dc4SChristophe Ricard 	return 0;
202b1fa4dc4SChristophe Ricard }
203b1fa4dc4SChristophe Ricard 
st_nci_hci_get_param(struct nfc_dev * dev,void * data,size_t data_len)204b1fa4dc4SChristophe Ricard static int st_nci_hci_get_param(struct nfc_dev *dev, void *data,
205b1fa4dc4SChristophe Ricard 				size_t data_len)
206b1fa4dc4SChristophe Ricard {
207b1fa4dc4SChristophe Ricard 	int r;
208b1fa4dc4SChristophe Ricard 	struct sk_buff *msg, *skb;
209b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
210b1fa4dc4SChristophe Ricard 	struct get_param_data *param = (struct get_param_data *)data;
211b1fa4dc4SChristophe Ricard 
212b1fa4dc4SChristophe Ricard 	if (data_len < sizeof(struct get_param_data))
213b1fa4dc4SChristophe Ricard 		return -EPROTO;
214b1fa4dc4SChristophe Ricard 
215b1fa4dc4SChristophe Ricard 	r = nci_hci_get_param(ndev, param->gate, param->data, &skb);
216b1fa4dc4SChristophe Ricard 	if (r)
217c7a551b2Swengjianfeng 		return r;
218b1fa4dc4SChristophe Ricard 
219b1fa4dc4SChristophe Ricard 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
220b1fa4dc4SChristophe Ricard 					     HCI_GET_PARAM, skb->len);
221b1fa4dc4SChristophe Ricard 	if (!msg) {
222b1fa4dc4SChristophe Ricard 		r = -ENOMEM;
223b1fa4dc4SChristophe Ricard 		goto free_skb;
224b1fa4dc4SChristophe Ricard 	}
225b1fa4dc4SChristophe Ricard 
226b1fa4dc4SChristophe Ricard 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
227b1fa4dc4SChristophe Ricard 		kfree_skb(msg);
228b1fa4dc4SChristophe Ricard 		r = -ENOBUFS;
229b1fa4dc4SChristophe Ricard 		goto free_skb;
230b1fa4dc4SChristophe Ricard 	}
231b1fa4dc4SChristophe Ricard 
232b1fa4dc4SChristophe Ricard 	r = nfc_vendor_cmd_reply(msg);
233b1fa4dc4SChristophe Ricard 
234b1fa4dc4SChristophe Ricard free_skb:
235b1fa4dc4SChristophe Ricard 	kfree_skb(skb);
236b1fa4dc4SChristophe Ricard 	return r;
237b1fa4dc4SChristophe Ricard }
238b1fa4dc4SChristophe Ricard 
st_nci_hci_dm_field_generator(struct nfc_dev * dev,void * data,size_t data_len)239b1fa4dc4SChristophe Ricard static int st_nci_hci_dm_field_generator(struct nfc_dev *dev, void *data,
240b1fa4dc4SChristophe Ricard 					 size_t data_len)
241b1fa4dc4SChristophe Ricard {
242b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
243b1fa4dc4SChristophe Ricard 
244b1fa4dc4SChristophe Ricard 	return nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
245b1fa4dc4SChristophe Ricard 				ST_NCI_HCI_DM_FIELD_GENERATOR, data, data_len, NULL);
246b1fa4dc4SChristophe Ricard }
247b1fa4dc4SChristophe Ricard 
st_nci_hci_dm_vdc_measurement_value(struct nfc_dev * dev,void * data,size_t data_len)248b1fa4dc4SChristophe Ricard static int st_nci_hci_dm_vdc_measurement_value(struct nfc_dev *dev, void *data,
249b1fa4dc4SChristophe Ricard 					       size_t data_len)
250b1fa4dc4SChristophe Ricard {
251b1fa4dc4SChristophe Ricard 	int r;
252b1fa4dc4SChristophe Ricard 	struct sk_buff *msg, *skb;
253b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
254b1fa4dc4SChristophe Ricard 
255b1fa4dc4SChristophe Ricard 	if (data_len != 4)
256b1fa4dc4SChristophe Ricard 		return -EPROTO;
257b1fa4dc4SChristophe Ricard 
258b1fa4dc4SChristophe Ricard 	r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
259b1fa4dc4SChristophe Ricard 			     ST_NCI_HCI_DM_VDC_MEASUREMENT_VALUE,
260b1fa4dc4SChristophe Ricard 			     data, data_len, &skb);
261b1fa4dc4SChristophe Ricard 	if (r)
262c7a551b2Swengjianfeng 		return r;
263b1fa4dc4SChristophe Ricard 
264b1fa4dc4SChristophe Ricard 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
265b1fa4dc4SChristophe Ricard 				HCI_DM_VDC_MEASUREMENT_VALUE, skb->len);
266b1fa4dc4SChristophe Ricard 	if (!msg) {
267b1fa4dc4SChristophe Ricard 		r = -ENOMEM;
268b1fa4dc4SChristophe Ricard 		goto free_skb;
269b1fa4dc4SChristophe Ricard 	}
270b1fa4dc4SChristophe Ricard 
271b1fa4dc4SChristophe Ricard 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
272b1fa4dc4SChristophe Ricard 		kfree_skb(msg);
273b1fa4dc4SChristophe Ricard 		r = -ENOBUFS;
274b1fa4dc4SChristophe Ricard 		goto free_skb;
275b1fa4dc4SChristophe Ricard 	}
276b1fa4dc4SChristophe Ricard 
277b1fa4dc4SChristophe Ricard 	r = nfc_vendor_cmd_reply(msg);
278b1fa4dc4SChristophe Ricard 
279b1fa4dc4SChristophe Ricard free_skb:
280b1fa4dc4SChristophe Ricard 	kfree_skb(skb);
281b1fa4dc4SChristophe Ricard 	return r;
282b1fa4dc4SChristophe Ricard }
283b1fa4dc4SChristophe Ricard 
st_nci_hci_dm_vdc_value_comparison(struct nfc_dev * dev,void * data,size_t data_len)284b1fa4dc4SChristophe Ricard static int st_nci_hci_dm_vdc_value_comparison(struct nfc_dev *dev, void *data,
285b1fa4dc4SChristophe Ricard 					      size_t data_len)
286b1fa4dc4SChristophe Ricard {
287b1fa4dc4SChristophe Ricard 	int r;
288b1fa4dc4SChristophe Ricard 	struct sk_buff *msg, *skb;
289b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
290b1fa4dc4SChristophe Ricard 
291b1fa4dc4SChristophe Ricard 	if (data_len != 2)
292b1fa4dc4SChristophe Ricard 		return -EPROTO;
293b1fa4dc4SChristophe Ricard 
294b1fa4dc4SChristophe Ricard 	r = nci_hci_send_cmd(ndev, ST_NCI_DEVICE_MGNT_GATE,
295b1fa4dc4SChristophe Ricard 			     ST_NCI_HCI_DM_VDC_VALUE_COMPARISON,
296b1fa4dc4SChristophe Ricard 			     data, data_len, &skb);
297b1fa4dc4SChristophe Ricard 	if (r)
298c7a551b2Swengjianfeng 		return r;
299b1fa4dc4SChristophe Ricard 
300b1fa4dc4SChristophe Ricard 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
301b1fa4dc4SChristophe Ricard 					HCI_DM_VDC_VALUE_COMPARISON, skb->len);
302b1fa4dc4SChristophe Ricard 	if (!msg) {
303b1fa4dc4SChristophe Ricard 		r = -ENOMEM;
304b1fa4dc4SChristophe Ricard 		goto free_skb;
305b1fa4dc4SChristophe Ricard 	}
306b1fa4dc4SChristophe Ricard 
307b1fa4dc4SChristophe Ricard 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
308b1fa4dc4SChristophe Ricard 		kfree_skb(msg);
309b1fa4dc4SChristophe Ricard 		r = -ENOBUFS;
310b1fa4dc4SChristophe Ricard 		goto free_skb;
311b1fa4dc4SChristophe Ricard 	}
312b1fa4dc4SChristophe Ricard 
313b1fa4dc4SChristophe Ricard 	r = nfc_vendor_cmd_reply(msg);
314b1fa4dc4SChristophe Ricard 
315b1fa4dc4SChristophe Ricard free_skb:
316b1fa4dc4SChristophe Ricard 	kfree_skb(skb);
317b1fa4dc4SChristophe Ricard 	return r;
318b1fa4dc4SChristophe Ricard }
319b1fa4dc4SChristophe Ricard 
st_nci_loopback(struct nfc_dev * dev,void * data,size_t data_len)3203aacd7feSChristophe Ricard static int st_nci_loopback(struct nfc_dev *dev, void *data,
321b1fa4dc4SChristophe Ricard 			   size_t data_len)
322b1fa4dc4SChristophe Ricard {
323b1fa4dc4SChristophe Ricard 	int r;
3243aacd7feSChristophe Ricard 	struct sk_buff *msg, *skb;
325b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
326b1fa4dc4SChristophe Ricard 
327b1fa4dc4SChristophe Ricard 	if (data_len <= 0)
328b1fa4dc4SChristophe Ricard 		return -EPROTO;
329b1fa4dc4SChristophe Ricard 
3303aacd7feSChristophe Ricard 	r = nci_nfcc_loopback(ndev, data, data_len, &skb);
3313aacd7feSChristophe Ricard 	if (r < 0)
3323aacd7feSChristophe Ricard 		return r;
333b1fa4dc4SChristophe Ricard 
3343aacd7feSChristophe Ricard 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
3353aacd7feSChristophe Ricard 					     LOOPBACK, skb->len);
336b1fa4dc4SChristophe Ricard 	if (!msg) {
337b1fa4dc4SChristophe Ricard 		r = -ENOMEM;
338b1fa4dc4SChristophe Ricard 		goto free_skb;
339b1fa4dc4SChristophe Ricard 	}
340b1fa4dc4SChristophe Ricard 
3413aacd7feSChristophe Ricard 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
342b1fa4dc4SChristophe Ricard 		kfree_skb(msg);
343b1fa4dc4SChristophe Ricard 		r = -ENOBUFS;
344b1fa4dc4SChristophe Ricard 		goto free_skb;
345b1fa4dc4SChristophe Ricard 	}
346b1fa4dc4SChristophe Ricard 
347b1fa4dc4SChristophe Ricard 	r = nfc_vendor_cmd_reply(msg);
348b1fa4dc4SChristophe Ricard free_skb:
3493aacd7feSChristophe Ricard 	kfree_skb(skb);
350b1fa4dc4SChristophe Ricard 	return r;
351b1fa4dc4SChristophe Ricard }
352b1fa4dc4SChristophe Ricard 
st_nci_manufacturer_specific(struct nfc_dev * dev,void * data,size_t data_len)353b1fa4dc4SChristophe Ricard static int st_nci_manufacturer_specific(struct nfc_dev *dev, void *data,
354b1fa4dc4SChristophe Ricard 					size_t data_len)
355b1fa4dc4SChristophe Ricard {
356b1fa4dc4SChristophe Ricard 	struct sk_buff *msg;
357b1fa4dc4SChristophe Ricard 	struct nci_dev *ndev = nfc_get_drvdata(dev);
358b1fa4dc4SChristophe Ricard 
359b1fa4dc4SChristophe Ricard 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
360b1fa4dc4SChristophe Ricard 					MANUFACTURER_SPECIFIC,
361b1fa4dc4SChristophe Ricard 					sizeof(ndev->manufact_specific_info));
362b1fa4dc4SChristophe Ricard 	if (!msg)
363b1fa4dc4SChristophe Ricard 		return -ENOMEM;
364b1fa4dc4SChristophe Ricard 
365b1fa4dc4SChristophe Ricard 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, sizeof(ndev->manufact_specific_info),
366b1fa4dc4SChristophe Ricard 		    &ndev->manufact_specific_info)) {
367b1fa4dc4SChristophe Ricard 		kfree_skb(msg);
368b1fa4dc4SChristophe Ricard 		return -ENOBUFS;
369b1fa4dc4SChristophe Ricard 	}
370b1fa4dc4SChristophe Ricard 
371b1fa4dc4SChristophe Ricard 	return nfc_vendor_cmd_reply(msg);
372b1fa4dc4SChristophe Ricard }
373b1fa4dc4SChristophe Ricard 
37415944ad2SKrzysztof Kozlowski static const struct nfc_vendor_cmd st_nci_vendor_cmds[] = {
375b1fa4dc4SChristophe Ricard 	{
376b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
377b1fa4dc4SChristophe Ricard 		.subcmd = FACTORY_MODE,
378b1fa4dc4SChristophe Ricard 		.doit = st_nci_factory_mode,
379b1fa4dc4SChristophe Ricard 	},
380b1fa4dc4SChristophe Ricard 	{
381b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
382b1fa4dc4SChristophe Ricard 		.subcmd = HCI_CLEAR_ALL_PIPES,
383b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_clear_all_pipes,
384b1fa4dc4SChristophe Ricard 	},
385b1fa4dc4SChristophe Ricard 	{
386b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
387b1fa4dc4SChristophe Ricard 		.subcmd = HCI_DM_PUT_DATA,
388b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_dm_put_data,
389b1fa4dc4SChristophe Ricard 	},
390b1fa4dc4SChristophe Ricard 	{
391b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
392b1fa4dc4SChristophe Ricard 		.subcmd = HCI_DM_UPDATE_AID,
393b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_dm_update_aid,
394b1fa4dc4SChristophe Ricard 	},
395b1fa4dc4SChristophe Ricard 	{
396b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
397b1fa4dc4SChristophe Ricard 		.subcmd = HCI_DM_GET_INFO,
398b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_dm_get_info,
399b1fa4dc4SChristophe Ricard 	},
400b1fa4dc4SChristophe Ricard 	{
401b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
402b1fa4dc4SChristophe Ricard 		.subcmd = HCI_DM_GET_DATA,
403b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_dm_get_data,
404b1fa4dc4SChristophe Ricard 	},
405b1fa4dc4SChristophe Ricard 	{
406b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
407b1fa4dc4SChristophe Ricard 		.subcmd = HCI_DM_DIRECT_LOAD,
408b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_dm_direct_load,
409b1fa4dc4SChristophe Ricard 	},
410b1fa4dc4SChristophe Ricard 	{
411b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
412b1fa4dc4SChristophe Ricard 		.subcmd = HCI_DM_RESET,
413b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_dm_reset,
414b1fa4dc4SChristophe Ricard 	},
415b1fa4dc4SChristophe Ricard 	{
416b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
417b1fa4dc4SChristophe Ricard 		.subcmd = HCI_GET_PARAM,
418b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_get_param,
419b1fa4dc4SChristophe Ricard 	},
420b1fa4dc4SChristophe Ricard 	{
421b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
422b1fa4dc4SChristophe Ricard 		.subcmd = HCI_DM_FIELD_GENERATOR,
423b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_dm_field_generator,
424b1fa4dc4SChristophe Ricard 	},
425b1fa4dc4SChristophe Ricard 	{
426b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
427b1fa4dc4SChristophe Ricard 		.subcmd = HCI_DM_FWUPD_START,
428b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_dm_fwupd_start,
429b1fa4dc4SChristophe Ricard 	},
430b1fa4dc4SChristophe Ricard 	{
431b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
432b1fa4dc4SChristophe Ricard 		.subcmd = HCI_DM_FWUPD_END,
433b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_dm_fwupd_end,
434b1fa4dc4SChristophe Ricard 	},
435b1fa4dc4SChristophe Ricard 	{
436b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
4373aacd7feSChristophe Ricard 		.subcmd = LOOPBACK,
4383aacd7feSChristophe Ricard 		.doit = st_nci_loopback,
439b1fa4dc4SChristophe Ricard 	},
440b1fa4dc4SChristophe Ricard 	{
441b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
442b1fa4dc4SChristophe Ricard 		.subcmd = HCI_DM_VDC_MEASUREMENT_VALUE,
443b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_dm_vdc_measurement_value,
444b1fa4dc4SChristophe Ricard 	},
445b1fa4dc4SChristophe Ricard 	{
446b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
447b1fa4dc4SChristophe Ricard 		.subcmd = HCI_DM_VDC_VALUE_COMPARISON,
448b1fa4dc4SChristophe Ricard 		.doit = st_nci_hci_dm_vdc_value_comparison,
449b1fa4dc4SChristophe Ricard 	},
450b1fa4dc4SChristophe Ricard 	{
451b1fa4dc4SChristophe Ricard 		.vendor_id = ST_NCI_VENDOR_OUI,
452b1fa4dc4SChristophe Ricard 		.subcmd = MANUFACTURER_SPECIFIC,
453b1fa4dc4SChristophe Ricard 		.doit = st_nci_manufacturer_specific,
454b1fa4dc4SChristophe Ricard 	},
455b1fa4dc4SChristophe Ricard };
456b1fa4dc4SChristophe Ricard 
st_nci_vendor_cmds_init(struct nci_dev * ndev)457b1fa4dc4SChristophe Ricard int st_nci_vendor_cmds_init(struct nci_dev *ndev)
458b1fa4dc4SChristophe Ricard {
459*f7bfd110SJakub Kicinski 	return nci_set_vendor_cmds(ndev, st_nci_vendor_cmds,
460b1fa4dc4SChristophe Ricard 				   sizeof(st_nci_vendor_cmds));
461b1fa4dc4SChristophe Ricard }
462b1fa4dc4SChristophe Ricard EXPORT_SYMBOL(st_nci_vendor_cmds_init);
463