Skip to content

Commit

Permalink
NFC: Add Core support to generate tag lost event
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eric Lapuyade authored and John W. Linville committed Apr 12, 2012
1 parent 144612c commit c8d56ae
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 1 deletion.
5 changes: 5 additions & 0 deletions include/net/nfc/nfc.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ struct nfc_ops {
int (*data_exchange)(struct nfc_dev *dev, u32 target_idx,
struct sk_buff *skb, data_exchange_cb_t cb,
void *cb_context);
int (*check_presence)(struct nfc_dev *dev, u32 target_idx);
};

#define NFC_TARGET_IDX_ANY -1
Expand Down Expand Up @@ -107,6 +108,10 @@ struct nfc_dev {
int tx_headroom;
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;
};
#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
Expand Down
72 changes: 71 additions & 1 deletion net/nfc/core.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@

#define VERSION "0.1"

#define NFC_CHECK_PRES_FREQ_MS 2000

int nfc_devlist_generation;
DEFINE_MUTEX(nfc_devlist_mutex);

Expand Down Expand Up @@ -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;
Expand All @@ -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;

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit c8d56ae

Please sign in to comment.