Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c8d56ae7 authored by Eric Lapuyade's avatar Eric Lapuyade Committed by John W. Linville
Browse files

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: default avatarEric Lapuyade <eric.lapuyade@intel.com>
Signed-off-by: default avatarSamuel Ortiz <sameo@linux.intel.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 144612ca
Loading
Loading
Loading
Loading
+5 −0
Original line number Original line Diff line number Diff line
@@ -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)
+71 −1
Original line number Original line Diff line number Diff line
@@ -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);