Root/
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_err(&_dev->nfc_dev->dev, \ |
23 | "%s: " fmt, __func__, ## args) |
24 | |
25 | #define DEV_DBG(_dev, fmt, args...) 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 | |
35 | struct 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 | |
60 | static struct nfcsim *dev0; |
61 | static struct nfcsim *dev1; |
62 | |
63 | static struct workqueue_struct *wq; |
64 | |
65 | static void nfcsim_cleanup_dev(struct nfcsim *dev, u8 shutdown) |
66 | { |
67 | DEV_DBG(dev, "shutdown=%d\n", 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 | |
83 | static int nfcsim_target_found(struct nfcsim *dev) |
84 | { |
85 | struct nfc_target nfc_tgt; |
86 | |
87 | DEV_DBG(dev, "\n"); |
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 | |
97 | static int nfcsim_dev_up(struct nfc_dev *nfc_dev) |
98 | { |
99 | struct nfcsim *dev = nfc_get_drvdata(nfc_dev); |
100 | |
101 | DEV_DBG(dev, "\n"); |
102 | |
103 | mutex_lock(&dev->lock); |
104 | |
105 | dev->up = 1; |
106 | |
107 | mutex_unlock(&dev->lock); |
108 | |
109 | return 0; |
110 | } |
111 | |
112 | static int nfcsim_dev_down(struct nfc_dev *nfc_dev) |
113 | { |
114 | struct nfcsim *dev = nfc_get_drvdata(nfc_dev); |
115 | |
116 | DEV_DBG(dev, "\n"); |
117 | |
118 | mutex_lock(&dev->lock); |
119 | |
120 | dev->up = 0; |
121 | |
122 | mutex_unlock(&dev->lock); |
123 | |
124 | return 0; |
125 | } |
126 | |
127 | static 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\n"); |
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\n"); |
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 | |
171 | static 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, "\n"); |
176 | |
177 | nfcsim_cleanup_dev(dev, 0); |
178 | |
179 | return 0; |
180 | } |
181 | |
182 | static 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\n"); |
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\n"); |
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\n", im_protocols, |
214 | tm_protocols); |
215 | |
216 | rc = 0; |
217 | exit: |
218 | mutex_unlock(&dev->lock); |
219 | |
220 | return rc; |
221 | } |
222 | |
223 | static 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\n"); |
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 | |
238 | static 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, "\n"); |
244 | |
245 | return -ENOTSUPP; |
246 | } |
247 | |
248 | static 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, "\n"); |
254 | } |
255 | |
256 | static 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\n"); |
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 | |
281 | exit: |
282 | dev->clone_skb = NULL; |
283 | |
284 | mutex_unlock(&dev->lock); |
285 | } |
286 | |
287 | static 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\n"); |
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; |
331 | exit: |
332 | dev_kfree_skb(skb); |
333 | |
334 | return err; |
335 | } |
336 | |
337 | static 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 | |
344 | static 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 | |
349 | static 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 | |
362 | static 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 | |
386 | static 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\n"); |
401 | goto unlock; |
402 | } |
403 | |
404 | DEV_DBG(dev, "Polling as %s", |
405 | dev->curr_polling_mode == NFCSIM_POLL_INITIATOR ? |
406 | "initiator\n" : "target\n"); |
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 | |
422 | sched_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 | |
433 | unlock: |
434 | mutex_unlock(&peer->lock); |
435 | mutex_unlock(&dev->lock); |
436 | } |
437 | |
438 | static 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 | |
466 | free_nfc_dev: |
467 | nfc_free_device(dev->nfc_dev); |
468 | |
469 | error: |
470 | kfree(dev); |
471 | |
472 | return ERR_PTR(rc); |
473 | } |
474 | |
475 | static 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 | |
484 | static int __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; |
517 | exit: |
518 | if (rc) |
519 | pr_err("Failed to initialize nfcsim driver (%d)\n", |
520 | rc); |
521 | |
522 | return rc; |
523 | } |
524 | |
525 | static void __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 | |
536 | module_init(nfcsim_init); |
537 | module_exit(nfcsim_exit); |
538 | |
539 | MODULE_DESCRIPTION("NFCSim driver ver " NFCSIM_VERSION); |
540 | MODULE_VERSION(NFCSIM_VERSION); |
541 | MODULE_LICENSE("GPL"); |
542 |
Branches:
ben-wpan
ben-wpan-stefan
javiroman/ks7010
jz-2.6.34
jz-2.6.34-rc5
jz-2.6.34-rc6
jz-2.6.34-rc7
jz-2.6.35
jz-2.6.36
jz-2.6.37
jz-2.6.38
jz-2.6.39
jz-3.0
jz-3.1
jz-3.11
jz-3.12
jz-3.13
jz-3.15
jz-3.16
jz-3.18-dt
jz-3.2
jz-3.3
jz-3.4
jz-3.5
jz-3.6
jz-3.6-rc2-pwm
jz-3.9
jz-3.9-clk
jz-3.9-rc8
jz47xx
jz47xx-2.6.38
master
Tags:
od-2011-09-04
od-2011-09-18
v2.6.34-rc5
v2.6.34-rc6
v2.6.34-rc7
v3.9