linux-wireless.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 0/6] NFC subsystem
@ 2011-06-28 18:20 Aloisio Almeida Jr
  2011-06-28 18:20 ` [PATCH v4 1/6] NFC: add nfc subsystem core Aloisio Almeida Jr
                   ` (5 more replies)
  0 siblings, 6 replies; 17+ messages in thread
From: Aloisio Almeida Jr @ 2011-06-28 18:20 UTC (permalink / raw)
  To: linville
  Cc: linux-wireless, sameo, johannes, lauro.venancio, marcio.macedo,
	Waldemar.Rymarkiewicz, padovan, rdunlap, Aloisio Almeida Jr

This version includes the following changes:

 1. NFC_ERR(), NFC_INFO() and NFC_DBG() were created for message output in the
    subsystem. Device drivers still have to use dev_*() functions;
 2. Now using dynamic debug, NFC_DEBUG config was removed;
 3. core.c: nfc_targets_found(): kzmalloc()/memcpy() changed to kmemdup();
 4. An eventual error on sending NFC_EVENT_DEVICE_ADDED and
    NFC_EVENT_DEVICE_REMOVED messages will be ignored;
 5. Added the attribute 'packed' to initiator_data structs in pn533 driver. It
    fixes the felica polling loop;
 6. Fixes in the Documentation/networking/nfc.txt.

As Johannes Berg's patch (netlink: advertise incomplete dumps) is already on
wireless-next tree, I removed the tag 'RFC' from this patch series.

Aloisio Almeida Jr (3):
  NFC: add NFC socket family
  NFC: pn533: add NXP pn533 nfc device driver
  NFC: add Documentation/networking/nfc.txt

Lauro Ramos Venancio (3):
  NFC: add nfc subsystem core
  NFC: add nfc generic netlink interface
  NFC: add the NFC socket raw protocol

 Documentation/networking/nfc.txt |  128 +++
 drivers/Kconfig                  |    2 -
 drivers/Makefile                 |    1 +
 drivers/nfc/Kconfig              |   24 +-
 drivers/nfc/Makefile             |    3 +
 drivers/nfc/pn533.c              | 1630 ++++++++++++++++++++++++++++++++++++++
 include/linux/nfc.h              |  126 +++
 include/linux/socket.h           |    4 +-
 include/net/nfc.h                |  152 ++++
 net/Kconfig                      |    1 +
 net/Makefile                     |    1 +
 net/core/sock.c                  |    6 +-
 net/nfc/Kconfig                  |   16 +
 net/nfc/Makefile                 |    7 +
 net/nfc/af_nfc.c                 |   98 +++
 net/nfc/core.c                   |  445 +++++++++++
 net/nfc/netlink.c                |  537 +++++++++++++
 net/nfc/nfc.h                    |  114 +++
 net/nfc/rawsock.c                |  351 ++++++++
 19 files changed, 3628 insertions(+), 18 deletions(-)
 create mode 100644 Documentation/networking/nfc.txt
 create mode 100644 drivers/nfc/pn533.c
 create mode 100644 include/linux/nfc.h
 create mode 100644 include/net/nfc.h
 create mode 100644 net/nfc/Kconfig
 create mode 100644 net/nfc/Makefile
 create mode 100644 net/nfc/af_nfc.c
 create mode 100644 net/nfc/core.c
 create mode 100644 net/nfc/netlink.c
 create mode 100644 net/nfc/nfc.h
 create mode 100644 net/nfc/rawsock.c

-- 
1.7.5.4


^ permalink raw reply	[flat|nested] 17+ messages in thread

* [PATCH v4 1/6] NFC: add nfc subsystem core
  2011-06-28 18:20 [PATCH v4 0/6] NFC subsystem Aloisio Almeida Jr
@ 2011-06-28 18:20 ` Aloisio Almeida Jr
  2011-06-28 20:18   ` Joe Perches
  2011-06-28 18:20 ` [PATCH v4 2/6] NFC: add nfc generic netlink interface Aloisio Almeida Jr
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 17+ messages in thread
From: Aloisio Almeida Jr @ 2011-06-28 18:20 UTC (permalink / raw)
  To: linville
  Cc: linux-wireless, sameo, johannes, lauro.venancio, marcio.macedo,
	Waldemar.Rymarkiewicz, padovan, rdunlap, Aloisio Almeida Jr

From: Lauro Ramos Venancio <lauro.venancio@openbossa.org>

The NFC subsystem core is responsible for providing the device driver
interface. It is also responsible for providing an interface to the control
operations and data exchange.

Signed-off-by: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/Kconfig      |    2 -
 drivers/Makefile     |    1 +
 drivers/nfc/Kconfig  |   16 +--
 drivers/nfc/Makefile |    2 +
 include/net/nfc.h    |  131 +++++++++++++++++++
 net/Kconfig          |    1 +
 net/Makefile         |    1 +
 net/nfc/Kconfig      |   16 +++
 net/nfc/Makefile     |    7 +
 net/nfc/core.c       |  344 ++++++++++++++++++++++++++++++++++++++++++++++++++
 net/nfc/nfc.h        |   75 +++++++++++
 11 files changed, 581 insertions(+), 15 deletions(-)
 create mode 100644 include/net/nfc.h
 create mode 100644 net/nfc/Kconfig
 create mode 100644 net/nfc/Makefile
 create mode 100644 net/nfc/core.c
 create mode 100644 net/nfc/nfc.h

diff --git a/drivers/Kconfig b/drivers/Kconfig
index 61631ed..a56b0b8 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -92,8 +92,6 @@ source "drivers/memstick/Kconfig"
 
 source "drivers/leds/Kconfig"
 
-source "drivers/nfc/Kconfig"
-
 source "drivers/accessibility/Kconfig"
 
 source "drivers/infiniband/Kconfig"
diff --git a/drivers/Makefile b/drivers/Makefile
index a29527f..843cd31 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -120,3 +120,4 @@ obj-y				+= ieee802154/
 obj-y				+= clk/
 
 obj-$(CONFIG_HWSPINLOCK)	+= hwspinlock/
+obj-$(CONFIG_NFC)		+= nfc/
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index ea15800..7809289 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -2,17 +2,8 @@
 # Near Field Communication (NFC) devices
 #
 
-menuconfig NFC_DEVICES
-	bool "Near Field Communication (NFC) devices"
-	default n
-	---help---
-	  You'll have to say Y if your computer contains an NFC device that
-	  you want to use under Linux.
-
-	  You can say N here if you don't have any Near Field Communication
-	  devices connected to your computer.
-
-if NFC_DEVICES
+menu "Near Field Communication (NFC) devices"
+	depends on NFC
 
 config PN544_NFC
 	tristate "PN544 NFC driver"
@@ -26,5 +17,4 @@ config PN544_NFC
 	  To compile this driver as a module, choose m here. The module will
 	  be called pn544.
 
-
-endif # NFC_DEVICES
+endmenu
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index a4efb16..25296f0 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -3,3 +3,5 @@
 #
 
 obj-$(CONFIG_PN544_NFC)		+= pn544.o
+
+ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/include/net/nfc.h b/include/net/nfc.h
new file mode 100644
index 0000000..11d63dc
--- /dev/null
+++ b/include/net/nfc.h
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011 Instituto Nokia de Tecnologia
+ *
+ * Authors:
+ *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+ *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __NET_NFC_H
+#define __NET_NFC_H
+
+#include <linux/device.h>
+#include <linux/skbuff.h>
+
+struct nfc_dev;
+
+/**
+ * data_exchange_cb_t - Definition of nfc_data_exchange callback
+ *
+ * @context: nfc_data_exchange cb_context parameter
+ * @skb: response data
+ * @err: If an error has occurred during data exchange, it is the
+ *	error number. Zero means no error.
+ *
+ * When a rx or tx package is lost or corrupted or the target gets out
+ * of the operating field, err is -EIO.
+ */
+typedef void (*data_exchange_cb_t)(void *context, struct sk_buff *skb,
+								int err);
+
+struct nfc_ops {
+	int (*start_poll)(struct nfc_dev *dev, u32 protocols);
+	void (*stop_poll)(struct nfc_dev *dev);
+	int (*activate_target)(struct nfc_dev *dev, u32 target_idx,
+							u32 protocol);
+	void (*deactivate_target)(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,
+							void *cb_context);
+};
+
+struct nfc_dev {
+	unsigned idx;
+	struct device dev;
+	bool polling;
+	u32 supported_protocols;
+
+	struct nfc_ops *ops;
+};
+#define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)
+
+extern struct class nfc_class;
+
+struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
+					u32 supported_protocols);
+
+/**
+ * nfc_free_device - free nfc device
+ *
+ * @dev: The nfc device to free
+ */
+static inline void nfc_free_device(struct nfc_dev *dev)
+{
+	put_device(&dev->dev);
+}
+
+int nfc_register_device(struct nfc_dev *dev);
+
+void nfc_unregister_device(struct nfc_dev *dev);
+
+/**
+ * nfc_set_parent_dev - set the parent device
+ *
+ * @nfc_dev: The nfc device whose parent is being set
+ * @dev: The parent device
+ */
+static inline void nfc_set_parent_dev(struct nfc_dev *nfc_dev,
+					struct device *dev)
+{
+	nfc_dev->dev.parent = dev;
+}
+
+/**
+ * nfc_set_drvdata - set driver specifc data
+ *
+ * @dev: The nfc device
+ * @data: Pointer to driver specifc data
+ */
+static inline void nfc_set_drvdata(struct nfc_dev *dev, void *data)
+{
+	dev_set_drvdata(&dev->dev, data);
+}
+
+/**
+ * nfc_get_drvdata - get driver specifc data
+ *
+ * @dev: The nfc device
+ */
+static inline void *nfc_get_drvdata(struct nfc_dev *dev)
+{
+	return dev_get_drvdata(&dev->dev);
+}
+
+/**
+ * nfc_device_name - get the nfc device name
+ *
+ * @dev: The nfc device whose name to return
+ */
+static inline const char *nfc_device_name(struct nfc_dev *dev)
+{
+	return dev_name(&dev->dev);
+}
+
+struct sk_buff *nfc_alloc_skb(unsigned int size, gfp_t gfp);
+
+#endif /* __NET_NFC_H */
diff --git a/net/Kconfig b/net/Kconfig
index 878151c..a073148 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -322,6 +322,7 @@ source "net/rfkill/Kconfig"
 source "net/9p/Kconfig"
 source "net/caif/Kconfig"
 source "net/ceph/Kconfig"
+source "net/nfc/Kconfig"
 
 
 endif   # if NET
diff --git a/net/Makefile b/net/Makefile
index a51d946..acdde49 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -68,3 +68,4 @@ obj-$(CONFIG_WIMAX)		+= wimax/
 obj-$(CONFIG_DNS_RESOLVER)	+= dns_resolver/
 obj-$(CONFIG_CEPH_LIB)		+= ceph/
 obj-$(CONFIG_BATMAN_ADV)	+= batman-adv/
+obj-$(CONFIG_NFC)		+= nfc/
diff --git a/net/nfc/Kconfig b/net/nfc/Kconfig
new file mode 100644
index 0000000..33e095b
--- /dev/null
+++ b/net/nfc/Kconfig
@@ -0,0 +1,16 @@
+#
+# NFC sybsystem configuration
+#
+
+menuconfig NFC
+	depends on NET && EXPERIMENTAL
+	tristate "NFC subsystem support (EXPERIMENTAL)"
+	default n
+	help
+	  Say Y here if you want to build support for NFC (Near field
+	  communication) devices.
+
+	  To compile this support as a module, choose M here: the module will
+	  be called nfc.
+
+source "drivers/nfc/Kconfig"
diff --git a/net/nfc/Makefile b/net/nfc/Makefile
new file mode 100644
index 0000000..28bee59
--- /dev/null
+++ b/net/nfc/Makefile
@@ -0,0 +1,7 @@
+#
+# Makefile for the Linux NFC subsystem.
+#
+
+obj-$(CONFIG_NFC) += nfc.o
+
+nfc-objs := core.o
diff --git a/net/nfc/core.c b/net/nfc/core.c
new file mode 100644
index 0000000..992bbc5
--- /dev/null
+++ b/net/nfc/core.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 2011 Instituto Nokia de Tecnologia
+ *
+ * Authors:
+ *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+ *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include "nfc.h"
+
+#define VERSION "0.1"
+
+int nfc_devlist_generation;
+DEFINE_MUTEX(nfc_devlist_mutex);
+
+/**
+ * nfc_start_poll - start polling for nfc targets
+ *
+ * @dev: The nfc device that must start polling
+ * @protocols: bitset of nfc protocols that must be used for polling
+ *
+ * The device remains polling for targets until a target is found or
+ * the nfc_stop_poll function is called.
+ */
+int nfc_start_poll(struct nfc_dev *dev, u32 protocols)
+{
+	int rc;
+
+	NFC_DBG("dev_name:%s protocols=0x%x", dev_name(&dev->dev), protocols);
+
+	if (!protocols)
+		return -EINVAL;
+
+	device_lock(&dev->dev);
+
+	if (!device_is_registered(&dev->dev)) {
+		rc = -ENODEV;
+		goto error;
+	}
+
+	if (dev->polling) {
+		rc = -EBUSY;
+		goto error;
+	}
+
+	rc = dev->ops->start_poll(dev, protocols);
+	if (!rc)
+		dev->polling = true;
+
+error:
+	device_unlock(&dev->dev);
+	return rc;
+}
+
+/**
+ * nfc_stop_poll - stop polling for nfc targets
+ *
+ * @dev: The nfc device that must stop polling
+ */
+int nfc_stop_poll(struct nfc_dev *dev)
+{
+	int rc = 0;
+
+	NFC_DBG("dev_name:%s", dev_name(&dev->dev));
+
+	device_lock(&dev->dev);
+
+	if (!device_is_registered(&dev->dev)) {
+		rc = -ENODEV;
+		goto error;
+	}
+
+	if (!dev->polling) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	dev->ops->stop_poll(dev);
+	dev->polling = false;
+
+error:
+	device_unlock(&dev->dev);
+	return rc;
+}
+
+/**
+ * nfc_activate_target - prepare the target for data exchange
+ *
+ * @dev: The nfc device that found the target
+ * @target_idx: index of the target that must be activated
+ * @protocol: nfc protocol that will be used for data exchange
+ */
+int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol)
+{
+	int rc;
+
+	NFC_DBG("dev_name:%s", dev_name(&dev->dev));
+
+	device_lock(&dev->dev);
+
+	if (!device_is_registered(&dev->dev)) {
+		rc = -ENODEV;
+		goto error;
+	}
+
+	rc = dev->ops->activate_target(dev, target_idx, protocol);
+
+error:
+	device_unlock(&dev->dev);
+	return rc;
+}
+
+/**
+ * nfc_deactivate_target - deactivate a nfc target
+ *
+ * @dev: The nfc device that found the target
+ * @target_idx: index of the target that must be deactivated
+ */
+int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx)
+{
+	int rc = 0;
+
+	NFC_DBG("dev_name:%s", dev_name(&dev->dev));
+
+	device_lock(&dev->dev);
+
+	if (!device_is_registered(&dev->dev)) {
+		rc = -ENODEV;
+		goto error;
+	}
+
+	dev->ops->deactivate_target(dev, target_idx);
+
+error:
+	device_unlock(&dev->dev);
+	return rc;
+}
+
+/**
+ * nfc_data_exchange - transceive data
+ *
+ * @dev: The nfc device that found the target
+ * @target_idx: index of the target
+ * @skb: data to be sent
+ * @cb: callback called when the response is received
+ * @cb_context: parameter for the callback function
+ *
+ * The user must wait for the callback before calling this function again.
+ */
+int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx,
+					struct sk_buff *skb,
+					data_exchange_cb_t cb,
+					void *cb_context)
+{
+	int rc;
+
+	NFC_DBG("dev_name:%s", dev_name(&dev->dev));
+
+	device_lock(&dev->dev);
+
+	if (!device_is_registered(&dev->dev)) {
+		rc = -ENODEV;
+		kfree_skb(skb);
+		goto error;
+	}
+
+	rc = dev->ops->data_exchange(dev, target_idx, skb, cb, cb_context);
+
+error:
+	device_unlock(&dev->dev);
+	return rc;
+}
+
+/**
+ * nfc_alloc_skb - allocate a skb for data exchange responses
+ *
+ * @size: size to allocate
+ * @gfp: gfp flags
+ */
+struct sk_buff *nfc_alloc_skb(unsigned int size, gfp_t gfp)
+{
+	struct sk_buff *skb;
+	unsigned int total_size;
+
+	total_size = size + 1;
+	skb = alloc_skb(total_size, gfp);
+
+	if (skb)
+		skb_reserve(skb, 1);
+
+	return skb;
+}
+EXPORT_SYMBOL(nfc_alloc_skb);
+
+static void nfc_release(struct device *d)
+{
+	struct nfc_dev *dev = to_nfc_dev(d);
+
+	NFC_DBG("dev_name:%s", dev_name(&dev->dev));
+
+	kfree(dev);
+}
+
+struct class nfc_class = {
+	.name = "nfc",
+	.dev_release = nfc_release,
+};
+EXPORT_SYMBOL(nfc_class);
+
+static int match_idx(struct device *d, void *data)
+{
+	struct nfc_dev *dev = to_nfc_dev(d);
+	unsigned *idx = data;
+
+	return dev->idx == *idx;
+}
+
+struct nfc_dev *nfc_get_device(unsigned idx)
+{
+	struct device *d;
+
+	d = class_find_device(&nfc_class, NULL, &idx, match_idx);
+	if (!d)
+		return NULL;
+
+	return to_nfc_dev(d);
+}
+
+/**
+ * nfc_allocate_device - allocate a new nfc device
+ *
+ * @ops: device operations
+ * @supported_protocols: NFC protocols supported by the device
+ */
+struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
+					u32 supported_protocols)
+{
+	static atomic_t dev_no = ATOMIC_INIT(0);
+	struct nfc_dev *dev;
+
+	if (!ops->start_poll || !ops->stop_poll || !ops->activate_target ||
+		!ops->deactivate_target || !ops->data_exchange)
+		return NULL;
+
+	if (!supported_protocols)
+		return NULL;
+
+	dev = kzalloc(sizeof(struct nfc_dev), GFP_KERNEL);
+	if (!dev)
+		return NULL;
+
+	dev->dev.class = &nfc_class;
+	dev->idx = atomic_inc_return(&dev_no) - 1;
+	dev_set_name(&dev->dev, "nfc%d", dev->idx);
+	device_initialize(&dev->dev);
+
+	dev->ops = ops;
+	dev->supported_protocols = supported_protocols;
+
+	return dev;
+}
+EXPORT_SYMBOL(nfc_allocate_device);
+
+/**
+ * nfc_register_device - register a nfc device in the nfc subsystem
+ *
+ * @dev: The nfc device to register
+ */
+int nfc_register_device(struct nfc_dev *dev)
+{
+	int rc;
+
+	NFC_DBG("dev_name:%s", dev_name(&dev->dev));
+
+	mutex_lock(&nfc_devlist_mutex);
+	nfc_devlist_generation++;
+	rc = device_add(&dev->dev);
+	mutex_unlock(&nfc_devlist_mutex);
+
+	return rc;
+}
+EXPORT_SYMBOL(nfc_register_device);
+
+/**
+ * nfc_unregister_device - unregister a nfc device in the nfc subsystem
+ *
+ * @dev: The nfc device to unregister
+ */
+void nfc_unregister_device(struct nfc_dev *dev)
+{
+	NFC_DBG("dev_name:%s", dev_name(&dev->dev));
+
+	mutex_lock(&nfc_devlist_mutex);
+	nfc_devlist_generation++;
+
+	/* lock to avoid unregistering a device while an operation
+	   is in progress */
+	device_lock(&dev->dev);
+	device_del(&dev->dev);
+	device_unlock(&dev->dev);
+
+	mutex_unlock(&nfc_devlist_mutex);
+}
+EXPORT_SYMBOL(nfc_unregister_device);
+
+static int __init nfc_init(void)
+{
+	NFC_INFO("NFC Core ver %s", VERSION);
+
+	return class_register(&nfc_class);
+}
+
+static void __exit nfc_exit(void)
+{
+	class_unregister(&nfc_class);
+}
+
+subsys_initcall(nfc_init);
+module_exit(nfc_exit);
+
+MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>");
+MODULE_DESCRIPTION("NFC Core ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
new file mode 100644
index 0000000..b0ff15c
--- /dev/null
+++ b/net/nfc/nfc.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2011 Instituto Nokia de Tecnologia
+ *
+ * Authors:
+ *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+ *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LOCAL_NFC_H
+#define __LOCAL_NFC_H
+
+#include <net/nfc.h>
+
+#define NFC_INFO(fmt, arg...) printk(KERN_INFO "NFC: " fmt "\n", ## arg)
+#define NFC_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n", __func__, ## arg)
+#define NFC_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg)
+
+extern int nfc_devlist_generation;
+extern struct mutex nfc_devlist_mutex;
+
+struct nfc_dev *nfc_get_device(unsigned idx);
+
+static inline void nfc_put_device(struct nfc_dev *dev)
+{
+	put_device(&dev->dev);
+}
+
+static inline void nfc_device_iter_init(struct class_dev_iter *iter)
+{
+	class_dev_iter_init(iter, &nfc_class, NULL, NULL);
+}
+
+static inline struct nfc_dev *nfc_device_iter_next(struct class_dev_iter *iter)
+{
+	struct device *d = class_dev_iter_next(iter);
+	if (!d)
+		return NULL;
+
+	return to_nfc_dev(d);
+}
+
+static inline void nfc_device_iter_exit(struct class_dev_iter *iter)
+{
+	class_dev_iter_exit(iter);
+}
+
+int nfc_start_poll(struct nfc_dev *dev, u32 protocols);
+
+int nfc_stop_poll(struct nfc_dev *dev);
+
+int nfc_activate_target(struct nfc_dev *dev, u32 target_idx, u32 protocol);
+
+int nfc_deactivate_target(struct nfc_dev *dev, u32 target_idx);
+
+int nfc_data_exchange(struct nfc_dev *dev, u32 target_idx,
+					struct sk_buff *skb,
+					data_exchange_cb_t cb,
+					void *cb_context);
+
+#endif /* __LOCAL_NFC_H */
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 2/6] NFC: add nfc generic netlink interface
  2011-06-28 18:20 [PATCH v4 0/6] NFC subsystem Aloisio Almeida Jr
  2011-06-28 18:20 ` [PATCH v4 1/6] NFC: add nfc subsystem core Aloisio Almeida Jr
@ 2011-06-28 18:20 ` Aloisio Almeida Jr
  2011-06-28 18:20 ` [PATCH v4 3/6] NFC: add NFC socket family Aloisio Almeida Jr
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Aloisio Almeida Jr @ 2011-06-28 18:20 UTC (permalink / raw)
  To: linville
  Cc: linux-wireless, sameo, johannes, lauro.venancio, marcio.macedo,
	Waldemar.Rymarkiewicz, padovan, rdunlap, Aloisio Almeida Jr

From: Lauro Ramos Venancio <lauro.venancio@openbossa.org>

The NFC generic netlink interface exports the NFC control operations
to the user space.

Signed-off-by: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
Reviewed-by: Johannes Berg <johannes@sipsolutions.net>
---
 include/linux/nfc.h |  112 +++++++++++
 include/net/nfc.h   |   21 ++
 net/nfc/Makefile    |    2 +-
 net/nfc/core.c      |   91 +++++++++-
 net/nfc/netlink.c   |  537 +++++++++++++++++++++++++++++++++++++++++++++++++++
 net/nfc/nfc.h       |   11 +
 6 files changed, 771 insertions(+), 3 deletions(-)
 create mode 100644 include/linux/nfc.h
 create mode 100644 net/nfc/netlink.c

diff --git a/include/linux/nfc.h b/include/linux/nfc.h
new file mode 100644
index 0000000..1170476
--- /dev/null
+++ b/include/linux/nfc.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011 Instituto Nokia de Tecnologia
+ *
+ * Authors:
+ *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+ *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __LINUX_NFC_H
+#define __LINUX_NFC_H
+
+#define NFC_GENL_NAME "nfc"
+#define NFC_GENL_VERSION 1
+
+#define NFC_GENL_MCAST_EVENT_NAME "events"
+
+/**
+ * enum nfc_commands - supported nfc commands
+ *
+ * @NFC_CMD_UNSPEC: unspecified command
+ *
+ * @NFC_CMD_GET_DEVICE: request information about a device (requires
+ *	%NFC_ATTR_DEVICE_INDEX) or dump request to get a list of all nfc devices
+ * @NFC_CMD_START_POLL: start polling for targets using the given protocols
+ *	(requires %NFC_ATTR_DEVICE_INDEX and %NFC_ATTR_PROTOCOLS)
+ * @NFC_CMD_STOP_POLL: stop polling for targets (requires
+ *	%NFC_ATTR_DEVICE_INDEX)
+ * @NFC_CMD_GET_TARGET: dump all targets found by the previous poll (requires
+ *	%NFC_ATTR_DEVICE_INDEX)
+ * @NFC_EVENT_TARGETS_FOUND: event emitted when a new target is found
+ *	(it sends %NFC_ATTR_DEVICE_INDEX)
+ * @NFC_EVENT_DEVICE_ADDED: event emitted when a new device is registred
+ *	(it sends %NFC_ATTR_DEVICE_NAME, %NFC_ATTR_DEVICE_INDEX and
+ *	%NFC_ATTR_PROTOCOLS)
+ * @NFC_EVENT_DEVICE_REMOVED: event emitted when a device is removed
+ *	(it sends %NFC_ATTR_DEVICE_INDEX)
+ */
+enum nfc_commands {
+	NFC_CMD_UNSPEC,
+	NFC_CMD_GET_DEVICE,
+	NFC_CMD_START_POLL,
+	NFC_CMD_STOP_POLL,
+	NFC_CMD_GET_TARGET,
+	NFC_EVENT_TARGETS_FOUND,
+	NFC_EVENT_DEVICE_ADDED,
+	NFC_EVENT_DEVICE_REMOVED,
+/* private: internal use only */
+	__NFC_CMD_AFTER_LAST
+};
+#define NFC_CMD_MAX (__NFC_CMD_AFTER_LAST - 1)
+
+/**
+ * enum nfc_attrs - supported nfc attributes
+ *
+ * @NFC_ATTR_UNSPEC: unspecified attribute
+ *
+ * @NFC_ATTR_DEVICE_INDEX: index of nfc device
+ * @NFC_ATTR_DEVICE_NAME: device name, max 8 chars
+ * @NFC_ATTR_PROTOCOLS: nfc protocols - bitwise or-ed combination from
+ *	NFC_PROTO_*_MASK constants
+ * @NFC_ATTR_TARGET_INDEX: index of the nfc target
+ * @NFC_ATTR_TARGET_SENS_RES: NFC-A targets extra information such as NFCID
+ * @NFC_ATTR_TARGET_SEL_RES: NFC-A targets extra information (useful if the
+ *	target is not NFC-Forum compliant)
+ */
+enum nfc_attrs {
+	NFC_ATTR_UNSPEC,
+	NFC_ATTR_DEVICE_INDEX,
+	NFC_ATTR_DEVICE_NAME,
+	NFC_ATTR_PROTOCOLS,
+	NFC_ATTR_TARGET_INDEX,
+	NFC_ATTR_TARGET_SENS_RES,
+	NFC_ATTR_TARGET_SEL_RES,
+/* private: internal use only */
+	__NFC_ATTR_AFTER_LAST
+};
+#define NFC_ATTR_MAX (__NFC_ATTR_AFTER_LAST - 1)
+
+#define NFC_DEVICE_NAME_MAXSIZE 8
+
+/* NFC protocols */
+#define NFC_PROTO_JEWEL		1
+#define NFC_PROTO_MIFARE	2
+#define NFC_PROTO_FELICA	3
+#define NFC_PROTO_ISO14443	4
+#define NFC_PROTO_NFC_DEP	5
+
+#define NFC_PROTO_MAX		6
+
+/* NFC protocols masks used in bitsets */
+#define NFC_PROTO_JEWEL_MASK	(1 << NFC_PROTO_JEWEL)
+#define NFC_PROTO_MIFARE_MASK	(1 << NFC_PROTO_MIFARE)
+#define NFC_PROTO_FELICA_MASK	(1 << NFC_PROTO_FELICA)
+#define NFC_PROTO_ISO14443_MASK	(1 << NFC_PROTO_ISO14443)
+#define NFC_PROTO_NFC_DEP_MASK	(1 << NFC_PROTO_NFC_DEP)
+
+#endif /*__LINUX_NFC_H */
diff --git a/include/net/nfc.h b/include/net/nfc.h
index 11d63dc..01a30b3 100644
--- a/include/net/nfc.h
+++ b/include/net/nfc.h
@@ -54,10 +54,28 @@ struct nfc_ops {
 							void *cb_context);
 };
 
+struct nfc_target {
+	u32 idx;
+	u32 supported_protocols;
+	u16 sens_res;
+	u8 sel_res;
+};
+
+struct nfc_genl_data {
+	u32 poll_req_pid;
+	struct mutex genl_data_mutex;
+};
+
 struct nfc_dev {
 	unsigned idx;
+	unsigned target_idx;
+	struct nfc_target *targets;
+	int n_targets;
+	int targets_generation;
+	spinlock_t targets_lock;
 	struct device dev;
 	bool polling;
+	struct nfc_genl_data genl_data;
 	u32 supported_protocols;
 
 	struct nfc_ops *ops;
@@ -128,4 +146,7 @@ static inline const char *nfc_device_name(struct nfc_dev *dev)
 
 struct sk_buff *nfc_alloc_skb(unsigned int size, gfp_t gfp);
 
+int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets,
+							int ntargets);
+
 #endif /* __NET_NFC_H */
diff --git a/net/nfc/Makefile b/net/nfc/Makefile
index 28bee59..fa6fc16 100644
--- a/net/nfc/Makefile
+++ b/net/nfc/Makefile
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_NFC) += nfc.o
 
-nfc-objs := core.o
+nfc-objs := core.o netlink.o
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 992bbc5..a073834 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -212,12 +212,60 @@ struct sk_buff *nfc_alloc_skb(unsigned int size, gfp_t gfp)
 }
 EXPORT_SYMBOL(nfc_alloc_skb);
 
+/**
+ * nfc_targets_found - inform that targets were found
+ *
+ * @dev: The nfc device that found the targets
+ * @targets: array of nfc targets found
+ * @ntargets: targets array size
+ *
+ * The device driver must call this function when one or many nfc targets
+ * are found. After calling this function, the device driver must stop
+ * polling for targets.
+ */
+int nfc_targets_found(struct nfc_dev *dev, struct nfc_target *targets,
+							int n_targets)
+{
+	int i;
+
+	NFC_DBG("dev_name:%s", dev_name(&dev->dev));
+
+	dev->polling = false;
+
+	for (i = 0; i < n_targets; i++)
+		targets[i].idx = dev->target_idx++;
+
+	spin_lock_bh(&dev->targets_lock);
+
+	dev->targets_generation++;
+
+	kfree(dev->targets);
+	dev->targets = kmemdup(targets, n_targets * sizeof(struct nfc_target),
+								GFP_ATOMIC);
+
+	if (!dev->targets) {
+		dev->n_targets = 0;
+		spin_unlock_bh(&dev->targets_lock);
+		return -ENOMEM;
+	}
+
+	dev->n_targets = n_targets;
+	spin_unlock_bh(&dev->targets_lock);
+
+	nfc_genl_targets_found(dev);
+
+	return 0;
+}
+EXPORT_SYMBOL(nfc_targets_found);
+
 static void nfc_release(struct device *d)
 {
 	struct nfc_dev *dev = to_nfc_dev(d);
 
 	NFC_DBG("dev_name:%s", dev_name(&dev->dev));
 
+	nfc_genl_data_exit(&dev->genl_data);
+	kfree(dev->targets);
 	kfree(dev);
 }
 
@@ -277,6 +325,12 @@ struct nfc_dev *nfc_allocate_device(struct nfc_ops *ops,
 	dev->ops = ops;
 	dev->supported_protocols = supported_protocols;
 
+	spin_lock_init(&dev->targets_lock);
+	nfc_genl_data_init(&dev->genl_data);
+
+	/* first generation must not be 0 */
+	dev->targets_generation = 1;
+
 	return dev;
 }
 EXPORT_SYMBOL(nfc_allocate_device);
@@ -297,7 +351,15 @@ int nfc_register_device(struct nfc_dev *dev)
 	rc = device_add(&dev->dev);
 	mutex_unlock(&nfc_devlist_mutex);
 
-	return rc;
+	if (rc < 0)
+		return rc;
+
+	rc = nfc_genl_device_added(dev);
+	if (rc)
+		NFC_DBG("The userspace won't be notified that the device %s was"
+						" added", dev_name(&dev->dev));
+
+	return 0;
 }
 EXPORT_SYMBOL(nfc_register_device);
 
@@ -308,6 +370,8 @@ EXPORT_SYMBOL(nfc_register_device);
  */
 void nfc_unregister_device(struct nfc_dev *dev)
 {
+	int rc;
+
 	NFC_DBG("dev_name:%s", dev_name(&dev->dev));
 
 	mutex_lock(&nfc_devlist_mutex);
@@ -320,18 +384,41 @@ void nfc_unregister_device(struct nfc_dev *dev)
 	device_unlock(&dev->dev);
 
 	mutex_unlock(&nfc_devlist_mutex);
+
+	rc = nfc_genl_device_removed(dev);
+	if (rc)
+		NFC_DBG("The userspace won't be notified that the device %s was"
+					" removed", dev_name(&dev->dev));
 }
 EXPORT_SYMBOL(nfc_unregister_device);
 
 static int __init nfc_init(void)
 {
+	int rc;
+
 	NFC_INFO("NFC Core ver %s", VERSION);
 
-	return class_register(&nfc_class);
+	rc = class_register(&nfc_class);
+	if (rc)
+		return rc;
+
+	rc = nfc_genl_init();
+	if (rc)
+		goto err_genl;
+
+	/* the first generation must not be 0 */
+	nfc_devlist_generation = 1;
+
+	return 0;
+
+err_genl:
+	class_unregister(&nfc_class);
+	return rc;
 }
 
 static void __exit nfc_exit(void)
 {
+	nfc_genl_exit();
 	class_unregister(&nfc_class);
 }
 
diff --git a/net/nfc/netlink.c b/net/nfc/netlink.c
new file mode 100644
index 0000000..b22b4e9
--- /dev/null
+++ b/net/nfc/netlink.c
@@ -0,0 +1,537 @@
+/*
+ * Copyright (C) 2011 Instituto Nokia de Tecnologia
+ *
+ * Authors:
+ *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+ *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <net/genetlink.h>
+#include <linux/nfc.h>
+#include <linux/slab.h>
+
+#include "nfc.h"
+
+static struct genl_multicast_group nfc_genl_event_mcgrp = {
+	.name = NFC_GENL_MCAST_EVENT_NAME,
+};
+
+struct genl_family nfc_genl_family = {
+	.id = GENL_ID_GENERATE,
+	.hdrsize = 0,
+	.name = NFC_GENL_NAME,
+	.version = NFC_GENL_VERSION,
+	.maxattr = NFC_ATTR_MAX,
+};
+
+static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
+	[NFC_ATTR_DEVICE_INDEX] = { .type = NLA_U32 },
+	[NFC_ATTR_DEVICE_NAME] = { .type = NLA_STRING,
+				.len = NFC_DEVICE_NAME_MAXSIZE },
+	[NFC_ATTR_PROTOCOLS] = { .type = NLA_U32 },
+};
+
+static int nfc_genl_send_target(struct sk_buff *msg, struct nfc_target *target,
+					struct netlink_callback *cb, int flags)
+{
+	void *hdr;
+
+	NFC_DBG("");
+
+	hdr = genlmsg_put(msg, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq,
+				&nfc_genl_family, flags, NFC_CMD_GET_TARGET);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
+
+	NLA_PUT_U32(msg, NFC_ATTR_TARGET_INDEX, target->idx);
+	NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS,
+				target->supported_protocols);
+	NLA_PUT_U16(msg, NFC_ATTR_TARGET_SENS_RES, target->sens_res);
+	NLA_PUT_U8(msg, NFC_ATTR_TARGET_SEL_RES, target->sel_res);
+
+	return genlmsg_end(msg, hdr);
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	return -EMSGSIZE;
+}
+
+static struct nfc_dev *__get_device_from_cb(struct netlink_callback *cb)
+{
+	struct nfc_dev *dev;
+	int rc;
+	u32 idx;
+
+	rc = nlmsg_parse(cb->nlh, GENL_HDRLEN + nfc_genl_family.hdrsize,
+						nfc_genl_family.attrbuf,
+						nfc_genl_family.maxattr,
+						nfc_genl_policy);
+	if (rc < 0)
+		return ERR_PTR(rc);
+
+	if (!nfc_genl_family.attrbuf[NFC_ATTR_DEVICE_INDEX])
+		return ERR_PTR(-EINVAL);
+
+	idx = nla_get_u32(nfc_genl_family.attrbuf[NFC_ATTR_DEVICE_INDEX]);
+
+	dev = nfc_get_device(idx);
+	if (!dev)
+		return ERR_PTR(-ENODEV);
+
+	return dev;
+}
+
+static int nfc_genl_dump_targets(struct sk_buff *skb,
+				struct netlink_callback *cb)
+{
+	int i = cb->args[0];
+	struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
+	int rc;
+
+	NFC_DBG("");
+
+	if (!dev) {
+		dev = __get_device_from_cb(cb);
+		if (IS_ERR(dev))
+			return PTR_ERR(dev);
+
+		cb->args[1] = (long) dev;
+	}
+
+	spin_lock_bh(&dev->targets_lock);
+
+	cb->seq = dev->targets_generation;
+
+	while (i < dev->n_targets) {
+		rc = nfc_genl_send_target(skb, &dev->targets[i], cb,
+								NLM_F_MULTI);
+		if (rc < 0)
+			break;
+
+		i++;
+	}
+
+	spin_unlock_bh(&dev->targets_lock);
+
+	cb->args[0] = i;
+
+	return skb->len;
+}
+
+static int nfc_genl_dump_targets_done(struct netlink_callback *cb)
+{
+	struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
+
+	NFC_DBG("");
+
+	if (dev)
+		nfc_put_device(dev);
+
+	return 0;
+}
+
+int nfc_genl_targets_found(struct nfc_dev *dev)
+{
+	struct sk_buff *msg;
+	void *hdr;
+
+	NFC_DBG("");
+
+	dev->genl_data.poll_req_pid = 0;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+				NFC_EVENT_TARGETS_FOUND);
+	if (!hdr)
+		goto free_msg;
+
+	NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
+
+	genlmsg_end(msg, hdr);
+
+	return genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_ATOMIC);
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+free_msg:
+	nlmsg_free(msg);
+	return -EMSGSIZE;
+}
+
+int nfc_genl_device_added(struct nfc_dev *dev)
+{
+	struct sk_buff *msg;
+	void *hdr;
+
+	NFC_DBG("");
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+				NFC_EVENT_DEVICE_ADDED);
+	if (!hdr)
+		goto free_msg;
+
+	NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev));
+	NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
+	NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols);
+
+	genlmsg_end(msg, hdr);
+
+	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+
+	return 0;
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+free_msg:
+	nlmsg_free(msg);
+	return -EMSGSIZE;
+}
+
+int nfc_genl_device_removed(struct nfc_dev *dev)
+{
+	struct sk_buff *msg;
+	void *hdr;
+
+	NFC_DBG("");
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg)
+		return -ENOMEM;
+
+	hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
+				NFC_EVENT_DEVICE_REMOVED);
+	if (!hdr)
+		goto free_msg;
+
+	NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
+
+	genlmsg_end(msg, hdr);
+
+	genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
+
+	return 0;
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+free_msg:
+	nlmsg_free(msg);
+	return -EMSGSIZE;
+}
+
+static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
+						u32 pid, u32 seq,
+						struct netlink_callback *cb,
+						int flags)
+{
+	void *hdr;
+
+	NFC_DBG("");
+
+	hdr = genlmsg_put(msg, pid, seq, &nfc_genl_family, flags,
+							NFC_CMD_GET_DEVICE);
+	if (!hdr)
+		return -EMSGSIZE;
+
+	if (cb)
+		genl_dump_check_consistent(cb, hdr, &nfc_genl_family);
+
+	NLA_PUT_STRING(msg, NFC_ATTR_DEVICE_NAME, nfc_device_name(dev));
+	NLA_PUT_U32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx);
+	NLA_PUT_U32(msg, NFC_ATTR_PROTOCOLS, dev->supported_protocols);
+
+	return genlmsg_end(msg, hdr);
+
+nla_put_failure:
+	genlmsg_cancel(msg, hdr);
+	return -EMSGSIZE;
+}
+
+static int nfc_genl_dump_devices(struct sk_buff *skb,
+				struct netlink_callback *cb)
+{
+	struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
+	struct nfc_dev *dev = (struct nfc_dev *) cb->args[1];
+	bool first_call = false;
+
+	NFC_DBG("");
+
+	if (!iter) {
+		first_call = true;
+		iter = kmalloc(sizeof(struct class_dev_iter), GFP_KERNEL);
+		if (!iter)
+			return -ENOMEM;
+		cb->args[0] = (long) iter;
+	}
+
+	mutex_lock(&nfc_devlist_mutex);
+
+	cb->seq = nfc_devlist_generation;
+
+	if (first_call) {
+		nfc_device_iter_init(iter);
+		dev = nfc_device_iter_next(iter);
+	}
+
+	while (dev) {
+		int rc;
+
+		rc = nfc_genl_send_device(skb, dev, NETLINK_CB(cb->skb).pid,
+							cb->nlh->nlmsg_seq,
+							cb, NLM_F_MULTI);
+		if (rc < 0)
+			break;
+
+		dev = nfc_device_iter_next(iter);
+	}
+
+	mutex_unlock(&nfc_devlist_mutex);
+
+	cb->args[1] = (long) dev;
+
+	return skb->len;
+}
+
+static int nfc_genl_dump_devices_done(struct netlink_callback *cb)
+{
+	struct class_dev_iter *iter = (struct class_dev_iter *) cb->args[0];
+
+	NFC_DBG("");
+
+	nfc_device_iter_exit(iter);
+	kfree(iter);
+
+	return 0;
+}
+
+static int nfc_genl_get_device(struct sk_buff *skb, struct genl_info *info)
+{
+	struct sk_buff *msg;
+	struct nfc_dev *dev;
+	u32 idx;
+	int rc = -ENOBUFS;
+
+	NFC_DBG("");
+
+	if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
+		return -EINVAL;
+
+	idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
+
+	dev = nfc_get_device(idx);
+	if (!dev)
+		return -ENODEV;
+
+	msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+	if (!msg) {
+		rc = -ENOMEM;
+		goto out_putdev;
+	}
+
+	rc = nfc_genl_send_device(msg, dev, info->snd_pid, info->snd_seq,
+								NULL, 0);
+	if (rc < 0)
+		goto out_free;
+
+	nfc_put_device(dev);
+
+	return genlmsg_reply(msg, info);
+
+out_free:
+	nlmsg_free(msg);
+out_putdev:
+	nfc_put_device(dev);
+	return rc;
+}
+
+static int nfc_genl_start_poll(struct sk_buff *skb, struct genl_info *info)
+{
+	struct nfc_dev *dev;
+	int rc;
+	u32 idx;
+	u32 protocols;
+
+	NFC_DBG("");
+
+	if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
+		!info->attrs[NFC_ATTR_PROTOCOLS])
+		return -EINVAL;
+
+	idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
+	protocols = nla_get_u32(info->attrs[NFC_ATTR_PROTOCOLS]);
+
+	dev = nfc_get_device(idx);
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->genl_data.genl_data_mutex);
+
+	rc = nfc_start_poll(dev, protocols);
+	if (!rc)
+		dev->genl_data.poll_req_pid = info->snd_pid;
+
+	mutex_unlock(&dev->genl_data.genl_data_mutex);
+
+	nfc_put_device(dev);
+	return rc;
+}
+
+static int nfc_genl_stop_poll(struct sk_buff *skb, struct genl_info *info)
+{
+	struct nfc_dev *dev;
+	int rc;
+	u32 idx;
+
+	NFC_DBG("");
+
+	if (!info->attrs[NFC_ATTR_DEVICE_INDEX])
+		return -EINVAL;
+
+	idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
+
+	dev = nfc_get_device(idx);
+	if (!dev)
+		return -ENODEV;
+
+	mutex_lock(&dev->genl_data.genl_data_mutex);
+
+	if (dev->genl_data.poll_req_pid != info->snd_pid) {
+		rc = -EBUSY;
+		goto out;
+	}
+
+	rc = nfc_stop_poll(dev);
+	dev->genl_data.poll_req_pid = 0;
+
+out:
+	mutex_unlock(&dev->genl_data.genl_data_mutex);
+	nfc_put_device(dev);
+	return rc;
+}
+
+static struct genl_ops nfc_genl_ops[] = {
+	{
+		.cmd = NFC_CMD_GET_DEVICE,
+		.doit = nfc_genl_get_device,
+		.dumpit = nfc_genl_dump_devices,
+		.done = nfc_genl_dump_devices_done,
+		.policy = nfc_genl_policy,
+	},
+	{
+		.cmd = NFC_CMD_START_POLL,
+		.doit = nfc_genl_start_poll,
+		.policy = nfc_genl_policy,
+	},
+	{
+		.cmd = NFC_CMD_STOP_POLL,
+		.doit = nfc_genl_stop_poll,
+		.policy = nfc_genl_policy,
+	},
+	{
+		.cmd = NFC_CMD_GET_TARGET,
+		.dumpit = nfc_genl_dump_targets,
+		.done = nfc_genl_dump_targets_done,
+		.policy = nfc_genl_policy,
+	},
+};
+
+static int nfc_genl_rcv_nl_event(struct notifier_block *this,
+						unsigned long event, void *ptr)
+{
+	struct netlink_notify *n = ptr;
+	struct class_dev_iter iter;
+	struct nfc_dev *dev;
+
+	if (event != NETLINK_URELEASE || n->protocol != NETLINK_GENERIC)
+		goto out;
+
+	NFC_DBG("NETLINK_URELEASE event from id %d", n->pid);
+
+	nfc_device_iter_init(&iter);
+	dev = nfc_device_iter_next(&iter);
+
+	while (dev) {
+		mutex_lock(&dev->genl_data.genl_data_mutex);
+		if (dev->genl_data.poll_req_pid == n->pid) {
+			nfc_stop_poll(dev);
+			dev->genl_data.poll_req_pid = 0;
+		}
+		mutex_unlock(&dev->genl_data.genl_data_mutex);
+		dev = nfc_device_iter_next(&iter);
+	}
+
+	nfc_device_iter_exit(&iter);
+
+out:
+	return NOTIFY_DONE;
+}
+
+void nfc_genl_data_init(struct nfc_genl_data *genl_data)
+{
+	genl_data->poll_req_pid = 0;
+	mutex_init(&genl_data->genl_data_mutex);
+}
+
+void nfc_genl_data_exit(struct nfc_genl_data *genl_data)
+{
+	mutex_destroy(&genl_data->genl_data_mutex);
+}
+
+static struct notifier_block nl_notifier = {
+	.notifier_call  = nfc_genl_rcv_nl_event,
+};
+
+/**
+ * nfc_genl_init() - Initialize netlink interface
+ *
+ * This initialization function registers the nfc netlink family.
+ */
+int __init nfc_genl_init(void)
+{
+	int rc;
+
+	rc = genl_register_family_with_ops(&nfc_genl_family, nfc_genl_ops,
+					ARRAY_SIZE(nfc_genl_ops));
+	if (rc)
+		return rc;
+
+	rc = genl_register_mc_group(&nfc_genl_family, &nfc_genl_event_mcgrp);
+
+	netlink_register_notifier(&nl_notifier);
+
+	return rc;
+}
+
+/**
+ * nfc_genl_exit() - Deinitialize netlink interface
+ *
+ * This exit function unregisters the nfc netlink family.
+ */
+void nfc_genl_exit(void)
+{
+	netlink_unregister_notifier(&nl_notifier);
+	genl_unregister_family(&nfc_genl_family);
+}
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index b0ff15c..b2eb3de 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -33,6 +33,17 @@
 extern int nfc_devlist_generation;
 extern struct mutex nfc_devlist_mutex;
 
+int __init nfc_genl_init(void);
+void nfc_genl_exit(void);
+
+void nfc_genl_data_init(struct nfc_genl_data *genl_data);
+void nfc_genl_data_exit(struct nfc_genl_data *genl_data);
+
+int nfc_genl_targets_found(struct nfc_dev *dev);
+
+int nfc_genl_device_added(struct nfc_dev *dev);
+int nfc_genl_device_removed(struct nfc_dev *dev);
+
 struct nfc_dev *nfc_get_device(unsigned idx);
 
 static inline void nfc_put_device(struct nfc_dev *dev)
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 3/6] NFC: add NFC socket family
  2011-06-28 18:20 [PATCH v4 0/6] NFC subsystem Aloisio Almeida Jr
  2011-06-28 18:20 ` [PATCH v4 1/6] NFC: add nfc subsystem core Aloisio Almeida Jr
  2011-06-28 18:20 ` [PATCH v4 2/6] NFC: add nfc generic netlink interface Aloisio Almeida Jr
@ 2011-06-28 18:20 ` Aloisio Almeida Jr
  2011-06-28 18:20 ` [PATCH v4 4/6] NFC: add the NFC socket raw protocol Aloisio Almeida Jr
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 17+ messages in thread
From: Aloisio Almeida Jr @ 2011-06-28 18:20 UTC (permalink / raw)
  To: linville
  Cc: linux-wireless, sameo, johannes, lauro.venancio, marcio.macedo,
	Waldemar.Rymarkiewicz, padovan, rdunlap, Aloisio Almeida Jr

Signed-off-by: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
---
 include/linux/nfc.h    |    3 +
 include/linux/socket.h |    4 +-
 net/core/sock.c        |    6 +-
 net/nfc/Makefile       |    2 +-
 net/nfc/af_nfc.c       |   98 ++++++++++++++++++++++++++++++++++++++++++++++++
 net/nfc/core.c         |    7 +++
 net/nfc/nfc.h          |   14 +++++++
 7 files changed, 129 insertions(+), 5 deletions(-)
 create mode 100644 net/nfc/af_nfc.c

diff --git a/include/linux/nfc.h b/include/linux/nfc.h
index 1170476..15f8cb3 100644
--- a/include/linux/nfc.h
+++ b/include/linux/nfc.h
@@ -109,4 +109,7 @@ enum nfc_attrs {
 #define NFC_PROTO_ISO14443_MASK	(1 << NFC_PROTO_ISO14443)
 #define NFC_PROTO_NFC_DEP_MASK	(1 << NFC_PROTO_NFC_DEP)
 
+/* NFC socket protocols */
+#define NFC_SOCKPROTO_MAX	0
+
 #endif /*__LINUX_NFC_H */
diff --git a/include/linux/socket.h b/include/linux/socket.h
index 4ef98e4..e17f822 100644
--- a/include/linux/socket.h
+++ b/include/linux/socket.h
@@ -192,7 +192,8 @@ struct ucred {
 #define AF_IEEE802154	36	/* IEEE802154 sockets		*/
 #define AF_CAIF		37	/* CAIF sockets			*/
 #define AF_ALG		38	/* Algorithm sockets		*/
-#define AF_MAX		39	/* For now.. */
+#define AF_NFC		39	/* NFC sockets			*/
+#define AF_MAX		40	/* For now.. */
 
 /* Protocol families, same as address families. */
 #define PF_UNSPEC	AF_UNSPEC
@@ -234,6 +235,7 @@ struct ucred {
 #define PF_IEEE802154	AF_IEEE802154
 #define PF_CAIF		AF_CAIF
 #define PF_ALG		AF_ALG
+#define PF_NFC		AF_NFC
 #define PF_MAX		AF_MAX
 
 /* Maximum queue length specifiable by listen.  */
diff --git a/net/core/sock.c b/net/core/sock.c
index 6e81978..84d6de8 100644
--- a/net/core/sock.c
+++ b/net/core/sock.c
@@ -158,7 +158,7 @@ static const char *const af_family_key_strings[AF_MAX+1] = {
   "sk_lock-AF_TIPC"  , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV"        ,
   "sk_lock-AF_RXRPC" , "sk_lock-AF_ISDN"     , "sk_lock-AF_PHONET"   ,
   "sk_lock-AF_IEEE802154", "sk_lock-AF_CAIF" , "sk_lock-AF_ALG"      ,
-  "sk_lock-AF_MAX"
+  "sk_lock-AF_NFC"   , "sk_lock-AF_MAX"
 };
 static const char *const af_family_slock_key_strings[AF_MAX+1] = {
   "slock-AF_UNSPEC", "slock-AF_UNIX"     , "slock-AF_INET"     ,
@@ -174,7 +174,7 @@ static const char *const af_family_slock_key_strings[AF_MAX+1] = {
   "slock-AF_TIPC"  , "slock-AF_BLUETOOTH", "slock-AF_IUCV"     ,
   "slock-AF_RXRPC" , "slock-AF_ISDN"     , "slock-AF_PHONET"   ,
   "slock-AF_IEEE802154", "slock-AF_CAIF" , "slock-AF_ALG"      ,
-  "slock-AF_MAX"
+  "slock-AF_NFC"   , "slock-AF_MAX"
 };
 static const char *const af_family_clock_key_strings[AF_MAX+1] = {
   "clock-AF_UNSPEC", "clock-AF_UNIX"     , "clock-AF_INET"     ,
@@ -190,7 +190,7 @@ static const char *const af_family_clock_key_strings[AF_MAX+1] = {
   "clock-AF_TIPC"  , "clock-AF_BLUETOOTH", "clock-AF_IUCV"     ,
   "clock-AF_RXRPC" , "clock-AF_ISDN"     , "clock-AF_PHONET"   ,
   "clock-AF_IEEE802154", "clock-AF_CAIF" , "clock-AF_ALG"      ,
-  "clock-AF_MAX"
+  "clock-AF_NFC"   , "clock-AF_MAX"
 };
 
 /*
diff --git a/net/nfc/Makefile b/net/nfc/Makefile
index fa6fc16..e081fdb 100644
--- a/net/nfc/Makefile
+++ b/net/nfc/Makefile
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_NFC) += nfc.o
 
-nfc-objs := core.o netlink.o
+nfc-objs := core.o netlink.o af_nfc.o
diff --git a/net/nfc/af_nfc.c b/net/nfc/af_nfc.c
new file mode 100644
index 0000000..e982cef
--- /dev/null
+++ b/net/nfc/af_nfc.c
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 Instituto Nokia de Tecnologia
+ *
+ * Authors:
+ *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/nfc.h>
+
+#include "nfc.h"
+
+static DEFINE_RWLOCK(proto_tab_lock);
+static const struct nfc_protocol *proto_tab[NFC_SOCKPROTO_MAX];
+
+static int nfc_sock_create(struct net *net, struct socket *sock, int proto,
+								int kern)
+{
+	int rc = -EPROTONOSUPPORT;
+
+	if (net != &init_net)
+		return -EAFNOSUPPORT;
+
+	if (proto < 0 || proto >= NFC_SOCKPROTO_MAX)
+		return -EINVAL;
+
+	read_lock(&proto_tab_lock);
+	if (proto_tab[proto] &&	try_module_get(proto_tab[proto]->owner)) {
+		rc = proto_tab[proto]->create(net, sock, proto_tab[proto]);
+		module_put(proto_tab[proto]->owner);
+	}
+	read_unlock(&proto_tab_lock);
+
+	return rc;
+}
+
+static struct net_proto_family nfc_sock_family_ops = {
+	.owner  = THIS_MODULE,
+	.family = PF_NFC,
+	.create = nfc_sock_create,
+};
+
+int nfc_proto_register(const struct nfc_protocol *nfc_proto)
+{
+	int rc;
+
+	if (nfc_proto->id < 0 || nfc_proto->id >= NFC_SOCKPROTO_MAX)
+		return -EINVAL;
+
+	rc = proto_register(nfc_proto->proto, 0);
+	if (rc)
+		return rc;
+
+	write_lock(&proto_tab_lock);
+	if (proto_tab[nfc_proto->id])
+		rc = -EBUSY;
+	else
+		proto_tab[nfc_proto->id] = nfc_proto;
+	write_unlock(&proto_tab_lock);
+
+	return rc;
+}
+EXPORT_SYMBOL(nfc_proto_register);
+
+void nfc_proto_unregister(const struct nfc_protocol *nfc_proto)
+{
+	write_lock(&proto_tab_lock);
+	proto_tab[nfc_proto->id] = NULL;
+	write_unlock(&proto_tab_lock);
+
+	proto_unregister(nfc_proto->proto);
+}
+EXPORT_SYMBOL(nfc_proto_unregister);
+
+int __init af_nfc_init(void)
+{
+	return sock_register(&nfc_sock_family_ops);
+}
+
+void af_nfc_exit(void)
+{
+	sock_unregister(PF_NFC);
+}
diff --git a/net/nfc/core.c b/net/nfc/core.c
index a073834..23e7ed7 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -409,8 +409,14 @@ static int __init nfc_init(void)
 	/* the first generation must not be 0 */
 	nfc_devlist_generation = 1;
 
+	rc = af_nfc_init();
+	if (rc)
+		goto err_af_nfc;
+
 	return 0;
 
+err_af_nfc:
+	nfc_genl_exit();
 err_genl:
 	class_unregister(&nfc_class);
 	return rc;
@@ -418,6 +424,7 @@ err_genl:
 
 static void __exit nfc_exit(void)
 {
+	af_nfc_exit();
 	nfc_genl_exit();
 	class_unregister(&nfc_class);
 }
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index b2eb3de..70a1c3a 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -25,11 +25,25 @@
 #define __LOCAL_NFC_H
 
 #include <net/nfc.h>
+#include <net/sock.h>
 
 #define NFC_INFO(fmt, arg...) printk(KERN_INFO "NFC: " fmt "\n", ## arg)
 #define NFC_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n", __func__, ## arg)
 #define NFC_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg)
 
+struct nfc_protocol {
+	int id;
+	struct proto *proto;
+	struct module *owner;
+	int (*create)(struct net *net, struct socket *sock,
+			const struct nfc_protocol *nfc_proto);
+};
+
+int __init af_nfc_init(void);
+void af_nfc_exit(void);
+int nfc_proto_register(const struct nfc_protocol *nfc_proto);
+void nfc_proto_unregister(const struct nfc_protocol *nfc_proto);
+
 extern int nfc_devlist_generation;
 extern struct mutex nfc_devlist_mutex;
 
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 4/6] NFC: add the NFC socket raw protocol
  2011-06-28 18:20 [PATCH v4 0/6] NFC subsystem Aloisio Almeida Jr
                   ` (2 preceding siblings ...)
  2011-06-28 18:20 ` [PATCH v4 3/6] NFC: add NFC socket family Aloisio Almeida Jr
@ 2011-06-28 18:20 ` Aloisio Almeida Jr
  2011-06-28 18:20 ` [PATCH v4 5/6] NFC: pn533: add NXP pn533 nfc device driver Aloisio Almeida Jr
  2011-06-28 18:20 ` [PATCH v4 6/6] NFC: add Documentation/networking/nfc.txt Aloisio Almeida Jr
  5 siblings, 0 replies; 17+ messages in thread
From: Aloisio Almeida Jr @ 2011-06-28 18:20 UTC (permalink / raw)
  To: linville
  Cc: linux-wireless, sameo, johannes, lauro.venancio, marcio.macedo,
	Waldemar.Rymarkiewicz, padovan, rdunlap, Aloisio Almeida Jr

From: Lauro Ramos Venancio <lauro.venancio@openbossa.org>

This socket protocol is used to perform data exchange with NFC
targets.

Signed-off-by: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 include/linux/nfc.h |   13 ++-
 net/nfc/Makefile    |    2 +-
 net/nfc/core.c      |    7 +
 net/nfc/nfc.h       |   14 ++
 net/nfc/rawsock.c   |  351 +++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 385 insertions(+), 2 deletions(-)
 create mode 100644 net/nfc/rawsock.c

diff --git a/include/linux/nfc.h b/include/linux/nfc.h
index 15f8cb3..330a4c5 100644
--- a/include/linux/nfc.h
+++ b/include/linux/nfc.h
@@ -24,6 +24,9 @@
 #ifndef __LINUX_NFC_H
 #define __LINUX_NFC_H
 
+#include <linux/types.h>
+#include <linux/socket.h>
+
 #define NFC_GENL_NAME "nfc"
 #define NFC_GENL_VERSION 1
 
@@ -109,7 +112,15 @@ enum nfc_attrs {
 #define NFC_PROTO_ISO14443_MASK	(1 << NFC_PROTO_ISO14443)
 #define NFC_PROTO_NFC_DEP_MASK	(1 << NFC_PROTO_NFC_DEP)
 
+struct sockaddr_nfc {
+	sa_family_t sa_family;
+	__u32 dev_idx;
+	__u32 target_idx;
+	__u32 nfc_protocol;
+};
+
 /* NFC socket protocols */
-#define NFC_SOCKPROTO_MAX	0
+#define NFC_SOCKPROTO_RAW	0
+#define NFC_SOCKPROTO_MAX	1
 
 #endif /*__LINUX_NFC_H */
diff --git a/net/nfc/Makefile b/net/nfc/Makefile
index e081fdb..16250c3 100644
--- a/net/nfc/Makefile
+++ b/net/nfc/Makefile
@@ -4,4 +4,4 @@
 
 obj-$(CONFIG_NFC) += nfc.o
 
-nfc-objs := core.o netlink.o af_nfc.o
+nfc-objs := core.o netlink.o af_nfc.o rawsock.o
diff --git a/net/nfc/core.c b/net/nfc/core.c
index 23e7ed7..259dd43 100644
--- a/net/nfc/core.c
+++ b/net/nfc/core.c
@@ -409,6 +409,10 @@ static int __init nfc_init(void)
 	/* the first generation must not be 0 */
 	nfc_devlist_generation = 1;
 
+	rc = rawsock_init();
+	if (rc)
+		goto err_rawsock;
+
 	rc = af_nfc_init();
 	if (rc)
 		goto err_af_nfc;
@@ -416,6 +420,8 @@ static int __init nfc_init(void)
 	return 0;
 
 err_af_nfc:
+	rawsock_exit();
+err_rawsock:
 	nfc_genl_exit();
 err_genl:
 	class_unregister(&nfc_class);
@@ -425,6 +431,7 @@ err_genl:
 static void __exit nfc_exit(void)
 {
 	af_nfc_exit();
+	rawsock_exit();
 	nfc_genl_exit();
 	class_unregister(&nfc_class);
 }
diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
index 70a1c3a..66c520e 100644
--- a/net/nfc/nfc.h
+++ b/net/nfc/nfc.h
@@ -39,6 +39,20 @@ struct nfc_protocol {
 			const struct nfc_protocol *nfc_proto);
 };
 
+struct nfc_rawsock {
+	struct sock sk;
+	struct nfc_dev *dev;
+	u32 target_idx;
+	struct work_struct tx_work;
+	bool tx_work_scheduled;
+};
+#define nfc_rawsock(sk) ((struct nfc_rawsock *) sk)
+#define to_rawsock_sk(_tx_work) \
+	((struct sock *) container_of(_tx_work, struct nfc_rawsock, tx_work))
+
+int __init rawsock_init(void);
+void rawsock_exit(void);
+
 int __init af_nfc_init(void);
 void af_nfc_exit(void);
 int nfc_proto_register(const struct nfc_protocol *nfc_proto);
diff --git a/net/nfc/rawsock.c b/net/nfc/rawsock.c
new file mode 100644
index 0000000..e588e04
--- /dev/null
+++ b/net/nfc/rawsock.c
@@ -0,0 +1,351 @@
+/*
+ * Copyright (C) 2011 Instituto Nokia de Tecnologia
+ *
+ * Authors:
+ *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <net/tcp_states.h>
+#include <linux/nfc.h>
+
+#include "nfc.h"
+
+static void rawsock_write_queue_purge(struct sock *sk)
+{
+	NFC_DBG("");
+
+	spin_lock_bh(&sk->sk_write_queue.lock);
+	__skb_queue_purge(&sk->sk_write_queue);
+	nfc_rawsock(sk)->tx_work_scheduled = false;
+	spin_unlock_bh(&sk->sk_write_queue.lock);
+}
+
+static void rawsock_report_error(struct sock *sk, int err)
+{
+	NFC_DBG("");
+
+	sk->sk_shutdown = SHUTDOWN_MASK;
+	sk->sk_err = -err;
+	sk->sk_error_report(sk);
+
+	rawsock_write_queue_purge(sk);
+}
+
+static int rawsock_release(struct socket *sock)
+{
+	struct sock *sk = sock->sk;
+
+	NFC_DBG("");
+
+	sock_orphan(sk);
+	sock_put(sk);
+
+	return 0;
+}
+
+static int rawsock_connect(struct socket *sock, struct sockaddr *_addr,
+							int len, int flags)
+{
+	struct sock *sk = sock->sk;
+	struct sockaddr_nfc *addr = (struct sockaddr_nfc *)_addr;
+	struct nfc_dev *dev;
+	int rc = 0;
+
+	NFC_DBG("");
+
+	if (!addr || len < sizeof(struct sockaddr_nfc) ||
+		addr->sa_family != AF_NFC)
+		return -EINVAL;
+
+	lock_sock(sk);
+
+	if (sock->state == SS_CONNECTED) {
+		rc = -EISCONN;
+		goto error;
+	}
+
+	dev = nfc_get_device(addr->dev_idx);
+	if (!dev) {
+		rc = -ENODEV;
+		goto error;
+	}
+
+	if (addr->target_idx > dev->target_idx - 1 ||
+		addr->target_idx < dev->target_idx - dev->n_targets) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	if (addr->target_idx > dev->target_idx - 1 ||
+		addr->target_idx < dev->target_idx - dev->n_targets) {
+		rc = -EINVAL;
+		goto error;
+	}
+
+	rc = nfc_activate_target(dev, addr->target_idx, addr->nfc_protocol);
+	if (rc)
+		goto put_dev;
+
+	nfc_rawsock(sk)->dev = dev;
+	nfc_rawsock(sk)->target_idx = addr->target_idx;
+	sock->state = SS_CONNECTED;
+	sk->sk_state = TCP_ESTABLISHED;
+	sk->sk_state_change(sk);
+
+	release_sock(sk);
+	return 0;
+
+put_dev:
+	nfc_put_device(dev);
+error:
+	release_sock(sk);
+	return rc;
+}
+
+static int rawsock_add_header(struct sk_buff *skb)
+{
+
+	if (skb_cow_head(skb, 1))
+		return -ENOMEM;
+
+	*skb_push(skb, 1) = 0;
+
+	return 0;
+}
+
+static void rawsock_data_exchange_complete(void *context, struct sk_buff *skb,
+								int err)
+{
+	struct sock *sk = (struct sock *) context;
+
+	BUG_ON(in_irq());
+
+	if (err)
+		goto error;
+
+	err = rawsock_add_header(skb);
+	if (err)
+		goto error;
+
+	err = sock_queue_rcv_skb(sk, skb);
+	if (err)
+		goto error;
+
+	spin_lock_bh(&sk->sk_write_queue.lock);
+	if (!skb_queue_empty(&sk->sk_write_queue))
+		schedule_work(&nfc_rawsock(sk)->tx_work);
+	else
+		nfc_rawsock(sk)->tx_work_scheduled = false;
+	spin_unlock_bh(&sk->sk_write_queue.lock);
+
+	sock_put(sk);
+	return;
+
+error:
+	rawsock_report_error(sk, err);
+	sock_put(sk);
+}
+
+static void rawsock_tx_work(struct work_struct *work)
+{
+	struct sock *sk = to_rawsock_sk(work);
+	struct nfc_dev *dev = nfc_rawsock(sk)->dev;
+	u32 target_idx = nfc_rawsock(sk)->target_idx;
+	struct sk_buff *skb;
+	int rc;
+
+	if (sk->sk_shutdown & SEND_SHUTDOWN) {
+		rawsock_write_queue_purge(sk);
+		return;
+	}
+
+	skb = skb_dequeue(&sk->sk_write_queue);
+
+	sock_hold(sk);
+	rc = nfc_data_exchange(dev, target_idx, skb,
+				rawsock_data_exchange_complete, sk);
+	if (rc) {
+		rawsock_report_error(sk, rc);
+		sock_put(sk);
+	}
+}
+
+static int rawsock_sendmsg(struct kiocb *iocb, struct socket *sock,
+					struct msghdr *msg, size_t len)
+{
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb;
+	int rc;
+
+	NFC_DBG("");
+
+	if (msg->msg_namelen)
+		return -EOPNOTSUPP;
+
+	if (sock->state != SS_CONNECTED)
+		return -ENOTCONN;
+
+	skb = sock_alloc_send_skb(sk, len, msg->msg_flags & MSG_DONTWAIT,
+									&rc);
+	if (!skb)
+		return rc;
+
+	rc = memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len);
+	if (rc < 0) {
+		kfree_skb(skb);
+		return rc;
+	}
+
+	spin_lock_bh(&sk->sk_write_queue.lock);
+	__skb_queue_tail(&sk->sk_write_queue, skb);
+	if (!nfc_rawsock(sk)->tx_work_scheduled) {
+		schedule_work(&nfc_rawsock(sk)->tx_work);
+		nfc_rawsock(sk)->tx_work_scheduled = true;
+	}
+	spin_unlock_bh(&sk->sk_write_queue.lock);
+
+	return len;
+}
+
+static int rawsock_recvmsg(struct kiocb *iocb, struct socket *sock,
+				struct msghdr *msg, size_t len, int flags)
+{
+	int noblock = flags & MSG_DONTWAIT;
+	struct sock *sk = sock->sk;
+	struct sk_buff *skb;
+	int copied;
+	int rc;
+
+	NFC_DBG("");
+
+	skb = skb_recv_datagram(sk, flags, noblock, &rc);
+	if (!skb)
+		return rc;
+
+	msg->msg_namelen = 0;
+
+	copied = skb->len;
+	if (len < copied) {
+		msg->msg_flags |= MSG_TRUNC;
+		copied = len;
+	}
+
+	rc = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied);
+
+	skb_free_datagram(sk, skb);
+
+	return rc ? : copied;
+}
+
+
+static const struct proto_ops rawsock_ops = {
+	.family         = PF_NFC,
+	.owner          = THIS_MODULE,
+	.release        = rawsock_release,
+	.bind           = sock_no_bind,
+	.connect        = rawsock_connect,
+	.socketpair     = sock_no_socketpair,
+	.accept         = sock_no_accept,
+	.getname        = sock_no_getname,
+	.poll           = datagram_poll,
+	.ioctl          = sock_no_ioctl,
+	.listen         = sock_no_listen,
+	.shutdown       = sock_no_shutdown,
+	.setsockopt     = sock_no_setsockopt,
+	.getsockopt     = sock_no_getsockopt,
+	.sendmsg        = rawsock_sendmsg,
+	.recvmsg        = rawsock_recvmsg,
+	.mmap           = sock_no_mmap,
+};
+
+static void rawsock_destruct(struct sock *sk)
+{
+	NFC_DBG("");
+
+	if (sk->sk_state == TCP_ESTABLISHED) {
+		nfc_deactivate_target(nfc_rawsock(sk)->dev,
+					nfc_rawsock(sk)->target_idx);
+		nfc_put_device(nfc_rawsock(sk)->dev);
+	}
+
+	skb_queue_purge(&sk->sk_receive_queue);
+
+	if (!sock_flag(sk, SOCK_DEAD)) {
+		NFC_ERR("Freeing alive NFC raw socket %p", sk);
+		return;
+	}
+}
+
+static int rawsock_create(struct net *net, struct socket *sock,
+				const struct nfc_protocol *nfc_proto)
+{
+	struct sock *sk;
+
+	NFC_DBG("");
+
+	if (sock->type != SOCK_SEQPACKET)
+		return -ESOCKTNOSUPPORT;
+
+	sock->ops = &rawsock_ops;
+
+	sk = sk_alloc(net, PF_NFC, GFP_KERNEL, nfc_proto->proto);
+	if (!sk)
+		return -ENOMEM;
+
+	sock_init_data(sock, sk);
+	sk->sk_protocol = nfc_proto->id;
+	sk->sk_destruct = rawsock_destruct;
+	sock->state = SS_UNCONNECTED;
+
+	INIT_WORK(&nfc_rawsock(sk)->tx_work, rawsock_tx_work);
+	nfc_rawsock(sk)->tx_work_scheduled = false;
+
+	return 0;
+}
+
+static struct proto rawsock_proto = {
+	.name     = "NFC_RAW",
+	.owner    = THIS_MODULE,
+	.obj_size = sizeof(struct nfc_rawsock),
+};
+
+static const struct nfc_protocol rawsock_nfc_proto = {
+	.id	  = NFC_SOCKPROTO_RAW,
+	.proto    = &rawsock_proto,
+	.owner    = THIS_MODULE,
+	.create   = rawsock_create
+};
+
+int __init rawsock_init(void)
+{
+	int rc;
+
+	NFC_DBG("");
+
+	rc = nfc_proto_register(&rawsock_nfc_proto);
+
+	return rc;
+}
+
+void rawsock_exit(void)
+{
+	NFC_DBG("");
+
+	nfc_proto_unregister(&rawsock_nfc_proto);
+}
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 5/6] NFC: pn533: add NXP pn533 nfc device driver
  2011-06-28 18:20 [PATCH v4 0/6] NFC subsystem Aloisio Almeida Jr
                   ` (3 preceding siblings ...)
  2011-06-28 18:20 ` [PATCH v4 4/6] NFC: add the NFC socket raw protocol Aloisio Almeida Jr
@ 2011-06-28 18:20 ` Aloisio Almeida Jr
  2011-06-28 18:20 ` [PATCH v4 6/6] NFC: add Documentation/networking/nfc.txt Aloisio Almeida Jr
  5 siblings, 0 replies; 17+ messages in thread
From: Aloisio Almeida Jr @ 2011-06-28 18:20 UTC (permalink / raw)
  To: linville
  Cc: linux-wireless, sameo, johannes, lauro.venancio, marcio.macedo,
	Waldemar.Rymarkiewicz, padovan, rdunlap, Aloisio Almeida Jr

Signed-off-by: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
---
 drivers/nfc/Kconfig  |   10 +
 drivers/nfc/Makefile |    1 +
 drivers/nfc/pn533.c  | 1630 ++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1641 insertions(+), 0 deletions(-)
 create mode 100644 drivers/nfc/pn533.c

diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 7809289..2acff43 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -17,4 +17,14 @@ config PN544_NFC
 	  To compile this driver as a module, choose m here. The module will
 	  be called pn544.
 
+config NFC_PN533
+	tristate "NXP PN533 USB driver"
+	depends on USB
+	help
+	  NXP PN533 USB driver.
+	  This driver provides support for NFC NXP PN533 devices.
+
+	  Say Y here to compile support for PN533 devices into the
+	  kernel or say M to compile it as module (pn533).
+
 endmenu
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index 25296f0..8ef446d 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -3,5 +3,6 @@
 #
 
 obj-$(CONFIG_PN544_NFC)		+= pn544.o
+obj-$(CONFIG_NFC_PN533)		+= pn533.o
 
 ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
new file mode 100644
index 0000000..e860542
--- /dev/null
+++ b/drivers/nfc/pn533.c
@@ -0,0 +1,1630 @@
+/*
+ * Copyright (C) 2011 Instituto Nokia de Tecnologia
+ *
+ * Authors:
+ *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
+ *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the
+ * Free Software Foundation, Inc.,
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/nfc.h>
+#include <linux/netdevice.h>
+#include <net/nfc.h>
+
+#define VERSION "0.1"
+
+#define PN533_VENDOR_ID 0x4CC
+#define PN533_PRODUCT_ID 0x2533
+
+#define SCM_VENDOR_ID 0x4E6
+#define SCL3711_PRODUCT_ID 0x5591
+
+static const struct usb_device_id pn533_table[] = {
+	{ USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID) },
+	{ USB_DEVICE(SCM_VENDOR_ID, SCL3711_PRODUCT_ID) },
+	{ }
+};
+MODULE_DEVICE_TABLE(usb, pn533_table);
+
+/* frame definitions */
+#define PN533_FRAME_TAIL_SIZE 2
+#define PN533_FRAME_SIZE(f) (sizeof(struct pn533_frame) + f->datalen + \
+				PN533_FRAME_TAIL_SIZE)
+#define PN533_FRAME_ACK_SIZE (sizeof(struct pn533_frame) + 1)
+#define PN533_FRAME_CHECKSUM(f) (f->data[f->datalen])
+#define PN533_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
+
+/* start of frame */
+#define PN533_SOF 0x00FF
+
+/* frame identifier: in/out/error */
+#define PN533_FRAME_IDENTIFIER(f) (f->data[0])
+#define PN533_DIR_OUT 0xD4
+#define PN533_DIR_IN 0xD5
+
+/* PN533 Commands */
+#define PN533_FRAME_CMD(f) (f->data[1])
+#define PN533_FRAME_CMD_PARAMS_PTR(f) (&f->data[2])
+#define PN533_FRAME_CMD_PARAMS_LEN(f) (f->datalen - 2)
+
+#define PN533_CMD_GET_FIRMWARE_VERSION 0x02
+#define PN533_CMD_RF_CONFIGURATION 0x32
+#define PN533_CMD_IN_DATA_EXCHANGE 0x40
+#define PN533_CMD_IN_LIST_PASSIVE_TARGET 0x4A
+#define PN533_CMD_IN_ATR 0x50
+#define PN533_CMD_IN_RELEASE 0x52
+
+#define PN533_CMD_RESPONSE(cmd) (cmd + 1)
+
+/* PN533 Return codes */
+#define PN533_CMD_RET_MASK 0x3F
+#define PN533_CMD_MI_MASK 0x40
+#define PN533_CMD_RET_SUCCESS 0x00
+
+struct pn533;
+
+typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg,
+					u8 *params, int params_len);
+
+/* structs for pn533 commands */
+
+/* PN533_CMD_GET_FIRMWARE_VERSION */
+struct pn533_fw_version {
+	u8 ic;
+	u8 ver;
+	u8 rev;
+	u8 support;
+};
+
+/* PN533_CMD_RF_CONFIGURATION */
+#define PN533_CFGITEM_MAX_RETRIES 0x05
+
+#define PN533_CONFIG_MAX_RETRIES_NO_RETRY 0x00
+#define PN533_CONFIG_MAX_RETRIES_ENDLESS 0xFF
+
+struct pn533_config_max_retries {
+	u8 mx_rty_atr;
+	u8 mx_rty_psl;
+	u8 mx_rty_passive_act;
+} __packed;
+
+/* PN533_CMD_IN_LIST_PASSIVE_TARGET */
+
+/* felica commands opcode */
+#define PN533_FELICA_OPC_SENSF_REQ 0
+#define PN533_FELICA_OPC_SENSF_RES 1
+/* felica SENSF_REQ parameters */
+#define PN533_FELICA_SENSF_SC_ALL 0xFFFF
+#define PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE 0
+#define PN533_FELICA_SENSF_RC_SYSTEM_CODE 1
+#define PN533_FELICA_SENSF_RC_ADVANCED_PROTOCOL 2
+
+/* type B initiator_data values */
+#define PN533_TYPE_B_AFI_ALL_FAMILIES 0
+#define PN533_TYPE_B_POLL_METHOD_TIMESLOT 0
+#define PN533_TYPE_B_POLL_METHOD_PROBABILISTIC 1
+
+union pn533_cmd_poll_initdata {
+	struct {
+		u8 afi;
+		u8 polling_method;
+	} __packed type_b;
+	struct {
+		u8 opcode;
+		__be16 sc;
+		u8 rc;
+		u8 tsn;
+	} __packed felica;
+};
+
+/* Poll modulations */
+enum {
+	PN533_POLL_MOD_106KBPS_A,
+	PN533_POLL_MOD_212KBPS_FELICA,
+	PN533_POLL_MOD_424KBPS_FELICA,
+	PN533_POLL_MOD_106KBPS_JEWEL,
+	PN533_POLL_MOD_847KBPS_B,
+
+	__PN533_POLL_MOD_AFTER_LAST,
+};
+#define PN533_POLL_MOD_MAX (__PN533_POLL_MOD_AFTER_LAST - 1)
+
+struct pn533_poll_modulations {
+	struct {
+		u8 maxtg;
+		u8 brty;
+		union pn533_cmd_poll_initdata initiator_data;
+	} __packed data;
+	u8 len;
+};
+
+const struct pn533_poll_modulations poll_mod[] = {
+	[PN533_POLL_MOD_106KBPS_A] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 0,
+		},
+		.len = 2,
+	},
+	[PN533_POLL_MOD_212KBPS_FELICA] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 1,
+			.initiator_data.felica = {
+				.opcode = PN533_FELICA_OPC_SENSF_REQ,
+				.sc = PN533_FELICA_SENSF_SC_ALL,
+				.rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE,
+				.tsn = 0,
+			},
+		},
+		.len = 7,
+	},
+	[PN533_POLL_MOD_424KBPS_FELICA] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 2,
+			.initiator_data.felica = {
+				.opcode = PN533_FELICA_OPC_SENSF_REQ,
+				.sc = PN533_FELICA_SENSF_SC_ALL,
+				.rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE,
+				.tsn = 0,
+			},
+		 },
+		.len = 7,
+	},
+	[PN533_POLL_MOD_106KBPS_JEWEL] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 4,
+		},
+		.len = 2,
+	},
+	[PN533_POLL_MOD_847KBPS_B] = {
+		.data = {
+			.maxtg = 1,
+			.brty = 8,
+			.initiator_data.type_b = {
+				.afi = PN533_TYPE_B_AFI_ALL_FAMILIES,
+				.polling_method =
+					PN533_TYPE_B_POLL_METHOD_TIMESLOT,
+			},
+		},
+		.len = 3,
+	},
+};
+
+/* PN533_CMD_IN_ATR */
+
+struct pn533_cmd_activate_param {
+	u8 tg;
+	u8 next;
+} __packed;
+
+struct pn533_cmd_activate_response {
+	u8 status;
+	u8 nfcid3t[10];
+	u8 didt;
+	u8 bst;
+	u8 brt;
+	u8 to;
+	u8 ppt;
+	/* optional */
+	u8 gt[];
+} __packed;
+
+
+struct pn533 {
+	struct usb_device *udev;
+	struct usb_interface *interface;
+	struct nfc_dev *nfc_dev;
+
+	struct urb *out_urb;
+	int out_maxlen;
+	struct pn533_frame *out_frame;
+
+	struct urb *in_urb;
+	int in_maxlen;
+	struct pn533_frame *in_frame;
+
+	struct tasklet_struct tasklet;
+	struct pn533_frame *tklt_in_frame;
+	int tklt_in_error;
+
+	pn533_cmd_complete_t cmd_complete;
+	void *cmd_complete_arg;
+	struct semaphore cmd_lock;
+	u8 cmd;
+
+	struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1];
+	u8 poll_mod_count;
+	u8 poll_mod_curr;
+	u32 poll_protocols;
+
+	u8 tgt_available_prots;
+	u8 tgt_active_prot;
+};
+
+struct pn533_frame {
+	u8 preamble;
+	__be16 start_frame;
+	u8 datalen;
+	u8 datalen_checksum;
+	u8 data[];
+} __packed;
+
+/* The rule: value + checksum = 0 */
+static inline u8 pn533_checksum(u8 value)
+{
+	return ~value + 1;
+}
+
+/* The rule: sum(data elements) + checksum = 0 */
+static u8 pn533_data_checksum(u8 *data, int datalen)
+{
+	u8 sum = 0;
+	int i;
+
+	for (i = 0; i < datalen; i++)
+		sum += data[i];
+
+	return pn533_checksum(sum);
+}
+
+/**
+ * pn533_tx_frame_ack - create a ack frame
+ * @frame:	The frame to be set as ack
+ *
+ * Ack is different type of standard frame. As a standard frame, it has
+ * preamble and start_frame. However the checksum of this frame must fail,
+ * i.e. datalen + datalen_checksum must NOT be zero. When the checksum test
+ * fails and datalen = 0 and datalen_checksum = 0xFF, the frame is a ack.
+ * After datalen_checksum field, the postamble is placed.
+ */
+static void pn533_tx_frame_ack(struct pn533_frame *frame)
+{
+	frame->preamble = 0;
+	frame->start_frame = cpu_to_be16(PN533_SOF);
+	frame->datalen = 0;
+	frame->datalen_checksum = 0xFF;
+	/* data[0] is used as postamble */
+	frame->data[0] = 0;
+}
+
+static void pn533_tx_frame_init(struct pn533_frame *frame, u8 cmd)
+{
+	frame->preamble = 0;
+	frame->start_frame = cpu_to_be16(PN533_SOF);
+	PN533_FRAME_IDENTIFIER(frame) = PN533_DIR_OUT;
+	PN533_FRAME_CMD(frame) = cmd;
+	frame->datalen = 2;
+}
+
+static void pn533_tx_frame_finish(struct pn533_frame *frame)
+{
+	frame->datalen_checksum = pn533_checksum(frame->datalen);
+
+	PN533_FRAME_CHECKSUM(frame) =
+		pn533_data_checksum(frame->data, frame->datalen);
+
+	PN533_FRAME_POSTAMBLE(frame) = 0;
+}
+
+static bool pn533_rx_frame_is_valid(struct pn533_frame *frame)
+{
+	u8 checksum;
+
+	if (frame->start_frame != cpu_to_be16(PN533_SOF))
+		return false;
+
+	checksum = pn533_checksum(frame->datalen);
+	if (checksum != frame->datalen_checksum)
+		return false;
+
+	checksum = pn533_data_checksum(frame->data, frame->datalen);
+	if (checksum != PN533_FRAME_CHECKSUM(frame))
+		return false;
+
+	return true;
+}
+
+static bool pn533_rx_frame_is_ack(struct pn533_frame *frame)
+{
+	if (frame->start_frame != cpu_to_be16(PN533_SOF))
+		return false;
+
+	if (frame->datalen != 0 || frame->datalen_checksum != 0xFF)
+		return false;
+
+	return true;
+}
+
+static bool pn533_rx_frame_is_cmd_response(struct pn533_frame *frame, u8 cmd)
+{
+	return (PN533_FRAME_CMD(frame) == PN533_CMD_RESPONSE(cmd));
+}
+
+static void pn533_tasklet_cmd_complete(unsigned long arg)
+{
+	struct pn533 *dev = (struct pn533 *) arg;
+	struct pn533_frame *in_frame = dev->tklt_in_frame;
+	int rc;
+
+	if (dev->tklt_in_error)
+		rc = dev->cmd_complete(dev, dev->cmd_complete_arg, NULL,
+							dev->tklt_in_error);
+	else
+		rc = dev->cmd_complete(dev, dev->cmd_complete_arg,
+					PN533_FRAME_CMD_PARAMS_PTR(in_frame),
+					PN533_FRAME_CMD_PARAMS_LEN(in_frame));
+
+	if (rc != -EINPROGRESS)
+		up(&dev->cmd_lock);
+}
+
+static void pn533_recv_response(struct urb *urb)
+{
+	struct pn533 *dev = urb->context;
+	struct pn533_frame *in_frame;
+
+	dev->tklt_in_frame = NULL;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		dev_dbg(&dev->interface->dev, "%s - urb shutting down with "
+					"status: %d", __func__, urb->status);
+		dev->tklt_in_error = urb->status;
+		goto sched_tasklet;
+	default:
+		dev_err(&dev->interface->dev, "%s - nonzero urb status "
+				"received: %d", __func__, urb->status);
+		dev->tklt_in_error = urb->status;
+		goto sched_tasklet;
+	}
+
+	in_frame = dev->in_urb->transfer_buffer;
+
+	if (!pn533_rx_frame_is_valid(in_frame)) {
+		dev_err(&dev->interface->dev, "Received an invalid frame");
+		dev->tklt_in_error = -EIO;
+		goto sched_tasklet;
+	}
+
+	if (!pn533_rx_frame_is_cmd_response(in_frame, dev->cmd)) {
+		dev_err(&dev->interface->dev, "The received frame is not "
+					"response to the last command");
+		dev->tklt_in_error = -EIO;
+		goto sched_tasklet;
+	}
+
+	dev_dbg(&dev->interface->dev, "Received a valid frame");
+	dev->tklt_in_error = 0;
+	dev->tklt_in_frame = in_frame;
+
+sched_tasklet:
+	tasklet_schedule(&dev->tasklet);
+}
+
+static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags)
+{
+	dev->in_urb->complete = pn533_recv_response;
+
+	return usb_submit_urb(dev->in_urb, flags);
+}
+
+static void pn533_recv_ack(struct urb *urb)
+{
+	struct pn533 *dev = urb->context;
+	struct pn533_frame *in_frame;
+	int rc;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		dev_dbg(&dev->interface->dev, "%s - urb shutting down with "
+					"status: %d", __func__, urb->status);
+		dev->tklt_in_error = urb->status;
+		goto sched_tasklet;
+	default:
+		dev_err(&dev->interface->dev, "%s - nonzero urb status "
+				"received: %d", __func__, urb->status);
+		dev->tklt_in_error = urb->status;
+		goto sched_tasklet;
+	}
+
+	in_frame = dev->in_urb->transfer_buffer;
+
+	if (!pn533_rx_frame_is_ack(in_frame)) {
+		dev_err(&dev->interface->dev, "%s - received an invalid ack",
+								__func__);
+		dev->tklt_in_error = -EIO;
+		goto sched_tasklet;
+	}
+
+	dev_dbg(&dev->interface->dev, "Received a valid ack");
+
+	rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC);
+	if (rc) {
+		dev_err(&dev->interface->dev, "%s - usb_submit_urb failed "
+					"with result %d", __func__, rc);
+		dev->tklt_in_error = rc;
+		goto sched_tasklet;
+	}
+
+	return;
+
+sched_tasklet:
+	dev->tklt_in_frame = NULL;
+	tasklet_schedule(&dev->tasklet);
+}
+
+static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags)
+{
+	dev->in_urb->complete = pn533_recv_ack;
+
+	return usb_submit_urb(dev->in_urb, flags);
+}
+
+static int pn533_send_ack(struct pn533 *dev, gfp_t flags)
+{
+	int rc;
+
+	dev_dbg(&dev->interface->dev, "Sending ack");
+
+	pn533_tx_frame_ack(dev->out_frame);
+
+	dev->out_urb->transfer_buffer = dev->out_frame;
+	dev->out_urb->transfer_buffer_length = PN533_FRAME_ACK_SIZE;
+	rc = usb_submit_urb(dev->out_urb, flags);
+
+	return rc;
+}
+
+static int __pn533_send_cmd_frame_async(struct pn533 *dev,
+					struct pn533_frame *out_frame,
+					struct pn533_frame *in_frame,
+					int in_frame_len,
+					pn533_cmd_complete_t cmd_complete,
+					void *arg, gfp_t flags)
+{
+	int rc;
+
+	dev_dbg(&dev->interface->dev, "Sending command 0x%x",
+				PN533_FRAME_CMD(out_frame));
+
+	dev->cmd = PN533_FRAME_CMD(out_frame);
+	dev->cmd_complete = cmd_complete;
+	dev->cmd_complete_arg = arg;
+
+	dev->out_urb->transfer_buffer = out_frame;
+	dev->out_urb->transfer_buffer_length =
+				PN533_FRAME_SIZE(out_frame);
+
+	dev->in_urb->transfer_buffer = in_frame;
+	dev->in_urb->transfer_buffer_length = in_frame_len;
+
+	rc = usb_submit_urb(dev->out_urb, flags);
+	if (rc)
+		return rc;
+
+	rc = pn533_submit_urb_for_ack(dev, flags);
+	if (rc)
+		goto error;
+
+	return 0;
+
+error:
+	usb_unlink_urb(dev->out_urb);
+	return rc;
+}
+
+static int pn533_send_cmd_frame_async(struct pn533 *dev,
+					struct pn533_frame *out_frame,
+					struct pn533_frame *in_frame,
+					int in_frame_len,
+					pn533_cmd_complete_t cmd_complete,
+					void *arg, gfp_t flags)
+{
+	int rc;
+
+	if (down_trylock(&dev->cmd_lock))
+		return -EBUSY;
+
+	rc = __pn533_send_cmd_frame_async(dev, out_frame, in_frame,
+					in_frame_len, cmd_complete, arg, flags);
+	if (rc)
+		goto error;
+
+	return 0;
+error:
+	up(&dev->cmd_lock);
+	return rc;
+}
+
+struct pn533_sync_cmd_response {
+	int rc;
+	struct completion done;
+};
+
+static int pn533_sync_cmd_complete(struct pn533 *dev, void *_arg,
+					u8 *params, int params_len)
+{
+	struct pn533_sync_cmd_response *arg = _arg;
+
+	arg->rc = 0;
+
+	if (params_len < 0) /* error */
+		arg->rc = params_len;
+
+	complete(&arg->done);
+
+	return 0;
+}
+
+static int pn533_send_cmd_frame_sync(struct pn533 *dev,
+						struct pn533_frame *out_frame,
+						struct pn533_frame *in_frame,
+						int in_frame_len)
+{
+	int rc;
+	struct pn533_sync_cmd_response arg;
+
+	init_completion(&arg.done);
+
+	rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, in_frame_len,
+				pn533_sync_cmd_complete, &arg, GFP_KERNEL);
+	if (rc)
+		return rc;
+
+	wait_for_completion(&arg.done);
+
+	return arg.rc;
+}
+
+static void pn533_send_complete(struct urb *urb)
+{
+	struct pn533 *dev = urb->context;
+
+	switch (urb->status) {
+	case 0:
+		/* success */
+		break;
+	case -ECONNRESET:
+	case -ENOENT:
+	case -ESHUTDOWN:
+		dev_dbg(&dev->interface->dev, "%s - urb shutting down with "
+			"status: %d", __func__, urb->status);
+		break;
+	default:
+		dev_dbg(&dev->interface->dev, "%s - nonzero urb status "
+				"received: %d", __func__, urb->status);
+	}
+}
+
+struct pn533_target_type_a {
+	__be16 sens_res;
+	u8 sel_res;
+	u8 nfcid_len;
+	u8 nfcid_data[];
+} __packed;
+
+
+#define PN533_TYPE_A_SENS_RES_NFCID1(x) ((u8)((be16_to_cpu(x) & 0x00C0) >> 6))
+#define PN533_TYPE_A_SENS_RES_SSD(x) ((u8)((be16_to_cpu(x) & 0x001F) >> 0))
+#define PN533_TYPE_A_SENS_RES_PLATCONF(x) ((u8)((be16_to_cpu(x) & 0x0F00) >> 8))
+
+#define PN533_TYPE_A_SENS_RES_SSD_JEWEL 0x00
+#define PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL 0x0C
+
+#define PN533_TYPE_A_SEL_PROT(x) (((x) & 0x60) >> 5)
+#define PN533_TYPE_A_SEL_CASCADE(x) (((x) & 0x04) >> 2)
+
+#define PN533_TYPE_A_SEL_PROT_MIFARE 0
+#define PN533_TYPE_A_SEL_PROT_ISO14443 1
+#define PN533_TYPE_A_SEL_PROT_DEP 2
+#define PN533_TYPE_A_SEL_PROT_ISO14443_DEP 3
+
+static bool pn533_target_type_a_is_valid(struct pn533_target_type_a *type_a,
+							int target_data_len)
+{
+	u8 ssd;
+	u8 platconf;
+
+	if (target_data_len < sizeof(struct pn533_target_type_a))
+		return false;
+
+	/* The lenght check of nfcid[] and ats[] are not being performed because
+	   the values are not being used */
+
+	/* Requirement 4.6.3.3 from NFC Forum Digital Spec */
+	ssd = PN533_TYPE_A_SENS_RES_SSD(type_a->sens_res);
+	platconf = PN533_TYPE_A_SENS_RES_PLATCONF(type_a->sens_res);
+
+	if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+			platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
+			(ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+			platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
+		return false;
+
+	/* Requirements 4.8.2.1, 4.8.2.3, 4.8.2.5 and 4.8.2.7 from NFC Forum */
+	if (PN533_TYPE_A_SEL_CASCADE(type_a->sel_res) != 0)
+		return false;
+
+	return true;
+}
+
+static int pn533_target_found_type_a(struct nfc_target *nfc_tgt, u8 *tgt_data,
+							int tgt_data_len)
+{
+	struct pn533_target_type_a *tgt_type_a;
+
+	tgt_type_a = (struct pn533_target_type_a *) tgt_data;
+
+	if (!pn533_target_type_a_is_valid(tgt_type_a, tgt_data_len))
+		return -EPROTO;
+
+	switch (PN533_TYPE_A_SEL_PROT(tgt_type_a->sel_res)) {
+	case PN533_TYPE_A_SEL_PROT_MIFARE:
+		nfc_tgt->supported_protocols = NFC_PROTO_MIFARE_MASK;
+		break;
+	case PN533_TYPE_A_SEL_PROT_ISO14443:
+		nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK;
+		break;
+	case PN533_TYPE_A_SEL_PROT_DEP:
+		nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+		break;
+	case PN533_TYPE_A_SEL_PROT_ISO14443_DEP:
+		nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK |
+							NFC_PROTO_NFC_DEP_MASK;
+		break;
+	}
+
+	nfc_tgt->sens_res = be16_to_cpu(tgt_type_a->sens_res);
+	nfc_tgt->sel_res = tgt_type_a->sel_res;
+
+	return 0;
+}
+
+struct pn533_target_felica {
+	u8 pol_res;
+	u8 opcode;
+	u8 nfcid2[8];
+	u8 pad[8];
+	/* optional */
+	u8 syst_code[];
+} __packed;
+
+#define PN533_FELICA_SENSF_NFCID2_DEP_B1 0x01
+#define PN533_FELICA_SENSF_NFCID2_DEP_B2 0xFE
+
+static bool pn533_target_felica_is_valid(struct pn533_target_felica *felica,
+							int target_data_len)
+{
+	if (target_data_len < sizeof(struct pn533_target_felica))
+		return false;
+
+	if (felica->opcode != PN533_FELICA_OPC_SENSF_RES)
+		return false;
+
+	return true;
+}
+
+static int pn533_target_found_felica(struct nfc_target *nfc_tgt, u8 *tgt_data,
+							int tgt_data_len)
+{
+	struct pn533_target_felica *tgt_felica;
+
+	tgt_felica = (struct pn533_target_felica *) tgt_data;
+
+	if (!pn533_target_felica_is_valid(tgt_felica, tgt_data_len))
+		return -EPROTO;
+
+	if (tgt_felica->nfcid2[0] == PN533_FELICA_SENSF_NFCID2_DEP_B1 &&
+					tgt_felica->nfcid2[1] ==
+					PN533_FELICA_SENSF_NFCID2_DEP_B2)
+		nfc_tgt->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+	else
+		nfc_tgt->supported_protocols = NFC_PROTO_FELICA_MASK;
+
+	return 0;
+}
+
+struct pn533_target_jewel {
+	__be16 sens_res;
+	u8 jewelid[4];
+} __packed;
+
+static bool pn533_target_jewel_is_valid(struct pn533_target_jewel *jewel,
+							int target_data_len)
+{
+	u8 ssd;
+	u8 platconf;
+
+	if (target_data_len < sizeof(struct pn533_target_jewel))
+		return false;
+
+	/* Requirement 4.6.3.3 from NFC Forum Digital Spec */
+	ssd = PN533_TYPE_A_SENS_RES_SSD(jewel->sens_res);
+	platconf = PN533_TYPE_A_SENS_RES_PLATCONF(jewel->sens_res);
+
+	if ((ssd == PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+			platconf != PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL) ||
+			(ssd != PN533_TYPE_A_SENS_RES_SSD_JEWEL &&
+			platconf == PN533_TYPE_A_SENS_RES_PLATCONF_JEWEL))
+		return false;
+
+	return true;
+}
+
+static int pn533_target_found_jewel(struct nfc_target *nfc_tgt, u8 *tgt_data,
+							int tgt_data_len)
+{
+	struct pn533_target_jewel *tgt_jewel;
+
+	tgt_jewel = (struct pn533_target_jewel *) tgt_data;
+
+	if (!pn533_target_jewel_is_valid(tgt_jewel, tgt_data_len))
+		return -EPROTO;
+
+	nfc_tgt->supported_protocols = NFC_PROTO_JEWEL_MASK;
+	nfc_tgt->sens_res = be16_to_cpu(tgt_jewel->sens_res);
+
+	return 0;
+}
+
+struct pn533_type_b_prot_info {
+	u8 bitrate;
+	u8 fsci_type;
+	u8 fwi_adc_fo;
+} __packed;
+
+#define PN533_TYPE_B_PROT_FCSI(x) (((x) & 0xF0) >> 4)
+#define PN533_TYPE_B_PROT_TYPE(x) (((x) & 0x0F) >> 0)
+#define PN533_TYPE_B_PROT_TYPE_RFU_MASK 0x8
+
+struct pn533_type_b_sens_res {
+	u8 opcode;
+	u8 nfcid[4];
+	u8 appdata[4];
+	struct pn533_type_b_prot_info prot_info;
+} __packed;
+
+#define PN533_TYPE_B_OPC_SENSB_RES 0x50
+
+struct pn533_target_type_b {
+	struct pn533_type_b_sens_res sensb_res;
+	u8 attrib_res_len;
+	u8 attrib_res[];
+} __packed;
+
+static bool pn533_target_type_b_is_valid(struct pn533_target_type_b *type_b,
+							int target_data_len)
+{
+	if (target_data_len < sizeof(struct pn533_target_type_b))
+		return false;
+
+	if (type_b->sensb_res.opcode != PN533_TYPE_B_OPC_SENSB_RES)
+		return false;
+
+	if (PN533_TYPE_B_PROT_TYPE(type_b->sensb_res.prot_info.fsci_type) &
+						PN533_TYPE_B_PROT_TYPE_RFU_MASK)
+		return false;
+
+	return true;
+}
+
+static int pn533_target_found_type_b(struct nfc_target *nfc_tgt, u8 *tgt_data,
+							int tgt_data_len)
+{
+	struct pn533_target_type_b *tgt_type_b;
+
+	tgt_type_b = (struct pn533_target_type_b *) tgt_data;
+
+	if (!pn533_target_type_b_is_valid(tgt_type_b, tgt_data_len))
+		return -EPROTO;
+
+	nfc_tgt->supported_protocols = NFC_PROTO_ISO14443_MASK;
+
+	return 0;
+}
+
+struct pn533_poll_response {
+	u8 nbtg;
+	u8 tg;
+	u8 target_data[];
+} __packed;
+
+static int pn533_target_found(struct pn533 *dev,
+			struct pn533_poll_response *resp, int resp_len)
+{
+	int target_data_len;
+	struct nfc_target nfc_tgt;
+	int rc;
+
+	dev_dbg(&dev->interface->dev, "%s - Target found - modulation=%d",
+						__func__, dev->poll_mod_curr);
+
+	if (resp->tg != 1)
+		return -EPROTO;
+
+	target_data_len = resp_len - sizeof(struct pn533_poll_response);
+
+	switch (dev->poll_mod_curr) {
+	case PN533_POLL_MOD_106KBPS_A:
+		rc = pn533_target_found_type_a(&nfc_tgt, resp->target_data,
+							target_data_len);
+		break;
+	case PN533_POLL_MOD_212KBPS_FELICA:
+	case PN533_POLL_MOD_424KBPS_FELICA:
+		rc = pn533_target_found_felica(&nfc_tgt, resp->target_data,
+							target_data_len);
+		break;
+	case PN533_POLL_MOD_106KBPS_JEWEL:
+		rc = pn533_target_found_jewel(&nfc_tgt, resp->target_data,
+							target_data_len);
+		break;
+	case PN533_POLL_MOD_847KBPS_B:
+		rc = pn533_target_found_type_b(&nfc_tgt, resp->target_data,
+							target_data_len);
+		break;
+	default:
+		dev_err(&dev->interface->dev, "%s - Unknown current poll"
+						" modulation", __func__);
+		return -EPROTO;
+	}
+
+	if (rc)
+		return rc;
+
+	if (!(nfc_tgt.supported_protocols & dev->poll_protocols)) {
+		dev_dbg(&dev->interface->dev, "%s - The target found does not"
+					" have the desired protocol", __func__);
+		return -EAGAIN;
+	}
+
+	dev_dbg(&dev->interface->dev, "%s - Target found - protocols=0x%x",
+				 __func__, nfc_tgt.supported_protocols);
+
+	dev->tgt_available_prots = nfc_tgt.supported_protocols;
+
+	nfc_targets_found(dev->nfc_dev, &nfc_tgt, 1);
+
+	return 0;
+}
+
+static void pn533_poll_reset_mod_list(struct pn533 *dev)
+{
+	dev->poll_mod_count = 0;
+}
+
+static void pn533_poll_add_mod(struct pn533 *dev, u8 mod_index)
+{
+	dev->poll_mod_active[dev->poll_mod_count] =
+		(struct pn533_poll_modulations *) &poll_mod[mod_index];
+	dev->poll_mod_count++;
+}
+
+static void pn533_poll_create_mod_list(struct pn533 *dev, u32 protocols)
+{
+	pn533_poll_reset_mod_list(dev);
+
+	if (protocols & NFC_PROTO_MIFARE_MASK
+					|| protocols & NFC_PROTO_ISO14443_MASK
+					|| protocols & NFC_PROTO_NFC_DEP_MASK)
+		pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_A);
+
+	if (protocols & NFC_PROTO_FELICA_MASK
+					|| protocols & NFC_PROTO_NFC_DEP_MASK) {
+		pn533_poll_add_mod(dev, PN533_POLL_MOD_212KBPS_FELICA);
+		pn533_poll_add_mod(dev, PN533_POLL_MOD_424KBPS_FELICA);
+	}
+
+	if (protocols & NFC_PROTO_JEWEL_MASK)
+		pn533_poll_add_mod(dev, PN533_POLL_MOD_106KBPS_JEWEL);
+
+	if (protocols & NFC_PROTO_ISO14443_MASK)
+		pn533_poll_add_mod(dev, PN533_POLL_MOD_847KBPS_B);
+}
+
+static void pn533_start_poll_frame(struct pn533_frame *frame,
+					struct pn533_poll_modulations *mod)
+{
+
+	pn533_tx_frame_init(frame, PN533_CMD_IN_LIST_PASSIVE_TARGET);
+
+	memcpy(PN533_FRAME_CMD_PARAMS_PTR(frame), &mod->data, mod->len);
+	frame->datalen += mod->len;
+
+	pn533_tx_frame_finish(frame);
+}
+
+static int pn533_start_poll_complete(struct pn533 *dev, void *arg,
+						u8 *params, int params_len)
+{
+	struct pn533_poll_response *resp;
+	struct pn533_poll_modulations *next_mod;
+	int rc;
+
+	if (params_len == -ENOENT) {
+		dev_dbg(&dev->interface->dev, "%s - poll has been stopped",
+								__func__);
+		goto stop_poll;
+	}
+
+	if (params_len < 0) {
+		dev_err(&dev->interface->dev, "%s - error %d when running poll",
+							__func__, params_len);
+		goto stop_poll;
+	}
+
+	resp = (struct pn533_poll_response *) params;
+	if (resp->nbtg) {
+		rc = pn533_target_found(dev, resp, params_len);
+
+		/* We must stop the poll after a valid target found */
+		if (rc == 0)
+			goto stop_poll;
+
+		if (rc != -EAGAIN)
+			dev_err(&dev->interface->dev, "%s - The target found is"
+						" not valid, continue to poll",
+						__func__);
+	}
+
+	dev->poll_mod_curr = (dev->poll_mod_curr + 1) % dev->poll_mod_count;
+
+	next_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+	dev_dbg(&dev->interface->dev, "%s - poll next modulation (0x%x)",
+						__func__, dev->poll_mod_curr);
+
+	pn533_start_poll_frame(dev->out_frame, next_mod);
+
+	/* Don't need to down the semaphore again */
+	rc = __pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
+				dev->in_maxlen, pn533_start_poll_complete,
+				NULL, GFP_ATOMIC);
+
+	if (rc == -EPERM) {
+		dev_dbg(&dev->interface->dev, "%s - cannot poll next modulation"
+				" because poll has been stopped", __func__);
+		goto stop_poll;
+	}
+
+	if (rc) {
+		dev_err(&dev->interface->dev, "%s - error %d when trying to"
+				" poll next modulation", __func__, rc);
+		goto stop_poll;
+	}
+
+	/* Inform caller function to do not up the semaphore */
+	return -EINPROGRESS;
+
+stop_poll:
+	pn533_poll_reset_mod_list(dev);
+	dev->poll_protocols = 0;
+	return 0;
+}
+
+static int pn533_start_poll(struct nfc_dev *nfc_dev, u32 protocols)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+	struct pn533_poll_modulations *start_mod;
+	int rc;
+
+	dev_dbg(&dev->interface->dev, "%s - protocols=0x%x", __func__,
+								protocols);
+
+	if (dev->poll_mod_count) {
+		dev_err(&dev->interface->dev, "%s - "
+				"poll already active", __func__);
+		return -EBUSY;
+	}
+
+	if (dev->tgt_active_prot) {
+		dev_err(&dev->interface->dev, "%s - cannot poll with a target"
+						" already activated", __func__);
+		return -EBUSY;
+	}
+
+	pn533_poll_create_mod_list(dev, protocols);
+
+	if (!dev->poll_mod_count) {
+		dev_err(&dev->interface->dev, "%s - "
+				"no valid protocols specified", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	dev_dbg(&dev->interface->dev, "%s - poll %d modulations types",
+					__func__, dev->poll_mod_count);
+
+	dev->poll_mod_curr = 0;
+	start_mod = dev->poll_mod_active[dev->poll_mod_curr];
+
+	pn533_start_poll_frame(dev->out_frame, start_mod);
+
+	rc = pn533_send_cmd_frame_async(dev, dev->out_frame, dev->in_frame,
+				dev->in_maxlen,	pn533_start_poll_complete,
+				NULL, GFP_KERNEL);
+
+	if (rc) {
+		dev_err(&dev->interface->dev, "%s - error %d when trying to"
+						" start poll", __func__, rc);
+		goto error;
+	}
+
+	dev->poll_protocols = protocols;
+
+	return 0;
+
+error:
+	pn533_poll_reset_mod_list(dev);
+	return rc;
+}
+
+static void pn533_stop_poll(struct nfc_dev *nfc_dev)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+
+	dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	if (!dev->poll_mod_count) {
+		dev_dbg(&dev->interface->dev, "%s - polling was not running",
+								__func__);
+		return;
+	}
+
+	/* An ack will cancel the last issued command (poll) */
+	pn533_send_ack(dev, GFP_KERNEL);
+
+	/* prevent pn533_start_poll_complete to issue a new poll meanwhile */
+	usb_kill_urb(dev->in_urb);
+}
+
+static int pn533_activate_target_nfcdep(struct pn533 *dev)
+{
+	struct pn533_cmd_activate_param param;
+	struct pn533_cmd_activate_response *resp;
+	int rc;
+
+	dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_ATR);
+
+	param.tg = 1;
+	param.next = 0;
+	memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), &param,
+				sizeof(struct pn533_cmd_activate_param));
+	dev->out_frame->datalen += sizeof(struct pn533_cmd_activate_param);
+
+	pn533_tx_frame_finish(dev->out_frame);
+
+	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
+								dev->in_maxlen);
+	if (rc)
+		return rc;
+
+	resp = (struct pn533_cmd_activate_response *)
+				PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame);
+	rc = resp->status & PN533_CMD_RET_MASK;
+	if (rc != PN533_CMD_RET_SUCCESS)
+		return -EIO;
+
+	return 0;
+}
+
+static int pn533_activate_target(struct nfc_dev *nfc_dev, u32 target_idx,
+								u32 protocol)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+	int rc;
+
+	dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	if (dev->poll_mod_count) {
+		dev_err(&dev->interface->dev, "%s - Cannot activate while"
+							" polling", __func__);
+		return -EBUSY;
+	}
+
+	if (dev->tgt_active_prot) {
+		dev_err(&dev->interface->dev, "%s - There is a target already"
+							" activated", __func__);
+		return -EBUSY;
+	}
+
+	if (!dev->tgt_available_prots) {
+		dev_err(&dev->interface->dev, "%s - There is no target"
+					" available to be activated", __func__);
+		return -EINVAL;
+	}
+
+	if (!(dev->tgt_available_prots & (1 << protocol))) {
+		dev_err(&dev->interface->dev, "%s - The found target does not"
+					" support the requested protocol %u",
+					__func__, protocol);
+		return -EINVAL;
+	}
+
+	dev_dbg(&dev->interface->dev, "%s - Activating target with protocol"
+						" %u", __func__, protocol);
+
+	if (protocol == NFC_PROTO_NFC_DEP) {
+		rc = pn533_activate_target_nfcdep(dev);
+		if (rc) {
+			dev_err(&dev->interface->dev, "%s - Error %d when "
+					" activating target with NFC_DEP"
+					" protocol", __func__, rc);
+			return rc;
+		}
+	}
+
+	dev->tgt_active_prot = protocol;
+	dev->tgt_available_prots = 0;
+
+	return 0;
+}
+
+static void pn533_deactivate_target(struct nfc_dev *nfc_dev, u32 target_idx)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+	u8 tg;
+	u8 status;
+	int rc;
+
+	dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	if (!dev->tgt_active_prot) {
+		dev_err(&dev->interface->dev, "%s - There is no activated"
+							" target", __func__);
+		return;
+	}
+
+	dev_dbg(&dev->interface->dev, "%s - Deactivating target with protocol"
+				" %u", __func__, dev->tgt_active_prot);
+
+	dev->tgt_active_prot = 0;
+
+	pn533_tx_frame_init(dev->out_frame, PN533_CMD_IN_RELEASE);
+
+	tg = 1;
+	memcpy(PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame), &tg, sizeof(u8));
+	dev->out_frame->datalen += sizeof(u8);
+
+	pn533_tx_frame_finish(dev->out_frame);
+
+	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
+								dev->in_maxlen);
+	if (rc) {
+		dev_err(&dev->interface->dev, "%s - Error when sending release"
+					" command to the controller", __func__);
+		return;
+	}
+
+	status = PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame)[0];
+	rc = status & PN533_CMD_RET_MASK;
+	if (rc != PN533_CMD_RET_SUCCESS)
+		dev_err(&dev->interface->dev, "%s - Error 0x%x when releasing"
+						" the target", __func__, rc);
+
+	return;
+}
+
+#define PN533_CMD_DATAEXCH_HEAD_LEN (sizeof(struct pn533_frame) + 3)
+#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
+
+static int pn533_data_exchange_tx_frame(struct pn533 *dev, struct sk_buff *skb)
+{
+	int payload_len = skb->len;
+	struct pn533_frame *out_frame;
+	struct sk_buff *discarded;
+	u8 tg;
+
+	dev_dbg(&dev->interface->dev, "%s - Sending %d bytes", __func__,
+								payload_len);
+
+	if (payload_len > PN533_CMD_DATAEXCH_DATA_MAXLEN) {
+		/* TODO: Implement support to multi-part data exchange */
+		dev_err(&dev->interface->dev, "%s - Data length greater than"
+					" the max allowed: %d", __func__,
+					PN533_CMD_DATAEXCH_DATA_MAXLEN);
+		return -ENOSYS;
+	}
+
+	/* Reserving header space */
+	if (skb_cow_head(skb, PN533_CMD_DATAEXCH_HEAD_LEN)) {
+		dev_err(&dev->interface->dev, "%s - Error to add header data",
+								__func__);
+		return -ENOMEM;
+	}
+
+	/* Reserving tail space, see pn533_tx_frame_finish */
+	if (skb_cow_data(skb, PN533_FRAME_TAIL_SIZE, &discarded) < 0) {
+		dev_err(&dev->interface->dev, "%s - Error to add tail data",
+							__func__);
+		return -ENOMEM;
+	}
+
+	skb_push(skb, PN533_CMD_DATAEXCH_HEAD_LEN);
+	out_frame = (struct pn533_frame *) skb->data;
+
+	pn533_tx_frame_init(out_frame, PN533_CMD_IN_DATA_EXCHANGE);
+
+	tg = 1;
+	memcpy(PN533_FRAME_CMD_PARAMS_PTR(out_frame), &tg, sizeof(u8));
+	out_frame->datalen += sizeof(u8);
+
+	/* The data is already in the out_frame, just update the datalen */
+	out_frame->datalen += payload_len;
+
+	pn533_tx_frame_finish(out_frame);
+	skb_put(skb, PN533_FRAME_TAIL_SIZE);
+
+	return 0;
+}
+
+struct pn533_data_exchange_arg {
+	struct sk_buff *skb_resp;
+	struct sk_buff *skb_out;
+	data_exchange_cb_t cb;
+	void *cb_context;
+};
+
+static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
+						u8 *params, int params_len)
+{
+	struct pn533_data_exchange_arg *arg = _arg;
+	struct sk_buff *skb_resp = arg->skb_resp;
+	struct pn533_frame *in_frame = (struct pn533_frame *) skb_resp->data;
+	int err = 0;
+	u8 status;
+	u8 cmd_ret;
+
+	dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	dev_kfree_skb_irq(arg->skb_out);
+
+	if (params_len < 0) { /* error */
+		err = params_len;
+		goto error;
+	}
+
+	skb_put(skb_resp, PN533_FRAME_SIZE(in_frame));
+
+	status = params[0];
+
+	cmd_ret = status & PN533_CMD_RET_MASK;
+	if (cmd_ret != PN533_CMD_RET_SUCCESS) {
+		dev_err(&dev->interface->dev, "%s - PN533 reported error %d"
+				" when exchanging data", __func__, cmd_ret);
+		err = -EIO;
+		goto error;
+	}
+
+	if (status & PN533_CMD_MI_MASK) {
+		/* TODO: Implement support to multi-part data exchange */
+		dev_err(&dev->interface->dev, "%s - Multi-part message not"
+					" supported yet", __func__);
+		/* Prevent the other messages from controller */
+		pn533_send_ack(dev, GFP_ATOMIC);
+		err = -ENOSYS;
+		goto error;
+	}
+
+	skb_pull(skb_resp, PN533_CMD_DATAEXCH_HEAD_LEN);
+	skb_trim(skb_resp, skb_resp->len - PN533_FRAME_TAIL_SIZE);
+
+	arg->cb(arg->cb_context, skb_resp, 0);
+	kfree(arg);
+	return 0;
+
+error:
+	dev_kfree_skb_irq(skb_resp);
+	arg->cb(arg->cb_context, NULL, err);
+	kfree(arg);
+	return 0;
+}
+
+int pn533_data_exchange(struct nfc_dev *nfc_dev, u32 target_idx,
+						struct sk_buff *skb,
+						data_exchange_cb_t cb,
+						void *cb_context)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+	struct pn533_frame *out_frame, *in_frame;
+	struct pn533_data_exchange_arg *arg;
+	struct sk_buff *skb_resp;
+	int skb_resp_len;
+	int rc;
+
+	dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	if (!dev->tgt_active_prot) {
+		dev_err(&dev->interface->dev, "%s - Cannot exchange data with"
+					" no activated target", __func__);
+		rc = -EINVAL;
+		goto error;
+	}
+
+	rc = pn533_data_exchange_tx_frame(dev, skb);
+	if (rc)
+		goto error;
+
+	skb_resp_len = PN533_CMD_DATAEXCH_HEAD_LEN +
+			PN533_CMD_DATAEXCH_DATA_MAXLEN +
+			PN533_FRAME_TAIL_SIZE;
+
+	skb_resp = nfc_alloc_skb(skb_resp_len, GFP_KERNEL);
+	if (!skb_resp) {
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	in_frame = (struct pn533_frame *) skb_resp->data;
+	out_frame = (struct pn533_frame *) skb->data;
+
+	arg = kmalloc(sizeof(struct pn533_data_exchange_arg), GFP_KERNEL);
+	if (!arg) {
+		rc = -ENOMEM;
+		goto free_skb_resp;
+	}
+
+	arg->skb_resp = skb_resp;
+	arg->skb_out = skb;
+	arg->cb = cb;
+	arg->cb_context = cb_context;
+
+	rc = pn533_send_cmd_frame_async(dev, out_frame, in_frame, skb_resp_len,
+					pn533_data_exchange_complete, arg,
+					GFP_KERNEL);
+	if (rc) {
+		dev_err(&dev->interface->dev, "%s - error %d when trying to"
+					" perform data_exchange", __func__, rc);
+		goto free_arg;
+	}
+
+	return 0;
+
+free_arg:
+	kfree(arg);
+free_skb_resp:
+	kfree_skb(skb_resp);
+error:
+	kfree_skb(skb);
+	return rc;
+}
+
+static int pn533_set_configuration(struct pn533 *dev, u8 cfgitem, u8 *cfgdata,
+								u8 cfgdata_len)
+{
+	int rc;
+	u8 *params;
+
+	pn533_tx_frame_init(dev->out_frame, PN533_CMD_RF_CONFIGURATION);
+
+	params = PN533_FRAME_CMD_PARAMS_PTR(dev->out_frame);
+	params[0] = cfgitem;
+	memcpy(&params[1], cfgdata, cfgdata_len);
+	dev->out_frame->datalen += (1 + cfgdata_len);
+
+	pn533_tx_frame_finish(dev->out_frame);
+
+	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
+								dev->in_maxlen);
+
+	return rc;
+}
+
+struct nfc_ops pn533_nfc_ops = {
+	.start_poll = pn533_start_poll,
+	.stop_poll = pn533_stop_poll,
+	.activate_target = pn533_activate_target,
+	.deactivate_target = pn533_deactivate_target,
+	.data_exchange = pn533_data_exchange,
+};
+
+static int pn533_probe(struct usb_interface *interface,
+			const struct usb_device_id *id)
+{
+	struct pn533_fw_version *fw_ver;
+	struct pn533 *dev;
+	struct usb_host_interface *iface_desc;
+	struct usb_endpoint_descriptor *endpoint;
+	struct pn533_config_max_retries max_retries;
+	int in_endpoint = 0;
+	int out_endpoint = 0;
+	int rc = -ENOMEM;
+	int i;
+	u32 protocols;
+
+	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+	if (!dev)
+		return -ENOMEM;
+
+	dev->udev = usb_get_dev(interface_to_usbdev(interface));
+	dev->interface = interface;
+	sema_init(&dev->cmd_lock, 1);
+
+	iface_desc = interface->cur_altsetting;
+	for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
+		endpoint = &iface_desc->endpoint[i].desc;
+
+		if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint)) {
+			dev->in_maxlen = le16_to_cpu(endpoint->wMaxPacketSize);
+			in_endpoint = endpoint->bEndpointAddress;
+		}
+
+		if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint)) {
+			dev->out_maxlen =
+				le16_to_cpu(endpoint->wMaxPacketSize);
+			out_endpoint = endpoint->bEndpointAddress;
+		}
+	}
+
+	if (!in_endpoint || !out_endpoint) {
+		dev_err(&interface->dev, "Could not find bulk-in or "
+						"bulk-out endpoint");
+		rc = -ENODEV;
+		goto error;
+	}
+
+	dev->in_frame = kmalloc(dev->in_maxlen, GFP_KERNEL);
+	dev->in_urb = usb_alloc_urb(0, GFP_KERNEL);
+	dev->out_frame = kmalloc(dev->out_maxlen, GFP_KERNEL);
+	dev->out_urb = usb_alloc_urb(0, GFP_KERNEL);
+
+	if (!dev->in_frame || !dev->out_frame ||
+		!dev->in_urb || !dev->out_urb)
+		goto error;
+
+	usb_fill_bulk_urb(dev->in_urb, dev->udev,
+			usb_rcvbulkpipe(dev->udev, in_endpoint),
+			NULL, 0, NULL, dev);
+	usb_fill_bulk_urb(dev->out_urb, dev->udev,
+			usb_sndbulkpipe(dev->udev, out_endpoint),
+			NULL, 0,
+			pn533_send_complete, dev);
+
+	tasklet_init(&dev->tasklet, pn533_tasklet_cmd_complete, (ulong)dev);
+
+	usb_set_intfdata(interface, dev);
+
+	pn533_tx_frame_init(dev->out_frame, PN533_CMD_GET_FIRMWARE_VERSION);
+	pn533_tx_frame_finish(dev->out_frame);
+
+	rc = pn533_send_cmd_frame_sync(dev, dev->out_frame, dev->in_frame,
+								dev->in_maxlen);
+	if (rc)
+		goto kill_tasklet;
+
+	fw_ver = (struct pn533_fw_version *)
+				PN533_FRAME_CMD_PARAMS_PTR(dev->in_frame);
+	dev_info(&interface->dev, "NXP PN533 firmware ver %d.%d now attached",
+						fw_ver->ver, fw_ver->rev);
+
+	protocols = NFC_PROTO_JEWEL_MASK
+			| NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
+			| NFC_PROTO_ISO14443_MASK
+			| NFC_PROTO_NFC_DEP_MASK;
+
+	dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols);
+	if (!dev->nfc_dev)
+		goto kill_tasklet;
+
+	nfc_set_parent_dev(dev->nfc_dev, &interface->dev);
+	nfc_set_drvdata(dev->nfc_dev, dev);
+
+	rc = nfc_register_device(dev->nfc_dev);
+	if (rc)
+		goto free_nfc_dev;
+
+	max_retries.mx_rty_atr = PN533_CONFIG_MAX_RETRIES_ENDLESS;
+	max_retries.mx_rty_psl = 2;
+	max_retries.mx_rty_passive_act = PN533_CONFIG_MAX_RETRIES_NO_RETRY;
+
+	rc = pn533_set_configuration(dev, PN533_CFGITEM_MAX_RETRIES,
+				(u8 *) &max_retries, sizeof(max_retries));
+
+	if (rc) {
+		dev_err(&interface->dev, "Error on setting MAX_RETRIES "
+								"config");
+		goto free_nfc_dev;
+	}
+
+	return 0;
+
+free_nfc_dev:
+	nfc_free_device(dev->nfc_dev);
+kill_tasklet:
+	tasklet_kill(&dev->tasklet);
+error:
+	kfree(dev->in_frame);
+	usb_free_urb(dev->in_urb);
+	kfree(dev->out_frame);
+	usb_free_urb(dev->out_urb);
+	kfree(dev);
+	return rc;
+}
+
+static void pn533_disconnect(struct usb_interface *interface)
+{
+	struct pn533 *dev;
+
+	dev = usb_get_intfdata(interface);
+	usb_set_intfdata(interface, NULL);
+
+	nfc_unregister_device(dev->nfc_dev);
+	nfc_free_device(dev->nfc_dev);
+
+	usb_kill_urb(dev->in_urb);
+	usb_kill_urb(dev->out_urb);
+
+	tasklet_kill(&dev->tasklet);
+
+	kfree(dev->in_frame);
+	usb_free_urb(dev->in_urb);
+	kfree(dev->out_frame);
+	usb_free_urb(dev->out_urb);
+	kfree(dev);
+
+	dev_info(&interface->dev, "NXP PN533 NFC device disconnected");
+}
+
+static struct usb_driver pn533_driver = {
+	.name =		"pn533",
+	.probe =	pn533_probe,
+	.disconnect =	pn533_disconnect,
+	.id_table =	pn533_table,
+};
+
+static int __init pn533_init(void)
+{
+	int rc;
+
+	rc = usb_register(&pn533_driver);
+	if (rc)
+		err("usb_register failed. Error number %d", rc);
+
+	return rc;
+}
+
+static void __exit pn533_exit(void)
+{
+	usb_deregister(&pn533_driver);
+}
+
+module_init(pn533_init);
+module_exit(pn533_exit);
+
+MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>");
+MODULE_DESCRIPTION("PN533 usb driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL");
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* [PATCH v4 6/6] NFC: add Documentation/networking/nfc.txt
  2011-06-28 18:20 [PATCH v4 0/6] NFC subsystem Aloisio Almeida Jr
                   ` (4 preceding siblings ...)
  2011-06-28 18:20 ` [PATCH v4 5/6] NFC: pn533: add NXP pn533 nfc device driver Aloisio Almeida Jr
@ 2011-06-28 18:20 ` Aloisio Almeida Jr
  5 siblings, 0 replies; 17+ messages in thread
From: Aloisio Almeida Jr @ 2011-06-28 18:20 UTC (permalink / raw)
  To: linville
  Cc: linux-wireless, sameo, johannes, lauro.venancio, marcio.macedo,
	Waldemar.Rymarkiewicz, padovan, rdunlap, Aloisio Almeida Jr

Signed-off-by: Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
Signed-off-by: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
---
 Documentation/networking/nfc.txt |  128 ++++++++++++++++++++++++++++++++++++++
 1 files changed, 128 insertions(+), 0 deletions(-)
 create mode 100644 Documentation/networking/nfc.txt

diff --git a/Documentation/networking/nfc.txt b/Documentation/networking/nfc.txt
new file mode 100644
index 0000000..b24c29b
--- /dev/null
+++ b/Documentation/networking/nfc.txt
@@ -0,0 +1,128 @@
+Linux NFC subsystem
+===================
+
+The Near Field Communication (NFC) subsystem is required to standardize the
+NFC device drivers development and to create an unified userspace interface.
+
+This document covers the architecture overview, the device driver interface
+description and the userspace interface description.
+
+Architecture overview
+---------------------
+
+The NFC subsystem is responsible for:
+      - NFC adapters management;
+      - Polling for targets;
+      - Low-level data exchange;
+
+The subsystem is divided in some parts. The 'core' is responsible for
+providing the device driver interface. On the other side, it is also
+responsible for providing an interface to control operations and low-level
+data exchange.
+
+The control operations are available to userspace via generic netlink.
+
+The low-level data exchange interface is provided by the new socket family
+PF_NFC. The NFC_SOCKPROTO_RAW performs raw communication with NFC targets.
+
+
+             +--------------------------------------+
+             |              USER SPACE              |
+             +--------------------------------------+
+                 ^                       ^
+                 | low-level             | control
+                 | data exchange         | operations
+                 |                       |
+                 |                       v
+                 |                  +-----------+
+                 | AF_NFC           |  netlink  |
+                 | socket           +-----------+
+                 | raw                   ^
+                 |                       |
+                 v                       v
+             +---------+            +-----------+
+             | rawsock | <--------> |   core    |
+             +---------+            +-----------+
+                                         ^
+                                         |
+                                         v
+                                    +-----------+
+                                    |  driver   |
+                                    +-----------+
+
+Device Driver Interface
+-----------------------
+
+When registering on the NFC subsystem, the device driver must inform the core
+of the set of supported NFC protocols and the set of ops callbacks. The ops
+callbacks that must be implemented are the following:
+
+* start_poll - setup the device to poll for targets
+* stop_poll - stop on progress polling operation
+* activate_target - select and initialize one of the targets found
+* deactivate_target - deselect and deinitialize the selected target
+* data_exchange - send data and receive the response (transceive operation)
+
+Userspace interface
+--------------------
+
+The userspace interface is divided in control operations and low-level data
+exchange operation.
+
+CONTROL OPERATIONS:
+
+Generic netlink is used to implement the interface to the control operations.
+The operations are composed by commands and events, all listed below:
+
+* NFC_CMD_GET_DEVICE - get specific device info or dump the device list
+* NFC_CMD_START_POLL - setup a specific device to polling for targets
+* NFC_CMD_STOP_POLL - stop the polling operation in a specific device
+* NFC_CMD_GET_TARGET - dump the list of targets found by a specific device
+
+* NFC_EVENT_DEVICE_ADDED - reports an NFC device addition
+* NFC_EVENT_DEVICE_REMOVED - reports an NFC device removal
+* NFC_EVENT_TARGETS_FOUND - reports START_POLL results when 1 or more targets
+are found
+
+The user must call START_POLL to poll for NFC targets, passing the desired NFC
+protocols through NFC_ATTR_PROTOCOLS attribute. The device remains in polling
+state until it finds any target. However, the user can stop the polling
+operation by calling STOP_POLL command. In this case, it will be checked if
+the requester of STOP_POLL is the same of START_POLL.
+
+If the polling operation finds one or more targets, the event TARGETS_FOUND is
+sent (including the device id). The user must call GET_TARGET to get the list of
+all targets found by such device. Each reply message has target attributes with
+relevant information such as the supported NFC protocols.
+
+All polling operations requested through one netlink socket are stopped when
+it's closed.
+
+LOW-LEVEL DATA EXCHANGE:
+
+The userspace must use PF_NFC sockets to perform any data communication with
+targets. All NFC sockets use AF_NFC:
+
+struct sockaddr_nfc {
+       sa_family_t sa_family;
+       __u32 dev_idx;
+       __u32 target_idx;
+       __u32 nfc_protocol;
+};
+
+To establish a connection with one target, the user must create an
+NFC_SOCKPROTO_RAW socket and call the 'connect' syscall with the sockaddr_nfc
+struct correctly filled. All information comes from NFC_EVENT_TARGETS_FOUND
+netlink event. As a target can support more than one NFC protocol, the user
+must inform which protocol it wants to use.
+
+Internally, 'connect' will result in an activate_target call to the driver.
+When the socket is closed, the target is deactivated.
+
+The data format exchanged through the sockets is NFC protocol dependent. For
+instance, when communicating with MIFARE tags, the data exchanged are MIFARE
+commands and their responses.
+
+The first received package is the response to the first sent package and so
+on. In order to allow valid "empty" responses, every data received has a NULL
+header of 1 byte.
-- 
1.7.5.4


^ permalink raw reply related	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 1/6] NFC: add nfc subsystem core
  2011-06-28 18:20 ` [PATCH v4 1/6] NFC: add nfc subsystem core Aloisio Almeida Jr
@ 2011-06-28 20:18   ` Joe Perches
  2011-06-28 23:31     ` Aloisio Almeida
  2011-06-29  1:31     ` Marcel Holtmann
  0 siblings, 2 replies; 17+ messages in thread
From: Joe Perches @ 2011-06-28 20:18 UTC (permalink / raw)
  To: Aloisio Almeida Jr
  Cc: linville, linux-wireless, sameo, johannes, lauro.venancio,
	marcio.macedo, Waldemar.Rymarkiewicz, padovan, rdunlap

On Tue, 2011-06-28 at 15:20 -0300, Aloisio Almeida Jr wrote:
> From: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
> The NFC subsystem core is responsible for providing the device driver
> interface. It is also responsible for providing an interface to the control
> operations and data exchange.
[]
> diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
[]
> +#define NFC_INFO(fmt, arg...) printk(KERN_INFO "NFC: " fmt "\n", ## arg)
> +#define NFC_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n", __func__, ## arg)
> +#define NFC_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg)

I think these #defines and their uses would be
better lower case.

#define nfc_info(etc...)
#define nfc_err(etc...)
#define nfc_dbg(etc...)

And because these don't really take any nfc specific
struct as an argument, may be better removed altogether
and replaced with the pr_<level> equivalents.

I think emitting __func__ rarely adds useful information.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 1/6] NFC: add nfc subsystem core
  2011-06-28 20:18   ` Joe Perches
@ 2011-06-28 23:31     ` Aloisio Almeida
  2011-06-28 23:52       ` Joe Perches
  2011-06-29  1:31     ` Marcel Holtmann
  1 sibling, 1 reply; 17+ messages in thread
From: Aloisio Almeida @ 2011-06-28 23:31 UTC (permalink / raw)
  To: Joe Perches
  Cc: linville, linux-wireless, sameo, johannes, lauro.venancio,
	marcio.macedo, Waldemar.Rymarkiewicz, padovan, rdunlap

Hi Joe,

On Tue, Jun 28, 2011 at 5:18 PM, Joe Perches <joe@perches.com> wrote:
> On Tue, 2011-06-28 at 15:20 -0300, Aloisio Almeida Jr wrote:
>> From: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
>> The NFC subsystem core is responsible for providing the device driver
>> interface. It is also responsible for providing an interface to the control
>> operations and data exchange.
> []
>> diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
> []
>> +#define NFC_INFO(fmt, arg...) printk(KERN_INFO "NFC: " fmt "\n", ## arg)
>> +#define NFC_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n", __func__, ## arg)
>> +#define NFC_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg)
>
> I think these #defines and their uses would be
> better lower case.
>
> #define nfc_info(etc...)
> #define nfc_err(etc...)
> #define nfc_dbg(etc...)
>
> And because these don't really take any nfc specific
> struct as an argument, may be better removed altogether
> and replaced with the pr_<level> equivalents.
>
I was using pr_*() on previous versions. One of the proposed changes
for v4 was to create these macros to avoid calling pr_*() functions
with same parameters every time. The implementation chosen is based on
BT_* macros from bluetooth subsystem.

> I think emitting __func__ rarely adds useful information.
>
I can say that during the implementation phase I considered __func__
useful, mainly for tracing the execution. That's the reason I left it
in the code.

Aloisio

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 1/6] NFC: add nfc subsystem core
  2011-06-28 23:31     ` Aloisio Almeida
@ 2011-06-28 23:52       ` Joe Perches
  0 siblings, 0 replies; 17+ messages in thread
From: Joe Perches @ 2011-06-28 23:52 UTC (permalink / raw)
  To: Aloisio Almeida
  Cc: linville, linux-wireless, sameo, johannes, lauro.venancio,
	marcio.macedo, Waldemar.Rymarkiewicz, padovan, rdunlap

On Tue, 2011-06-28 at 20:31 -0300, Aloisio Almeida wrote:
> Hi Joe,

Oi Aloisio.

> On Tue, Jun 28, 2011 at 5:18 PM, Joe Perches <joe@perches.com> wrote:
> > On Tue, 2011-06-28 at 15:20 -0300, Aloisio Almeida Jr wrote:
> >> From: Lauro Ramos Venancio <lauro.venancio@openbossa.org>
> >> The NFC subsystem core is responsible for providing the device driver
> >> interface. It is also responsible for providing an interface to the control
> >> operations and data exchange.
> > []
> >> diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
> > []
> >> +#define NFC_INFO(fmt, arg...) printk(KERN_INFO "NFC: " fmt "\n", ## arg)
> >> +#define NFC_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n", __func__, ## arg)
> >> +#define NFC_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg)
> >
> > I think these #defines and their uses would be
> > better lower case.
> >
> > #define nfc_info(etc...)
> > #define nfc_err(etc...)
> > #define nfc_dbg(etc...)
> >
> > And because these don't really take any nfc specific
> > struct as an argument, may be better removed altogether
> > and replaced with the pr_<level> equivalents.
> I was using pr_*() on previous versions. One of the proposed changes
> for v4 was to create these macros to avoid calling pr_*() functions
> with same parameters every time. The implementation chosen is based on
> BT_* macros from bluetooth subsystem.
> > I think emitting __func__ rarely adds useful information.
> I can say that during the implementation phase I considered __func__
> useful, mainly for tracing the execution. That's the reason I left it
> in the code.

Up to you, but regardless, I think the bluetooth macros
aren't good ones to follow.  Most all of the other
<foo>_<level> output logging forms are lowercase.

cheers, Joe


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 1/6] NFC: add nfc subsystem core
  2011-06-28 20:18   ` Joe Perches
  2011-06-28 23:31     ` Aloisio Almeida
@ 2011-06-29  1:31     ` Marcel Holtmann
  2011-06-29  1:49       ` Joe Perches
  1 sibling, 1 reply; 17+ messages in thread
From: Marcel Holtmann @ 2011-06-29  1:31 UTC (permalink / raw)
  To: Joe Perches
  Cc: Aloisio Almeida Jr, linville, linux-wireless, sameo, johannes,
	lauro.venancio, marcio.macedo, Waldemar.Rymarkiewicz, padovan,
	rdunlap

Hi Joe,

> > The NFC subsystem core is responsible for providing the device driver
> > interface. It is also responsible for providing an interface to the control
> > operations and data exchange.
> []
> > diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
> []
> > +#define NFC_INFO(fmt, arg...) printk(KERN_INFO "NFC: " fmt "\n", ## arg)
> > +#define NFC_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n", __func__, ## arg)
> > +#define NFC_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg)
> 
> I think these #defines and their uses would be
> better lower case.
> 
> #define nfc_info(etc...)
> #define nfc_err(etc...)
> #define nfc_dbg(etc...)
> 
> And because these don't really take any nfc specific
> struct as an argument, may be better removed altogether
> and replaced with the pr_<level> equivalents.

it is similar to what we do in the Bluetooth subsystem, but in the end
upper-case vs lower-case is a bit more personal taste.

The pr_<level> ones are nice and I wished we had them all back in the
days, but the NFC ones actually could take the controller as argument
and then us the dev_* versions of these commands.

At this stage of the project it is a bit too early to tell I guess.

> I think emitting __func__ rarely adds useful information.

Depends on how you are using your debug statements. I find it really
helpful since then you can keep the text detail to a minimum.

Regards

Marcel



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 1/6] NFC: add nfc subsystem core
  2011-06-29  1:31     ` Marcel Holtmann
@ 2011-06-29  1:49       ` Joe Perches
  2011-06-29 18:00         ` Marcel Holtmann
  0 siblings, 1 reply; 17+ messages in thread
From: Joe Perches @ 2011-06-29  1:49 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Aloisio Almeida Jr, linville, linux-wireless, sameo, johannes,
	lauro.venancio, marcio.macedo, Waldemar.Rymarkiewicz, padovan,
	rdunlap

On Tue, 2011-06-28 at 18:31 -0700, Marcel Holtmann wrote:
> Hi Joe,

Hello Marcel.

> > > The NFC subsystem core is responsible for providing the device driver
> > > interface. It is also responsible for providing an interface to the control
> > > operations and data exchange.
> > []
> > > diff --git a/net/nfc/nfc.h b/net/nfc/nfc.h
> > []
> > > +#define NFC_INFO(fmt, arg...) printk(KERN_INFO "NFC: " fmt "\n", ## arg)
> > > +#define NFC_ERR(fmt, arg...) printk(KERN_ERR "%s: " fmt "\n", __func__, ## arg)
> > > +#define NFC_DBG(fmt, arg...) pr_debug("%s: " fmt "\n", __func__, ## arg)
> > I think these #defines and their uses would be
> > better lower case.
> > #define nfc_info(etc...)
> > #define nfc_err(etc...)
> > #define nfc_dbg(etc...)
> > And because these don't really take any nfc specific
> > struct as an argument, may be better removed altogether
> > and replaced with the pr_<level> equivalents.
> 
> it is similar to what we do in the Bluetooth subsystem, but in the end
> upper-case vs lower-case is a bit more personal taste.

And a bit of of coding style agreement too.

> The pr_<level> ones are nice and I wished we had them all back in the
> days, but the NFC ones actually could take the controller as argument
> and then us the dev_* versions of these commands.

I do think that if there's a controller struct that's always
or mostly used with nfc_<level>, then it should be added and
passed to the functions arguments, maybe with NULL used where
necessary.

> At this stage of the project it is a bit too early to tell I guess.
> > I think emitting __func__ rarely adds useful information.
> Depends on how you are using your debug statements. I find it really
> helpful since then you can keep the text detail to a minimum.

I don't disagree that while debugging function names
and tracing function entries/exits are useful.

Today, dynamic_debug can add __func__ to the output as
desired so I think that it's not really necessary
to add to any <foo>_dbg callsite.

I don't think they're ever useful on <foo>_err.
If they are, then the message probably isn't
descriptive enough and adding %s/__func__ as
necessary is OK.

cheers, Joe



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 1/6] NFC: add nfc subsystem core
  2011-06-29  1:49       ` Joe Perches
@ 2011-06-29 18:00         ` Marcel Holtmann
  2011-06-29 23:23           ` Aloisio Almeida
  0 siblings, 1 reply; 17+ messages in thread
From: Marcel Holtmann @ 2011-06-29 18:00 UTC (permalink / raw)
  To: Joe Perches
  Cc: Aloisio Almeida Jr, linville, linux-wireless, sameo, johannes,
	lauro.venancio, marcio.macedo, Waldemar.Rymarkiewicz, padovan,
	rdunlap

Hi Joe,

> > The pr_<level> ones are nice and I wished we had them all back in the
> > days, but the NFC ones actually could take the controller as argument
> > and then us the dev_* versions of these commands.
> 
> I do think that if there's a controller struct that's always
> or mostly used with nfc_<level>, then it should be added and
> passed to the functions arguments, maybe with NULL used where
> necessary.
> 
> > At this stage of the project it is a bit too early to tell I guess.
> > > I think emitting __func__ rarely adds useful information.
> > Depends on how you are using your debug statements. I find it really
> > helpful since then you can keep the text detail to a minimum.
> 
> I don't disagree that while debugging function names
> and tracing function entries/exits are useful.
> 
> Today, dynamic_debug can add __func__ to the output as
> desired so I think that it's not really necessary
> to add to any <foo>_dbg callsite.

I did not know that. Then we might should go ahead and also cleanup the
Bluetooth subsystem.

We do use an implied "Bluetooth: " prefix when calling BT_INFO, but that
can be easily changed to bt_info() as well since I do not care about
that part. 

The Bluetooth subsystem has a Linux 2.4 legacy history and a lot of
things can be done a lot nicer these days.

Regards

Marcel



^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 1/6] NFC: add nfc subsystem core
  2011-06-29 18:00         ` Marcel Holtmann
@ 2011-06-29 23:23           ` Aloisio Almeida
  2011-06-29 23:46             ` Joe Perches
  0 siblings, 1 reply; 17+ messages in thread
From: Aloisio Almeida @ 2011-06-29 23:23 UTC (permalink / raw)
  To: Marcel Holtmann
  Cc: Joe Perches, linville, linux-wireless, sameo, johannes,
	lauro.venancio, marcio.macedo, Waldemar.Rymarkiewicz, padovan,
	rdunlap

Hi Joe and Marcel,

On Wed, Jun 29, 2011 at 3:00 PM, Marcel Holtmann <marcel@holtmann.org> wrote:
> Hi Joe,
>
>> > The pr_<level> ones are nice and I wished we had them all back in the
>> > days, but the NFC ones actually could take the controller as argument
>> > and then us the dev_* versions of these commands.
>>
>> I do think that if there's a controller struct that's always
>> or mostly used with nfc_<level>, then it should be added and
>> passed to the functions arguments, maybe with NULL used where
>> necessary.
>>
>> > At this stage of the project it is a bit too early to tell I guess.
>> > > I think emitting __func__ rarely adds useful information.
>> > Depends on how you are using your debug statements. I find it really
>> > helpful since then you can keep the text detail to a minimum.
>>
>> I don't disagree that while debugging function names
>> and tracing function entries/exits are useful.
>>
>> Today, dynamic_debug can add __func__ to the output as
>> desired so I think that it's not really necessary
>> to add to any <foo>_dbg callsite.
>
> I did not know that. Then we might should go ahead and also cleanup the
> Bluetooth subsystem.

That's true only for pr_debug() function. You cannot add __func__ info
on dev_dbg() calls dynamically.

So, for net/nfc/* I propose to use directly pr_*() functions.

For device drivers the following macros would be provided:

#define nfc_dev_info(dev, fmt, arg...) dev_info((dev), "NFC: " fmt, ## arg)
#define nfc_dev_err(dev, fmt, arg...) dev_err((dev), "%s: " fmt,
__func__, ## arg)
#define nfc_dev_dbg(dev, fmt, arg...) dev_dbg((dev), "%s: " fmt,
__func__, ## arg)

What do you think?

Aloisio

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 1/6] NFC: add nfc subsystem core
  2011-06-29 23:23           ` Aloisio Almeida
@ 2011-06-29 23:46             ` Joe Perches
  2011-06-30  3:26               ` Aloisio Almeida
  0 siblings, 1 reply; 17+ messages in thread
From: Joe Perches @ 2011-06-29 23:46 UTC (permalink / raw)
  To: Aloisio Almeida, Jason Baron
  Cc: Marcel Holtmann, linville, linux-wireless, sameo, johannes,
	lauro.venancio, marcio.macedo, Waldemar.Rymarkiewicz, padovan,
	rdunlap

On Wed, 2011-06-29 at 20:23 -0300, Aloisio Almeida wrote:
> >> Today, dynamic_debug can add __func__ to the output as
> >> desired so I think that it's not really necessary
> >> to add to any <foo>_dbg callsite.
> That's true only for pr_debug() function. You cannot add __func__ info
> on dev_dbg() calls dynamically.

I believe that's false.  It's definitely stored.

#define dynamic_dev_dbg(dev, fmt, ...) do {				\
	static struct _ddebug descriptor				\
	__used								\
	__attribute__((section("__verbose"), aligned(8))) =		\
	{ KBUILD_MODNAME, __func__, __FILE__, fmt, __LINE__,		\
		_DPRINTK_FLAGS_DEFAULT };				\
	if (unlikely(descriptor.enabled))				\
		dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__);	\
	} while (0)

Jason?  True or false?

> So, for net/nfc/* I propose to use directly pr_*() functions.
> For device drivers the following macros would be provided:
> #define nfc_dev_info(dev, fmt, arg...) dev_info((dev), "NFC: " fmt, ## arg)
> #define nfc_dev_err(dev, fmt, arg...) dev_err((dev), "%s: " fmt,
> __func__, ## arg)
> #define nfc_dev_dbg(dev, fmt, arg...) dev_dbg((dev), "%s: " fmt,
> __func__, ## arg)
> What do you think?

I still think __func__ isn't useful ;)
I think you should add NFC to nfc_dev_err too.

cheers, Joe


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [PATCH v4 1/6] NFC: add nfc subsystem core
  2011-06-29 23:46             ` Joe Perches
@ 2011-06-30  3:26               ` Aloisio Almeida
  2011-06-30  4:28                 ` RFC: Add __dynamic_dev_dbg Joe Perches
  0 siblings, 1 reply; 17+ messages in thread
From: Aloisio Almeida @ 2011-06-30  3:26 UTC (permalink / raw)
  To: Joe Perches
  Cc: Jason Baron, Marcel Holtmann, linville, linux-wireless, sameo,
	johannes, lauro.venancio, marcio.macedo, Waldemar.Rymarkiewicz,
	padovan, rdunlap

Hi Joe,

On Wed, Jun 29, 2011 at 8:46 PM, Joe Perches <joe@perches.com> wrote:
> On Wed, 2011-06-29 at 20:23 -0300, Aloisio Almeida wrote:
>> >> Today, dynamic_debug can add __func__ to the output as
>> >> desired so I think that it's not really necessary
>> >> to add to any <foo>_dbg callsite.
>> That's true only for pr_debug() function. You cannot add __func__ info
>> on dev_dbg() calls dynamically.
>
> I believe that's false.  It's definitely stored.
>
> #define dynamic_dev_dbg(dev, fmt, ...) do {                             \
>        static struct _ddebug descriptor                                \
>        __used                                                          \
>        __attribute__((section("__verbose"), aligned(8))) =             \
>        { KBUILD_MODNAME, __func__, __FILE__, fmt, __LINE__,            \
>                _DPRINTK_FLAGS_DEFAULT };                               \
>        if (unlikely(descriptor.enabled))                               \
>                dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__);        \
>        } while (0)
>
> Jason?  True or false?

It's stored but not retrieved. If you check lib/dynamic_debug.c you
see that only __dynamic_pr_debug() (called by dynamic_pr_debug() )
adds such information on prints. The dev_printk() does not check
_DPRINTK_FLAGS_INCL_* flags.

> I think you should add NFC to nfc_dev_err too.

That's make sense to me also.

Aloisio

^ permalink raw reply	[flat|nested] 17+ messages in thread

* RFC: Add __dynamic_dev_dbg
  2011-06-30  3:26               ` Aloisio Almeida
@ 2011-06-30  4:28                 ` Joe Perches
  0 siblings, 0 replies; 17+ messages in thread
From: Joe Perches @ 2011-06-30  4:28 UTC (permalink / raw)
  To: Aloisio Almeida
  Cc: Jason Baron, Marcel Holtmann, linville, linux-wireless, sameo,
	johannes, lauro.venancio, marcio.macedo, Waldemar.Rymarkiewicz,
	padovan, rdunlap

On Thu, 2011-06-30 at 00:26 -0300, Aloisio Almeida wrote:
> It's stored but not retrieved. If you check lib/dynamic_debug.c you
> see that only __dynamic_pr_debug() (called by dynamic_pr_debug() )
> adds such information on prints. The dev_printk() does not check
> _DPRINTK_FLAGS_INCL_* flags.

That seems enough easy to fix.

Jason?  How does this look?

---

 drivers/base/core.c           |    5 +++--
 include/linux/device.h        |    5 +++++
 include/linux/dynamic_debug.h |   10 ++++++++--
 lib/dynamic_debug.c           |   38 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 54 insertions(+), 4 deletions(-)

diff --git a/drivers/base/core.c b/drivers/base/core.c
index bc8729d..82c8654 100644
--- a/drivers/base/core.c
+++ b/drivers/base/core.c
@@ -1764,8 +1764,8 @@ void device_shutdown(void)
 
 #ifdef CONFIG_PRINTK
 
-static int __dev_printk(const char *level, const struct device *dev,
-			struct va_format *vaf)
+int __dev_printk(const char *level, const struct device *dev,
+		 struct va_format *vaf)
 {
 	if (!dev)
 		return printk("%s(NULL device *): %pV", level, vaf);
@@ -1773,6 +1773,7 @@ static int __dev_printk(const char *level, const struct device *dev,
 	return printk("%s%s %s: %pV",
 		      level, dev_driver_string(dev), dev_name(dev), vaf);
 }
+EXPORT_SYMBOL(__dev_printk);
 
 int dev_printk(const char *level, const struct device *dev,
 	       const char *fmt, ...)
diff --git a/include/linux/device.h b/include/linux/device.h
index e4f62d8..53711f2 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -785,6 +785,8 @@ extern const char *dev_driver_string(const struct device *dev);
 
 #ifdef CONFIG_PRINTK
 
+extern int __dev_printk(const char *level, const struct device *dev,
+			struct va_format *vaf);
 extern int dev_printk(const char *level, const struct device *dev,
 		      const char *fmt, ...)
 	__attribute__ ((format (printf, 3, 4)));
@@ -805,6 +807,9 @@ extern int _dev_info(const struct device *dev, const char *fmt, ...)
 
 #else
 
+static inline int __dev_printk(const char *level, const struct device *dev,
+			       struct va_format *vaf)
+	 { return 0; }
 static inline int dev_printk(const char *level, const struct device *dev,
 		      const char *fmt, ...)
 	__attribute__ ((format (printf, 3, 4)));
diff --git a/include/linux/dynamic_debug.h b/include/linux/dynamic_debug.h
index e747ecd..bdf1531 100644
--- a/include/linux/dynamic_debug.h
+++ b/include/linux/dynamic_debug.h
@@ -47,6 +47,13 @@ extern int ddebug_remove_module(const char *mod_name);
 extern int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
 	__attribute__ ((format (printf, 2, 3)));
 
+struct device;
+
+extern int __dynamic_dev_dbg(struct _ddebug *descriptor,
+			     const struct device *dev,
+			     const char *fmt, ...)
+	__attribute__ ((format (printf, 3, 4)));
+
 #define dynamic_pr_debug(fmt, ...) do {					\
 	static struct _ddebug descriptor				\
 	__used								\
@@ -57,7 +64,6 @@ extern int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
 		__dynamic_pr_debug(&descriptor, pr_fmt(fmt), ##__VA_ARGS__); \
 	} while (0)
 
-
 #define dynamic_dev_dbg(dev, fmt, ...) do {				\
 	static struct _ddebug descriptor				\
 	__used								\
@@ -65,7 +71,7 @@ extern int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
 	{ KBUILD_MODNAME, __func__, __FILE__, fmt, __LINE__,		\
 		_DPRINTK_FLAGS_DEFAULT };				\
 	if (unlikely(descriptor.enabled))				\
-		dev_printk(KERN_DEBUG, dev, fmt, ##__VA_ARGS__);	\
+		__dynamic_dev_dbg(&descriptor, dev, fmt, ##__VA_ARGS__);	\
 	} while (0)
 
 #else
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index 75ca78f..5c5f8f9 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -30,6 +30,7 @@
 #include <linux/jump_label.h>
 #include <linux/hardirq.h>
 #include <linux/sched.h>
+#include <linux/device.h>
 
 extern struct _ddebug __start___verbose[];
 extern struct _ddebug __stop___verbose[];
@@ -456,6 +457,43 @@ int __dynamic_pr_debug(struct _ddebug *descriptor, const char *fmt, ...)
 }
 EXPORT_SYMBOL(__dynamic_pr_debug);
 
+int __dynamic_dev_dbg(struct _ddebug *descriptor,
+		      const struct device *dev, const char *fmt, ...)
+{
+	struct va_format vaf;
+	va_list args;
+	int res;
+
+	BUG_ON(!descriptor);
+	BUG_ON(!fmt);
+
+	va_start(args, fmt);
+
+	vaf.fmt = fmt;
+	vaf.va = &args;
+
+	res = printk(KERN_DEBUG);
+	if (descriptor->flags & _DPRINTK_FLAGS_INCL_TID) {
+		if (in_interrupt())
+			res += printk(KERN_CONT "<intr> ");
+		else
+			res += printk(KERN_CONT "[%d] ", task_pid_vnr(current));
+	}
+	if (descriptor->flags & _DPRINTK_FLAGS_INCL_MODNAME)
+		res += printk(KERN_CONT "%s:", descriptor->modname);
+	if (descriptor->flags & _DPRINTK_FLAGS_INCL_FUNCNAME)
+		res += printk(KERN_CONT "%s:", descriptor->function);
+	if (descriptor->flags & _DPRINTK_FLAGS_INCL_LINENO)
+		res += printk(KERN_CONT "%d ", descriptor->lineno);
+
+	res += __dev_printk("", dev, &vaf);
+
+	va_end(args);
+
+	return res;
+}
+EXPORT_SYMBOL(__dynamic_dev_dbg);
+
 static __initdata char ddebug_setup_string[1024];
 static __init int ddebug_setup_query(char *str)
 {



^ permalink raw reply related	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2011-06-30  4:28 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-06-28 18:20 [PATCH v4 0/6] NFC subsystem Aloisio Almeida Jr
2011-06-28 18:20 ` [PATCH v4 1/6] NFC: add nfc subsystem core Aloisio Almeida Jr
2011-06-28 20:18   ` Joe Perches
2011-06-28 23:31     ` Aloisio Almeida
2011-06-28 23:52       ` Joe Perches
2011-06-29  1:31     ` Marcel Holtmann
2011-06-29  1:49       ` Joe Perches
2011-06-29 18:00         ` Marcel Holtmann
2011-06-29 23:23           ` Aloisio Almeida
2011-06-29 23:46             ` Joe Perches
2011-06-30  3:26               ` Aloisio Almeida
2011-06-30  4:28                 ` RFC: Add __dynamic_dev_dbg Joe Perches
2011-06-28 18:20 ` [PATCH v4 2/6] NFC: add nfc generic netlink interface Aloisio Almeida Jr
2011-06-28 18:20 ` [PATCH v4 3/6] NFC: add NFC socket family Aloisio Almeida Jr
2011-06-28 18:20 ` [PATCH v4 4/6] NFC: add the NFC socket raw protocol Aloisio Almeida Jr
2011-06-28 18:20 ` [PATCH v4 5/6] NFC: pn533: add NXP pn533 nfc device driver Aloisio Almeida Jr
2011-06-28 18:20 ` [PATCH v4 6/6] NFC: add Documentation/networking/nfc.txt Aloisio Almeida Jr

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).