diff options
| author | Eric Lapuyade <eric.lapuyade@intel.com> | 2012-04-10 19:43:12 +0200 | 
|---|---|---|
| committer | John W. Linville <linville@tuxdriver.com> | 2012-04-12 15:10:39 -0400 | 
| commit | c8d56ae78653c02fc6e6f304a18f860302481c2d (patch) | |
| tree | c60fce9156d96a746e809302ebeb1eab86e73f25 /net/nfc | |
| parent | 144612cacc0b5c230f0b3aebc3a3a53854c332ee (diff) | |
| download | linux-c8d56ae78653c02fc6e6f304a18f860302481c2d.tar.bz2 | |
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 @@  #define VERSION "0.1" +#define NFC_CHECK_PRES_FREQ_MS	2000 +  int nfc_devlist_generation;  DEFINE_MUTEX(nfc_devlist_mutex); @@ -292,9 +294,14 @@ int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)  	}  	rc = dev->ops->activate_target(dev, target_idx, protocol); -	if (!rc) +	if (!rc) {  		dev->activated_target_idx = target_idx; +		if (dev->ops->check_presence) +			mod_timer(&dev->check_pres_timer, jiffies + +				  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); +	} +  error:  	device_unlock(&dev->dev);  	return rc; @@ -320,6 +327,9 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx)  		goto error;  	} +	if (dev->ops->check_presence) +		del_timer_sync(&dev->check_pres_timer); +  	dev->ops->deactivate_target(dev, target_idx);  	dev->activated_target_idx = NFC_TARGET_IDX_NONE; @@ -367,8 +377,15 @@ int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx, struct sk_buff *skb,  		goto error;  	} +	if (dev->ops->check_presence) +		del_timer_sync(&dev->check_pres_timer); +  	rc = dev->ops->data_exchange(dev, target_idx, skb, cb, cb_context); +	if (!rc && dev->ops->check_presence) +		mod_timer(&dev->check_pres_timer, jiffies + +			  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); +  error:  	device_unlock(&dev->dev);  	return rc; @@ -521,11 +538,46 @@ static void nfc_release(struct device *d)  	pr_debug("dev_name=%s\n", dev_name(&dev->dev)); +	if (dev->ops->check_presence) { +		del_timer_sync(&dev->check_pres_timer); +		destroy_workqueue(dev->check_pres_wq); +	} +  	nfc_genl_data_exit(&dev->genl_data);  	kfree(dev->targets);  	kfree(dev);  } +static void nfc_check_pres_work(struct work_struct *work) +{ +	struct nfc_dev *dev = container_of(work, struct nfc_dev, +					   check_pres_work); +	int rc; + +	device_lock(&dev->dev); + +	if (dev->activated_target_idx != NFC_TARGET_IDX_NONE && +	    timer_pending(&dev->check_pres_timer) == 0) { +		rc = dev->ops->check_presence(dev, dev->activated_target_idx); +		if (!rc) { +			mod_timer(&dev->check_pres_timer, jiffies + +				  msecs_to_jiffies(NFC_CHECK_PRES_FREQ_MS)); +		} else { +			nfc_target_lost(dev, dev->activated_target_idx); +			dev->activated_target_idx = NFC_TARGET_IDX_NONE; +		} +	} + +	device_unlock(&dev->dev); +} + +static void nfc_check_pres_timeout(unsigned long data) +{ +	struct nfc_dev *dev = (struct nfc_dev *)data; + +	queue_work(dev->check_pres_wq, &dev->check_pres_work); +} +  struct class nfc_class = {  	.name = "nfc",  	.dev_release = nfc_release, @@ -593,6 +645,24 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,  	dev->activated_target_idx = NFC_TARGET_IDX_NONE; +	if (ops->check_presence) { +		char name[32]; +		init_timer(&dev->check_pres_timer); +		dev->check_pres_timer.data = (unsigned long)dev; +		dev->check_pres_timer.function = nfc_check_pres_timeout; + +		INIT_WORK(&dev->check_pres_work, nfc_check_pres_work); +		snprintf(name, sizeof(name), "nfc%d_check_pres_wq", dev->idx); +		dev->check_pres_wq = alloc_workqueue(name, WQ_NON_REENTRANT | +						     WQ_UNBOUND | +						     WQ_MEM_RECLAIM, 1); +		if (dev->check_pres_wq == NULL) { +			kfree(dev); +			return NULL; +		} +	} + +  	return dev;  }  EXPORT_SYMBOL(nfc_allocate_device);  |