blob: 40b4846509f419be81a5fe01a8785729d08f9f67 [file] [log] [blame]
Thierry Escande7cbe0ff2013-06-06 16:23:23 +02001/*
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>
Thierry Escande204bddc2016-06-23 11:20:26 +020021#include <net/nfc/digital.h>
Thierry Escande7cbe0ff2013-06-06 16:23:23 +020022
Thierry Escande204bddc2016-06-23 11:20:26 +020023#define NFCSIM_ERR(d, fmt, args...) nfc_err(&d->nfc_digital_dev->nfc_dev->dev, \
24 "%s: " fmt, __func__, ## args)
Thierry Escande7cbe0ff2013-06-06 16:23:23 +020025
Thierry Escande204bddc2016-06-23 11:20:26 +020026#define NFCSIM_DBG(d, fmt, args...) dev_dbg(&d->nfc_digital_dev->nfc_dev->dev, \
27 "%s: " fmt, __func__, ## args)
Thierry Escande7cbe0ff2013-06-06 16:23:23 +020028
Thierry Escande204bddc2016-06-23 11:20:26 +020029#define NFCSIM_VERSION "0.2"
Thierry Escande7cbe0ff2013-06-06 16:23:23 +020030
Thierry Escande204bddc2016-06-23 11:20:26 +020031#define NFCSIM_MODE_NONE 0
32#define NFCSIM_MODE_INITIATOR 1
33#define NFCSIM_MODE_TARGET 2
Thierry Escande7cbe0ff2013-06-06 16:23:23 +020034
Thierry Escande204bddc2016-06-23 11:20:26 +020035#define NFCSIM_CAPABILITIES (NFC_DIGITAL_DRV_CAPS_IN_CRC | \
36 NFC_DIGITAL_DRV_CAPS_TG_CRC)
Saurabh Sengara440f1a2015-12-21 00:29:30 +053037
Thierry Escande7cbe0ff2013-06-06 16:23:23 +020038struct nfcsim {
Thierry Escande204bddc2016-06-23 11:20:26 +020039 struct nfc_digital_dev *nfc_digital_dev;
Thierry Escande7cbe0ff2013-06-06 16:23:23 +020040
Thierry Escande204bddc2016-06-23 11:20:26 +020041 struct work_struct recv_work;
42 struct delayed_work send_work;
43
44 struct nfcsim_link *link_in;
45 struct nfcsim_link *link_out;
46
47 bool up;
48 u8 mode;
49 u8 rf_tech;
50
51 u16 recv_timeout;
52
53 nfc_digital_cmd_complete_t cb;
54 void *arg;
55};
56
57struct nfcsim_link {
Thierry Escande7cbe0ff2013-06-06 16:23:23 +020058 struct mutex lock;
59
Thierry Escande204bddc2016-06-23 11:20:26 +020060 u8 rf_tech;
61 u8 mode;
Thierry Escande7cbe0ff2013-06-06 16:23:23 +020062
Thierry Escande204bddc2016-06-23 11:20:26 +020063 u8 shutdown;
Thierry Escande7cbe0ff2013-06-06 16:23:23 +020064
Thierry Escande204bddc2016-06-23 11:20:26 +020065 struct sk_buff *skb;
66 wait_queue_head_t recv_wait;
67 u8 cond;
Thierry Escande7cbe0ff2013-06-06 16:23:23 +020068};
69
Thierry Escande204bddc2016-06-23 11:20:26 +020070static struct nfcsim_link *nfcsim_link_new(void)
71{
72 struct nfcsim_link *link;
73
74 link = kzalloc(sizeof(struct nfcsim_link), GFP_KERNEL);
75 if (!link)
76 return NULL;
77
78 mutex_init(&link->lock);
79 init_waitqueue_head(&link->recv_wait);
80
81 return link;
82}
83
84static void nfcsim_link_free(struct nfcsim_link *link)
85{
86 dev_kfree_skb(link->skb);
87 kfree(link);
88}
89
90static void nfcsim_link_recv_wake(struct nfcsim_link *link)
91{
92 link->cond = 1;
93 wake_up_interruptible(&link->recv_wait);
94}
95
96static void nfcsim_link_set_skb(struct nfcsim_link *link, struct sk_buff *skb,
97 u8 rf_tech, u8 mode)
98{
99 mutex_lock(&link->lock);
100
101 dev_kfree_skb(link->skb);
102 link->skb = skb;
103 link->rf_tech = rf_tech;
104 link->mode = mode;
105
106 mutex_unlock(&link->lock);
107}
108
109static void nfcsim_link_recv_cancel(struct nfcsim_link *link)
110{
111 mutex_lock(&link->lock);
112
113 link->mode = NFCSIM_MODE_NONE;
114
115 mutex_unlock(&link->lock);
116
117 nfcsim_link_recv_wake(link);
118}
119
120static void nfcsim_link_shutdown(struct nfcsim_link *link)
121{
122 mutex_lock(&link->lock);
123
124 link->shutdown = 1;
125 link->mode = NFCSIM_MODE_NONE;
126
127 mutex_unlock(&link->lock);
128
129 nfcsim_link_recv_wake(link);
130}
131
132static struct sk_buff *nfcsim_link_recv_skb(struct nfcsim_link *link,
133 int timeout, u8 rf_tech, u8 mode)
134{
135 int rc;
136 struct sk_buff *skb;
137
138 rc = wait_event_interruptible_timeout(link->recv_wait,
139 link->cond,
140 msecs_to_jiffies(timeout));
141
142 mutex_lock(&link->lock);
143
144 skb = link->skb;
145 link->skb = NULL;
146
147 if (!rc) {
148 rc = -ETIMEDOUT;
149 goto done;
150 }
151
152 if (!skb || link->rf_tech != rf_tech || link->mode == mode) {
153 rc = -EINVAL;
154 goto done;
155 }
156
157 if (link->shutdown) {
158 rc = -ENODEV;
159 goto done;
160 }
161
162done:
163 mutex_unlock(&link->lock);
164
165 if (rc < 0) {
166 dev_kfree_skb(skb);
167 skb = ERR_PTR(rc);
168 }
169
170 link->cond = 0;
171
172 return skb;
173}
174
175static void nfcsim_send_wq(struct work_struct *work)
176{
177 struct nfcsim *dev = container_of(work, struct nfcsim, send_work.work);
178
179 /*
180 * To effectively send data, the device just wake up its link_out which
181 * is the link_in of the peer device. The exchanged skb has already been
182 * stored in the dev->link_out through nfcsim_link_set_skb().
183 */
184 nfcsim_link_recv_wake(dev->link_out);
185}
186
187static void nfcsim_recv_wq(struct work_struct *work)
188{
189 struct nfcsim *dev = container_of(work, struct nfcsim, recv_work);
190 struct sk_buff *skb;
191
192 skb = nfcsim_link_recv_skb(dev->link_in, dev->recv_timeout,
193 dev->rf_tech, dev->mode);
194
195 if (!dev->up) {
196 NFCSIM_ERR(dev, "Device is down\n");
197
198 if (!IS_ERR(skb))
199 dev_kfree_skb(skb);
200
201 skb = ERR_PTR(-ENODEV);
202 }
203
204 dev->cb(dev->nfc_digital_dev, dev->arg, skb);
205}
206
207static int nfcsim_send(struct nfc_digital_dev *ddev, struct sk_buff *skb,
208 u16 timeout, nfc_digital_cmd_complete_t cb, void *arg)
209{
210 struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
211 u8 delay;
212
213 if (!dev->up) {
214 NFCSIM_ERR(dev, "Device is down\n");
215 return -ENODEV;
216 }
217
218 dev->recv_timeout = timeout;
219 dev->cb = cb;
220 dev->arg = arg;
221
222 schedule_work(&dev->recv_work);
223
224 if (skb) {
225 nfcsim_link_set_skb(dev->link_out, skb, dev->rf_tech,
226 dev->mode);
227
228 /* Add random delay (between 3 and 10 ms) before sending data */
229 get_random_bytes(&delay, 1);
230 delay = 3 + (delay & 0x07);
231
232 schedule_delayed_work(&dev->send_work, msecs_to_jiffies(delay));
233 }
234
235 return 0;
236}
237
238static void nfcsim_abort_cmd(struct nfc_digital_dev *ddev)
239{
240 struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
241
242 nfcsim_link_recv_cancel(dev->link_in);
243}
244
245static int nfcsim_switch_rf(struct nfc_digital_dev *ddev, bool on)
246{
247 struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
248
249 dev->up = on;
250
251 return 0;
252}
253
254static int nfcsim_in_configure_hw(struct nfc_digital_dev *ddev,
255 int type, int param)
256{
257 struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
258
259 switch (type) {
260 case NFC_DIGITAL_CONFIG_RF_TECH:
261 dev->up = true;
262 dev->mode = NFCSIM_MODE_INITIATOR;
263 dev->rf_tech = param;
264 break;
265
266 case NFC_DIGITAL_CONFIG_FRAMING:
267 break;
268
269 default:
270 NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type);
271 return -EINVAL;
272 }
273
274 return 0;
275}
276
277static int nfcsim_in_send_cmd(struct nfc_digital_dev *ddev,
278 struct sk_buff *skb, u16 timeout,
279 nfc_digital_cmd_complete_t cb, void *arg)
280{
281 return nfcsim_send(ddev, skb, timeout, cb, arg);
282}
283
284static int nfcsim_tg_configure_hw(struct nfc_digital_dev *ddev,
285 int type, int param)
286{
287 struct nfcsim *dev = nfc_digital_get_drvdata(ddev);
288
289 switch (type) {
290 case NFC_DIGITAL_CONFIG_RF_TECH:
291 dev->up = true;
292 dev->mode = NFCSIM_MODE_TARGET;
293 dev->rf_tech = param;
294 break;
295
296 case NFC_DIGITAL_CONFIG_FRAMING:
297 break;
298
299 default:
300 NFCSIM_ERR(dev, "Invalid configuration type: %d\n", type);
301 return -EINVAL;
302 }
303
304 return 0;
305}
306
307static int nfcsim_tg_send_cmd(struct nfc_digital_dev *ddev,
308 struct sk_buff *skb, u16 timeout,
309 nfc_digital_cmd_complete_t cb, void *arg)
310{
311 return nfcsim_send(ddev, skb, timeout, cb, arg);
312}
313
314static int nfcsim_tg_listen(struct nfc_digital_dev *ddev, u16 timeout,
315 nfc_digital_cmd_complete_t cb, void *arg)
316{
317 return nfcsim_send(ddev, NULL, timeout, cb, arg);
318}
319
320static struct nfc_digital_ops nfcsim_digital_ops = {
321 .in_configure_hw = nfcsim_in_configure_hw,
322 .in_send_cmd = nfcsim_in_send_cmd,
323
324 .tg_listen = nfcsim_tg_listen,
325 .tg_configure_hw = nfcsim_tg_configure_hw,
326 .tg_send_cmd = nfcsim_tg_send_cmd,
327
328 .abort_cmd = nfcsim_abort_cmd,
329 .switch_rf = nfcsim_switch_rf,
330};
331
332static struct nfcsim *nfcsim_device_new(struct nfcsim_link *link_in,
333 struct nfcsim_link *link_out)
334{
335 struct nfcsim *dev;
336 int rc;
337
338 dev = kzalloc(sizeof(struct nfcsim), GFP_KERNEL);
339 if (!dev)
340 return ERR_PTR(-ENOMEM);
341
342 INIT_DELAYED_WORK(&dev->send_work, nfcsim_send_wq);
343 INIT_WORK(&dev->recv_work, nfcsim_recv_wq);
344
345 dev->nfc_digital_dev =
346 nfc_digital_allocate_device(&nfcsim_digital_ops,
347 NFC_PROTO_NFC_DEP_MASK,
348 NFCSIM_CAPABILITIES,
349 0, 0);
350 if (!dev->nfc_digital_dev) {
351 kfree(dev);
352 return ERR_PTR(-ENOMEM);
353 }
354
355 nfc_digital_set_drvdata(dev->nfc_digital_dev, dev);
356
357 dev->link_in = link_in;
358 dev->link_out = link_out;
359
360 rc = nfc_digital_register_device(dev->nfc_digital_dev);
361 if (rc) {
362 pr_err("Could not register digital device (%d)\n", rc);
363 nfc_digital_free_device(dev->nfc_digital_dev);
364 kfree(dev);
365
366 return ERR_PTR(rc);
367 }
368
369 return dev;
370}
371
372static void nfcsim_device_free(struct nfcsim *dev)
373{
374 nfc_digital_unregister_device(dev->nfc_digital_dev);
375
376 dev->up = false;
377
378 nfcsim_link_shutdown(dev->link_in);
379
380 cancel_delayed_work_sync(&dev->send_work);
381 cancel_work_sync(&dev->recv_work);
382
383 nfc_digital_free_device(dev->nfc_digital_dev);
384
385 kfree(dev);
386}
387
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200388static struct nfcsim *dev0;
389static struct nfcsim *dev1;
390
Thierry Escande40dac372013-06-24 12:02:28 +0200391static int __init nfcsim_init(void)
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200392{
Thierry Escande204bddc2016-06-23 11:20:26 +0200393 struct nfcsim_link *link0, *link1;
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200394 int rc;
395
Thierry Escande204bddc2016-06-23 11:20:26 +0200396 link0 = nfcsim_link_new();
397 link1 = nfcsim_link_new();
398 if (!link0 || !link1) {
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200399 rc = -ENOMEM;
Thierry Escande204bddc2016-06-23 11:20:26 +0200400 goto exit_err;
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200401 }
402
Thierry Escande204bddc2016-06-23 11:20:26 +0200403 dev0 = nfcsim_device_new(link0, link1);
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200404 if (IS_ERR(dev0)) {
405 rc = PTR_ERR(dev0);
Thierry Escande204bddc2016-06-23 11:20:26 +0200406 goto exit_err;
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200407 }
408
Thierry Escande204bddc2016-06-23 11:20:26 +0200409 dev1 = nfcsim_device_new(link1, link0);
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200410 if (IS_ERR(dev1)) {
Thierry Escande204bddc2016-06-23 11:20:26 +0200411 nfcsim_device_free(dev0);
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200412
413 rc = PTR_ERR(dev1);
Thierry Escande204bddc2016-06-23 11:20:26 +0200414 goto exit_err;
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200415 }
416
Thierry Escande204bddc2016-06-23 11:20:26 +0200417 pr_info("nfcsim " NFCSIM_VERSION " initialized\n");
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200418
Thierry Escande204bddc2016-06-23 11:20:26 +0200419 return 0;
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200420
Thierry Escande204bddc2016-06-23 11:20:26 +0200421exit_err:
422 pr_err("Failed to initialize nfcsim driver (%d)\n", rc);
423
424 nfcsim_link_free(link0);
425 nfcsim_link_free(link1);
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200426
427 return rc;
428}
429
Thierry Escande40dac372013-06-24 12:02:28 +0200430static void __exit nfcsim_exit(void)
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200431{
Thierry Escande204bddc2016-06-23 11:20:26 +0200432 struct nfcsim_link *link0, *link1;
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200433
Thierry Escande204bddc2016-06-23 11:20:26 +0200434 link0 = dev0->link_in;
435 link1 = dev0->link_out;
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200436
Thierry Escande204bddc2016-06-23 11:20:26 +0200437 nfcsim_device_free(dev0);
438 nfcsim_device_free(dev1);
439
440 nfcsim_link_free(link0);
441 nfcsim_link_free(link1);
Thierry Escande7cbe0ff2013-06-06 16:23:23 +0200442}
443
444module_init(nfcsim_init);
445module_exit(nfcsim_exit);
446
447MODULE_DESCRIPTION("NFCSim driver ver " NFCSIM_VERSION);
448MODULE_VERSION(NFCSIM_VERSION);
449MODULE_LICENSE("GPL");