aboutsummaryrefslogtreecommitdiffstats
path: root/net/nfc/core.c
diff options
context:
space:
mode:
authorEric Lapuyade <eric.lapuyade@intel.com>2012-04-10 13:43:12 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-12 15:10:39 -0400
commitc8d56ae78653c02fc6e6f304a18f860302481c2d (patch)
treec60fce9156d96a746e809302ebeb1eab86e73f25 /net/nfc/core.c
parent144612cacc0b5c230f0b3aebc3a3a53854c332ee (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/core.c')
-rw-r--r--net/nfc/core.c72
1 files changed, 71 insertions, 1 deletions
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 44a701806ba..da353275fbc 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
36int nfc_devlist_generation; 38int nfc_devlist_generation;
37DEFINE_MUTEX(nfc_devlist_mutex); 39DEFINE_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
298error: 305error:
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
372error: 389error:
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
551static 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
574static 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
529struct class nfc_class = { 581struct 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}
598EXPORT_SYMBOL(nfc_allocate_device); 668EXPORT_SYMBOL(nfc_allocate_device);