1 /*
2  * Proprietary commands extension for STMicroelectronics NFC Chip
3  *
4  * Copyright (C) 2014-2015  STMicroelectronics SAS. All rights reserved.
5  *
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.
9  *
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.
14  *
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/>.
17  */
18 
19 #include <net/genetlink.h>
20 #include <linux/module.h>
21 #include <linux/nfc.h>
22 #include <net/nfc/hci.h>
23 #include <net/nfc/llc.h>
24 
25 #include "st21nfca.h"
26 
27 #define ST21NFCA_HCI_DM_GETDATA			0x10
28 #define ST21NFCA_HCI_DM_PUTDATA			0x11
29 #define ST21NFCA_HCI_DM_LOAD			0x12
30 #define ST21NFCA_HCI_DM_GETINFO			0x13
31 #define ST21NFCA_HCI_DM_UPDATE_AID		0x20
32 #define ST21NFCA_HCI_DM_RESET			0x3e
33 
34 #define ST21NFCA_HCI_DM_FIELD_GENERATOR		0x32
35 
36 #define ST21NFCA_FACTORY_MODE_ON		1
37 #define ST21NFCA_FACTORY_MODE_OFF		0
38 
39 #define ST21NFCA_EVT_POST_DATA			0x02
40 
41 struct get_param_data {
42 	u8 gate;
43 	u8 data;
44 } __packed;
45 
46 static int st21nfca_factory_mode(struct nfc_dev *dev, void *data,
47 			       size_t data_len)
48 {
49 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
50 
51 	if (data_len != 1)
52 		return -EINVAL;
53 
54 	pr_debug("factory mode: %x\n", ((u8 *)data)[0]);
55 
56 	switch (((u8 *)data)[0]) {
57 	case ST21NFCA_FACTORY_MODE_ON:
58 		test_and_set_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
59 	break;
60 	case ST21NFCA_FACTORY_MODE_OFF:
61 		clear_bit(ST21NFCA_FACTORY_MODE, &hdev->quirks);
62 	break;
63 	default:
64 		return -EINVAL;
65 	}
66 
67 	return 0;
68 }
69 
70 static int st21nfca_hci_clear_all_pipes(struct nfc_dev *dev, void *data,
71 				      size_t data_len)
72 {
73 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
74 
75 	return nfc_hci_disconnect_all_gates(hdev);
76 }
77 
78 static int st21nfca_hci_dm_put_data(struct nfc_dev *dev, void *data,
79 				  size_t data_len)
80 {
81 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
82 
83 	return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
84 				ST21NFCA_HCI_DM_PUTDATA, data,
85 				data_len, NULL);
86 }
87 
88 static int st21nfca_hci_dm_update_aid(struct nfc_dev *dev, void *data,
89 				    size_t data_len)
90 {
91 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
92 
93 	return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
94 			ST21NFCA_HCI_DM_UPDATE_AID, data, data_len, NULL);
95 }
96 
97 static int st21nfca_hci_dm_get_info(struct nfc_dev *dev, void *data,
98 				    size_t data_len)
99 {
100 	int r;
101 	struct sk_buff *msg, *skb;
102 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
103 
104 	r = nfc_hci_send_cmd(hdev,
105 			     ST21NFCA_DEVICE_MGNT_GATE,
106 			     ST21NFCA_HCI_DM_GETINFO,
107 			     data, data_len, &skb);
108 	if (r)
109 		goto exit;
110 
111 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
112 					     HCI_DM_GET_INFO, skb->len);
113 	if (!msg) {
114 		r = -ENOMEM;
115 		goto free_skb;
116 	}
117 
118 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
119 		kfree_skb(msg);
120 		r = -ENOBUFS;
121 		goto free_skb;
122 	}
123 
124 	r = nfc_vendor_cmd_reply(msg);
125 
126 free_skb:
127 	kfree_skb(skb);
128 exit:
129 	return r;
130 }
131 
132 static int st21nfca_hci_dm_get_data(struct nfc_dev *dev, void *data,
133 				    size_t data_len)
134 {
135 	int r;
136 	struct sk_buff *msg, *skb;
137 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
138 
139 	r = nfc_hci_send_cmd(hdev,
140 			     ST21NFCA_DEVICE_MGNT_GATE,
141 			     ST21NFCA_HCI_DM_GETDATA,
142 			     data, data_len, &skb);
143 	if (r)
144 		goto exit;
145 
146 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
147 					     HCI_DM_GET_DATA, skb->len);
148 	if (!msg) {
149 		r = -ENOMEM;
150 		goto free_skb;
151 	}
152 
153 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
154 		kfree_skb(msg);
155 		r = -ENOBUFS;
156 		goto free_skb;
157 	}
158 
159 	r = nfc_vendor_cmd_reply(msg);
160 
161 free_skb:
162 	kfree_skb(skb);
163 exit:
164 	return r;
165 }
166 
167 static int st21nfca_hci_dm_load(struct nfc_dev *dev, void *data,
168 				size_t data_len)
169 {
170 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
171 
172 	return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
173 				ST21NFCA_HCI_DM_LOAD, data, data_len, NULL);
174 }
175 
176 static int st21nfca_hci_dm_reset(struct nfc_dev *dev, void *data,
177 				 size_t data_len)
178 {
179 	int r;
180 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
181 
182 	r = nfc_hci_send_cmd_async(hdev, ST21NFCA_DEVICE_MGNT_GATE,
183 			ST21NFCA_HCI_DM_RESET, data, data_len, NULL, NULL);
184 	if (r < 0)
185 		return r;
186 
187 	r = nfc_llc_stop(hdev->llc);
188 	if (r < 0)
189 		return r;
190 
191 	return nfc_llc_start(hdev->llc);
192 }
193 
194 static int st21nfca_hci_get_param(struct nfc_dev *dev, void *data,
195 				  size_t data_len)
196 {
197 	int r;
198 	struct sk_buff *msg, *skb;
199 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
200 	struct get_param_data *param = (struct get_param_data *)data;
201 
202 	if (data_len < sizeof(struct get_param_data))
203 		return -EPROTO;
204 
205 	r = nfc_hci_get_param(hdev, param->gate, param->data, &skb);
206 	if (r)
207 		goto exit;
208 
209 	msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST21NFCA_VENDOR_OUI,
210 					     HCI_GET_PARAM, skb->len);
211 	if (!msg) {
212 		r = -ENOMEM;
213 		goto free_skb;
214 	}
215 
216 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
217 		kfree_skb(msg);
218 		r = -ENOBUFS;
219 		goto free_skb;
220 	}
221 
222 	r = nfc_vendor_cmd_reply(msg);
223 
224 free_skb:
225 	kfree_skb(skb);
226 exit:
227 	return r;
228 }
229 
230 static int st21nfca_hci_dm_field_generator(struct nfc_dev *dev, void *data,
231 					   size_t data_len)
232 {
233 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
234 
235 	return nfc_hci_send_cmd(hdev,
236 				ST21NFCA_DEVICE_MGNT_GATE,
237 				ST21NFCA_HCI_DM_FIELD_GENERATOR,
238 				data, data_len, NULL);
239 }
240 
241 int st21nfca_hci_loopback_event_received(struct nfc_hci_dev *hdev, u8 event,
242 					 struct sk_buff *skb)
243 {
244 	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
245 
246 	switch (event) {
247 	case ST21NFCA_EVT_POST_DATA:
248 		info->vendor_info.rx_skb = skb;
249 	break;
250 	default:
251 		nfc_err(&hdev->ndev->dev, "Unexpected event on loopback gate\n");
252 	}
253 	complete(&info->vendor_info.req_completion);
254 	return 0;
255 }
256 EXPORT_SYMBOL(st21nfca_hci_loopback_event_received);
257 
258 static int st21nfca_hci_loopback(struct nfc_dev *dev, void *data,
259 				 size_t data_len)
260 {
261 	int r;
262 	struct sk_buff *msg;
263 	struct nfc_hci_dev *hdev = nfc_get_drvdata(dev);
264 	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
265 
266 	if (data_len <= 0)
267 		return -EPROTO;
268 
269 	reinit_completion(&info->vendor_info.req_completion);
270 	info->vendor_info.rx_skb = NULL;
271 
272 	r = nfc_hci_send_event(hdev, NFC_HCI_LOOPBACK_GATE,
273 			       ST21NFCA_EVT_POST_DATA, data, data_len);
274 	if (r < 0) {
275 		r = -EPROTO;
276 		goto exit;
277 	}
278 
279 	wait_for_completion_interruptible(&info->vendor_info.req_completion);
280 	if (!info->vendor_info.rx_skb ||
281 	    info->vendor_info.rx_skb->len != data_len) {
282 		r = -EPROTO;
283 		goto exit;
284 	}
285 
286 	msg = nfc_vendor_cmd_alloc_reply_skb(hdev->ndev,
287 					ST21NFCA_VENDOR_OUI,
288 					HCI_LOOPBACK,
289 					info->vendor_info.rx_skb->len);
290 	if (!msg) {
291 		r = -ENOMEM;
292 		goto free_skb;
293 	}
294 
295 	if (nla_put(msg, NFC_ATTR_VENDOR_DATA, info->vendor_info.rx_skb->len,
296 		    info->vendor_info.rx_skb->data)) {
297 		kfree_skb(msg);
298 		r = -ENOBUFS;
299 		goto free_skb;
300 	}
301 
302 	r = nfc_vendor_cmd_reply(msg);
303 free_skb:
304 	kfree_skb(info->vendor_info.rx_skb);
305 exit:
306 	return r;
307 }
308 
309 static struct nfc_vendor_cmd st21nfca_vendor_cmds[] = {
310 	{
311 		.vendor_id = ST21NFCA_VENDOR_OUI,
312 		.subcmd = FACTORY_MODE,
313 		.doit = st21nfca_factory_mode,
314 	},
315 	{
316 		.vendor_id = ST21NFCA_VENDOR_OUI,
317 		.subcmd = HCI_CLEAR_ALL_PIPES,
318 		.doit = st21nfca_hci_clear_all_pipes,
319 	},
320 	{
321 		.vendor_id = ST21NFCA_VENDOR_OUI,
322 		.subcmd = HCI_DM_PUT_DATA,
323 		.doit = st21nfca_hci_dm_put_data,
324 	},
325 	{
326 		.vendor_id = ST21NFCA_VENDOR_OUI,
327 		.subcmd = HCI_DM_UPDATE_AID,
328 		.doit = st21nfca_hci_dm_update_aid,
329 	},
330 	{
331 		.vendor_id = ST21NFCA_VENDOR_OUI,
332 		.subcmd = HCI_DM_GET_INFO,
333 		.doit = st21nfca_hci_dm_get_info,
334 	},
335 	{
336 		.vendor_id = ST21NFCA_VENDOR_OUI,
337 		.subcmd = HCI_DM_GET_DATA,
338 		.doit = st21nfca_hci_dm_get_data,
339 	},
340 	{
341 		.vendor_id = ST21NFCA_VENDOR_OUI,
342 		.subcmd = HCI_DM_LOAD,
343 		.doit = st21nfca_hci_dm_load,
344 	},
345 	{
346 		.vendor_id = ST21NFCA_VENDOR_OUI,
347 		.subcmd = HCI_DM_RESET,
348 		.doit = st21nfca_hci_dm_reset,
349 	},
350 	{
351 		.vendor_id = ST21NFCA_VENDOR_OUI,
352 		.subcmd = HCI_GET_PARAM,
353 		.doit = st21nfca_hci_get_param,
354 	},
355 	{
356 		.vendor_id = ST21NFCA_VENDOR_OUI,
357 		.subcmd = HCI_DM_FIELD_GENERATOR,
358 		.doit = st21nfca_hci_dm_field_generator,
359 	},
360 	{
361 		.vendor_id = ST21NFCA_VENDOR_OUI,
362 		.subcmd = HCI_LOOPBACK,
363 		.doit = st21nfca_hci_loopback,
364 	},
365 };
366 
367 int st21nfca_vendor_cmds_init(struct nfc_hci_dev *hdev)
368 {
369 	struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
370 
371 	init_completion(&info->vendor_info.req_completion);
372 	return nfc_set_vendor_cmds(hdev->ndev, st21nfca_vendor_cmds,
373 				   sizeof(st21nfca_vendor_cmds));
374 }
375 EXPORT_SYMBOL(st21nfca_vendor_cmds_init);
376