aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorThierry Escande <thierry.escande@linux.intel.com>2013-06-06 10:23:23 -0400
committerSamuel Ortiz <sameo@linux.intel.com>2013-06-14 07:45:06 -0400
commit7cbe0ff3e475b7268ad9b55057048b2299fd60e0 (patch)
treead3616b39db5418225be61ce7110795367cef860
parentf1b79dc8915ebf176d6f1fcfc4fee001b6d5ca46 (diff)
NFC: Add a nfc hardware simulation driver
This driver declares two virtual NFC devices supporting NFC-DEP protocol. An LLCP connection can be established between them and all packets sent from one device is sent back to the other, acting as loopback devices. Once established, the LLCP link can be disconnected by disabling the target device (with rfkill, nfctool, or neard disable-adapter test script). Signed-off-by: Thierry Escande <thierry.escande@linux.intel.com> Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
-rw-r--r--drivers/nfc/Kconfig10
-rw-r--r--drivers/nfc/Makefile1
-rw-r--r--drivers/nfc/nfcsim.c541
3 files changed, 552 insertions, 0 deletions
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 74a852e4e41f..b0b64ccb7d7d 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -36,6 +36,16 @@ config NFC_MEI_PHY
36 36
37 If unsure, say N. 37 If unsure, say N.
38 38
39config NFC_SIM
40 tristate "NFC hardware simulator driver"
41 help
42 This driver declares two virtual NFC devices supporting NFC-DEP
43 protocol. An LLCP connection can be established between them and
44 all packets sent from one device is sent back to the other, acting as
45 loopback devices.
46
47 If unsure, say N.
48
39source "drivers/nfc/pn544/Kconfig" 49source "drivers/nfc/pn544/Kconfig"
40source "drivers/nfc/microread/Kconfig" 50source "drivers/nfc/microread/Kconfig"
41 51
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index aa6bd657ef40..be7636abcb3f 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -7,5 +7,6 @@ obj-$(CONFIG_NFC_MICROREAD) += microread/
7obj-$(CONFIG_NFC_PN533) += pn533.o 7obj-$(CONFIG_NFC_PN533) += pn533.o
8obj-$(CONFIG_NFC_WILINK) += nfcwilink.o 8obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
9obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o 9obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o
10obj-$(CONFIG_NFC_SIM) += nfcsim.o
10 11
11ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG 12ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/nfcsim.c b/drivers/nfc/nfcsim.c
new file mode 100644
index 000000000000..c5c30fb1d7bf
--- /dev/null
+++ b/drivers/nfc/nfcsim.c
@@ -0,0 +1,541 @@
1/*
2 * NFC hardware simulation driver
3 * Copyright (c) 2013, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#include <linux/device.h>
17#include <linux/kernel.h>
18#include <linux/module.h>
19#include <linux/nfc.h>
20#include <net/nfc/nfc.h>
21
22#define DEV_ERR(_dev, fmt, args...) nfc_dev_err(&_dev->nfc_dev->dev, \
23 "%s: " fmt, __func__, ## args)
24
25#define DEV_DBG(_dev, fmt, args...) nfc_dev_dbg(&_dev->nfc_dev->dev, \
26 "%s: " fmt, __func__, ## args)
27
28#define NFCSIM_VERSION "0.1"
29
30#define NFCSIM_POLL_NONE 0
31#define NFCSIM_POLL_INITIATOR 1
32#define NFCSIM_POLL_TARGET 2
33#define NFCSIM_POLL_DUAL (NFCSIM_POLL_INITIATOR | NFCSIM_POLL_TARGET)
34
35struct nfcsim {
36 struct nfc_dev *nfc_dev;
37
38 struct mutex lock;
39
40 struct delayed_work recv_work;
41
42 struct sk_buff *clone_skb;
43
44 struct delayed_work poll_work;
45 u8 polling_mode;
46 u8 curr_polling_mode;
47
48 u8 shutting_down;
49
50 u8 up;
51
52 u8 initiator;
53
54 data_exchange_cb_t cb;
55 void *cb_context;
56
57 struct nfcsim *peer_dev;
58};
59
60static struct nfcsim *dev0;
61static struct nfcsim *dev1;
62
63struct workqueue_struct *wq;
64
65static void nfcsim_cleanup_dev(struct nfcsim *dev, u8 shutdown)
66{
67 DEV_DBG(dev, "shutdown=%d", shutdown);
68
69 mutex_lock(&dev->lock);
70
71 dev->polling_mode = NFCSIM_POLL_NONE;
72 dev->shutting_down = shutdown;
73 dev->cb = NULL;
74 dev_kfree_skb(dev->clone_skb);
75 dev->clone_skb = NULL;
76
77 mutex_unlock(&dev->lock);
78
79 cancel_delayed_work_sync(&dev->poll_work);
80 cancel_delayed_work_sync(&dev->recv_work);
81}
82
83static int nfcsim_target_found(struct nfcsim *dev)
84{
85 struct nfc_target nfc_tgt;
86
87 DEV_DBG(dev, "");
88
89 memset(&nfc_tgt, 0, sizeof(struct nfc_target));
90
91 nfc_tgt.supported_protocols = NFC_PROTO_NFC_DEP_MASK;
92 nfc_targets_found(dev->nfc_dev, &nfc_tgt, 1);
93
94 return 0;
95}
96
97static int nfcsim_dev_up(struct nfc_dev *nfc_dev)
98{
99 struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
100
101 DEV_DBG(dev, "");
102
103 mutex_lock(&dev->lock);
104
105 dev->up = 1;
106
107 mutex_unlock(&dev->lock);
108
109 return 0;
110}
111
112static int nfcsim_dev_down(struct nfc_dev *nfc_dev)
113{
114 struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
115
116 DEV_DBG(dev, "");
117
118 mutex_lock(&dev->lock);
119
120 dev->up = 0;
121
122 mutex_unlock(&dev->lock);
123
124 return 0;
125}
126
127static int nfcsim_dep_link_up(struct nfc_dev *nfc_dev,
128 struct nfc_target *target,
129 u8 comm_mode, u8 *gb, size_t gb_len)
130{
131 int rc;
132 struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
133 struct nfcsim *peer = dev->peer_dev;
134 u8 *remote_gb;
135 size_t remote_gb_len;
136
137 DEV_DBG(dev, "target_idx: %d, comm_mode: %d\n", target->idx, comm_mode);
138
139 mutex_lock(&peer->lock);
140
141 nfc_tm_activated(peer->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
142 NFC_COMM_ACTIVE, gb, gb_len);
143
144 remote_gb = nfc_get_local_general_bytes(peer->nfc_dev, &remote_gb_len);
145 if (!remote_gb) {
146 DEV_ERR(peer, "Can't get remote general bytes");
147
148 mutex_unlock(&peer->lock);
149 return -EINVAL;
150 }
151
152 mutex_unlock(&peer->lock);
153
154 mutex_lock(&dev->lock);
155
156 rc = nfc_set_remote_general_bytes(nfc_dev, remote_gb, remote_gb_len);
157 if (rc) {
158 DEV_ERR(dev, "Can't set remote general bytes");
159 mutex_unlock(&dev->lock);
160 return rc;
161 }
162
163 rc = nfc_dep_link_is_up(nfc_dev, target->idx, NFC_COMM_ACTIVE,
164 NFC_RF_INITIATOR);
165
166 mutex_unlock(&dev->lock);
167
168 return rc;
169}
170
171static int nfcsim_dep_link_down(struct nfc_dev *nfc_dev)
172{
173 struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
174
175 DEV_DBG(dev, "");
176
177 nfcsim_cleanup_dev(dev, 0);
178
179 return 0;
180}
181
182static int nfcsim_start_poll(struct nfc_dev *nfc_dev,
183 u32 im_protocols, u32 tm_protocols)
184{
185 struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
186 int rc;
187
188 mutex_lock(&dev->lock);
189
190 if (dev->polling_mode != NFCSIM_POLL_NONE) {
191 DEV_ERR(dev, "Already in polling mode");
192 rc = -EBUSY;
193 goto exit;
194 }
195
196 if (im_protocols & NFC_PROTO_NFC_DEP_MASK)
197 dev->polling_mode |= NFCSIM_POLL_INITIATOR;
198
199 if (tm_protocols & NFC_PROTO_NFC_DEP_MASK)
200 dev->polling_mode |= NFCSIM_POLL_TARGET;
201
202 if (dev->polling_mode == NFCSIM_POLL_NONE) {
203 DEV_ERR(dev, "Unsupported polling mode");
204 rc = -EINVAL;
205 goto exit;
206 }
207
208 dev->initiator = 0;
209 dev->curr_polling_mode = NFCSIM_POLL_NONE;
210
211 queue_delayed_work(wq, &dev->poll_work, 0);
212
213 DEV_DBG(dev, "Start polling: im: 0x%X, tm: 0x%X", im_protocols,
214 tm_protocols);
215
216 rc = 0;
217exit:
218 mutex_unlock(&dev->lock);
219
220 return rc;
221}
222
223static void nfcsim_stop_poll(struct nfc_dev *nfc_dev)
224{
225 struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
226
227 DEV_DBG(dev, "Stop poll");
228
229 mutex_lock(&dev->lock);
230
231 dev->polling_mode = NFCSIM_POLL_NONE;
232
233 mutex_unlock(&dev->lock);
234
235 cancel_delayed_work_sync(&dev->poll_work);
236}
237
238static int nfcsim_activate_target(struct nfc_dev *nfc_dev,
239 struct nfc_target *target, u32 protocol)
240{
241 struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
242
243 DEV_DBG(dev, "");
244
245 return -ENOTSUPP;
246}
247
248static void nfcsim_deactivate_target(struct nfc_dev *nfc_dev,
249 struct nfc_target *target)
250{
251 struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
252
253 DEV_DBG(dev, "");
254}
255
256static void nfcsim_wq_recv(struct work_struct *work)
257{
258 struct nfcsim *dev = container_of(work, struct nfcsim,
259 recv_work.work);
260
261 mutex_lock(&dev->lock);
262
263 if (dev->shutting_down || !dev->up || !dev->clone_skb) {
264 dev_kfree_skb(dev->clone_skb);
265 goto exit;
266 }
267
268 if (dev->initiator) {
269 if (!dev->cb) {
270 DEV_ERR(dev, "Null recv callback");
271 dev_kfree_skb(dev->clone_skb);
272 goto exit;
273 }
274
275 dev->cb(dev->cb_context, dev->clone_skb, 0);
276 dev->cb = NULL;
277 } else {
278 nfc_tm_data_received(dev->nfc_dev, dev->clone_skb);
279 }
280
281exit:
282 dev->clone_skb = NULL;
283
284 mutex_unlock(&dev->lock);
285}
286
287static int nfcsim_tx(struct nfc_dev *nfc_dev, struct nfc_target *target,
288 struct sk_buff *skb, data_exchange_cb_t cb,
289 void *cb_context)
290{
291 struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
292 struct nfcsim *peer = dev->peer_dev;
293 int err;
294
295 mutex_lock(&dev->lock);
296
297 if (dev->shutting_down || !dev->up) {
298 mutex_unlock(&dev->lock);
299 err = -ENODEV;
300 goto exit;
301 }
302
303 dev->cb = cb;
304 dev->cb_context = cb_context;
305
306 mutex_unlock(&dev->lock);
307
308 mutex_lock(&peer->lock);
309
310 peer->clone_skb = skb_clone(skb, GFP_KERNEL);
311
312 if (!peer->clone_skb) {
313 DEV_ERR(dev, "skb_clone failed");
314 mutex_unlock(&peer->lock);
315 err = -ENOMEM;
316 goto exit;
317 }
318
319 /* This simulates an arbitrary transmission delay between the 2 devices.
320 * If packet transmission occurs immediately between them, we have a
321 * non-stop flow of several tens of thousands SYMM packets per second
322 * and a burning cpu.
323 *
324 * TODO: Add support for a sysfs entry to control this delay.
325 */
326 queue_delayed_work(wq, &peer->recv_work, msecs_to_jiffies(5));
327
328 mutex_unlock(&peer->lock);
329
330 err = 0;
331exit:
332 dev_kfree_skb(skb);
333
334 return err;
335}
336
337static int nfcsim_im_transceive(struct nfc_dev *nfc_dev,
338 struct nfc_target *target, struct sk_buff *skb,
339 data_exchange_cb_t cb, void *cb_context)
340{
341 return nfcsim_tx(nfc_dev, target, skb, cb, cb_context);
342}
343
344static int nfcsim_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
345{
346 return nfcsim_tx(nfc_dev, NULL, skb, NULL, NULL);
347}
348
349static struct nfc_ops nfcsim_nfc_ops = {
350 .dev_up = nfcsim_dev_up,
351 .dev_down = nfcsim_dev_down,
352 .dep_link_up = nfcsim_dep_link_up,
353 .dep_link_down = nfcsim_dep_link_down,
354 .start_poll = nfcsim_start_poll,
355 .stop_poll = nfcsim_stop_poll,
356 .activate_target = nfcsim_activate_target,
357 .deactivate_target = nfcsim_deactivate_target,
358 .im_transceive = nfcsim_im_transceive,
359 .tm_send = nfcsim_tm_send,
360};
361
362static void nfcsim_set_polling_mode(struct nfcsim *dev)
363{
364 if (dev->polling_mode == NFCSIM_POLL_NONE) {
365 dev->curr_polling_mode = NFCSIM_POLL_NONE;
366 return;
367 }
368
369 if (dev->curr_polling_mode == NFCSIM_POLL_NONE) {
370 if (dev->polling_mode & NFCSIM_POLL_INITIATOR)
371 dev->curr_polling_mode = NFCSIM_POLL_INITIATOR;
372 else
373 dev->curr_polling_mode = NFCSIM_POLL_TARGET;
374
375 return;
376 }
377
378 if (dev->polling_mode == NFCSIM_POLL_DUAL) {
379 if (dev->curr_polling_mode == NFCSIM_POLL_TARGET)
380 dev->curr_polling_mode = NFCSIM_POLL_INITIATOR;
381 else
382 dev->curr_polling_mode = NFCSIM_POLL_TARGET;
383 }
384}
385
386static void nfcsim_wq_poll(struct work_struct *work)
387{
388 struct nfcsim *dev = container_of(work, struct nfcsim, poll_work.work);
389 struct nfcsim *peer = dev->peer_dev;
390
391 /* These work items run on an ordered workqueue and are therefore
392 * serialized. So we can take both mutexes without being dead locked.
393 */
394 mutex_lock(&dev->lock);
395 mutex_lock(&peer->lock);
396
397 nfcsim_set_polling_mode(dev);
398
399 if (dev->curr_polling_mode == NFCSIM_POLL_NONE) {
400 DEV_DBG(dev, "Not polling");
401 goto unlock;
402 }
403
404 DEV_DBG(dev, "Polling as %s",
405 dev->curr_polling_mode == NFCSIM_POLL_INITIATOR ?
406 "initiator" : "target");
407
408 if (dev->curr_polling_mode == NFCSIM_POLL_TARGET)
409 goto sched_work;
410
411 if (peer->curr_polling_mode == NFCSIM_POLL_TARGET) {
412 peer->polling_mode = NFCSIM_POLL_NONE;
413 dev->polling_mode = NFCSIM_POLL_NONE;
414
415 dev->initiator = 1;
416
417 nfcsim_target_found(dev);
418
419 goto unlock;
420 }
421
422sched_work:
423 /* This defines the delay for an initiator to check if the other device
424 * is polling in target mode.
425 * If the device starts in dual mode polling, it switches between
426 * initiator and target at every round.
427 * Because the wq is ordered and only 1 work item is executed at a time,
428 * we'll always have one device polling as initiator and the other as
429 * target at some point, even if both are started in dual mode.
430 */
431 queue_delayed_work(wq, &dev->poll_work, msecs_to_jiffies(200));
432
433unlock:
434 mutex_unlock(&peer->lock);
435 mutex_unlock(&dev->lock);
436}
437
438static struct nfcsim *nfcsim_init_dev(void)
439{
440 struct nfcsim *dev;
441 int rc = -ENOMEM;
442
443 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
444 if (dev == NULL)
445 return ERR_PTR(-ENOMEM);
446
447 mutex_init(&dev->lock);
448
449 INIT_DELAYED_WORK(&dev->recv_work, nfcsim_wq_recv);
450 INIT_DELAYED_WORK(&dev->poll_work, nfcsim_wq_poll);
451
452 dev->nfc_dev = nfc_allocate_device(&nfcsim_nfc_ops,
453 NFC_PROTO_NFC_DEP_MASK,
454 0, 0);
455 if (!dev->nfc_dev)
456 goto error;
457
458 nfc_set_drvdata(dev->nfc_dev, dev);
459
460 rc = nfc_register_device(dev->nfc_dev);
461 if (rc)
462 goto free_nfc_dev;
463
464 return dev;
465
466free_nfc_dev:
467 nfc_free_device(dev->nfc_dev);
468
469error:
470 kfree(dev);
471
472 return ERR_PTR(rc);
473}
474
475static void nfcsim_free_device(struct nfcsim *dev)
476{
477 nfc_unregister_device(dev->nfc_dev);
478
479 nfc_free_device(dev->nfc_dev);
480
481 kfree(dev);
482}
483
484int __init nfcsim_init(void)
485{
486 int rc;
487
488 /* We need an ordered wq to ensure that poll_work items are executed
489 * one at a time.
490 */
491 wq = alloc_ordered_workqueue("nfcsim", 0);
492 if (!wq) {
493 rc = -ENOMEM;
494 goto exit;
495 }
496
497 dev0 = nfcsim_init_dev();
498 if (IS_ERR(dev0)) {
499 rc = PTR_ERR(dev0);
500 goto exit;
501 }
502
503 dev1 = nfcsim_init_dev();
504 if (IS_ERR(dev1)) {
505 kfree(dev0);
506
507 rc = PTR_ERR(dev1);
508 goto exit;
509 }
510
511 dev0->peer_dev = dev1;
512 dev1->peer_dev = dev0;
513
514 pr_debug("NFCsim " NFCSIM_VERSION " initialized\n");
515
516 rc = 0;
517exit:
518 if (rc)
519 pr_err("Failed to initialize nfcsim driver (%d)\n",
520 rc);
521
522 return rc;
523}
524
525void __exit nfcsim_exit(void)
526{
527 nfcsim_cleanup_dev(dev0, 1);
528 nfcsim_cleanup_dev(dev1, 1);
529
530 nfcsim_free_device(dev0);
531 nfcsim_free_device(dev1);
532
533 destroy_workqueue(wq);
534}
535
536module_init(nfcsim_init);
537module_exit(nfcsim_exit);
538
539MODULE_DESCRIPTION("NFCSim driver ver " NFCSIM_VERSION);
540MODULE_VERSION(NFCSIM_VERSION);
541MODULE_LICENSE("GPL");