blob: a258575485248b38764127d37eb273b5d6588340 [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
44static void nci_cmd_work(struct work_struct *work);
45static void nci_rx_work(struct work_struct *work);
46static void nci_tx_work(struct work_struct *work);
47
Christophe Ricard4aeee6872015-02-01 22:26:08 +010048struct nci_conn_info *nci_get_conn_info_by_conn_id(struct nci_dev *ndev,
49 int conn_id)
50{
51 struct nci_conn_info *conn_info;
52
53 list_for_each_entry(conn_info, &ndev->conn_info_list, list) {
54 if (conn_info->conn_id == conn_id)
55 return conn_info;
56 }
57
58 return NULL;
59}
60
Ilan Elias6a2968a2011-09-18 11:19:35 +030061/* ---- NCI requests ---- */
62
63void nci_req_complete(struct nci_dev *ndev, int result)
64{
65 if (ndev->req_status == NCI_REQ_PEND) {
66 ndev->req_result = result;
67 ndev->req_status = NCI_REQ_DONE;
68 complete(&ndev->req_completion);
69 }
70}
71
72static void nci_req_cancel(struct nci_dev *ndev, int err)
73{
74 if (ndev->req_status == NCI_REQ_PEND) {
75 ndev->req_result = err;
76 ndev->req_status = NCI_REQ_CANCELED;
77 complete(&ndev->req_completion);
78 }
79}
80
81/* Execute request and wait for completion. */
82static int __nci_request(struct nci_dev *ndev,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +010083 void (*req)(struct nci_dev *ndev, unsigned long opt),
84 unsigned long opt, __u32 timeout)
Ilan Elias6a2968a2011-09-18 11:19:35 +030085{
86 int rc = 0;
Dan Carpenterf8c141c2011-12-09 09:35:39 +030087 long completion_rc;
Ilan Elias6a2968a2011-09-18 11:19:35 +030088
89 ndev->req_status = NCI_REQ_PEND;
90
Axel Lin9bec44b2014-02-13 13:25:48 +080091 reinit_completion(&ndev->req_completion);
Ilan Elias6a2968a2011-09-18 11:19:35 +030092 req(ndev, opt);
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +010093 completion_rc =
94 wait_for_completion_interruptible_timeout(&ndev->req_completion,
95 timeout);
Ilan Elias6a2968a2011-09-18 11:19:35 +030096
Joe Perches20c239c2011-11-29 11:37:33 -080097 pr_debug("wait_for_completion return %ld\n", completion_rc);
Ilan Elias6a2968a2011-09-18 11:19:35 +030098
99 if (completion_rc > 0) {
100 switch (ndev->req_status) {
101 case NCI_REQ_DONE:
102 rc = nci_to_errno(ndev->req_result);
103 break;
104
105 case NCI_REQ_CANCELED:
106 rc = -ndev->req_result;
107 break;
108
109 default:
110 rc = -ETIMEDOUT;
111 break;
112 }
113 } else {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800114 pr_err("wait_for_completion_interruptible_timeout failed %ld\n",
115 completion_rc);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300116
117 rc = ((completion_rc == 0) ? (-ETIMEDOUT) : (completion_rc));
118 }
119
120 ndev->req_status = ndev->req_result = 0;
121
122 return rc;
123}
124
125static inline int nci_request(struct nci_dev *ndev,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100126 void (*req)(struct nci_dev *ndev,
127 unsigned long opt),
128 unsigned long opt, __u32 timeout)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300129{
130 int rc;
131
132 if (!test_bit(NCI_UP, &ndev->flags))
133 return -ENETDOWN;
134
135 /* Serialize all requests */
136 mutex_lock(&ndev->req_lock);
137 rc = __nci_request(ndev, req, opt, timeout);
138 mutex_unlock(&ndev->req_lock);
139
140 return rc;
141}
142
143static void nci_reset_req(struct nci_dev *ndev, unsigned long opt)
144{
Ilan Eliase8c0dac2011-11-09 12:09:14 +0200145 struct nci_core_reset_cmd cmd;
146
147 cmd.reset_type = NCI_RESET_TYPE_RESET_CONFIG;
148 nci_send_cmd(ndev, NCI_OP_CORE_RESET_CMD, 1, &cmd);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300149}
150
151static void nci_init_req(struct nci_dev *ndev, unsigned long opt)
152{
153 nci_send_cmd(ndev, NCI_OP_CORE_INIT_CMD, 0, NULL);
154}
155
156static void nci_init_complete_req(struct nci_dev *ndev, unsigned long opt)
157{
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300158 struct nci_rf_disc_map_cmd cmd;
159 struct disc_map_config *cfg = cmd.mapping_configs;
160 __u8 *num = &cmd.num_mapping_configs;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300161 int i;
162
Ilan Elias6a2968a2011-09-18 11:19:35 +0300163 /* set rf mapping configurations */
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300164 *num = 0;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300165
166 /* by default mapping is set to NCI_RF_INTERFACE_FRAME */
167 for (i = 0; i < ndev->num_supported_rf_interfaces; i++) {
168 if (ndev->supported_rf_interfaces[i] ==
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100169 NCI_RF_INTERFACE_ISO_DEP) {
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300170 cfg[*num].rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
Ilan Elias637d85a2011-12-20 16:57:40 +0200171 cfg[*num].mode = NCI_DISC_MAP_MODE_POLL |
172 NCI_DISC_MAP_MODE_LISTEN;
173 cfg[*num].rf_interface = NCI_RF_INTERFACE_ISO_DEP;
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300174 (*num)++;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300175 } else if (ndev->supported_rf_interfaces[i] ==
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100176 NCI_RF_INTERFACE_NFC_DEP) {
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300177 cfg[*num].rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
Ilan Elias637d85a2011-12-20 16:57:40 +0200178 cfg[*num].mode = NCI_DISC_MAP_MODE_POLL |
179 NCI_DISC_MAP_MODE_LISTEN;
180 cfg[*num].rf_interface = NCI_RF_INTERFACE_NFC_DEP;
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300181 (*num)++;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300182 }
183
Ilan Elias2eb1dc12011-09-22 10:47:52 +0300184 if (*num == NCI_MAX_NUM_MAPPING_CONFIGS)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300185 break;
186 }
187
188 nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_MAP_CMD,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100189 (1 + ((*num) * sizeof(struct disc_map_config))), &cmd);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300190}
191
Ilan Elias7e035232012-08-15 11:46:22 +0300192struct nci_set_config_param {
193 __u8 id;
194 size_t len;
195 __u8 *val;
196};
197
198static void nci_set_config_req(struct nci_dev *ndev, unsigned long opt)
199{
200 struct nci_set_config_param *param = (struct nci_set_config_param *)opt;
201 struct nci_core_set_config_cmd cmd;
202
203 BUG_ON(param->len > NCI_MAX_PARAM_LEN);
204
205 cmd.num_params = 1;
206 cmd.param.id = param->id;
207 cmd.param.len = param->len;
208 memcpy(cmd.param.val, param->val, param->len);
209
210 nci_send_cmd(ndev, NCI_OP_CORE_SET_CONFIG_CMD, (3 + param->len), &cmd);
211}
212
Julien Lefrique772dccf2014-10-21 16:52:44 +0200213struct nci_rf_discover_param {
214 __u32 im_protocols;
215 __u32 tm_protocols;
216};
217
Ilan Elias6a2968a2011-09-18 11:19:35 +0300218static void nci_rf_discover_req(struct nci_dev *ndev, unsigned long opt)
219{
Julien Lefrique772dccf2014-10-21 16:52:44 +0200220 struct nci_rf_discover_param *param =
221 (struct nci_rf_discover_param *)opt;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300222 struct nci_rf_disc_cmd cmd;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300223
224 cmd.num_disc_configs = 0;
225
226 if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
Julien Lefrique772dccf2014-10-21 16:52:44 +0200227 (param->im_protocols & NFC_PROTO_JEWEL_MASK ||
228 param->im_protocols & NFC_PROTO_MIFARE_MASK ||
229 param->im_protocols & NFC_PROTO_ISO14443_MASK ||
230 param->im_protocols & NFC_PROTO_NFC_DEP_MASK)) {
Ilan Elias637d85a2011-12-20 16:57:40 +0200231 cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100232 NCI_NFC_A_PASSIVE_POLL_MODE;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300233 cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
234 cmd.num_disc_configs++;
235 }
236
237 if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
Julien Lefrique772dccf2014-10-21 16:52:44 +0200238 (param->im_protocols & NFC_PROTO_ISO14443_B_MASK)) {
Ilan Elias637d85a2011-12-20 16:57:40 +0200239 cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100240 NCI_NFC_B_PASSIVE_POLL_MODE;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300241 cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
242 cmd.num_disc_configs++;
243 }
244
245 if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
Julien Lefrique772dccf2014-10-21 16:52:44 +0200246 (param->im_protocols & NFC_PROTO_FELICA_MASK ||
247 param->im_protocols & NFC_PROTO_NFC_DEP_MASK)) {
Ilan Elias637d85a2011-12-20 16:57:40 +0200248 cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100249 NCI_NFC_F_PASSIVE_POLL_MODE;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300250 cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
251 cmd.num_disc_configs++;
252 }
253
Vincent Cuissardcfdbeea2014-07-22 19:48:38 +0200254 if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS) &&
Julien Lefrique772dccf2014-10-21 16:52:44 +0200255 (param->im_protocols & NFC_PROTO_ISO15693_MASK)) {
Vincent Cuissardcfdbeea2014-07-22 19:48:38 +0200256 cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
257 NCI_NFC_V_PASSIVE_POLL_MODE;
258 cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
259 cmd.num_disc_configs++;
260 }
261
Julien Lefrique772dccf2014-10-21 16:52:44 +0200262 if ((cmd.num_disc_configs < NCI_MAX_NUM_RF_CONFIGS - 1) &&
263 (param->tm_protocols & NFC_PROTO_NFC_DEP_MASK)) {
264 cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
265 NCI_NFC_A_PASSIVE_LISTEN_MODE;
266 cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
267 cmd.num_disc_configs++;
268 cmd.disc_configs[cmd.num_disc_configs].rf_tech_and_mode =
269 NCI_NFC_F_PASSIVE_LISTEN_MODE;
270 cmd.disc_configs[cmd.num_disc_configs].frequency = 1;
271 cmd.num_disc_configs++;
272 }
273
Ilan Elias6a2968a2011-09-18 11:19:35 +0300274 nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_CMD,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100275 (1 + (cmd.num_disc_configs * sizeof(struct disc_config))),
276 &cmd);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300277}
278
Ilan Elias019c4fb2012-01-18 13:16:14 +0200279struct nci_rf_discover_select_param {
280 __u8 rf_discovery_id;
281 __u8 rf_protocol;
282};
283
284static void nci_rf_discover_select_req(struct nci_dev *ndev, unsigned long opt)
285{
286 struct nci_rf_discover_select_param *param =
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100287 (struct nci_rf_discover_select_param *)opt;
Ilan Elias019c4fb2012-01-18 13:16:14 +0200288 struct nci_rf_discover_select_cmd cmd;
289
290 cmd.rf_discovery_id = param->rf_discovery_id;
291 cmd.rf_protocol = param->rf_protocol;
292
293 switch (cmd.rf_protocol) {
294 case NCI_RF_PROTOCOL_ISO_DEP:
295 cmd.rf_interface = NCI_RF_INTERFACE_ISO_DEP;
296 break;
297
298 case NCI_RF_PROTOCOL_NFC_DEP:
299 cmd.rf_interface = NCI_RF_INTERFACE_NFC_DEP;
300 break;
301
302 default:
303 cmd.rf_interface = NCI_RF_INTERFACE_FRAME;
304 break;
305 }
306
307 nci_send_cmd(ndev, NCI_OP_RF_DISCOVER_SELECT_CMD,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100308 sizeof(struct nci_rf_discover_select_cmd), &cmd);
Ilan Elias019c4fb2012-01-18 13:16:14 +0200309}
310
Ilan Elias6a2968a2011-09-18 11:19:35 +0300311static void nci_rf_deactivate_req(struct nci_dev *ndev, unsigned long opt)
312{
313 struct nci_rf_deactivate_cmd cmd;
314
Christophe Ricard9295b5b2014-12-02 21:27:49 +0100315 cmd.type = opt;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300316
317 nci_send_cmd(ndev, NCI_OP_RF_DEACTIVATE_CMD,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100318 sizeof(struct nci_rf_deactivate_cmd), &cmd);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300319}
320
321static int nci_open_device(struct nci_dev *ndev)
322{
323 int rc = 0;
324
325 mutex_lock(&ndev->req_lock);
326
327 if (test_bit(NCI_UP, &ndev->flags)) {
328 rc = -EALREADY;
329 goto done;
330 }
331
332 if (ndev->ops->open(ndev)) {
333 rc = -EIO;
334 goto done;
335 }
336
337 atomic_set(&ndev->cmd_cnt, 1);
338
339 set_bit(NCI_INIT, &ndev->flags);
340
341 rc = __nci_request(ndev, nci_reset_req, 0,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100342 msecs_to_jiffies(NCI_RESET_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300343
Amitkumar Karwar44a589c2014-02-06 11:28:31 -0800344 if (ndev->ops->setup)
Amitkumar Karwar86e85862014-01-06 12:58:17 -0800345 ndev->ops->setup(ndev);
346
Ilan Elias6a2968a2011-09-18 11:19:35 +0300347 if (!rc) {
348 rc = __nci_request(ndev, nci_init_req, 0,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100349 msecs_to_jiffies(NCI_INIT_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300350 }
351
352 if (!rc) {
353 rc = __nci_request(ndev, nci_init_complete_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 clear_bit(NCI_INIT, &ndev->flags);
358
359 if (!rc) {
360 set_bit(NCI_UP, &ndev->flags);
Ilan Elias019c4fb2012-01-18 13:16:14 +0200361 nci_clear_target_list(ndev);
Ilan Elias8939e472012-01-18 13:16:12 +0200362 atomic_set(&ndev->state, NCI_IDLE);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300363 } else {
364 /* Init failed, cleanup */
365 skb_queue_purge(&ndev->cmd_q);
366 skb_queue_purge(&ndev->rx_q);
367 skb_queue_purge(&ndev->tx_q);
368
369 ndev->ops->close(ndev);
370 ndev->flags = 0;
371 }
372
373done:
374 mutex_unlock(&ndev->req_lock);
375 return rc;
376}
377
378static int nci_close_device(struct nci_dev *ndev)
379{
380 nci_req_cancel(ndev, ENODEV);
381 mutex_lock(&ndev->req_lock);
382
383 if (!test_and_clear_bit(NCI_UP, &ndev->flags)) {
384 del_timer_sync(&ndev->cmd_timer);
Ilan Eliasc4bf98b2012-01-17 12:03:50 +0200385 del_timer_sync(&ndev->data_timer);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300386 mutex_unlock(&ndev->req_lock);
387 return 0;
388 }
389
390 /* Drop RX and TX queues */
391 skb_queue_purge(&ndev->rx_q);
392 skb_queue_purge(&ndev->tx_q);
393
394 /* Flush RX and TX wq */
395 flush_workqueue(ndev->rx_wq);
396 flush_workqueue(ndev->tx_wq);
397
398 /* Reset device */
399 skb_queue_purge(&ndev->cmd_q);
400 atomic_set(&ndev->cmd_cnt, 1);
401
402 set_bit(NCI_INIT, &ndev->flags);
403 __nci_request(ndev, nci_reset_req, 0,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100404 msecs_to_jiffies(NCI_RESET_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300405 clear_bit(NCI_INIT, &ndev->flags);
406
Amitkumar Karwarfa9be5f2013-12-23 14:15:13 -0800407 del_timer_sync(&ndev->cmd_timer);
408
Ilan Elias6a2968a2011-09-18 11:19:35 +0300409 /* Flush cmd wq */
410 flush_workqueue(ndev->cmd_wq);
411
412 /* After this point our queues are empty
413 * and no works are scheduled. */
414 ndev->ops->close(ndev);
415
416 /* Clear flags */
417 ndev->flags = 0;
418
419 mutex_unlock(&ndev->req_lock);
420
421 return 0;
422}
423
424/* NCI command timer function */
425static void nci_cmd_timer(unsigned long arg)
426{
427 struct nci_dev *ndev = (void *) arg;
428
Ilan Elias6a2968a2011-09-18 11:19:35 +0300429 atomic_set(&ndev->cmd_cnt, 1);
430 queue_work(ndev->cmd_wq, &ndev->cmd_work);
431}
432
Ilan Eliasc4bf98b2012-01-17 12:03:50 +0200433/* NCI data exchange timer function */
434static void nci_data_timer(unsigned long arg)
435{
436 struct nci_dev *ndev = (void *) arg;
437
438 set_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
439 queue_work(ndev->rx_wq, &ndev->rx_work);
440}
441
Ilan Elias6a2968a2011-09-18 11:19:35 +0300442static int nci_dev_up(struct nfc_dev *nfc_dev)
443{
444 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
445
Ilan Elias6a2968a2011-09-18 11:19:35 +0300446 return nci_open_device(ndev);
447}
448
449static int nci_dev_down(struct nfc_dev *nfc_dev)
450{
451 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
452
Ilan Elias6a2968a2011-09-18 11:19:35 +0300453 return nci_close_device(ndev);
454}
455
Amitkumar Karwar22c15bf2014-01-06 12:58:18 -0800456int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val)
457{
458 struct nci_set_config_param param;
459
460 if (!val || !len)
461 return 0;
462
463 param.id = id;
464 param.len = len;
465 param.val = val;
466
467 return __nci_request(ndev, nci_set_config_req, (unsigned long)&param,
468 msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
469}
470EXPORT_SYMBOL(nci_set_config);
471
Christophe Ricardaf9c8aa2015-02-01 22:26:10 +0100472static void nci_nfcee_discover_req(struct nci_dev *ndev, unsigned long opt)
473{
474 struct nci_nfcee_discover_cmd cmd;
475 __u8 action = opt;
476
477 cmd.discovery_action = action;
478
479 nci_send_cmd(ndev, NCI_OP_NFCEE_DISCOVER_CMD, 1, &cmd);
480}
481
482int nci_nfcee_discover(struct nci_dev *ndev, u8 action)
483{
484 return nci_request(ndev, nci_nfcee_discover_req, action,
485 msecs_to_jiffies(NCI_CMD_TIMEOUT));
486}
487EXPORT_SYMBOL(nci_nfcee_discover);
488
Ilan Elias7e035232012-08-15 11:46:22 +0300489static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)
490{
491 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
492 struct nci_set_config_param param;
Julien Lefrique529ee062014-10-21 16:52:47 +0200493 int rc;
Ilan Elias7e035232012-08-15 11:46:22 +0300494
495 param.val = nfc_get_local_general_bytes(nfc_dev, &param.len);
496 if ((param.val == NULL) || (param.len == 0))
Szymon Jancf9fc36f2012-10-04 15:15:46 +0200497 return 0;
Ilan Elias7e035232012-08-15 11:46:22 +0300498
Szymon Janc460d8f92012-10-04 15:15:45 +0200499 if (param.len > NFC_MAX_GT_LEN)
Ilan Elias7e035232012-08-15 11:46:22 +0300500 return -EINVAL;
501
Ilan Elias7e035232012-08-15 11:46:22 +0300502 param.id = NCI_PN_ATR_REQ_GEN_BYTES;
Ilan Elias7e035232012-08-15 11:46:22 +0300503
Julien Lefrique529ee062014-10-21 16:52:47 +0200504 rc = nci_request(ndev, nci_set_config_req, (unsigned long)&param,
505 msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
506 if (rc)
507 return rc;
508
509 param.id = NCI_LN_ATR_RES_GEN_BYTES;
510
Szymon Jancf9fc36f2012-10-04 15:15:46 +0200511 return nci_request(ndev, nci_set_config_req, (unsigned long)&param,
512 msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
Ilan Elias7e035232012-08-15 11:46:22 +0300513}
514
Julien Lefrique90d78c12014-10-21 16:52:45 +0200515static int nci_set_listen_parameters(struct nfc_dev *nfc_dev)
516{
517 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
518 int rc;
519 __u8 val;
520
521 val = NCI_LA_SEL_INFO_NFC_DEP_MASK;
522
523 rc = nci_set_config(ndev, NCI_LA_SEL_INFO, 1, &val);
524 if (rc)
525 return rc;
526
527 val = NCI_LF_PROTOCOL_TYPE_NFC_DEP_MASK;
528
529 rc = nci_set_config(ndev, NCI_LF_PROTOCOL_TYPE, 1, &val);
530 if (rc)
531 return rc;
532
533 val = NCI_LF_CON_BITR_F_212 | NCI_LF_CON_BITR_F_424;
534
535 return nci_set_config(ndev, NCI_LF_CON_BITR_F, 1, &val);
536}
537
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200538static int nci_start_poll(struct nfc_dev *nfc_dev,
539 __u32 im_protocols, __u32 tm_protocols)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300540{
541 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
Julien Lefrique772dccf2014-10-21 16:52:44 +0200542 struct nci_rf_discover_param param;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300543 int rc;
544
Ilan Elias019c4fb2012-01-18 13:16:14 +0200545 if ((atomic_read(&ndev->state) == NCI_DISCOVERY) ||
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100546 (atomic_read(&ndev->state) == NCI_W4_ALL_DISCOVERIES)) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800547 pr_err("unable to start poll, since poll is already active\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300548 return -EBUSY;
549 }
550
Ilan Eliasde054792011-09-22 11:13:01 +0300551 if (ndev->target_active_prot) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800552 pr_err("there is an active target\n");
Ilan Eliasde054792011-09-22 11:13:01 +0300553 return -EBUSY;
554 }
555
Ilan Elias019c4fb2012-01-18 13:16:14 +0200556 if ((atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) ||
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100557 (atomic_read(&ndev->state) == NCI_POLL_ACTIVE)) {
Ilan Elias019c4fb2012-01-18 13:16:14 +0200558 pr_debug("target active or w4 select, implicitly deactivate\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300559
Christophe Ricard9295b5b2014-12-02 21:27:49 +0100560 rc = nci_request(ndev, nci_rf_deactivate_req,
561 NCI_DEACTIVATE_TYPE_IDLE_MODE,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100562 msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300563 if (rc)
564 return -EBUSY;
565 }
566
Julien Lefrique529ee062014-10-21 16:52:47 +0200567 if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) {
Ilan Elias7e035232012-08-15 11:46:22 +0300568 rc = nci_set_local_general_bytes(nfc_dev);
569 if (rc) {
570 pr_err("failed to set local general bytes\n");
571 return rc;
572 }
573 }
574
Julien Lefrique90d78c12014-10-21 16:52:45 +0200575 if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
576 rc = nci_set_listen_parameters(nfc_dev);
577 if (rc)
578 pr_err("failed to set listen parameters\n");
579 }
580
Julien Lefrique772dccf2014-10-21 16:52:44 +0200581 param.im_protocols = im_protocols;
582 param.tm_protocols = tm_protocols;
583 rc = nci_request(ndev, nci_rf_discover_req, (unsigned long)&param,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100584 msecs_to_jiffies(NCI_RF_DISC_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300585
586 if (!rc)
Samuel Ortizfe7c5802012-05-15 15:57:06 +0200587 ndev->poll_prots = im_protocols;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300588
589 return rc;
590}
591
592static void nci_stop_poll(struct nfc_dev *nfc_dev)
593{
594 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
595
Ilan Elias019c4fb2012-01-18 13:16:14 +0200596 if ((atomic_read(&ndev->state) != NCI_DISCOVERY) &&
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100597 (atomic_read(&ndev->state) != NCI_W4_ALL_DISCOVERIES)) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800598 pr_err("unable to stop poll, since poll is not active\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300599 return;
600 }
601
Christophe Ricard9295b5b2014-12-02 21:27:49 +0100602 nci_request(ndev, nci_rf_deactivate_req, NCI_DEACTIVATE_TYPE_IDLE_MODE,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100603 msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300604}
605
Eric Lapuyade90099432012-05-07 12:31:13 +0200606static int nci_activate_target(struct nfc_dev *nfc_dev,
607 struct nfc_target *target, __u32 protocol)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300608{
609 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
Ilan Elias019c4fb2012-01-18 13:16:14 +0200610 struct nci_rf_discover_select_param param;
Eric Lapuyade90099432012-05-07 12:31:13 +0200611 struct nfc_target *nci_target = NULL;
Ilan Elias019c4fb2012-01-18 13:16:14 +0200612 int i;
613 int rc = 0;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300614
Eric Lapuyade90099432012-05-07 12:31:13 +0200615 pr_debug("target_idx %d, protocol 0x%x\n", target->idx, protocol);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300616
Ilan Elias019c4fb2012-01-18 13:16:14 +0200617 if ((atomic_read(&ndev->state) != NCI_W4_HOST_SELECT) &&
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100618 (atomic_read(&ndev->state) != NCI_POLL_ACTIVE)) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800619 pr_err("there is no available target to activate\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300620 return -EINVAL;
621 }
622
623 if (ndev->target_active_prot) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800624 pr_err("there is already an active target\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300625 return -EBUSY;
626 }
627
Ilan Elias019c4fb2012-01-18 13:16:14 +0200628 for (i = 0; i < ndev->n_targets; i++) {
Eric Lapuyade90099432012-05-07 12:31:13 +0200629 if (ndev->targets[i].idx == target->idx) {
630 nci_target = &ndev->targets[i];
Ilan Elias019c4fb2012-01-18 13:16:14 +0200631 break;
632 }
633 }
634
Eric Lapuyade90099432012-05-07 12:31:13 +0200635 if (!nci_target) {
Ilan Elias019c4fb2012-01-18 13:16:14 +0200636 pr_err("unable to find the selected target\n");
637 return -EINVAL;
638 }
639
Eric Lapuyade90099432012-05-07 12:31:13 +0200640 if (!(nci_target->supported_protocols & (1 << protocol))) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800641 pr_err("target does not support the requested protocol 0x%x\n",
642 protocol);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300643 return -EINVAL;
644 }
645
Ilan Elias019c4fb2012-01-18 13:16:14 +0200646 if (atomic_read(&ndev->state) == NCI_W4_HOST_SELECT) {
Eric Lapuyade90099432012-05-07 12:31:13 +0200647 param.rf_discovery_id = nci_target->logical_idx;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300648
Ilan Elias019c4fb2012-01-18 13:16:14 +0200649 if (protocol == NFC_PROTO_JEWEL)
650 param.rf_protocol = NCI_RF_PROTOCOL_T1T;
651 else if (protocol == NFC_PROTO_MIFARE)
652 param.rf_protocol = NCI_RF_PROTOCOL_T2T;
653 else if (protocol == NFC_PROTO_FELICA)
654 param.rf_protocol = NCI_RF_PROTOCOL_T3T;
Samuel Ortiz01d719a2012-07-04 00:14:04 +0200655 else if (protocol == NFC_PROTO_ISO14443 ||
656 protocol == NFC_PROTO_ISO14443_B)
Ilan Elias019c4fb2012-01-18 13:16:14 +0200657 param.rf_protocol = NCI_RF_PROTOCOL_ISO_DEP;
658 else
659 param.rf_protocol = NCI_RF_PROTOCOL_NFC_DEP;
660
661 rc = nci_request(ndev, nci_rf_discover_select_req,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100662 (unsigned long)&param,
663 msecs_to_jiffies(NCI_RF_DISC_SELECT_TIMEOUT));
Ilan Elias019c4fb2012-01-18 13:16:14 +0200664 }
665
666 if (!rc)
667 ndev->target_active_prot = protocol;
668
669 return rc;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300670}
671
Eric Lapuyade90099432012-05-07 12:31:13 +0200672static void nci_deactivate_target(struct nfc_dev *nfc_dev,
673 struct nfc_target *target)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300674{
675 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
676
Ilan Elias767f19a2012-08-15 11:46:24 +0300677 pr_debug("entry\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300678
679 if (!ndev->target_active_prot) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800680 pr_err("unable to deactivate target, no active target\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300681 return;
682 }
683
684 ndev->target_active_prot = 0;
685
Ilan Elias8939e472012-01-18 13:16:12 +0200686 if (atomic_read(&ndev->state) == NCI_POLL_ACTIVE) {
Christophe Ricard9295b5b2014-12-02 21:27:49 +0100687 nci_request(ndev, nci_rf_deactivate_req,
688 NCI_DEACTIVATE_TYPE_SLEEP_MODE,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100689 msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +0300690 }
691}
692
Ilan Elias767f19a2012-08-15 11:46:24 +0300693static int nci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
694 __u8 comm_mode, __u8 *gb, size_t gb_len)
695{
696 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
697 int rc;
698
699 pr_debug("target_idx %d, comm_mode %d\n", target->idx, comm_mode);
700
701 rc = nci_activate_target(nfc_dev, target, NFC_PROTO_NFC_DEP);
702 if (rc)
703 return rc;
704
705 rc = nfc_set_remote_general_bytes(nfc_dev, ndev->remote_gb,
706 ndev->remote_gb_len);
707 if (!rc)
708 rc = nfc_dep_link_is_up(nfc_dev, target->idx, NFC_COMM_PASSIVE,
709 NFC_RF_INITIATOR);
710
711 return rc;
712}
713
714static int nci_dep_link_down(struct nfc_dev *nfc_dev)
715{
Julien Lefriqued7979e12014-10-21 16:52:53 +0200716 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
717 int rc;
718
Ilan Elias767f19a2012-08-15 11:46:24 +0300719 pr_debug("entry\n");
720
Julien Lefriqued7979e12014-10-21 16:52:53 +0200721 if (nfc_dev->rf_mode == NFC_RF_INITIATOR) {
722 nci_deactivate_target(nfc_dev, NULL);
723 } else {
724 if (atomic_read(&ndev->state) == NCI_LISTEN_ACTIVE ||
725 atomic_read(&ndev->state) == NCI_DISCOVERY) {
726 nci_request(ndev, nci_rf_deactivate_req, 0,
727 msecs_to_jiffies(NCI_RF_DEACTIVATE_TIMEOUT));
728 }
729
730 rc = nfc_tm_deactivated(nfc_dev);
731 if (rc)
732 pr_err("error when signaling tm deactivation\n");
733 }
Ilan Elias767f19a2012-08-15 11:46:24 +0300734
735 return 0;
736}
737
738
Samuel Ortizbe9ae4c2012-05-16 15:55:48 +0200739static int nci_transceive(struct nfc_dev *nfc_dev, struct nfc_target *target,
740 struct sk_buff *skb,
741 data_exchange_cb_t cb, void *cb_context)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300742{
743 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
Ilan Elias38f04c62011-09-22 11:36:19 +0300744 int rc;
Christophe Ricard4aeee6872015-02-01 22:26:08 +0100745 struct nci_conn_info *conn_info;
746
747 conn_info = nci_get_conn_info_by_conn_id(ndev, NCI_STATIC_RF_CONN_ID);
748 if (!conn_info)
749 return -EPROTO;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300750
Eric Lapuyade90099432012-05-07 12:31:13 +0200751 pr_debug("target_idx %d, len %d\n", target->idx, skb->len);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300752
753 if (!ndev->target_active_prot) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -0800754 pr_err("unable to exchange data, no active target\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +0300755 return -EINVAL;
756 }
757
Ilan Elias38f04c62011-09-22 11:36:19 +0300758 if (test_and_set_bit(NCI_DATA_EXCHANGE, &ndev->flags))
759 return -EBUSY;
760
Ilan Elias6a2968a2011-09-18 11:19:35 +0300761 /* store cb and context to be used on receiving data */
Christophe Ricard4aeee6872015-02-01 22:26:08 +0100762 conn_info->data_exchange_cb = cb;
763 conn_info->data_exchange_cb_context = cb_context;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300764
Ilan Eliase8c0dac2011-11-09 12:09:14 +0200765 rc = nci_send_data(ndev, NCI_STATIC_RF_CONN_ID, skb);
Ilan Elias38f04c62011-09-22 11:36:19 +0300766 if (rc)
767 clear_bit(NCI_DATA_EXCHANGE, &ndev->flags);
768
769 return rc;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300770}
771
Julien Lefrique485f4422014-10-21 16:52:48 +0200772static int nci_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
773{
774 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
775 int rc;
776
777 rc = nci_send_data(ndev, NCI_STATIC_RF_CONN_ID, skb);
778 if (rc)
779 pr_err("unable to send data\n");
780
781 return rc;
782}
783
Samuel Ortiz0a946302013-05-10 11:57:06 +0200784static int nci_enable_se(struct nfc_dev *nfc_dev, u32 se_idx)
785{
Christophe Ricard93bca2b2014-11-13 00:30:36 +0100786 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
787
788 if (ndev->ops->enable_se)
789 return ndev->ops->enable_se(ndev, se_idx);
790
Samuel Ortiz0a946302013-05-10 11:57:06 +0200791 return 0;
792}
793
794static int nci_disable_se(struct nfc_dev *nfc_dev, u32 se_idx)
795{
Christophe Ricarde9ef9432014-11-13 00:30:37 +0100796 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
797
798 if (ndev->ops->disable_se)
799 return ndev->ops->disable_se(ndev, se_idx);
800
Samuel Ortiz0a946302013-05-10 11:57:06 +0200801 return 0;
802}
803
804static int nci_discover_se(struct nfc_dev *nfc_dev)
805{
Christophe Ricardba4db552014-11-13 00:30:35 +0100806 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
807
808 if (ndev->ops->discover_se)
809 return ndev->ops->discover_se(ndev);
810
Samuel Ortiz0a946302013-05-10 11:57:06 +0200811 return 0;
812}
813
Christophe Ricarda688bf52014-11-13 00:30:38 +0100814static int nci_se_io(struct nfc_dev *nfc_dev, u32 se_idx,
815 u8 *apdu, size_t apdu_length,
816 se_io_cb_t cb, void *cb_context)
817{
818 struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
819
820 if (ndev->ops->se_io)
821 return ndev->ops->se_io(ndev, se_idx, apdu,
822 apdu_length, cb, cb_context);
823
824 return 0;
825}
826
Ilan Elias6a2968a2011-09-18 11:19:35 +0300827static struct nfc_ops nci_nfc_ops = {
828 .dev_up = nci_dev_up,
829 .dev_down = nci_dev_down,
830 .start_poll = nci_start_poll,
831 .stop_poll = nci_stop_poll,
Ilan Elias767f19a2012-08-15 11:46:24 +0300832 .dep_link_up = nci_dep_link_up,
833 .dep_link_down = nci_dep_link_down,
Ilan Elias6a2968a2011-09-18 11:19:35 +0300834 .activate_target = nci_activate_target,
835 .deactivate_target = nci_deactivate_target,
Samuel Ortizbe9ae4c2012-05-16 15:55:48 +0200836 .im_transceive = nci_transceive,
Julien Lefrique485f4422014-10-21 16:52:48 +0200837 .tm_send = nci_tm_send,
Samuel Ortiz0a946302013-05-10 11:57:06 +0200838 .enable_se = nci_enable_se,
839 .disable_se = nci_disable_se,
840 .discover_se = nci_discover_se,
Christophe Ricarda688bf52014-11-13 00:30:38 +0100841 .se_io = nci_se_io,
Ilan Elias6a2968a2011-09-18 11:19:35 +0300842};
843
844/* ---- Interface to NCI drivers ---- */
845
846/**
847 * nci_allocate_device - allocate a new nci device
848 *
849 * @ops: device operations
850 * @supported_protocols: NFC protocols supported by the device
851 */
852struct nci_dev *nci_allocate_device(struct nci_ops *ops,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100853 __u32 supported_protocols,
854 int tx_headroom, int tx_tailroom)
Ilan Elias6a2968a2011-09-18 11:19:35 +0300855{
Dan Carpenter8ebafde2011-09-23 09:14:35 +0300856 struct nci_dev *ndev;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300857
Joe Perches24bf3302011-11-29 11:37:35 -0800858 pr_debug("supported_protocols 0x%x\n", supported_protocols);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300859
860 if (!ops->open || !ops->close || !ops->send)
Dan Carpenter8ebafde2011-09-23 09:14:35 +0300861 return NULL;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300862
863 if (!supported_protocols)
Dan Carpenter8ebafde2011-09-23 09:14:35 +0300864 return NULL;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300865
866 ndev = kzalloc(sizeof(struct nci_dev), GFP_KERNEL);
867 if (!ndev)
Dan Carpenter8ebafde2011-09-23 09:14:35 +0300868 return NULL;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300869
870 ndev->ops = ops;
871 ndev->tx_headroom = tx_headroom;
872 ndev->tx_tailroom = tx_tailroom;
Axel Lin9bec44b2014-02-13 13:25:48 +0800873 init_completion(&ndev->req_completion);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300874
875 ndev->nfc_dev = nfc_allocate_device(&nci_nfc_ops,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100876 supported_protocols,
877 tx_headroom + NCI_DATA_HDR_SIZE,
878 tx_tailroom);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300879 if (!ndev->nfc_dev)
880 goto free_exit;
881
882 nfc_set_drvdata(ndev->nfc_dev, ndev);
883
Dan Carpenter8ebafde2011-09-23 09:14:35 +0300884 return ndev;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300885
886free_exit:
887 kfree(ndev);
Dan Carpenter8ebafde2011-09-23 09:14:35 +0300888 return NULL;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300889}
890EXPORT_SYMBOL(nci_allocate_device);
891
892/**
893 * nci_free_device - deallocate nci device
894 *
895 * @ndev: The nci device to deallocate
896 */
897void nci_free_device(struct nci_dev *ndev)
898{
Ilan Elias6a2968a2011-09-18 11:19:35 +0300899 nfc_free_device(ndev->nfc_dev);
900 kfree(ndev);
901}
902EXPORT_SYMBOL(nci_free_device);
903
904/**
905 * nci_register_device - register a nci device in the nfc subsystem
906 *
907 * @dev: The nci device to register
908 */
909int nci_register_device(struct nci_dev *ndev)
910{
911 int rc;
912 struct device *dev = &ndev->nfc_dev->dev;
913 char name[32];
914
Ilan Elias6a2968a2011-09-18 11:19:35 +0300915 ndev->flags = 0;
916
917 INIT_WORK(&ndev->cmd_work, nci_cmd_work);
918 snprintf(name, sizeof(name), "%s_nci_cmd_wq", dev_name(dev));
919 ndev->cmd_wq = create_singlethread_workqueue(name);
920 if (!ndev->cmd_wq) {
921 rc = -ENOMEM;
Vincent Cuissard3c1c0f52014-07-22 19:48:39 +0200922 goto exit;
Ilan Elias6a2968a2011-09-18 11:19:35 +0300923 }
924
925 INIT_WORK(&ndev->rx_work, nci_rx_work);
926 snprintf(name, sizeof(name), "%s_nci_rx_wq", dev_name(dev));
927 ndev->rx_wq = create_singlethread_workqueue(name);
928 if (!ndev->rx_wq) {
929 rc = -ENOMEM;
930 goto destroy_cmd_wq_exit;
931 }
932
933 INIT_WORK(&ndev->tx_work, nci_tx_work);
934 snprintf(name, sizeof(name), "%s_nci_tx_wq", dev_name(dev));
935 ndev->tx_wq = create_singlethread_workqueue(name);
936 if (!ndev->tx_wq) {
937 rc = -ENOMEM;
938 goto destroy_rx_wq_exit;
939 }
940
941 skb_queue_head_init(&ndev->cmd_q);
942 skb_queue_head_init(&ndev->rx_q);
943 skb_queue_head_init(&ndev->tx_q);
944
945 setup_timer(&ndev->cmd_timer, nci_cmd_timer,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100946 (unsigned long) ndev);
Ilan Eliasc4bf98b2012-01-17 12:03:50 +0200947 setup_timer(&ndev->data_timer, nci_data_timer,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +0100948 (unsigned long) ndev);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300949
950 mutex_init(&ndev->req_lock);
Christophe Ricard4aeee6872015-02-01 22:26:08 +0100951 INIT_LIST_HEAD(&ndev->conn_info_list);
Ilan Elias6a2968a2011-09-18 11:19:35 +0300952
Vincent Cuissard3c1c0f52014-07-22 19:48:39 +0200953 rc = nfc_register_device(ndev->nfc_dev);
954 if (rc)
955 goto destroy_rx_wq_exit;
956
Ilan Elias6a2968a2011-09-18 11:19:35 +0300957 goto exit;
958
959destroy_rx_wq_exit:
960 destroy_workqueue(ndev->rx_wq);
961
962destroy_cmd_wq_exit:
963 destroy_workqueue(ndev->cmd_wq);
964
Ilan Elias6a2968a2011-09-18 11:19:35 +0300965exit:
966 return rc;
967}
968EXPORT_SYMBOL(nci_register_device);
969
970/**
971 * nci_unregister_device - unregister a nci device in the nfc subsystem
972 *
973 * @dev: The nci device to unregister
974 */
975void nci_unregister_device(struct nci_dev *ndev)
976{
Christophe Ricard4aeee6872015-02-01 22:26:08 +0100977 struct nci_conn_info *conn_info, *n;
978
Ilan Elias6a2968a2011-09-18 11:19:35 +0300979 nci_close_device(ndev);
980
981 destroy_workqueue(ndev->cmd_wq);
982 destroy_workqueue(ndev->rx_wq);
983 destroy_workqueue(ndev->tx_wq);
984
Christophe Ricard4aeee6872015-02-01 22:26:08 +0100985 list_for_each_entry_safe(conn_info, n, &ndev->conn_info_list, list) {
986 list_del(&conn_info->list);
987 /* conn_info is allocated with devm_kzalloc */
988 }
989
Ilan Elias6a2968a2011-09-18 11:19:35 +0300990 nfc_unregister_device(ndev->nfc_dev);
991}
992EXPORT_SYMBOL(nci_unregister_device);
993
994/**
995 * nci_recv_frame - receive frame from NCI drivers
996 *
Frederic Danis1095e692013-05-22 11:36:17 +0200997 * @ndev: The nci device
Ilan Elias6a2968a2011-09-18 11:19:35 +0300998 * @skb: The sk_buff to receive
999 */
Frederic Danis1095e692013-05-22 11:36:17 +02001000int nci_recv_frame(struct nci_dev *ndev, struct sk_buff *skb)
Ilan Elias6a2968a2011-09-18 11:19:35 +03001001{
Joe Perches24bf3302011-11-29 11:37:35 -08001002 pr_debug("len %d\n", skb->len);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001003
Szymon Janc874934f2012-10-04 15:15:51 +02001004 if (!ndev || (!test_bit(NCI_UP, &ndev->flags) &&
1005 !test_bit(NCI_INIT, &ndev->flags))) {
Ilan Elias6a2968a2011-09-18 11:19:35 +03001006 kfree_skb(skb);
1007 return -ENXIO;
1008 }
1009
1010 /* Queue frame for rx worker thread */
1011 skb_queue_tail(&ndev->rx_q, skb);
1012 queue_work(ndev->rx_wq, &ndev->rx_work);
1013
1014 return 0;
1015}
1016EXPORT_SYMBOL(nci_recv_frame);
1017
Frederic Danis1095e692013-05-22 11:36:17 +02001018static int nci_send_frame(struct nci_dev *ndev, struct sk_buff *skb)
Ilan Elias6a2968a2011-09-18 11:19:35 +03001019{
Joe Perches24bf3302011-11-29 11:37:35 -08001020 pr_debug("len %d\n", skb->len);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001021
1022 if (!ndev) {
1023 kfree_skb(skb);
1024 return -ENODEV;
1025 }
1026
1027 /* Get rid of skb owner, prior to sending to the driver. */
1028 skb_orphan(skb);
1029
Hiren Tandel05158292014-05-05 19:52:27 +09001030 /* Send copy to sniffer */
1031 nfc_send_to_raw_sock(ndev->nfc_dev, skb,
1032 RAW_PAYLOAD_NCI, NFC_DIRECTION_TX);
1033
Frederic Danis1095e692013-05-22 11:36:17 +02001034 return ndev->ops->send(ndev, skb);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001035}
1036
1037/* Send NCI command */
1038int nci_send_cmd(struct nci_dev *ndev, __u16 opcode, __u8 plen, void *payload)
1039{
1040 struct nci_ctrl_hdr *hdr;
1041 struct sk_buff *skb;
1042
Joe Perches24bf3302011-11-29 11:37:35 -08001043 pr_debug("opcode 0x%x, plen %d\n", opcode, plen);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001044
1045 skb = nci_skb_alloc(ndev, (NCI_CTRL_HDR_SIZE + plen), GFP_KERNEL);
1046 if (!skb) {
Joe Perchesed1e0ad2011-11-29 11:37:32 -08001047 pr_err("no memory for command\n");
Ilan Elias6a2968a2011-09-18 11:19:35 +03001048 return -ENOMEM;
1049 }
1050
1051 hdr = (struct nci_ctrl_hdr *) skb_put(skb, NCI_CTRL_HDR_SIZE);
1052 hdr->gid = nci_opcode_gid(opcode);
1053 hdr->oid = nci_opcode_oid(opcode);
1054 hdr->plen = plen;
1055
1056 nci_mt_set((__u8 *)hdr, NCI_MT_CMD_PKT);
1057 nci_pbf_set((__u8 *)hdr, NCI_PBF_LAST);
1058
1059 if (plen)
1060 memcpy(skb_put(skb, plen), payload, plen);
1061
Ilan Elias6a2968a2011-09-18 11:19:35 +03001062 skb_queue_tail(&ndev->cmd_q, skb);
1063 queue_work(ndev->cmd_wq, &ndev->cmd_work);
1064
1065 return 0;
1066}
1067
1068/* ---- NCI TX Data worker thread ---- */
1069
1070static void nci_tx_work(struct work_struct *work)
1071{
1072 struct nci_dev *ndev = container_of(work, struct nci_dev, tx_work);
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001073 struct nci_conn_info *conn_info;
Ilan Elias6a2968a2011-09-18 11:19:35 +03001074 struct sk_buff *skb;
1075
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001076 conn_info = nci_get_conn_info_by_conn_id(ndev, ndev->cur_conn_id);
1077 if (!conn_info)
1078 return;
1079
1080 pr_debug("credits_cnt %d\n", atomic_read(&conn_info->credits_cnt));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001081
1082 /* Send queued tx data */
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001083 while (atomic_read(&conn_info->credits_cnt)) {
Ilan Elias6a2968a2011-09-18 11:19:35 +03001084 skb = skb_dequeue(&ndev->tx_q);
1085 if (!skb)
1086 return;
1087
Ilan Eliasdb98c822011-11-09 12:09:16 +02001088 /* Check if data flow control is used */
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001089 if (atomic_read(&conn_info->credits_cnt) !=
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +01001090 NCI_DATA_FLOW_CONTROL_NOT_USED)
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001091 atomic_dec(&conn_info->credits_cnt);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001092
Joe Perches20c239c2011-11-29 11:37:33 -08001093 pr_debug("NCI TX: MT=data, PBF=%d, conn_id=%d, plen=%d\n",
1094 nci_pbf(skb->data),
1095 nci_conn_id(skb->data),
1096 nci_plen(skb->data));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001097
Frederic Danis1095e692013-05-22 11:36:17 +02001098 nci_send_frame(ndev, skb);
Ilan Eliasc4bf98b2012-01-17 12:03:50 +02001099
1100 mod_timer(&ndev->data_timer,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +01001101 jiffies + msecs_to_jiffies(NCI_DATA_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001102 }
1103}
1104
1105/* ----- NCI RX worker thread (data & control) ----- */
1106
1107static void nci_rx_work(struct work_struct *work)
1108{
1109 struct nci_dev *ndev = container_of(work, struct nci_dev, rx_work);
1110 struct sk_buff *skb;
1111
1112 while ((skb = skb_dequeue(&ndev->rx_q))) {
Hiren Tandel05158292014-05-05 19:52:27 +09001113
1114 /* Send copy to sniffer */
1115 nfc_send_to_raw_sock(ndev->nfc_dev, skb,
1116 RAW_PAYLOAD_NCI, NFC_DIRECTION_RX);
1117
Ilan Elias6a2968a2011-09-18 11:19:35 +03001118 /* Process frame */
1119 switch (nci_mt(skb->data)) {
1120 case NCI_MT_RSP_PKT:
1121 nci_rsp_packet(ndev, skb);
1122 break;
1123
1124 case NCI_MT_NTF_PKT:
1125 nci_ntf_packet(ndev, skb);
1126 break;
1127
1128 case NCI_MT_DATA_PKT:
1129 nci_rx_data_packet(ndev, skb);
1130 break;
1131
1132 default:
Joe Perchesed1e0ad2011-11-29 11:37:32 -08001133 pr_err("unknown MT 0x%x\n", nci_mt(skb->data));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001134 kfree_skb(skb);
1135 break;
1136 }
1137 }
Ilan Eliasc4bf98b2012-01-17 12:03:50 +02001138
1139 /* check if a data exchange timout has occurred */
1140 if (test_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags)) {
1141 /* complete the data exchange transaction, if exists */
1142 if (test_bit(NCI_DATA_EXCHANGE, &ndev->flags))
Christophe Ricard4aeee6872015-02-01 22:26:08 +01001143 nci_data_exchange_complete(ndev, NULL,
1144 ndev->cur_conn_id,
1145 -ETIMEDOUT);
Ilan Eliasc4bf98b2012-01-17 12:03:50 +02001146
1147 clear_bit(NCI_DATA_EXCHANGE_TO, &ndev->flags);
1148 }
Ilan Elias6a2968a2011-09-18 11:19:35 +03001149}
1150
1151/* ----- NCI TX CMD worker thread ----- */
1152
1153static void nci_cmd_work(struct work_struct *work)
1154{
1155 struct nci_dev *ndev = container_of(work, struct nci_dev, cmd_work);
1156 struct sk_buff *skb;
1157
Joe Perches24bf3302011-11-29 11:37:35 -08001158 pr_debug("cmd_cnt %d\n", atomic_read(&ndev->cmd_cnt));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001159
1160 /* Send queued command */
1161 if (atomic_read(&ndev->cmd_cnt)) {
1162 skb = skb_dequeue(&ndev->cmd_q);
1163 if (!skb)
1164 return;
1165
1166 atomic_dec(&ndev->cmd_cnt);
1167
Joe Perches20c239c2011-11-29 11:37:33 -08001168 pr_debug("NCI TX: MT=cmd, PBF=%d, GID=0x%x, OID=0x%x, plen=%d\n",
1169 nci_pbf(skb->data),
1170 nci_opcode_gid(nci_opcode(skb->data)),
1171 nci_opcode_oid(nci_opcode(skb->data)),
1172 nci_plen(skb->data));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001173
Frederic Danis1095e692013-05-22 11:36:17 +02001174 nci_send_frame(ndev, skb);
Ilan Elias6a2968a2011-09-18 11:19:35 +03001175
1176 mod_timer(&ndev->cmd_timer,
Samuel Ortizeb9bc6e2012-03-05 01:03:54 +01001177 jiffies + msecs_to_jiffies(NCI_CMD_TIMEOUT));
Ilan Elias6a2968a2011-09-18 11:19:35 +03001178 }
1179}
Dave Jones8a70e7f2012-07-12 19:17:34 +02001180
1181MODULE_LICENSE("GPL");