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>
This commit is contained in:
committed by
John W. Linville
parent
144612cacc
commit
c8d56ae786
@@ -62,6 +62,7 @@ struct nfc_ops {
|
|||||||
int (*data_exchange)(struct nfc_dev *dev, u32 target_idx,
|
int (*data_exchange)(struct nfc_dev *dev, u32 target_idx,
|
||||||
struct sk_buff *skb, data_exchange_cb_t cb,
|
struct sk_buff *skb, data_exchange_cb_t cb,
|
||||||
void *cb_context);
|
void *cb_context);
|
||||||
|
int (*check_presence)(struct nfc_dev *dev, u32 target_idx);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define NFC_TARGET_IDX_ANY -1
|
#define NFC_TARGET_IDX_ANY -1
|
||||||
@@ -107,6 +108,10 @@ struct nfc_dev {
|
|||||||
int tx_headroom;
|
int tx_headroom;
|
||||||
int tx_tailroom;
|
int tx_tailroom;
|
||||||
|
|
||||||
|
struct timer_list check_pres_timer;
|
||||||
|
struct workqueue_struct *check_pres_wq;
|
||||||
|
struct work_struct check_pres_work;
|
||||||
|
|
||||||
struct nfc_ops *ops;
|
struct nfc_ops *ops;
|
||||||
};
|
};
|
||||||
#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
|
#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
|
||||||
|
@@ -33,6 +33,8 @@
|
|||||||
|
|
||||||
#define VERSION "0.1"
|
#define VERSION "0.1"
|
||||||
|
|
||||||
|
#define NFC_CHECK_PRES_FREQ_MS 2000
|
||||||
|
|
||||||
int nfc_devlist_generation;
|
int nfc_devlist_generation;
|
||||||
DEFINE_MUTEX(nfc_devlist_mutex);
|
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);
|
rc = dev->ops->activate_target(dev, target_idx, protocol);
|
||||||
if (!rc)
|
if (!rc) {
|
||||||
dev->activated_target_idx = target_idx;
|
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:
|
error:
|
||||||
device_unlock(&dev->dev);
|
device_unlock(&dev->dev);
|
||||||
return rc;
|
return rc;
|
||||||
@@ -320,6 +327,9 @@ int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx)
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dev->ops->check_presence)
|
||||||
|
del_timer_sync(&dev->check_pres_timer);
|
||||||
|
|
||||||
dev->ops->deactivate_target(dev, target_idx);
|
dev->ops->deactivate_target(dev, target_idx);
|
||||||
dev->activated_target_idx = NFC_TARGET_IDX_NONE;
|
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;
|
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);
|
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:
|
error:
|
||||||
device_unlock(&dev->dev);
|
device_unlock(&dev->dev);
|
||||||
return rc;
|
return rc;
|
||||||
@@ -521,11 +538,46 @@ static void nfc_release(struct device *d)
|
|||||||
|
|
||||||
pr_debug("dev_name=%s\n", dev_name(&dev->dev));
|
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);
|
nfc_genl_data_exit(&dev->genl_data);
|
||||||
kfree(dev->targets);
|
kfree(dev->targets);
|
||||||
kfree(dev);
|
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 = {
|
struct class nfc_class = {
|
||||||
.name = "nfc",
|
.name = "nfc",
|
||||||
.dev_release = nfc_release,
|
.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;
|
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;
|
return dev;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(nfc_allocate_device);
|
EXPORT_SYMBOL(nfc_allocate_device);
|
||||||
|
Reference in New Issue
Block a user