blob: 49ff321060809a320966d5efc24ea6aaaab1add8 [file] [log] [blame]
Ilan Elias6a2968a2011-09-18 11:19:35 +03001/*
2 * The NFC Controller Interface is the communication protocol between an
3 * NFC Controller (NFCC) and a Device Host (DH).
4 *
5 * Copyright (C) 2011 Texas Instruments, Inc.
Julien Lefrique772dccf2014-10-21 16:52:44 +02006 * Copyright (C) 2014 Marvell International Ltd.
Ilan Elias6a2968a2011-09-18 11:19:35 +03007 *
8 * Written by Ilan Elias <ilane@ti.com>
9 *
10 * Acknowledgements:
11 * This file is based on hci_core.c, which was written
12 * by Maxim Krasnyansky.
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2
16 * as published by the Free Software Foundation
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
Jeff Kirsher98b32de2013-12-06 08:56:16 -080024 * along with this program; if not, see <http://www.gnu.org/licenses/>.
Ilan Elias6a2968a2011-09-18 11:19:35 +030025 *
26 */
27
Samuel Ortiz52858b52011-12-14 16:43:05 +010028#define pr_fmt(fmt) KBUILD_MODNAME ": %s: " fmt, __func__
Joe Perchesed1e0ad2011-11-29 11:37:32 -080029
Dave Jones8a70e7f2012-07-12 19:17:34 +020030#include <linux/module.h>
Ilan Elias6a2968a2011-09-18 11:19:35 +030031#include <linux/types.h>
32#include <linux/workqueue.h>
33#include <linux/completion.h>
Paul Gortmakerbc3b2d72011-07-15 11:47:34 -040034#include <linux/export.h>
Ilan Elias6a2968a2011-09-18 11:19:35 +030035#include <linux/sched.h>
36#include <linux/bitops.h>
37#include <linux/skbuff.h>
38
39#include "../nfc.h"
40#include <net/nfc/nci.h>
41#include <net/nfc/nci_core.h>
42#include <linux/nfc.h>
43
Christophe Ricardb16ae712015-02-03 19:48:05 +010044struct core_conn_create_data {
45 int length;
46 struct nci_core_conn_create_cmd *cmd;
47};
48
Ilan Elias6a2968a2011-09-18 11:19:35 +030049static void nci_cmd_work(struct work_struct *work);
50static void nci_rx_work(struct work_struct *work);
51static void nci_tx_work(struct work_struct *work);
52
Christophe Ricard4aeee6872015-02-01 22:26:08 +010053struct nci_conn_info *nci_get_conn_info_by_conn_id(struct nci_dev *ndev,
54 int conn_id)
55{
56 struct nci_conn_info *conn_info;
57
58 list_for_each_entry(conn_info, &ndev->conn_info_list, list) {
59 if (conn_info->conn_id == conn_id)
60 return conn_info;
61 }
62
63 return NULL;
64}
65
Ilan Elias6a2968a2011-09-18 11:19:35 +030066/* ---- NCI requests ---- */
67
68void nci_req_complete(struct nci_dev *ndev, int result)
69{
70 if (ndev->req_status == NCI_REQ_PEND) {
71 ndev->req_result = result;
72 ndev->req_status = NCI_REQ_DONE;
73 complete(&ndev->req_completion);
74 }
75}
76
77static void nci_req_cancel(struct nci_dev *ndev, int err)
78{
79 if (ndev->req_status == NCI_REQ_PEND) {
80 ndev->req_result = err;
81 ndev->req_status = NCI_REQ_CANCELED;
82 complete(&ndev->req_completion);
83 }
84}
85
86/* Execute request and wait for completion. */
87static int __nci_request(struct nci_dev *ndev,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +010088 void (*req)(struct nci_dev *ndev, unsigned long opt),
89 unsigned long opt, __u32 timeout)
Ilan Elias6a2968a2011-09-18 11:19:35 +030090{
91 int rc = 0;
Dan Carpenterf8c141c2011-12-09 09:35:39 +030092 long completion_rc;
Ilan Elias6a2968a2011-09-18 11:19:35 +030093
94 ndev->req_status = NCI_REQ_PEND;
95
Axel Lin9bec44b2014-02-13 13:25:48 +080096 reinit_completion(&ndev->req_completion);
Ilan Elias6a2968a2011-09-18 11:19:35 +030097 req(ndev, opt);
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +010098 completion_rc =
99 wait_for_completion_interruptible_timeout(&ndev->req_completion,
100 timeout);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300101
Joe Perches20c239c2011-11-29 11:37:33 -0800102 pr_debug("wait_for_completion return %ld\n", completion_rc);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300103
104 if (completion_rc > 0) {
105 switch (ndev->req_status) {
106 case NCI_REQ_DONE:
107 rc = nci_to_errno(ndev->req_result);
108 break;
109
110 case NCI_REQ_CANCELED:
111 rc = -ndev->req_result;
112 break;
113
114 default:
115 rc = -ETIMEDOUT;
116 break;
117 }
118 } else {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800119 pr_err("wait_for_completion_interruptible_timeout failed %ld\n",
120 completion_rc);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300121
122 rc = ((completion_rc == 0) ? (-ETIMEDOUT) : (completion_rc));
123 }
124
125 ndev->req_status = ndev->req_result = 0;
126
127 return rc;
128}
129
Christophe Ricard11f54f22015-02-01 22:26:14 +0100130inline int nci_request(struct nci_dev *ndev,
131 void (*req)(struct nci_dev *ndev,
132 unsigned long opt),
133 unsigned long opt, __u32 timeout)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300134{
135 int rc;
136
137 if (!test_bit(NCI_UP, &ndev->flags))
138 return -ENETDOWN;
139
140 /* Serialize all requests */
141 mutex_lock(&ndev->req_lock);
142 rc = __nci_request(ndev, req, opt, timeout);
143 mutex_unlock(&ndev->req_lock);
144
145 return rc;
146}
147
148static void nci_reset_req(struct nci_dev *ndev, unsigned long opt)
149{
Ilan Eliase8c0dac2011-11-09 12:09:14 +0200150 struct nci_core_reset_cmd cmd;
151
152 cmd.reset_type = NCI_RESET_TYPE_RESET_CONFIG;
153 nci_send_cmd(ndev, NCI_OP_CORE_RESET_CMD, 1, &cmd);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300154}
155
156static void nci_init_req(struct nci_dev *ndev, unsigned long opt)
157{
158 nci_send_cmd(ndev, NCI_OP_CORE_INIT_CMD, 0, NULL);
159}
160
161static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
162{
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300163 struct nci_rf_disc_map_cmd cmd;
164 struct disc_map_config *cfg = cmd.mapping_configs;
165 __u8 *num = &cmd.num_mapping_configs;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300166 int i;
167
Ilan Elias6a2968a2011-09-18 11:19:35 +0300168 /* set rf mapping configurations */
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300169 *num = 0;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300170
171 /* by default mapping is set to NCI_RF_INTERFACE_FRAME */
172 for (i = 0; i < ndev->num_supported_rf_interfaces; i++) {
173 if (ndev->supported_rf_interfaces[i] ==
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100174 NCI_RF_INTERFACE_ISO_DEP) {
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300175 cfg[*num].rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
Ilan Elias637d85a2011-12-20 16:57:40 +0200176 cfg[*num].mode = NCI_DISC_MAP_MODE_POLL |
177 NCI_DISC_MAP_MODE_LISTEN;
178 cfg[*num].rf_interface = NCI_RF_INTERFACE_ISO_DEP;
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300179 (*num)++;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300180 } else if (ndev->supported_rf_interfaces[i] ==
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100181 NCI_RF_INTERFACE_NFC_DEP) {
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300182 cfg[*num].rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
Ilan Elias637d85a2011-12-20 16:57:40 +0200183 cfg[*num].mode = NCI_DISC_MAP_MODE_POLL |
184 NCI_DISC_MAP_MODE_LISTEN;
185 cfg[*num].rf_interface = NCI_RF_INTERFACE_NFC_DEP;
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300186 (*num)++;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300187 }
188
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300189 if (*num == NCI_MAX_NUM_MAPPING_CONFIGS)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300190 break;
191 }
192
193 nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_MAP_CMD,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100194 (1 + ((*num) * sizeof(struct disc_map_config))), &cmd);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300195}
196
Ilan Elias7e035232012-08-15 11:46:22 +0300197struct nci_set_config_param {
198 __u8 id;
199 size_t len;
200 __u8 *val;
201};
202
203static void nci_set_config_req(struct nci_dev *ndev, unsigned long opt)
204{
205 struct nci_set_config_param *param = (struct nci_set_config_param *)opt;
206 struct nci_core_set_config_cmd cmd;
207
208 BUG_ON(param->len > NCI_MAX_PARAM_LEN);
209
210 cmd.num_params = 1;
211 cmd.param.id = param->id;
212 cmd.param.len = param->len;
213 memcpy(cmd.param.val, param->val, param->len);
214
215 nci_send_cmd(ndev, NCI_OP_CORE_SET_CONFIG_CMD, (3 + param->len), &cmd);
216}
217
Julien Lefrique772dccf2014-10-21 16:52:44 +0200218struct nci_rf_discover_param {
219 __u32 im_protocols;
220 __u32 tm_protocols;
221};
222
Ilan Elias6a2968a2011-09-18 11:19:35 +0300223static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
224{
Julien Lefrique772dccf2014-10-21 16:52:44 +0200225 struct nci_rf_discover_param *param =
226 (struct nci_rf_discover_param *)opt;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300227 struct nci_rf_disc_cmd cmd;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300228
229 cmd.num_disc_configs = 0;
230
231 if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
Julien Lefrique772dccf2014-10-21 16:52:44 +0200232 (param->im_protocols & NFC_PROTO_JEWEL_MASK ||
233 param->im_protocols & NFC_PROTO_MIFARE_MASK ||
234 param->im_protocols & NFC_PROTO_ISO14443_MASK ||
235 param->im_protocols & NFC_PROTO_NFC_DEP_MASK)) {
Ilan Elias637d85a2011-12-20 16:57:40 +0200236 cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100237 NCI_NFC_A_PASSIVE_POLL_MODE;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300238 cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
239 cmd.num_disc_configs++;
240 }
241
242 if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
Julien Lefrique772dccf2014-10-21 16:52:44 +0200243 (param->im_protocols & NFC_PROTO_ISO14443_B_MASK)) {
Ilan Elias637d85a2011-12-20 16:57:40 +0200244 cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100245 NCI_NFC_B_PASSIVE_POLL_MODE;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300246 cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
247 cmd.num_disc_configs++;
248 }
249
250 if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
Julien Lefrique772dccf2014-10-21 16:52:44 +0200251 (param->im_protocols & NFC_PROTO_FELICA_MASK ||
252 param->im_protocols & NFC_PROTO_NFC_DEP_MASK)) {
Ilan Elias637d85a2011-12-20 16:57:40 +0200253 cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100254 NCI_NFC_F_PASSIVE_POLL_MODE;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300255 cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
256 cmd.num_disc_configs++;
257 }
258
Vincent Cuissardcfdbeea2014-07-22 19:48:38 +0200259 if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
Julien Lefrique772dccf2014-10-21 16:52:44 +0200260 (param->im_protocols & NFC_PROTO_ISO15693_MASK)) {
Vincent Cuissardcfdbeea2014-07-22 19:48:38 +0200261 cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
262 NCI_NFC_V_PASSIVE_POLL_MODE;
263 cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
264 cmd.num_disc_configs++;
265 }
266
Julien Lefrique772dccf2014-10-21 16:52:44 +0200267 if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS - 1) &&
268 (param->tm_protocols & NFC_PROTO_NFC_DEP_MASK)) {
269 cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
270 NCI_NFC_A_PASSIVE_LISTEN_MODE;
271 cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
272 cmd.num_disc_configs++;
273 cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
274 NCI_NFC_F_PASSIVE_LISTEN_MODE;
275 cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
276 cmd.num_disc_configs++;
277 }
278
Ilan Elias6a2968a2011-09-18 11:19:35 +0300279 nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_CMD,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100280 (1 + (cmd.num_disc_configs * sizeof(struct disc_config))),
281 &cmd);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300282}
283
Ilan Elias019c4fb2012-01-18 13:16:14 +0200284struct nci_rf_discover_select_param {
285 __u8 rf_discovery_id;
286 __u8 rf_protocol;
287};
288
289static void nci_rf_discover_select_req(struct nci_dev *ndev, unsigned long opt)
290{
291 struct nci_rf_discover_select_param *param =
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100292 (struct nci_rf_discover_select_param *)opt;
Ilan Elias019c4fb2012-01-18 13:16:14 +0200293 struct nci_rf_discover_select_cmd cmd;
294
295 cmd.rf_discovery_id = param->rf_discovery_id;
296 cmd.rf_protocol = param->rf_protocol;
297
298 switch (cmd.rf_protocol) {
299 case NCI_RF_PROTOCOL_ISO_DEP:
300 cmd.rf_interface = NCI_RF_INTERFACE_ISO_DEP;
301 break;
302
303 case NCI_RF_PROTOCOL_NFC_DEP:
304 cmd.rf_interface = NCI_RF_INTERFACE_NFC_DEP;
305 break;
306
307 default:
308 cmd.rf_interface = NCI_RF_INTERFACE_FRAME;
309 break;
310 }
311
312 nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_SELECT_CMD,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100313 sizeof(struct nci_rf_discover_select_cmd), &cmd);
Ilan Elias019c4fb2012-01-18 13:16:14 +0200314}
315
Ilan Elias6a2968a2011-09-18 11:19:35 +0300316static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt)
317{
318 struct nci_rf_deactivate_cmd cmd;
319
Christophe Ricard9295b5b2014-12-02 21:27:49 +0100320 cmd.type = opt;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300321
322 nci_send_cmd(ndev, NCI_OP_RF_DEACTIVATE_CMD,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100323 sizeof(struct nci_rf_deactivate_cmd), &cmd);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300324}
325
326static int nci_open_device(struct nci_dev *ndev)
327{
328 int rc = 0;
329
330 mutex_lock(&ndev->req_lock);
331
332 if (test_bit(NCI_UP, &ndev->flags)) {
333 rc = -EALREADY;
334 goto done;
335 }
336
337 if (ndev->ops->open(ndev)) {
338 rc = -EIO;
339 goto done;
340 }
341
342 atomic_set(&ndev->cmd_cnt, 1);
343
344 set_bit(NCI_INIT, &ndev->flags);
345
346 rc = __nci_request(ndev, nci_reset_req, 0,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100347 msecs_to_jiffies(NCI_RESET_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300348
Amitkumar Karwar44a589c2014-02-06 11:28:31 -0800349 if (ndev->ops->setup)
Amitkumar Karwar86e85862014-01-06 12:58:17 -0800350 ndev->ops->setup(ndev);
351
Ilan Elias6a2968a2011-09-18 11:19:35 +0300352 if (!rc) {
353 rc = __nci_request(ndev, nci_init_req, 0,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100354 msecs_to_jiffies(NCI_INIT_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300355 }
356
357 if (!rc) {
358 rc = __nci_request(ndev, nci_init_complete_req, 0,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100359 msecs_to_jiffies(NCI_INIT_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300360 }
361
362 clear_bit(NCI_INIT, &ndev->flags);
363
364 if (!rc) {
365 set_bit(NCI_UP, &ndev->flags);
Ilan Elias019c4fb2012-01-18 13:16:14 +0200366 nci_clear_target_list(ndev);
Ilan Elias8939e472012-01-18 13:16:12 +0200367 atomic_set(&ndev->state, NCI_IDLE);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300368 } else {
369 /* Init failed, cleanup */
370 skb_queue_purge(&ndev->cmd_q);
371 skb_queue_purge(&ndev->rx_q);
372 skb_queue_purge(&ndev->tx_q);
373
374 ndev->ops->close(ndev);
375 ndev->flags = 0;
376 }
377
378done:
379 mutex_unlock(&ndev->req_lock);
380 return rc;
381}
382
383static int nci_close_device(struct nci_dev *ndev)
384{
385 nci_req_cancel(ndev, ENODEV);
386 mutex_lock(&ndev->req_lock);
387
388 if (!test_and_clear_bit(NCI_UP, &ndev->flags)) {
389 del_timer_sync(&ndev->cmd_timer);
Ilan Eliasc4bf98b2012-01-17 12:03:50 +0200390 del_timer_sync(&ndev->data_timer);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300391 mutex_unlock(&ndev->req_lock);
392 return 0;
393 }
394
395 /* Drop RX and TX queues */
396 skb_queue_purge(&ndev->rx_q);
397 skb_queue_purge(&ndev->tx_q);
398
399 /* Flush RX and TX wq */
400 flush_workqueue(ndev->rx_wq);
401 flush_workqueue(ndev->tx_wq);
402
403 /* Reset device */
404 skb_queue_purge(&ndev->cmd_q);
405 atomic_set(&ndev->cmd_cnt, 1);
406
407 set_bit(NCI_INIT, &ndev->flags);
408 __nci_request(ndev, nci_reset_req, 0,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100409 msecs_to_jiffies(NCI_RESET_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300410 clear_bit(NCI_INIT, &ndev->flags);
411
Amitkumar Karwarfa9be5f2013-12-23 14:15:13 -0800412 del_timer_sync(&ndev->cmd_timer);
413
Ilan Elias6a2968a2011-09-18 11:19:35 +0300414 /* Flush cmd wq */
415 flush_workqueue(ndev->cmd_wq);
416
417 /* After this point our queues are empty
418 * and no works are scheduled. */
419 ndev->ops->close(ndev);
420
421 /* Clear flags */
422 ndev->flags = 0;
423
424 mutex_unlock(&ndev->req_lock);
425
426 return 0;
427}
428
429/* NCI command timer function */
430static void nci_cmd_timer(unsigned long arg)
431{
432 struct nci_dev *ndev = (void *) arg;
433
Ilan Elias6a2968a2011-09-18 11:19:35 +0300434 atomic_set(&ndev->cmd_cnt, 1);
435 queue_work(ndev->cmd_wq, &ndev->cmd_work);
436}
437
Ilan Eliasc4bf98b2012-01-17 12:03:50 +0200438/* NCI data exchange timer function */
439static void nci_data_timer(unsigned long arg)
440{
441 struct nci_dev *ndev = (void *) arg;
442
443 set_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
444 queue_work(ndev->rx_wq, &ndev->rx_work);
445}
446
Ilan Elias6a2968a2011-09-18 11:19:35 +0300447static int nci_dev_up(struct nfc_dev *nfc_dev)
448{
449 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
450
Ilan Elias6a2968a2011-09-18 11:19:35 +0300451 return nci_open_device(ndev);
452}
453
454static int nci_dev_down(struct nfc_dev *nfc_dev)
455{
456 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
457
Ilan Elias6a2968a2011-09-18 11:19:35 +0300458 return nci_close_device(ndev);
459}
460
Amitkumar Karwar22c15bf2014-01-06 12:58:18 -0800461int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val)
462{
463 struct nci_set_config_param param;
464
465 if (!val || !len)
466 return 0;
467
468 param.id = id;
469 param.len = len;
470 param.val = val;
471
472 return __nci_request(ndev, nci_set_config_req, (unsigned long)&param,
473 msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
474}
475EXPORT_SYMBOL(nci_set_config);
476
Christophe Ricardaf9c8aa2015-02-01 22:26:10 +0100477static void nci_nfcee_discover_req(struct nci_dev *ndev, unsigned long opt)
478{
479 struct nci_nfcee_discover_cmd cmd;
480 __u8 action = opt;
481
482 cmd.discovery_action = action;
483
484 nci_send_cmd(ndev, NCI_OP_NFCEE_DISCOVER_CMD, 1, &cmd);
485}
486
487int nci_nfcee_discover(struct nci_dev *ndev, u8 action)
488{
489 return nci_request(ndev, nci_nfcee_discover_req, action,
490 msecs_to_jiffies(NCI_CMD_TIMEOUT));
491}
492EXPORT_SYMBOL(nci_nfcee_discover);
493
Christophe Ricardf7f793f2015-02-01 22:26:11 +0100494static void nci_nfcee_mode_set_req(struct nci_dev *ndev, unsigned long opt)
495{
496 struct nci_nfcee_mode_set_cmd *cmd =
497 (struct nci_nfcee_mode_set_cmd *)opt;
498
499 nci_send_cmd(ndev, NCI_OP_NFCEE_MODE_SET_CMD,
500 sizeof(struct nci_nfcee_mode_set_cmd), cmd);
501}
502
503int nci_nfcee_mode_set(struct nci_dev *ndev, u8 nfcee_id, u8 nfcee_mode)
504{
505 struct nci_nfcee_mode_set_cmd cmd;
506
507 cmd.nfcee_id = nfcee_id;
508 cmd.nfcee_mode = nfcee_mode;
509
510 return nci_request(ndev, nci_nfcee_mode_set_req, (unsigned long)&cmd,
511 msecs_to_jiffies(NCI_CMD_TIMEOUT));
512}
513EXPORT_SYMBOL(nci_nfcee_mode_set);
514
Christophe Ricard736bb952015-02-01 22:26:12 +0100515static void nci_core_conn_create_req(struct nci_dev *ndev, unsigned long opt)
516{
Christophe Ricardb16ae712015-02-03 19:48:05 +0100517 struct core_conn_create_data *data =
518 (struct core_conn_create_data *)opt;
Christophe Ricard736bb952015-02-01 22:26:12 +0100519
Christophe Ricardb16ae712015-02-03 19:48:05 +0100520 nci_send_cmd(ndev, NCI_OP_CORE_CONN_CREATE_CMD, data->length, data->cmd);
Christophe Ricard736bb952015-02-01 22:26:12 +0100521}
522
Christophe Ricardb16ae712015-02-03 19:48:05 +0100523int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type,
524 u8 number_destination_params,
525 size_t params_len,
Christophe Ricard736bb952015-02-01 22:26:12 +0100526 struct core_conn_create_dest_spec_params *params)
527{
Christophe Ricardb16ae712015-02-03 19:48:05 +0100528 int r;
529 struct nci_core_conn_create_cmd *cmd;
530 struct core_conn_create_data data;
531
532 data.length = params_len + sizeof(struct nci_core_conn_create_cmd);
533 cmd = kzalloc(data.length, GFP_KERNEL);
534 if (!cmd)
535 return -ENOMEM;
536
537 cmd->destination_type = destination_type;
538 cmd->number_destination_params = number_destination_params;
539 memcpy(cmd->params, params, params_len);
540
541 data.cmd = cmd;
542 ndev->cur_id = params->value[DEST_SPEC_PARAMS_ID_INDEX];
543
544 r = __nci_request(ndev, nci_core_conn_create_req,
545 (unsigned long)&data,
546 msecs_to_jiffies(NCI_CMD_TIMEOUT));
547 kfree(cmd);
548 return r;
Christophe Ricard736bb952015-02-01 22:26:12 +0100549}
550EXPORT_SYMBOL(nci_core_conn_create);
551
552static void nci_core_conn_close_req(struct nci_dev *ndev, unsigned long opt)
553{
554 __u8 conn_id = opt;
555
556 nci_send_cmd(ndev, NCI_OP_CORE_CONN_CLOSE_CMD, 1, &conn_id);
557}
558
559int nci_core_conn_close(struct nci_dev *ndev, u8 conn_id)
560{
561 return nci_request(ndev, nci_core_conn_close_req, conn_id,
562 msecs_to_jiffies(NCI_CMD_TIMEOUT));
563}
564EXPORT_SYMBOL(nci_core_conn_close);
565
Ilan Elias7e035232012-08-15 11:46:22 +0300566static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)
567{
568 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
569 struct nci_set_config_param param;
Julien Lefrique529ee062014-10-21 16:52:47 +0200570 int rc;
Ilan Elias7e035232012-08-15 11:46:22 +0300571
572 param.val = nfc_get_local_general_bytes(nfc_dev, &param.len);
573 if ((param.val == NULL) || (param.len == 0))
Szymon Jancf9fc36f2012-10-04 15:15:46 +0200574 return 0;
Ilan Elias7e035232012-08-15 11:46:22 +0300575
Szymon Janc460d8f92012-10-04 15:15:45 +0200576 if (param.len > NFC_MAX_GT_LEN)
Ilan Elias7e035232012-08-15 11:46:22 +0300577 return -EINVAL;
578
Ilan Elias7e035232012-08-15 11:46:22 +0300579 param.id = NCI_PN_ATR_REQ_GEN_BYTES;
Ilan Elias7e035232012-08-15 11:46:22 +0300580
Julien Lefrique529ee062014-10-21 16:52:47 +0200581 rc = nci_request(ndev, nci_set_config_req, (unsigned long)&param,
582 msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
583 if (rc)
584 return rc;
585
586 param.id = NCI_LN_ATR_RES_GEN_BYTES;
587
Szymon Jancf9fc36f2012-10-04 15:15:46 +0200588 return nci_request(ndev, nci_set_config_req, (unsigned long)&param,
589 msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
Ilan Elias7e035232012-08-15 11:46:22 +0300590}
591
Julien Lefrique90d78c12014-10-21 16:52:45 +0200592static int nci_set_listen_parameters(struct nfc_dev *nfc_dev)
593{
594 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
595 int rc;
596 __u8 val;
597
598 val = NCI_LA_SEL_INFO_NFC_DEP_MASK;
599
600 rc = nci_set_config(ndev, NCI_LA_SEL_INFO, 1, &val);
601 if (rc)
602 return rc;
603
604 val = NCI_LF_PROTOCOL_TYPE_NFC_DEP_MASK;
605
606 rc = nci_set_config(ndev, NCI_LF_PROTOCOL_TYPE, 1, &val);
607 if (rc)
608 return rc;
609
610 val = NCI_LF_CON_BITR_F_212 | NCI_LF_CON_BITR_F_424;
611
612 return nci_set_config(ndev, NCI_LF_CON_BITR_F, 1, &val);
613}
614
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200615static int nci_start_poll(struct nfc_dev *nfc_dev,
616 __u32 im_protocols, __u32 tm_protocols)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300617{
618 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
Julien Lefrique772dccf2014-10-21 16:52:44 +0200619 struct nci_rf_discover_param param;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300620 int rc;
621
Ilan Elias019c4fb2012-01-18 13:16:14 +0200622 if ((atomic_read(&ndev->state) == NCI_DISCOVERY) ||
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100623 (atomic_read(&ndev->state) == NCI_W4_ALL_DISCOVERIES)) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800624 pr_err("unable to start poll, since poll is already active\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300625 return -EBUSY;
626 }
627
Ilan Eliasde054792011-09-22 11:13:01 +0300628 if (ndev->target_active_prot) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800629 pr_err("there is an active target\n");
Ilan Eliasde054792011-09-22 11:13:01 +0300630 return -EBUSY;
631 }
632
Ilan Elias019c4fb2012-01-18 13:16:14 +0200633 if ((atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) ||
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100634 (atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) {
Ilan Elias019c4fb2012-01-18 13:16:14 +0200635 pr_debug("target active or w4 select, implicitly deactivate\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300636
Christophe Ricard9295b5b2014-12-02 21:27:49 +0100637 rc = nci_request(ndev, nci_rf_deactivate_req,
638 NCI_DEACTIVATE_TYPE_IDLE_MODE,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100639 msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300640 if (rc)
641 return -EBUSY;
642 }
643
Julien Lefrique529ee062014-10-21 16:52:47 +0200644 if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) {
Ilan Elias7e035232012-08-15 11:46:22 +0300645 rc = nci_set_local_general_bytes(nfc_dev);
646 if (rc) {
647 pr_err("failed to set local general bytes\n");
648 return rc;
649 }
650 }
651
Julien Lefrique90d78c12014-10-21 16:52:45 +0200652 if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
653 rc = nci_set_listen_parameters(nfc_dev);
654 if (rc)
655 pr_err("failed to set listen parameters\n");
656 }
657
Julien Lefrique772dccf2014-10-21 16:52:44 +0200658 param.im_protocols = im_protocols;
659 param.tm_protocols = tm_protocols;
660 rc = nci_request(ndev, nci_rf_discover_req, (unsigned long)&param,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100661 msecs_to_jiffies(NCI_RF_DISC_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300662
663 if (!rc)
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200664 ndev->poll_prots = im_protocols;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300665
666 return rc;
667}
668
669static void nci_stop_poll(struct nfc_dev *nfc_dev)
670{
671 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
672
Ilan Elias019c4fb2012-01-18 13:16:14 +0200673 if ((atomic_read(&ndev->state) != NCI_DISCOVERY) &&
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100674 (atomic_read(&ndev->state) != NCI_W4_ALL_DISCOVERIES)) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800675 pr_err("unable to stop poll, since poll is not active\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300676 return;
677 }
678
Christophe Ricard9295b5b2014-12-02 21:27:49 +0100679 nci_request(ndev, nci_rf_deactivate_req, NCI_DEACTIVATE_TYPE_IDLE_MODE,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100680 msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300681}
682
Eric Lapuyade90099432012-05-07 12:31:13 +0200683static int nci_activate_target(struct nfc_dev *nfc_dev,
684 struct nfc_target *target, __u32 protocol)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300685{
686 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
Ilan Elias019c4fb2012-01-18 13:16:14 +0200687 struct nci_rf_discover_select_param param;
Eric Lapuyade90099432012-05-07 12:31:13 +0200688 struct nfc_target *nci_target = NULL;
Ilan Elias019c4fb2012-01-18 13:16:14 +0200689 int i;
690 int rc = 0;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300691
Eric Lapuyade90099432012-05-07 12:31:13 +0200692 pr_debug("target_idx %d, protocol 0x%x\n", target->idx, protocol);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300693
Ilan Elias019c4fb2012-01-18 13:16:14 +0200694 if ((atomic_read(&ndev->state) != NCI_W4_HOST_SELECT) &&
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100695 (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800696 pr_err("there is no available target to activate\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300697 return -EINVAL;
698 }
699
700 if (ndev->target_active_prot) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800701 pr_err("there is already an active target\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300702 return -EBUSY;
703 }
704
Ilan Elias019c4fb2012-01-18 13:16:14 +0200705 for (i = 0; i < ndev->n_targets; i++) {
Eric Lapuyade90099432012-05-07 12:31:13 +0200706 if (ndev->targets[i].idx == target->idx) {
707 nci_target = &ndev->targets[i];
Ilan Elias019c4fb2012-01-18 13:16:14 +0200708 break;
709 }
710 }
711
Eric Lapuyade90099432012-05-07 12:31:13 +0200712 if (!nci_target) {
Ilan Elias019c4fb2012-01-18 13:16:14 +0200713 pr_err("unable to find the selected target\n");
714 return -EINVAL;
715 }
716
Eric Lapuyade90099432012-05-07 12:31:13 +0200717 if (!(nci_target->supported_protocols & (1 << protocol))) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800718 pr_err("target does not support the requested protocol 0x%x\n",
719 protocol);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300720 return -EINVAL;
721 }
722
Ilan Elias019c4fb2012-01-18 13:16:14 +0200723 if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) {
Eric Lapuyade90099432012-05-07 12:31:13 +0200724 param.rf_discovery_id = nci_target->logical_idx;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300725
Ilan Elias019c4fb2012-01-18 13:16:14 +0200726 if (protocol == NFC_PROTO_JEWEL)
727 param.rf_protocol = NCI_RF_PROTOCOL_T1T;
728 else if (protocol == NFC_PROTO_MIFARE)
729 param.rf_protocol = NCI_RF_PROTOCOL_T2T;
730 else if (protocol == NFC_PROTO_FELICA)
731 param.rf_protocol = NCI_RF_PROTOCOL_T3T;
Samuel Ortiz01d719a2012-07-04 00:14:04 +0200732 else if (protocol == NFC_PROTO_ISO14443 ||
733 protocol == NFC_PROTO_ISO14443_B)
Ilan Elias019c4fb2012-01-18 13:16:14 +0200734 param.rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
735 else
736 param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
737
738 rc = nci_request(ndev, nci_rf_discover_select_req,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100739 (unsigned long)&param,
740 msecs_to_jiffies(NCI_RF_DISC_SELECT_TIMEOUT));
Ilan Elias019c4fb2012-01-18 13:16:14 +0200741 }
742
743 if (!rc)
744 ndev->target_active_prot = protocol;
745
746 return rc;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300747}
748
Eric Lapuyade90099432012-05-07 12:31:13 +0200749static void nci_deactivate_target(struct nfc_dev *nfc_dev,
750 struct nfc_target *target)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300751{
752 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
753
Ilan Elias767f19a2012-08-15 11:46:24 +0300754 pr_debug("entry\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300755
756 if (!ndev->target_active_prot) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800757 pr_err("unable to deactivate target, no active target\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300758 return;
759 }
760
761 ndev->target_active_prot = 0;
762
Ilan Elias8939e472012-01-18 13:16:12 +0200763 if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) {
Christophe Ricard9295b5b2014-12-02 21:27:49 +0100764 nci_request(ndev, nci_rf_deactivate_req,
765 NCI_DEACTIVATE_TYPE_SLEEP_MODE,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100766 msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300767 }
768}
769
Ilan Elias767f19a2012-08-15 11:46:24 +0300770static int nci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
771 __u8 comm_mode, __u8 *gb, size_t gb_len)
772{
773 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
774 int rc;
775
776 pr_debug("target_idx %d, comm_mode %d\n", target->idx, comm_mode);
777
778 rc = nci_activate_target(nfc_dev, target, NFC_PROTO_NFC_DEP);
779 if (rc)
780 return rc;
781
782 rc = nfc_set_remote_general_bytes(nfc_dev, ndev->remote_gb,
783 ndev->remote_gb_len);
784 if (!rc)
785 rc = nfc_dep_link_is_up(nfc_dev, target->idx, NFC_COMM_PASSIVE,
786 NFC_RF_INITIATOR);
787
788 return rc;
789}
790
791static int nci_dep_link_down(struct nfc_dev *nfc_dev)
792{
Julien Lefriqued7979e12014-10-21 16:52:53 +0200793 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
794 int rc;
795
Ilan Elias767f19a2012-08-15 11:46:24 +0300796 pr_debug("entry\n");
797
Julien Lefriqued7979e12014-10-21 16:52:53 +0200798 if (nfc_dev->rf_mode == NFC_RF_INITIATOR) {
799 nci_deactivate_target(nfc_dev, NULL);
800 } else {
801 if (atomic_read(&ndev->state) == NCI_LISTEN_ACTIVE ||
802 atomic_read(&ndev->state) == NCI_DISCOVERY) {
803 nci_request(ndev, nci_rf_deactivate_req, 0,
804 msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
805 }
806
807 rc = nfc_tm_deactivated(nfc_dev);
808 if (rc)
809 pr_err("error when signaling tm deactivation\n");
810 }
Ilan Elias767f19a2012-08-15 11:46:24 +0300811
812 return 0;
813}
814
815
Samuel Ortizbe9ae4c2012-05-16 15:55:48 +0200816static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
817 struct sk_buff *skb,
818 data_exchange_cb_t cb, void *cb_context)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300819{
820 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
Ilan Elias38f04c62011-09-22 11:36:19 +0300821 int rc;
Christophe Ricard4aeee6872015-02-01 22:26:08 +0100822 struct nci_conn_info *conn_info;
823
Christophe Ricard12bdf272015-02-03 19:48:04 +0100824 conn_info = ndev->rf_conn_info;
Christophe Ricard4aeee6872015-02-01 22:26:08 +0100825 if (!conn_info)
826 return -EPROTO;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300827
Eric Lapuyade90099432012-05-07 12:31:13 +0200828 pr_debug("target_idx %d, len %d\n", target->idx, skb->len);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300829
830 if (!ndev->target_active_prot) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800831 pr_err("unable to exchange data, no active target\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300832 return -EINVAL;
833 }
834
Ilan Elias38f04c62011-09-22 11:36:19 +0300835 if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags))
836 return -EBUSY;
837
Ilan Elias6a2968a2011-09-18 11:19:35 +0300838 /* store cb and context to be used on receiving data */
Christophe Ricard4aeee6872015-02-01 22:26:08 +0100839 conn_info->data_exchange_cb = cb;
840 conn_info->data_exchange_cb_context = cb_context;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300841
Ilan Eliase8c0dac2011-11-09 12:09:14 +0200842 rc = nci_send_data(ndev, NCI_STATIC_RF_CONN_ID, skb);
Ilan Elias38f04c62011-09-22 11:36:19 +0300843 if (rc)
844 clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
845
846 return rc;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300847}
848
Julien Lefrique485f4422014-10-21 16:52:48 +0200849static int nci_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
850{
851 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
852 int rc;
853
854 rc = nci_send_data(ndev, NCI_STATIC_RF_CONN_ID, skb);
855 if (rc)
856 pr_err("unable to send data\n");
857
858 return rc;
859}
860
Samuel Ortiz0a946302013-05-10 11:57:06 +0200861static int nci_enable_se(struct nfc_dev *nfc_dev, u32 se_idx)
862{
Christophe Ricard93bca2b2014-11-13 00:30:36 +0100863 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
864
865 if (ndev->ops->enable_se)
866 return ndev->ops->enable_se(ndev, se_idx);
867
Samuel Ortiz0a946302013-05-10 11:57:06 +0200868 return 0;
869}
870
871static int nci_disable_se(struct nfc_dev *nfc_dev, u32 se_idx)
872{
Christophe Ricarde9ef9432014-11-13 00:30:37 +0100873 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
874
875 if (ndev->ops->disable_se)
876 return ndev->ops->disable_se(ndev, se_idx);
877
Samuel Ortiz0a946302013-05-10 11:57:06 +0200878 return 0;
879}
880
881static int nci_discover_se(struct nfc_dev *nfc_dev)
882{
Christophe Ricardfa00e8f2015-02-03 19:48:08 +0100883 int r;
Christophe Ricardba4db552014-11-13 00:30:35 +0100884 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
885
Christophe Ricardfa00e8f2015-02-03 19:48:08 +0100886 if (ndev->ops->discover_se) {
887 r = nci_nfcee_discover(ndev, NCI_NFCEE_DISCOVERY_ACTION_ENABLE);
888 if (r != NCI_STATUS_OK)
889 return -EPROTO;
890
Christophe Ricardba4db552014-11-13 00:30:35 +0100891 return ndev->ops->discover_se(ndev);
Christophe Ricardfa00e8f2015-02-03 19:48:08 +0100892 }
Christophe Ricardba4db552014-11-13 00:30:35 +0100893
Samuel Ortiz0a946302013-05-10 11:57:06 +0200894 return 0;
895}
896
Christophe Ricarda688bf52014-11-13 00:30:38 +0100897static int nci_se_io(struct nfc_dev *nfc_dev, u32 se_idx,
898 u8 *apdu, size_t apdu_length,
899 se_io_cb_t cb, void *cb_context)
900{
901 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
902
903 if (ndev->ops->se_io)
904 return ndev->ops->se_io(ndev, se_idx, apdu,
905 apdu_length, cb, cb_context);
906
907 return 0;
908}
909
Clément Perrochaud25af01ed2015-03-09 11:12:03 +0100910static int nci_fw_download(struct nfc_dev *nfc_dev, const char *firmware_name)
911{
912 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
913
914 if (!ndev->ops->fw_download)
915 return -ENOTSUPP;
916
917 return ndev->ops->fw_download(ndev, firmware_name);
918}
919
Ilan Elias6a2968a2011-09-18 11:19:35 +0300920static struct nfc_ops nci_nfc_ops = {
921 .dev_up = nci_dev_up,
922 .dev_down = nci_dev_down,
923 .start_poll = nci_start_poll,
924 .stop_poll = nci_stop_poll,
Ilan Elias767f19a2012-08-15 11:46:24 +0300925 .dep_link_up = nci_dep_link_up,
926 .dep_link_down = nci_dep_link_down,
Ilan Elias6a2968a2011-09-18 11:19:35 +0300927 .activate_target = nci_activate_target,
928 .deactivate_target = nci_deactivate_target,
Samuel Ortizbe9ae4c2012-05-16 15:55:48 +0200929 .im_transceive = nci_transceive,
Julien Lefrique485f4422014-10-21 16:52:48 +0200930 .tm_send = nci_tm_send,
Samuel Ortiz0a946302013-05-10 11:57:06 +0200931 .enable_se = nci_enable_se,
932 .disable_se = nci_disable_se,
933 .discover_se = nci_discover_se,
Christophe Ricarda688bf52014-11-13 00:30:38 +0100934 .se_io = nci_se_io,
Clément Perrochaud25af01ed2015-03-09 11:12:03 +0100935 .fw_download = nci_fw_download,
Ilan Elias6a2968a2011-09-18 11:19:35 +0300936};
937
938/* ---- Interface to NCI drivers ---- */
Ilan Elias6a2968a2011-09-18 11:19:35 +0300939/**
940 * nci_allocate_device - allocate a new nci device
941 *
942 * @ops: device operations
943 * @supported_protocols: NFC protocols supported by the device
944 */
945struct nci_dev *nci_allocate_device(struct nci_ops *ops,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100946 __u32 supported_protocols,
947 int tx_headroom, int tx_tailroom)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300948{
Dan Carpenter8ebafde2011-09-23 09:14:35 +0300949 struct nci_dev *ndev;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300950
Joe Perches24bf3302011-11-29 11:37:35 -0800951 pr_debug("supported_protocols 0x%x\n", supported_protocols);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300952
953 if (!ops->open || !ops->close || !ops->send)
Dan Carpenter8ebafde2011-09-23 09:14:35 +0300954 return NULL;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300955
956 if (!supported_protocols)
Dan Carpenter8ebafde2011-09-23 09:14:35 +0300957 return NULL;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300958
959 ndev = kzalloc(sizeof(struct nci_dev), GFP_KERNEL);
960 if (!ndev)
Dan Carpenter8ebafde2011-09-23 09:14:35 +0300961 return NULL;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300962
963 ndev->ops = ops;
964 ndev->tx_headroom = tx_headroom;
965 ndev->tx_tailroom = tx_tailroom;
Axel Lin9bec44b2014-02-13 13:25:48 +0800966 init_completion(&ndev->req_completion);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300967
968 ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100969 supported_protocols,
970 tx_headroom + NCI_DATA_HDR_SIZE,
971 tx_tailroom);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300972 if (!ndev->nfc_dev)
Christophe Ricard11f54f22015-02-01 22:26:14 +0100973 goto free_nci;
974
975 ndev->hci_dev = nci_hci_allocate(ndev);
976 if (!ndev->hci_dev)
977 goto free_nfc;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300978
979 nfc_set_drvdata(ndev->nfc_dev, ndev);
980
Dan Carpenter8ebafde2011-09-23 09:14:35 +0300981 return ndev;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300982
Christophe Ricard11f54f22015-02-01 22:26:14 +0100983free_nfc:
984 kfree(ndev->nfc_dev);
985
986free_nci:
Ilan Elias6a2968a2011-09-18 11:19:35 +0300987 kfree(ndev);
Dan Carpenter8ebafde2011-09-23 09:14:35 +0300988 return NULL;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300989}
990EXPORT_SYMBOL(nci_allocate_device);
991
992/**
993 * nci_free_device - deallocate nci device
994 *
995 * @ndev: The nci device to deallocate
996 */
997void nci_free_device(struct nci_dev *ndev)
998{
Ilan Elias6a2968a2011-09-18 11:19:35 +0300999 nfc_free_device(ndev->nfc_dev);
1000 kfree(ndev);
1001}
1002EXPORT_SYMBOL(nci_free_device);
1003
1004/**
1005 * nci_register_device - register a nci device in the nfc subsystem
1006 *
1007 * @dev: The nci device to register
1008 */
1009int nci_register_device(struct nci_dev *ndev)
1010{
1011 int rc;
1012 struct device *dev = &ndev->nfc_dev->dev;
1013 char name[32];
1014
Ilan Elias6a2968a2011-09-18 11:19:35 +03001015 ndev->flags = 0;
1016
1017 INIT_WORK(&ndev->cmd_work, nci_cmd_work);
1018 snprintf(name, sizeof(name), "%s_nci_cmd_wq", dev_name(dev));
1019 ndev->cmd_wq = create_singlethread_workqueue(name);
1020 if (!ndev->cmd_wq) {
1021 rc = -ENOMEM;
Vincent Cuissard3c1c0f52014-07-22 19:48:39 +02001022 goto exit;
Ilan Elias6a2968a2011-09-18 11:19:35 +03001023 }
1024
1025 INIT_WORK(&ndev->rx_work, nci_rx_work);
1026 snprintf(name, sizeof(name), "%s_nci_rx_wq", dev_name(dev));
1027 ndev->rx_wq = create_singlethread_workqueue(name);
1028 if (!ndev->rx_wq) {
1029 rc = -ENOMEM;
1030 goto destroy_cmd_wq_exit;
1031 }
1032
1033 INIT_WORK(&ndev->tx_work, nci_tx_work);
1034 snprintf(name, sizeof(name), "%s_nci_tx_wq", dev_name(dev));
1035 ndev->tx_wq = create_singlethread_workqueue(name);
1036 if (!ndev->tx_wq) {
1037 rc = -ENOMEM;
1038 goto destroy_rx_wq_exit;
1039 }
1040
1041 skb_queue_head_init(&ndev->cmd_q);
1042 skb_queue_head_init(&ndev->rx_q);
1043 skb_queue_head_init(&ndev->tx_q);
1044
1045 setup_timer(&ndev->cmd_timer, nci_cmd_timer,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +01001046 (unsigned long) ndev);
Ilan Eliasc4bf98b2012-01-17 12:03:50 +02001047 setup_timer(&ndev->data_timer, nci_data_timer,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +01001048 (unsigned long) ndev);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001049
1050 mutex_init(&ndev->req_lock);
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001051 INIT_LIST_HEAD(&ndev->conn_info_list);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001052
Vincent Cuissard3c1c0f52014-07-22 19:48:39 +02001053 rc = nfc_register_device(ndev->nfc_dev);
1054 if (rc)
1055 goto destroy_rx_wq_exit;
1056
Ilan Elias6a2968a2011-09-18 11:19:35 +03001057 goto exit;
1058
1059destroy_rx_wq_exit:
1060 destroy_workqueue(ndev->rx_wq);
1061
1062destroy_cmd_wq_exit:
1063 destroy_workqueue(ndev->cmd_wq);
1064
Ilan Elias6a2968a2011-09-18 11:19:35 +03001065exit:
1066 return rc;
1067}
1068EXPORT_SYMBOL(nci_register_device);
1069
1070/**
1071 * nci_unregister_device - unregister a nci device in the nfc subsystem
1072 *
1073 * @dev: The nci device to unregister
1074 */
1075void nci_unregister_device(struct nci_dev *ndev)
1076{
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001077 struct nci_conn_info *conn_info, *n;
1078
Ilan Elias6a2968a2011-09-18 11:19:35 +03001079 nci_close_device(ndev);
1080
1081 destroy_workqueue(ndev->cmd_wq);
1082 destroy_workqueue(ndev->rx_wq);
1083 destroy_workqueue(ndev->tx_wq);
1084
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001085 list_for_each_entry_safe(conn_info, n, &ndev->conn_info_list, list) {
1086 list_del(&conn_info->list);
1087 /* conn_info is allocated with devm_kzalloc */
1088 }
1089
Ilan Elias6a2968a2011-09-18 11:19:35 +03001090 nfc_unregister_device(ndev->nfc_dev);
1091}
1092EXPORT_SYMBOL(nci_unregister_device);
1093
1094/**
1095 * nci_recv_frame - receive frame from NCI drivers
1096 *
Frederic Danis1095e692013-05-22 11:36:17 +02001097 * @ndev: The nci device
Ilan Elias6a2968a2011-09-18 11:19:35 +03001098 * @skb: The sk_buff to receive
1099 */
Frederic Danis1095e692013-05-22 11:36:17 +02001100int nci_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
Ilan Elias6a2968a2011-09-18 11:19:35 +03001101{
Joe Perches24bf3302011-11-29 11:37:35 -08001102 pr_debug("len %d\n", skb->len);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001103
Szymon Janc874934f2012-10-04 15:15:51 +02001104 if (!ndev || (!test_bit(NCI_UP, &ndev->flags) &&
1105 !test_bit(NCI_INIT, &ndev->flags))) {
Ilan Elias6a2968a2011-09-18 11:19:35 +03001106 kfree_skb(skb);
1107 return -ENXIO;
1108 }
1109
1110 /* Queue frame for rx worker thread */
1111 skb_queue_tail(&ndev->rx_q, skb);
1112 queue_work(ndev->rx_wq, &ndev->rx_work);
1113
1114 return 0;
1115}
1116EXPORT_SYMBOL(nci_recv_frame);
1117
Frederic Danis1095e692013-05-22 11:36:17 +02001118static int nci_send_frame(struct nci_dev *ndev, struct sk_buff *skb)
Ilan Elias6a2968a2011-09-18 11:19:35 +03001119{
Joe Perches24bf3302011-11-29 11:37:35 -08001120 pr_debug("len %d\n", skb->len);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001121
1122 if (!ndev) {
1123 kfree_skb(skb);
1124 return -ENODEV;
1125 }
1126
1127 /* Get rid of skb owner, prior to sending to the driver. */
1128 skb_orphan(skb);
1129
Hiren Tandel05158292014-05-05 19:52:27 +09001130 /* Send copy to sniffer */
1131 nfc_send_to_raw_sock(ndev->nfc_dev, skb,
1132 RAW_PAYLOAD_NCI, NFC_DIRECTION_TX);
1133
Frederic Danis1095e692013-05-22 11:36:17 +02001134 return ndev->ops->send(ndev, skb);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001135}
1136
1137/* Send NCI command */
1138int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload)
1139{
1140 struct nci_ctrl_hdr *hdr;
1141 struct sk_buff *skb;
1142
Joe Perches24bf3302011-11-29 11:37:35 -08001143 pr_debug("opcode 0x%x, plen %d\n", opcode, plen);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001144
1145 skb = nci_skb_alloc(ndev, (NCI_CTRL_HDR_SIZE + plen), GFP_KERNEL);
1146 if (!skb) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -08001147 pr_err("no memory for command\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +03001148 return -ENOMEM;
1149 }
1150
1151 hdr = (struct nci_ctrl_hdr *) skb_put(skb, NCI_CTRL_HDR_SIZE);
1152 hdr->gid = nci_opcode_gid(opcode);
1153 hdr->oid = nci_opcode_oid(opcode);
1154 hdr->plen = plen;
1155
1156 nci_mt_set((__u8 *)hdr, NCI_MT_CMD_PKT);
1157 nci_pbf_set((__u8 *)hdr, NCI_PBF_LAST);
1158
1159 if (plen)
1160 memcpy(skb_put(skb, plen), payload, plen);
1161
Ilan Elias6a2968a2011-09-18 11:19:35 +03001162 skb_queue_tail(&ndev->cmd_q, skb);
1163 queue_work(ndev->cmd_wq, &ndev->cmd_work);
1164
1165 return 0;
1166}
1167
1168/* ---- NCI TX Data worker thread ---- */
1169
1170static void nci_tx_work(struct work_struct *work)
1171{
1172 struct nci_dev *ndev = container_of(work, struct nci_dev, tx_work);
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001173 struct nci_conn_info *conn_info;
Ilan Elias6a2968a2011-09-18 11:19:35 +03001174 struct sk_buff *skb;
1175
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001176 conn_info = nci_get_conn_info_by_conn_id(ndev, ndev->cur_conn_id);
1177 if (!conn_info)
1178 return;
1179
1180 pr_debug("credits_cnt %d\n", atomic_read(&conn_info->credits_cnt));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001181
1182 /* Send queued tx data */
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001183 while (atomic_read(&conn_info->credits_cnt)) {
Ilan Elias6a2968a2011-09-18 11:19:35 +03001184 skb = skb_dequeue(&ndev->tx_q);
1185 if (!skb)
1186 return;
1187
Ilan Eliasdb98c822011-11-09 12:09:16 +02001188 /* Check if data flow control is used */
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001189 if (atomic_read(&conn_info->credits_cnt) !=
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +01001190 NCI_DATA_FLOW_CONTROL_NOT_USED)
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001191 atomic_dec(&conn_info->credits_cnt);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001192
Joe Perches20c239c2011-11-29 11:37:33 -08001193 pr_debug("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d\n",
1194 nci_pbf(skb->data),
1195 nci_conn_id(skb->data),
1196 nci_plen(skb->data));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001197
Frederic Danis1095e692013-05-22 11:36:17 +02001198 nci_send_frame(ndev, skb);
Ilan Eliasc4bf98b2012-01-17 12:03:50 +02001199
1200 mod_timer(&ndev->data_timer,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +01001201 jiffies + msecs_to_jiffies(NCI_DATA_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001202 }
1203}
1204
1205/* ----- NCI RX worker thread (data & control) ----- */
1206
1207static void nci_rx_work(struct work_struct *work)
1208{
1209 struct nci_dev *ndev = container_of(work, struct nci_dev, rx_work);
1210 struct sk_buff *skb;
1211
1212 while ((skb = skb_dequeue(&ndev->rx_q))) {
Hiren Tandel05158292014-05-05 19:52:27 +09001213
1214 /* Send copy to sniffer */
1215 nfc_send_to_raw_sock(ndev->nfc_dev, skb,
1216 RAW_PAYLOAD_NCI, NFC_DIRECTION_RX);
1217
Ilan Elias6a2968a2011-09-18 11:19:35 +03001218 /* Process frame */
1219 switch (nci_mt(skb->data)) {
1220 case NCI_MT_RSP_PKT:
1221 nci_rsp_packet(ndev, skb);
1222 break;
1223
1224 case NCI_MT_NTF_PKT:
1225 nci_ntf_packet(ndev, skb);
1226 break;
1227
1228 case NCI_MT_DATA_PKT:
1229 nci_rx_data_packet(ndev, skb);
1230 break;
1231
1232 default:
Joe Perchesed1e0ad2011-11-29 11:37:32 -08001233 pr_err("unknown MT 0x%x\n", nci_mt(skb->data));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001234 kfree_skb(skb);
1235 break;
1236 }
1237 }
Ilan Eliasc4bf98b2012-01-17 12:03:50 +02001238
1239 /* check if a data exchange timout has occurred */
1240 if (test_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags)) {
1241 /* complete the data exchange transaction, if exists */
1242 if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001243 nci_data_exchange_complete(ndev, NULL,
1244 ndev->cur_conn_id,
1245 -ETIMEDOUT);
Ilan Eliasc4bf98b2012-01-17 12:03:50 +02001246
1247 clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
1248 }
Ilan Elias6a2968a2011-09-18 11:19:35 +03001249}
1250
1251/* ----- NCI TX CMD worker thread ----- */
1252
1253static void nci_cmd_work(struct work_struct *work)
1254{
1255 struct nci_dev *ndev = container_of(work, struct nci_dev, cmd_work);
1256 struct sk_buff *skb;
1257
Joe Perches24bf3302011-11-29 11:37:35 -08001258 pr_debug("cmd_cnt %d\n", atomic_read(&ndev->cmd_cnt));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001259
1260 /* Send queued command */
1261 if (atomic_read(&ndev->cmd_cnt)) {
1262 skb = skb_dequeue(&ndev->cmd_q);
1263 if (!skb)
1264 return;
1265
1266 atomic_dec(&ndev->cmd_cnt);
1267
Joe Perches20c239c2011-11-29 11:37:33 -08001268 pr_debug("NCI TX: MT=cmd, PBF=%d, GID=0x%x, OID=0x%x, plen=%d\n",
1269 nci_pbf(skb->data),
1270 nci_opcode_gid(nci_opcode(skb->data)),
1271 nci_opcode_oid(nci_opcode(skb->data)),
1272 nci_plen(skb->data));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001273
Frederic Danis1095e692013-05-22 11:36:17 +02001274 nci_send_frame(ndev, skb);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001275
1276 mod_timer(&ndev->cmd_timer,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +01001277 jiffies + msecs_to_jiffies(NCI_CMD_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001278 }
1279}
Dave Jones8a70e7f2012-07-12 19:17:34 +02001280
1281MODULE_LICENSE("GPL");