diff options
author | Eric Lapuyade <eric.lapuyade@intel.com> | 2012-04-10 13:43:12 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2012-04-12 15:10:39 -0400 |
commit | c8d56ae78653c02fc6e6f304a18f860302481c2d (patch) | |
tree | c60fce9156d96a746e809302ebeb1eab86e73f25 /net/nfc | |
parent | 144612cacc0b5c230f0b3aebc3a3a53854c332ee (diff) |
NFC: Add Core support to generate tag lost event
Some HW/drivers get notifications when a tag moves out of the radio field.
This notification is now forwarded to user space through netlink.
Signed-off-by: Eric Lapuyade <eric.lapuyade@intel.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'net/nfc')
-rw-r--r-- | net/nfc/core.c | 72 |
1 files changed, 71 insertions, 1 deletions
diff --git a/net/nfc/core.c b/net/nfc/core.c index 44a701806ba5..da353275fbc6 100644 --- a/net/nfc/core.c +++ b/net/nfc/core.c | |||
@@ -33,6 +33,8 @@ | |||
33 | 33 | ||
34 | #define VERSION "0.1" | 34 | #define VERSION "0.1" |
35 | 35 | ||
36 | #define NFC_CHECK_PRES_FREQ_MS 2000 | ||
37 | |||
36 | int nfc_devlist_generation; | 38 | int nfc_devlist_generation; |
37 | DEFINE_MUTEX(nfc_devlist_mutex); | 39 | DEFINE_MUTEX(nfc_devlist_mutex); |
38 | 40 | ||
@@ -292,9 +294,14 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol) | |||
292 | } | 294 | } |
293 | 295 | ||
294 | rc = dev->ops->activate_target(dev, target_idx, protocol); | 296 | rc = dev->ops->activate_target(dev, target_idx, protocol); |
295 | if (!rc) | 297 | if (!rc) { |
296 | dev->activated_target_idx = target_idx; | 298 | dev->activated_target_idx = target_idx; |
297 | 299 | ||
300 | if (dev->ops->check_presence) | ||
301 | mod_timer(&dev->check_pres_timer, jiffies + | ||
302 | msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); | ||
303 | } | ||
304 | |||
298 | error: | 305 | error: |
299 | device_unlock(&dev->dev); | 306 | device_unlock(&dev->dev); |
300 | return rc; | 307 | return rc; |
@@ -320,6 +327,9 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx) | |||
320 | goto error; | 327 | goto error; |
321 | } | 328 | } |
322 | 329 | ||
330 | if (dev->ops->check_presence) | ||
331 | del_timer_sync(&dev->check_pres_timer); | ||
332 | |||
323 | dev->ops->deactivate_target(dev, target_idx); | 333 | dev->ops->deactivate_target(dev, target_idx); |
324 | dev->activated_target_idx = NFC_TARGET_IDX_NONE; | 334 | dev->activated_target_idx = NFC_TARGET_IDX_NONE; |
325 | 335 | ||
@@ -367,8 +377,15 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb, | |||
367 | goto error; | 377 | goto error; |
368 | } | 378 | } |
369 | 379 | ||
380 | if (dev->ops->check_presence) | ||
381 | del_timer_sync(&dev->check_pres_timer); | ||
382 | |||
370 | rc = dev->ops->data_exchange(dev, target_idx, skb, cb, cb_context); | 383 | rc = dev->ops->data_exchange(dev, target_idx, skb, cb, cb_context); |
371 | 384 | ||
385 | if (!rc && dev->ops->check_presence) | ||
386 | mod_timer(&dev->check_pres_timer, jiffies + | ||
387 | msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); | ||
388 | |||
372 | error: | 389 | error: |
373 | device_unlock(&dev->dev); | 390 | device_unlock(&dev->dev); |
374 | return rc; | 391 | return rc; |
@@ -521,11 +538,46 @@ static void nfc_release(struct device *d) | |||
521 | 538 | ||
522 | pr_debug("dev_name=%s\n", dev_name(&dev->dev)); | 539 | pr_debug("dev_name=%s\n", dev_name(&dev->dev)); |
523 | 540 | ||
541 | if (dev->ops->check_presence) { | ||
542 | del_timer_sync(&dev->check_pres_timer); | ||
543 | destroy_workqueue(dev->check_pres_wq); | ||
544 | } | ||
545 | |||
524 | nfc_genl_data_exit(&dev->genl_data); | 546 | nfc_genl_data_exit(&dev->genl_data); |
525 | kfree(dev->targets); | 547 | kfree(dev->targets); |
526 | kfree(dev); | 548 | kfree(dev); |
527 | } | 549 | } |
528 | 550 | ||
551 | static void nfc_check_pres_work(struct work_struct *work) | ||
552 | { | ||
553 | struct nfc_dev *dev = container_of(work, struct nfc_dev, | ||
554 | check_pres_work); | ||
555 | int rc; | ||
556 | |||
557 | device_lock(&dev->dev); | ||
558 | |||
559 | if (dev->activated_target_idx != NFC_TARGET_IDX_NONE && | ||
560 | timer_pending(&dev->check_pres_timer) == 0) { | ||
561 | rc = dev->ops->check_presence(dev, dev->activated_target_idx); | ||
562 | if (!rc) { | ||
563 | mod_timer(&dev->check_pres_timer, jiffies + | ||
564 | msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); | ||
565 | } else { | ||
566 | nfc_target_lost(dev, dev->activated_target_idx); | ||
567 | dev->activated_target_idx = NFC_TARGET_IDX_NONE; | ||
568 | } | ||
569 | } | ||
570 | |||
571 | device_unlock(&dev->dev); | ||
572 | } | ||
573 | |||
574 | static void nfc_check_pres_timeout(unsigned long data) | ||
575 | { | ||
576 | struct nfc_dev *dev = (struct nfc_dev *)data; | ||
577 | |||
578 | queue_work(dev->check_pres_wq, &dev->check_pres_work); | ||
579 | } | ||
580 | |||
529 | struct class nfc_class = { | 581 | struct class nfc_class = { |
530 | .name = "nfc", | 582 | .name = "nfc", |
531 | .dev_release = nfc_release, | 583 | .dev_release = nfc_release, |
@@ -593,6 +645,24 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops, | |||
593 | 645 | ||
594 | dev->activated_target_idx = NFC_TARGET_IDX_NONE; | 646 | dev->activated_target_idx = NFC_TARGET_IDX_NONE; |
595 | 647 | ||
648 | if (ops->check_presence) { | ||
649 | char name[32]; | ||
650 | init_timer(&dev->check_pres_timer); | ||
651 | dev->check_pres_timer.data = (unsigned long)dev; | ||
652 | dev->check_pres_timer.function = nfc_check_pres_timeout; | ||
653 | |||
654 | INIT_WORK(&dev->check_pres_work, nfc_check_pres_work); | ||
655 | snprintf(name, sizeof(name), "nfc%d_check_pres_wq", dev->idx); | ||
656 | dev->check_pres_wq = alloc_workqueue(name, WQ_NON_REENTRANT | | ||
657 | WQ_UNBOUND | | ||
658 | WQ_MEM_RECLAIM, 1); | ||
659 | if (dev->check_pres_wq == NULL) { | ||
660 | kfree(dev); | ||
661 | return NULL; | ||
662 | } | ||
663 | } | ||
664 | |||
665 | |||
596 | return dev; | 666 | return dev; |
597 | } | 667 | } |
598 | EXPORT_SYMBOL(nfc_allocate_device); | 668 | EXPORT_SYMBOL(nfc_allocate_device); |