All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 0/1] PN544 NFC driver.
@ 2010-10-29  6:26 Matti J. Aaltonen
       [not found] ` <1288333569-19979-1-git-send-email-matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
  0 siblings, 1 reply; 9+ messages in thread
From: Matti J. Aaltonen @ 2010-10-29  6:26 UTC (permalink / raw)
  To: linux-i2c-u79uwXL29TY76Z2rM5mHXA, akpm-DgEjT+Ai2ygdnm+yROfE0A
  Cc: Matti J. Aaltonen

Hello.

And thanks to Andrew for the comments.

>> include/linux/pn544.h |   99 ++++++
> 
> Is drivers/misc/ the best place for this?
> 
> Don't be afraid to create a new drivers/nfc/ even if it has only one
> driver in it.  If someone later comes in and adds a new NFC driver then
> things will all fall into place.

OK. Now I've created directories drivers/nfc, include/linux/nfc and Documentation/nfc.

>> +      Say yes if you want PN544 Near Field Communication driver.
> 
> OK, I did google it ;)  Interesting.

I agree... ;-)

>> +     pr_info("\n");
> 
> You might be able to use print_hex_dump() here, but I wouldn't blame
> you if you didn't ;)

I replaced the debug function with calls to print_hex_dump.


>> +/* sysfs interface */
> 
> OK, this is more serious.
> 
> You're proposing a permanent addition to the kernel ABI.  This is the
> most important part of the driver because it is something we can never
> change.  This interface is the very first thing we'll want to
> understand and review, before we even look at the implementation.
> 
> And it isn't even described!  Not in the changelog, not in a
> documentation file, not even in code comments.
> 
> Please, provide a description of this proposed interface.  Sufficient
> for reviewers to understand it and for users to use it.  Pobably this
> will require some description of the hardware functions as well.
> 
> Please also consider updating Documentation/ABI/

I've added a documentation file. But I didn't make changes to the interface
yet.

>> +                                            GFP_KERNEL);
> 
> From my reading, later code will crash the kernel if this allocation failed.
> 
> Also, is there a race here between reading info->fw_buf and setting it?
> Can two CPUs get into thei function at the same time?  If so, there
> should be locking.  Say, a mutex local to this function.

I moved the data buffer allocation to probe and also changed the locking.

>> +             return -EBADMSG;
> 
> EBADMSG is a unix streams errno.  It's quite inappropriate that a
> device driver be using it.  Imagine the poor user's confution if he
> sees this message pop up on his screen.

Changed to EINVAL.

>> +     if (r == -EREMOTEIO) { /* Retry, chip was in standby */
> 
> And what on earth is EREMOTEIO?  Is it appropriate for use in a driver?

I think it is, because it comes from i2c_master_send and it's kind of
just forwarded here.

>> +             return -EOVERFLOW;
> 
> EOVERFLOW refers to a floating point overflow!

It's used for buffer overflow in many places in the kernel, but that's
not an excuse so I removed it.

>> +             return -ENOSPC;
> 
> Disk full!

Also removed...

>> +     mutex_unlock(&info->read_mutex);
> 
> It usually doesn't make much sense to add locking around a single
> atomic read instruction.

Yes, but if there's a sequence of instructions somewhere else in the
code that the single instruction is not allowd to intersect then it
can be valid.

>> +                       size_t count, loff_t *offset)
> 
> Again, I really cannot review this code when I haven't been told what
> it's reading from, what's in the payload, what it is all to be used
> for, etc.  It's just C code to me.
> 

I've added a documentation file to explain things but basically the
driver doesn't much care about the data it passes through, apart from
message lengths and check sums.

>> +             len = min(count, (size_t) PN544_MAX_I2C_TRANSFER);
> 
> min_t() is the preferred way of solving this.

Good to know, but because of a code change it wasn't necessary.

> +}
> 
> So it can poll() somethnig as well!  This driver *really* needs
> documentation!
> 

Yes, you can wait for something to read.

>> +     if (info->state == PN544_ST_FW_READY) {
> 
> Is some locking needed here?  What prevents info->state from
> transitioning while this code is executing?

Locking added.

>> +static long pn544_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
> 
> And an ioctl interface as well!  An undocmented one.
> 
> ioctls are pretty unpopular for various reasons.  To a large extent,
> people have been using sysfs interfaces as a repalcement for ioctl()s.
> But this driver has both!

Some explanatory text written into the documentation file.
 
> Does this code need compat handling, or it is 32/64-bit clean?

I think it is...

>> +                     pn544_disable(info);
> 
> bug.  pn544_disable() calls msleep(), but msleep() is very illegal
> under spin_lock_irqsave().  This tells me that this code hasn't been
> tested with even rudimentary kernel rimtime debugging options enabled.
> Documentation/SubmitChecklist section 12 is fairly up-to-date here.

Removed spinlocks and in general revised the locking...

>> +                     pn544_disable(info);
> 
> Many more such bugs there.

Well, yes...

>> +#ifdef DO_RSET_TEST
> 
> I'd suggest enabling this via a module parameter if it's at all useful.
> Otherwise it should be enabled with a Kconfig variable, not via a code
> edit.

Removed the test...

>> +     flush_scheduled_work();
> 
> This seems unneeded?  We're trying to get rid of flush_scheduled_work(), btw.

Removed flush_scheduled_work...

Cheers,
Matti

Matti J. Aaltonen (1):
  NFC: Driver for NXP Semiconductors PN544 NFC chip.

 Documentation/nfc/nfc-pn544.txt |  105 +++++
 drivers/Kconfig                 |    2 +
 drivers/Makefile                |    2 +-
 drivers/nfc/Kconfig             |   30 ++
 drivers/nfc/Makefile            |    5 +
 drivers/nfc/pn544.c             |  893 +++++++++++++++++++++++++++++++++++++++
 include/linux/nfc/pn544.h       |   99 +++++
 7 files changed, 1135 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/nfc/nfc-pn544.txt
 create mode 100644 drivers/nfc/Kconfig
 create mode 100644 drivers/nfc/Makefile
 create mode 100644 drivers/nfc/pn544.c
 create mode 100644 include/linux/nfc/pn544.h

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

* [PATCH v2 1/1] NFC: Driver for NXP Semiconductors PN544 NFC chip.
       [not found] ` <1288333569-19979-1-git-send-email-matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
@ 2010-10-29  6:26   ` Matti J. Aaltonen
       [not found]     ` <1288333569-19979-2-git-send-email-matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
  2010-10-29 21:33   ` [PATCH v2 0/1] PN544 NFC driver Andrew Morton
  1 sibling, 1 reply; 9+ messages in thread
From: Matti J. Aaltonen @ 2010-10-29  6:26 UTC (permalink / raw)
  To: linux-i2c-u79uwXL29TY76Z2rM5mHXA, akpm-DgEjT+Ai2ygdnm+yROfE0A
  Cc: Matti J. Aaltonen

This is a driver for the pn544 NFC device. The driver transfers
ETSI messages between the device and the user space.

Signed-off-by: Matti J. Aaltonen <matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
---
 Documentation/nfc/nfc-pn544.txt |  105 +++++
 drivers/Kconfig                 |    2 +
 drivers/Makefile                |    2 +-
 drivers/nfc/Kconfig             |   30 ++
 drivers/nfc/Makefile            |    5 +
 drivers/nfc/pn544.c             |  893 +++++++++++++++++++++++++++++++++++++++
 include/linux/nfc/pn544.h       |   99 +++++
 7 files changed, 1135 insertions(+), 1 deletions(-)
 create mode 100644 Documentation/nfc/nfc-pn544.txt
 create mode 100644 drivers/nfc/Kconfig
 create mode 100644 drivers/nfc/Makefile
 create mode 100644 drivers/nfc/pn544.c
 create mode 100644 include/linux/nfc/pn544.h

diff --git a/Documentation/nfc/nfc-pn544.txt b/Documentation/nfc/nfc-pn544.txt
new file mode 100644
index 0000000..8adcffa
--- /dev/null
+++ b/Documentation/nfc/nfc-pn544.txt
@@ -0,0 +1,105 @@
+Kernel driver for PN544
+========================
+
+* NXP Semiconductor PN544 Near Field Communication (NFC) chip
+
+Author: Jari Vanhala
+Contact: Matti Aaltonen (matti.j.aaltonen at nokia.com)
+
+Description
+-----------
+
+The PN544 is an integrated transmission module for contactless
+communication. The driver goes under drives/nfc/ and is compiled as a
+module named "pn544". It registers a misc device and creates a device
+file named "/dev/pn544".
+
+The driver, is quite simple and it mainly passes data between the
+hardware and the user space.  There are two operating modes: The HCI
+(normal) mode and the firmware update mode. It can write and read in
+both modes.  The hardware sends an interrupt when data is available
+for reading.  Data is read when the read function is called by some
+user space application. Poll() checks the IRQ state. Configuration and
+self testing are done from the user space using read and write.
+
+The chip is powered up when the device is opened and otherwise
+it's turned off. Only one instance can use the device at a time.
+
+Host Interfaces: consisting of I2C, SPI and HSU as physical
+interfaces, this driver support I2C.
+
+The chip is controlled from the user spase by sending SWP/HCI (Single
+Wire Protocol) messages according to the ETSI/SCP standard, see
+http://www.etsi.org/WebSite/Technologies/ProtocolSpecification.aspx
+
+The driver handles two kinds of messages: the normal HCI messages and
+the firmware update messages. HCI messages consist of and eight bit
+header and the message body. The header contains the message length.
+Maximum size for an HCI message is 33. In HCI mode sent packets are
+tested for a correct CRC.
+
+Firmware update messages, which can be read and written in the
+firmware upload mode have the length in the second (MSB) and third
+(LSB) bytes of the message.  The maximum FW message size is 1024
+bytes.
+
+The interfaces for pn544 users:
+
+There is a sysfs interface for testing that the hardware is
+operational. Reading from the sysfs file activates the test.  The test
+returns one on success and zero on failure.
+
+Example:
+> cat /sys/module/pn544/drivers/i2c\:pn544/3-002b/nfc_test
+1
+
+For mode setting there is an IOCTL interface, which consists of
+two messages:
+
+PN544_GET_FW_MODE returns 1 if the device is in firmware
+update mode and zero in the normal (HCI) mode.
+
+PN544_SET_FW_MODE is for setting the mode.  The message parameter
+value defines the mode: one corresponds firmware update and zero the
+HCI mode.
+
+
+Example platform data:
+
+static int rx71_pn544_nfc_request_resources(struct i2c_client *client)
+{
+	/* Get and setup the HW resources for the device */
+}
+
+static void rx71_pn544_nfc_free_resources(void)
+{
+	/* Release the HW resources */
+}
+
+static void rx71_pn544_nfc_enable(int fw)
+{
+	/* Turn the device on */
+}
+
+static int rx71_pn544_nfc_test(void)
+{
+	/*
+	 * Put the device into the FW update mode
+	 * and then back to the normal mode.
+	 * Return one on success and zero on
+         * failure.
+         */
+}
+
+static void rx71_pn544_nfc_disable(void)
+{
+	/* turn the power off */
+}
+
+static struct pn544_nfc_platform_data rx71_nfc_data = {
+	.request_resources = rx71_pn544_nfc_request_resources,
+	.free_resources = rx71_pn544_nfc_free_resources,
+	.enable = rx71_pn544_nfc_enable,
+	.test = rx71_pn544_nfc_test,
+	.disable = rx71_pn544_nfc_disable,
+};
diff --git a/drivers/Kconfig b/drivers/Kconfig
index a2b902f..d7f27d6 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -111,4 +111,6 @@ source "drivers/xen/Kconfig"
 source "drivers/staging/Kconfig"
 
 source "drivers/platform/Kconfig"
+
+source "drivers/nfc/Kconfig"
 endmenu
diff --git a/drivers/Makefile b/drivers/Makefile
index a2aea53..a6705ff 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -39,7 +39,7 @@ obj-$(CONFIG_FB_INTEL)          += video/intelfb/
 
 obj-y				+= serial/
 obj-$(CONFIG_PARPORT)		+= parport/
-obj-y				+= base/ block/ misc/ mfd/
+obj-y				+= base/ block/ misc/ mfd/ nfc/
 obj-$(CONFIG_NUBUS)		+= nubus/
 obj-y				+= macintosh/
 obj-$(CONFIG_IDE)		+= ide/
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
new file mode 100644
index 0000000..ffedfd4
--- /dev/null
+++ b/drivers/nfc/Kconfig
@@ -0,0 +1,30 @@
+#
+# Near Field Communication (NFC) devices
+#
+
+menuconfig NFC_DEVICES
+	bool "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
+
+config PN544_NFC
+	tristate "PN544 NFC driver"
+	depends on I2C
+	select CRC_CCITT
+	default n
+	---help---
+	  Say yes if you want PN544 Near Field Communication driver.
+	  This is for i2c connected version. If unsure, say N here.
+
+	  To compile this driver as a module, choose m here. The module will
+	  be called pn544.
+
+
+endif # NFC_DEVICES
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
new file mode 100644
index 0000000..a4efb16
--- /dev/null
+++ b/drivers/nfc/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for nfc devices
+#
+
+obj-$(CONFIG_PN544_NFC)		+= pn544.o
diff --git a/drivers/nfc/pn544.c b/drivers/nfc/pn544.c
new file mode 100644
index 0000000..8891023
--- /dev/null
+++ b/drivers/nfc/pn544.c
@@ -0,0 +1,893 @@
+/*
+ * Driver for the PN544 NFC chip.
+ *
+ * Copyright (C) Nokia Corporation
+ *
+ * Author: Jari Vanhala <ext-jari.vanhala-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
+ * Contact: Matti Aaltonen <matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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/completion.h>
+#include <linux/crc-ccitt.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/miscdevice.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/nfc/pn544.h>
+#include <linux/poll.h>
+#include <linux/regulator/consumer.h>
+#include <linux/serial_core.h> /* for TCGETS */
+#include <linux/slab.h>
+
+#define DRIVER_CARD	"PN544 NFC"
+#define DRIVER_DESC	"NFC driver for PN544"
+
+static struct i2c_device_id pn544_id_table[] = {
+	{ PN544_DRIVER_NAME, 0 },
+	{ }
+};
+MODULE_DEVICE_TABLE(i2c, pn544_id_table);
+
+#define HCI_MODE	0
+#define FW_MODE		1
+
+enum pn544_state {
+	PN544_ST_COLD,
+	PN544_ST_FW_READY,
+	PN544_ST_READY,
+};
+
+enum pn544_irq {
+	PN544_NONE,
+	PN544_INT,
+};
+
+struct pn544_info {
+	struct miscdevice miscdev;
+	struct i2c_client *i2c_dev;
+	struct regulator_bulk_data regs[2];
+
+	enum pn544_state state;
+	wait_queue_head_t read_wait;
+	loff_t read_offset;
+	enum pn544_irq read_irq;
+	struct mutex read_mutex; /* Serialize read_irq access */
+	struct mutex mutex; /* Serialize info struct access */
+	u8 *buf;
+	unsigned int buflen;
+};
+
+static const char reg_vdd_io[]	= "Vdd_IO";
+static const char reg_vbat[]	= "VBat";
+
+/* sysfs interface */
+static ssize_t pn544_test(struct device *dev,
+			  struct device_attribute *attr, char *buf)
+{
+	struct pn544_info *info = dev_get_drvdata(dev);
+	struct i2c_client *client = info->i2c_dev;
+	struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
+
+	return snprintf(buf, PAGE_SIZE, "%d\n", pdata->test());
+}
+
+static int pn544_enable(struct pn544_info *info, int mode)
+{
+	struct pn544_nfc_platform_data *pdata;
+	struct i2c_client *client = info->i2c_dev;
+
+	int r;
+
+	r = regulator_bulk_enable(ARRAY_SIZE(info->regs), info->regs);
+	if (r < 0)
+		return r;
+
+	pdata = client->dev.platform_data;
+	info->read_irq = PN544_NONE;
+	if (pdata->enable)
+		pdata->enable(mode);
+
+	if (mode) {
+		info->state = PN544_ST_FW_READY;
+		dev_dbg(&client->dev, "now in FW-mode\n");
+	} else {
+		info->state = PN544_ST_READY;
+		dev_dbg(&client->dev, "now in HCI-mode\n");
+	}
+
+	msleep(PN544_BOOT_TIME);
+
+	return 0;
+}
+
+static void pn544_disable(struct pn544_info *info)
+{
+	struct pn544_nfc_platform_data *pdata;
+	struct i2c_client *client = info->i2c_dev;
+
+	pdata = client->dev.platform_data;
+	if (pdata->disable)
+		pdata->disable();
+
+	info->state = PN544_ST_COLD;
+
+	dev_dbg(&client->dev, "Now in OFF-mode\n");
+
+	msleep(PN544_RESETVEN_TIME);
+
+	info->read_irq = PN544_NONE;
+	regulator_bulk_disable(ARRAY_SIZE(info->regs), info->regs);
+}
+
+static int check_crc(u8 *buf, int buflen)
+{
+	u8 len;
+	u16 crc;
+
+	len = buf[0] + 1;
+	if (len < 4 || len != buflen || len > PN544_MSG_MAX_SIZE) {
+		pr_err(PN544_DRIVER_NAME
+		       ": CRC; corrupt packet len %u (%d)\n", len, buflen);
+		print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
+			       16, 2, buf, buflen, false);
+		return -EPERM;
+	}
+	crc = crc_ccitt(0xffff, buf, len - 2);
+	crc = ~crc;
+
+	if (buf[len-2] != (crc & 0xff) || buf[len-1] != (crc >> 8)) {
+		pr_err(PN544_DRIVER_NAME ": CRC error 0x%x != 0x%x 0x%x\n",
+		       crc, buf[len-1], buf[len-2]);
+
+		print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
+			       16, 2, buf, buflen, false);
+		return -EPERM;
+	}
+	return 0;
+}
+
+static int pn544_i2c_write(struct i2c_client *client, u8 *buf, int len)
+{
+	int r;
+
+	if (len < 4 || len != (buf[0] + 1)) {
+		dev_err(&client->dev, "%s: Illegal message length: %d\n",
+			__func__, len);
+		return -EINVAL;
+	}
+
+	if (check_crc(buf, len))
+		return -EINVAL;
+
+
+	msleep(PN544_I2C_IO_TIME);
+
+	r = i2c_master_send(client, buf, len);
+	dev_dbg(&client->dev, "send: %d\n", r);
+
+	if (r == -EREMOTEIO) { /* Retry, chip was in standby */
+		msleep(PN544_WAKEUP_GUARD);
+		r = i2c_master_send(client, buf, len);
+		dev_dbg(&client->dev, "send2: %d\n", r);
+	}
+
+	if (r != len)
+		return -EREMOTEIO;
+
+	return r;
+}
+
+static int pn544_i2c_read(struct i2c_client *client, u8 *buf, int buflen)
+{
+	int r;
+	u8 len;
+
+	/*
+	 * You could read a packet in one go, but then you'd need to read
+	 * max size and rest would be 0xff fill, so we do split reads.
+	 */
+	r = i2c_master_recv(client, &len, 1);
+	dev_dbg(&client->dev, "recv1: %d\n", r);
+
+	if (r != 1)
+		return -EREMOTEIO;
+
+	if (len < PN544_LLC_HCI_OVERHEAD)
+		len = PN544_LLC_HCI_OVERHEAD;
+	else if (len > (PN544_MSG_MAX_SIZE - 1))
+		len = PN544_MSG_MAX_SIZE - 1;
+
+	if (1 + len > buflen) /* len+(data+crc16) */
+		return -EMSGSIZE;
+
+	buf[0] = len;
+
+	r = i2c_master_recv(client, buf + 1, len);
+	dev_dbg(&client->dev, "recv2: %d\n", r);
+
+	if (r != len)
+		return -EREMOTEIO;
+
+	msleep(PN544_I2C_IO_TIME);
+
+	return r + 1;
+}
+
+static int pn544_fw_write(struct i2c_client *client, u8 *buf, int len)
+{
+	int r;
+
+	dev_dbg(&client->dev, "%s\n", __func__);
+
+	if (len < PN544_FW_HEADER_SIZE ||
+	    (PN544_FW_HEADER_SIZE + (buf[1] << 8) + buf[2]) != len)
+		return -EINVAL;
+
+	r = i2c_master_send(client, buf, len);
+	dev_dbg(&client->dev, "fw send: %d\n", r);
+
+	if (r == -EREMOTEIO) { /* Retry, chip was in standby */
+		msleep(PN544_WAKEUP_GUARD);
+		r = i2c_master_send(client, buf, len);
+		dev_dbg(&client->dev, "fw send2: %d\n", r);
+	}
+
+	if (r != len)
+		return -EREMOTEIO;
+
+	return r;
+}
+
+static int pn544_fw_read(struct i2c_client *client, u8 *buf, int buflen)
+{
+	int r, len;
+
+	if (buflen < PN544_FW_HEADER_SIZE)
+		return -EINVAL;
+
+	r = i2c_master_recv(client, buf, PN544_FW_HEADER_SIZE);
+	dev_dbg(&client->dev, "FW recv1: %d\n", r);
+
+	if (r < 0)
+		return r;
+
+	if (r < PN544_FW_HEADER_SIZE)
+		return -EINVAL;
+
+	len = (buf[1] << 8) + buf[2];
+	if (len == 0) /* just header, no additional data */
+		return r;
+
+	if (len > buflen - PN544_FW_HEADER_SIZE)
+		return -EMSGSIZE;
+
+	r = i2c_master_recv(client, buf + PN544_FW_HEADER_SIZE, len);
+	dev_dbg(&client->dev, "fw recv2: %d\n", r);
+
+	if (r != len)
+		return -EINVAL;
+
+	return r + PN544_FW_HEADER_SIZE;
+}
+
+static irqreturn_t pn544_irq_thread_fn(int irq, void *dev_id)
+{
+	struct pn544_info *info = dev_id;
+	struct i2c_client *client = info->i2c_dev;
+
+	BUG_ON(!info);
+	BUG_ON(irq != info->i2c_dev->irq);
+
+	dev_dbg(&client->dev, "IRQ\n");
+
+	mutex_lock(&info->read_mutex);
+	info->read_irq = PN544_INT;
+	mutex_unlock(&info->read_mutex);
+
+	wake_up_interruptible(&info->read_wait);
+
+	return IRQ_HANDLED;
+}
+
+static enum pn544_irq pn544_irq_state(struct pn544_info *info)
+{
+	enum pn544_irq irq;
+
+	mutex_lock(&info->read_mutex);
+	irq = info->read_irq;
+	mutex_unlock(&info->read_mutex);
+	/*
+	 * XXX: should we check GPIO-line status directly?
+	 * return pdata->irq_status() ? PN544_INT : PN544_NONE;
+	 */
+
+	return irq;
+}
+
+static ssize_t pn544_read(struct file *file, char __user *buf,
+			  size_t count, loff_t *offset)
+{
+	struct pn544_info *info = container_of(file->private_data,
+					       struct pn544_info, miscdev);
+	struct i2c_client *client = info->i2c_dev;
+	enum pn544_irq irq;
+	size_t len;
+	int r = 0;
+
+	dev_dbg(&client->dev, "%s: info: %p, count: %d\n", __func__,
+		info, count);
+
+	mutex_lock(&info->mutex);
+
+	if (info->state == PN544_ST_COLD) {
+		r = -ENODEV;
+		goto out;
+	}
+
+	irq = pn544_irq_state(info);
+	if (irq == PN544_NONE) {
+		if (file->f_flags & O_NONBLOCK) {
+			r = -EAGAIN;
+			goto out;
+		}
+
+		if (wait_event_interruptible(info->read_wait,
+					     (info->read_irq == PN544_INT))) {
+			r = -ERESTARTSYS;
+			goto out;
+		}
+	}
+
+	if (info->state == PN544_ST_FW_READY) {
+		len = min(count, info->buflen);
+
+		mutex_lock(&info->read_mutex);
+		r = pn544_fw_read(info->i2c_dev, info->buf, len);
+		info->read_irq = PN544_NONE;
+		mutex_unlock(&info->read_mutex);
+
+		if (r < 0) {
+			dev_err(&info->i2c_dev->dev, "FW read failed: %d\n", r);
+			goto out;
+		}
+
+		print_hex_dump(KERN_DEBUG, "FW read: ", DUMP_PREFIX_NONE,
+			       16, 2, info->buf, r, false);
+
+		*offset += r;
+		if (copy_to_user(buf, info->buf, r)) {
+			r = -EFAULT;
+			goto out;
+		}
+	} else {
+		len = min(count, info->buflen);
+
+		mutex_lock(&info->read_mutex);
+		r = pn544_i2c_read(info->i2c_dev, info->buf, len);
+		info->read_irq = PN544_NONE;
+		mutex_unlock(&info->read_mutex);
+
+		if (r < 0) {
+			dev_err(&info->i2c_dev->dev, "read failed (%d)\n", r);
+			goto out;
+		}
+		print_hex_dump(KERN_DEBUG, "read: ", DUMP_PREFIX_NONE,
+			       16, 2, info->buf, r, false);
+
+		*offset += r;
+		if (copy_to_user(buf, info->buf, r)) {
+			r = -EFAULT;
+			goto out;
+		}
+	}
+
+out:
+	mutex_unlock(&info->mutex);
+
+	return r;
+}
+
+static unsigned int pn544_poll(struct file *file, poll_table *wait)
+{
+	struct pn544_info *info = container_of(file->private_data,
+					       struct pn544_info, miscdev);
+	struct i2c_client *client = info->i2c_dev;
+	int r = 0;
+
+	dev_dbg(&client->dev, "%s: info: %p\n", __func__, info);
+
+	mutex_lock(&info->mutex);
+
+	if (info->state == PN544_ST_COLD) {
+		r = -ENODEV;
+		goto out;
+	}
+
+	poll_wait(file, &info->read_wait, wait);
+
+	if (pn544_irq_state(info) == PN544_INT) {
+		r = POLLIN | POLLRDNORM;
+		goto out;
+	}
+out:
+	mutex_unlock(&info->mutex);
+
+	return r;
+}
+
+static ssize_t pn544_write(struct file *file, const char __user *buf,
+			   size_t count, loff_t *ppos)
+{
+	struct pn544_info *info = container_of(file->private_data,
+					       struct pn544_info, miscdev);
+	struct i2c_client *client = info->i2c_dev;
+	ssize_t	len;
+	int r;
+
+	dev_dbg(&client->dev, "%s: info: %p, count %d\n", __func__,
+		info, count);
+
+	mutex_lock(&info->mutex);
+
+	if (info->state == PN544_ST_COLD) {
+		r = -ENODEV;
+		goto out;
+	}
+
+	/*
+	 * XXX: should we detect rset-writes and clean possible
+	 * read_irq state
+	 */
+	if (info->state == PN544_ST_FW_READY) {
+		size_t fw_len;
+
+		if (count < PN544_FW_HEADER_SIZE) {
+			r = -EINVAL;
+			goto out;
+		}
+
+		len = min(count, info->buflen);
+		if (copy_from_user(info->buf, buf, len)) {
+			r = -EFAULT;
+			goto out;
+		}
+
+		print_hex_dump(KERN_DEBUG, "FW write: ", DUMP_PREFIX_NONE,
+			       16, 2, info->buf, len, false);
+
+		fw_len = PN544_FW_HEADER_SIZE + (info->buf[1] << 8) +
+			info->buf[2];
+
+		if (len > fw_len) /* 1 msg at a time */
+			len = fw_len;
+
+		r = pn544_fw_write(info->i2c_dev, info->buf, len);
+	} else {
+		if (count < PN544_LLC_MIN_SIZE) {
+			r = -EINVAL;
+			goto out;
+		}
+
+		len = min(count, info->buflen);
+		if (copy_from_user(info->buf, buf, len)) {
+			r = -EFAULT;
+			goto out;
+		}
+
+		print_hex_dump(KERN_DEBUG, "write: ", DUMP_PREFIX_NONE,
+			       16, 2, info->buf, len, false);
+
+		if (len > (info->buf[0] + 1)) /* 1 msg at a time */
+			len  = info->buf[0] + 1;
+
+		r = pn544_i2c_write(info->i2c_dev, info->buf, len);
+	}
+out:
+	mutex_unlock(&info->mutex);
+
+	return r;
+
+}
+
+static long pn544_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	struct pn544_info *info = container_of(file->private_data,
+					       struct pn544_info, miscdev);
+	struct i2c_client *client = info->i2c_dev;
+	struct pn544_nfc_platform_data *pdata;
+	unsigned int val;
+	int r = 0;
+
+	dev_dbg(&client->dev, "%s: info: %p, cmd: 0x%x\n", __func__, info, cmd);
+
+	mutex_lock(&info->mutex);
+
+	if (info->state == PN544_ST_COLD) {
+		r = -ENODEV;
+		goto out;
+	}
+
+	pdata = info->i2c_dev->dev.platform_data;
+	switch (cmd) {
+	case PN544_GET_FW_MODE:
+		dev_dbg(&client->dev, "%s:  PN544_GET_FW_MODE\n", __func__);
+
+		val = (info->state == PN544_ST_FW_READY);
+		if (copy_to_user((void __user *)arg, &val, sizeof(val))) {
+			r = -EFAULT;
+			goto out;
+		}
+
+		break;
+
+	case PN544_SET_FW_MODE:
+		dev_dbg(&client->dev, "%s:  PN544_SET_FW_MODE\n", __func__);
+
+		if (copy_from_user(&val, (void __user *)arg, sizeof(val))) {
+			r = -EFAULT;
+			goto out;
+		}
+
+		if (val) {
+			if (info->state == PN544_ST_FW_READY)
+				break;
+
+			pn544_disable(info);
+			r = pn544_enable(info, FW_MODE);
+			if (r < 0)
+				goto out;
+		} else {
+			if (info->state == PN544_ST_READY)
+				break;
+			pn544_disable(info);
+			r = pn544_enable(info, HCI_MODE);
+			if (r < 0)
+				goto out;
+		}
+		file->f_pos = info->read_offset;
+		break;
+
+	case TCGETS:
+		dev_dbg(&client->dev, "%s:  TCGETS\n", __func__);
+
+		r = -ENOIOCTLCMD;
+		break;
+
+	default:
+		dev_err(&client->dev, "Unknown ioctl 0x%x\n", cmd);
+		r = -ENOIOCTLCMD;
+		break;
+	}
+
+out:
+	mutex_unlock(&info->mutex);
+
+	return r;
+}
+
+static int pn544_open(struct inode *inode, struct file *file)
+{
+	struct pn544_info *info = container_of(file->private_data,
+					       struct pn544_info, miscdev);
+	struct i2c_client *client = info->i2c_dev;
+	int r = 0;
+
+	dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__,
+		info, info->i2c_dev);
+
+	mutex_lock(&info->mutex);
+
+	/*
+	 * Only 1 at a time.
+	 * XXX: maybe user (counter) would work better
+	 */
+	if (info->state != PN544_ST_COLD) {
+		r = -EBUSY;
+		goto out;
+	}
+
+	file->f_pos = info->read_offset;
+	r = pn544_enable(info, HCI_MODE);
+
+out:
+	mutex_unlock(&info->mutex);
+	return r;
+}
+
+static int pn544_close(struct inode *inode, struct file *file)
+{
+	struct pn544_info *info = container_of(file->private_data,
+					       struct pn544_info, miscdev);
+	struct i2c_client *client = info->i2c_dev;
+
+	dev_dbg(&client->dev, "%s: info: %p, client %p\n",
+		__func__, info, info->i2c_dev);
+
+	mutex_lock(&info->mutex);
+	pn544_disable(info);
+	mutex_unlock(&info->mutex);
+
+	return 0;
+}
+
+static const struct file_operations pn544_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= pn544_read,
+	.write		= pn544_write,
+	.poll		= pn544_poll,
+	.open		= pn544_open,
+	.release	= pn544_close,
+	.unlocked_ioctl		= pn544_ioctl,
+};
+
+#ifdef CONFIG_PM
+static int pn544_suspend(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pn544_info *info;
+	int r = 0;
+
+	dev_info(&client->dev, "***\n%s: client %p\n***\n", __func__, client);
+
+	info = i2c_get_clientdata(client);
+	dev_info(&client->dev, "%s: info: %p, client %p\n", __func__,
+		 info, client);
+
+	mutex_lock(&info->mutex);
+
+	switch (info->state) {
+	case PN544_ST_FW_READY:
+		/* Do not suspend while upgrading FW, please! */
+		r = -EPERM;
+		break;
+
+	case PN544_ST_READY:
+		/*
+		 * CHECK: Device should be in standby-mode. No way to check?
+		 * Allowing low power mode for the regulator is potentially
+		 * dangerous if pn544 does not go to suspension.
+		 */
+		break;
+
+	case PN544_ST_COLD:
+		break;
+	};
+
+	mutex_unlock(&info->mutex);
+	return r;
+}
+
+static int pn544_resume(struct device *dev)
+{
+	struct i2c_client *client = to_i2c_client(dev);
+	struct pn544_info *info = i2c_get_clientdata(client);
+	int r = 0;
+
+	dev_dbg(&client->dev, "%s: info: %p, client %p\n", __func__,
+		info, client);
+
+	mutex_lock(&info->mutex);
+
+	switch (info->state) {
+	case PN544_ST_READY:
+		/*
+		 * CHECK: If regulator low power mode is allowed in
+		 * pn544_suspend, we should go back to normal mode
+		 * here.
+		 */
+		break;
+
+	case PN544_ST_COLD:
+		break;
+
+	case PN544_ST_FW_READY:
+		break;
+	};
+
+	mutex_unlock(&info->mutex);
+
+	return r;
+}
+
+static SIMPLE_DEV_PM_OPS(pn544_pm_ops, pn544_suspend, pn544_resume);
+#endif
+
+static struct device_attribute pn544_attr =
+	__ATTR(nfc_test, S_IRUGO, pn544_test, NULL);
+
+static int __devinit pn544_probe(struct i2c_client *client,
+				 const struct i2c_device_id *id)
+{
+	struct pn544_info *info;
+	struct pn544_nfc_platform_data *pdata;
+	int r = 0;
+
+	dev_dbg(&client->dev, "%s\n", __func__);
+	dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
+
+	/* private data allocation */
+	info = kzalloc(sizeof(struct pn544_info), GFP_KERNEL);
+	if (!info) {
+		dev_err(&client->dev,
+			"Cannot allocate memory for pn544_info.\n");
+		r = -ENOMEM;
+		goto err_info_alloc;
+	}
+
+	info->buflen = max(PN544_MSG_MAX_SIZE, PN544_MAX_I2C_TRANSFER);
+	info->buf = kzalloc(info->buflen, GFP_KERNEL);
+	if (!info->buf) {
+		dev_err(&client->dev,
+			"Cannot allocate memory for pn544_info->buf.\n");
+		r = -ENOMEM;
+		goto err_buf_alloc;
+	}
+
+	info->regs[0].supply = reg_vdd_io;
+	info->regs[1].supply = reg_vbat;
+	r = regulator_bulk_get(&client->dev, ARRAY_SIZE(info->regs),
+				 info->regs);
+	if (r < 0)
+		goto err_kmalloc;
+
+	info->i2c_dev = client;
+	info->state = PN544_ST_COLD;
+	info->read_irq = PN544_NONE;
+	mutex_init(&info->read_mutex);
+	mutex_init(&info->mutex);
+	init_waitqueue_head(&info->read_wait);
+	i2c_set_clientdata(client, info);
+	pdata = client->dev.platform_data;
+	if (!pdata) {
+		dev_err(&client->dev, "No platform data\n");
+		r = -EINVAL;
+		goto err_reg;
+	}
+
+	if (!pdata->request_resources) {
+		dev_err(&client->dev, "request_resources() missing\n");
+		r = -EINVAL;
+		goto err_reg;
+	}
+
+	r = pdata->request_resources(client);
+	if (r) {
+		dev_err(&client->dev, "Cannot get platform resources\n");
+		goto err_reg;
+	}
+
+	r = request_threaded_irq(client->irq, NULL, pn544_irq_thread_fn,
+				 IRQF_TRIGGER_RISING, PN544_DRIVER_NAME,
+				 info);
+	if (r < 0) {
+		dev_err(&client->dev, "Unable to register IRQ handler\n");
+		goto err_res;
+	}
+
+	/* If we don't have the test we don't need the sysfs file */
+	if (pdata->test) {
+		r = device_create_file(&client->dev, &pn544_attr);
+		if (r) {
+			dev_err(&client->dev,
+				"sysfs registration failed, error %d\n", r);
+			goto err_irq;
+		}
+	}
+
+	info->miscdev.minor = MISC_DYNAMIC_MINOR;
+	info->miscdev.name = PN544_DRIVER_NAME;
+	info->miscdev.fops = &pn544_fops;
+	info->miscdev.parent = &client->dev;
+	r = misc_register(&info->miscdev);
+	if (r < 0) {
+		dev_err(&client->dev, "Device registration failed\n");
+		goto err_sysfs;
+	}
+
+	dev_dbg(&client->dev, "%s: info: %p, pdata %p, client %p\n",
+		__func__, info, pdata, client);
+
+	return 0;
+
+err_sysfs:
+	if (pdata->test)
+		device_remove_file(&client->dev, &pn544_attr);
+err_irq:
+	free_irq(client->irq, info);
+err_res:
+	if (pdata->free_resources)
+		pdata->free_resources();
+err_reg:
+	regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs);
+err_kmalloc:
+	kfree(info->buf);
+err_buf_alloc:
+	kfree(info);
+err_info_alloc:
+	return r;
+}
+
+static __devexit int pn544_remove(struct i2c_client *client)
+{
+	struct pn544_info *info = i2c_get_clientdata(client);
+	struct pn544_nfc_platform_data *pdata = client->dev.platform_data;
+
+	dev_dbg(&client->dev, "%s\n", __func__);
+
+	misc_deregister(&info->miscdev);
+	if (pdata->test)
+		device_remove_file(&client->dev, &pn544_attr);
+
+	if (info->state != PN544_ST_COLD) {
+		if (pdata->disable)
+			pdata->disable();
+
+		info->read_irq = PN544_NONE;
+	}
+
+	free_irq(client->irq, info);
+	if (pdata->free_resources)
+		pdata->free_resources();
+
+	regulator_bulk_free(ARRAY_SIZE(info->regs), info->regs);
+	kfree(info->buf);
+	kfree(info);
+
+	return 0;
+}
+
+static struct i2c_driver pn544_driver = {
+	.driver = {
+		.name = PN544_DRIVER_NAME,
+#ifdef CONFIG_PM
+		.pm = &pn544_pm_ops,
+#endif
+	},
+	.probe = pn544_probe,
+	.id_table = pn544_id_table,
+	.remove = __devexit_p(pn544_remove),
+};
+
+static int __init pn544_init(void)
+{
+	int r;
+
+	pr_debug(DRIVER_DESC ": %s\n", __func__);
+
+	r = i2c_add_driver(&pn544_driver);
+	if (r) {
+		pr_err(PN544_DRIVER_NAME ": driver registration failed\n");
+		return r;
+	}
+
+	return 0;
+}
+
+static void __exit pn544_exit(void)
+{
+	flush_scheduled_work();
+	i2c_del_driver(&pn544_driver);
+	pr_info(DRIVER_DESC ", Exiting.\n");
+}
+
+module_init(pn544_init);
+module_exit(pn544_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/include/linux/nfc/pn544.h b/include/linux/nfc/pn544.h
new file mode 100644
index 0000000..e7df641
--- /dev/null
+++ b/include/linux/nfc/pn544.h
@@ -0,0 +1,99 @@
+/*
+ * Driver include for the PN544 NFC chip.
+ *
+ * Copyright (C) Nokia Corporation
+ *
+ * Author: Jari Vanhala <ext-jari.vanhala-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
+ * Contact: Matti Aaltoenn <matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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 _PN544_H_
+#define _PN544_H_
+
+#include <linux/i2c.h>
+
+#define PN544_DRIVER_NAME	"pn544"
+#define PN544_MAXWINDOW_SIZE	7
+#define PN544_WINDOW_SIZE	4
+#define PN544_RETRIES		10
+#define PN544_MAX_I2C_TRANSFER	0x0400
+#define PN544_MSG_MAX_SIZE	0x21 /* at normal HCI mode */
+
+/* ioctl */
+#define PN544_CHAR_BASE		'P'
+#define PN544_IOR(num, dtype)	_IOR(PN544_CHAR_BASE, num, dtype)
+#define PN544_IOW(num, dtype)	_IOW(PN544_CHAR_BASE, num, dtype)
+#define PN544_GET_FW_MODE	PN544_IOW(1, unsigned int)
+#define PN544_SET_FW_MODE	PN544_IOW(2, unsigned int)
+#define PN544_GET_DEBUG		PN544_IOW(3, unsigned int)
+#define PN544_SET_DEBUG		PN544_IOW(4, unsigned int)
+
+/* Timing restrictions (ms) */
+#define PN544_RESETVEN_TIME	30 /* 7 */
+#define PN544_PVDDVEN_TIME	0
+#define PN544_VBATVEN_TIME	0
+#define PN544_GPIO4VEN_TIME	0
+#define PN544_BOOT_TIME		10 /* 3 */
+#define PN544_I2C_IO_TIME	3 /* 100 */
+#define PN544_WAKEUP_ACK	5
+#define PN544_WAKEUP_GUARD	(PN544_WAKEUP_ACK + 1)
+#define PN544_INACTIVITY_TIME	1000
+#define PN544_INTERFRAME_DELAY	200 /* us */
+#define PN544_BAUDRATE_CHANGE	150 /* us */
+
+/* Debug bits */
+#define PN544_DEBUG_BUF		0x01
+#define PN544_DEBUG_READ	0x02
+#define PN544_DEBUG_WRITE	0x04
+#define PN544_DEBUG_IRQ		0x08
+#define PN544_DEBUG_CALLS	0x10
+#define PN544_DEBUG_MODE	0x20
+
+/* Normal (HCI) mode */
+#define PN544_LLC_HCI_OVERHEAD	3 /* header + crc (to length) */
+#define PN544_LLC_MIN_SIZE	(1 + PN544_LLC_HCI_OVERHEAD) /* length + */
+#define PN544_LLC_MAX_DATA	(PN544_MSG_MAX_SIZE - 2)
+#define PN544_LLC_MAX_HCI_SIZE	(PN544_LLC_MAX_DATA - 2)
+
+struct pn544_llc_packet {
+	unsigned char length; /* of rest of packet */
+	unsigned char header;
+	unsigned char data[PN544_LLC_MAX_DATA]; /* includes crc-ccitt */
+};
+
+/* Firmware upgrade mode */
+#define PN544_FW_HEADER_SIZE	3
+/* max fw transfer is 1024bytes, but I2C limits it to 0xC0 */
+#define PN544_MAX_FW_DATA	(PN544_MAX_I2C_TRANSFER - PN544_FW_HEADER_SIZE)
+
+struct pn544_fw_packet {
+	unsigned char command; /* status in answer */
+	unsigned char length[2]; /* big-endian order (msf) */
+	unsigned char data[PN544_MAX_FW_DATA];
+};
+
+#ifdef __KERNEL__
+/* board config */
+struct pn544_nfc_platform_data {
+	int (*request_resources) (struct i2c_client *client);
+	void (*free_resources) (void);
+	void (*enable) (int fw);
+	int (*test) (void);
+	void (*disable) (void);
+};
+#endif /* __KERNEL__ */
+
+#endif /* _PN544_H_ */
-- 
1.6.1.3

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

* Re: [PATCH v2 0/1] PN544 NFC driver.
       [not found] ` <1288333569-19979-1-git-send-email-matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
  2010-10-29  6:26   ` [PATCH v2 1/1] NFC: Driver for NXP Semiconductors PN544 NFC chip Matti J. Aaltonen
@ 2010-10-29 21:33   ` Andrew Morton
       [not found]     ` <20101029143333.db43953b.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
  1 sibling, 1 reply; 9+ messages in thread
From: Andrew Morton @ 2010-10-29 21:33 UTC (permalink / raw)
  To: Matti J. Aaltonen; +Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA

On Fri, 29 Oct 2010 09:26:08 +0300
"Matti J. Aaltonen" <matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org> wrote:

> Hello.
> 
> And thanks to Andrew for the comments.
> 
> >> include/linux/pn544.h |   99 ++++++
> > 
> > Is drivers/misc/ the best place for this?
> > 
> > Don't be afraid to create a new drivers/nfc/ even if it has only one
> > driver in it.  If someone later comes in and adds a new NFC driver then
> > things will all fall into place.
> 
> OK. Now I've created directories drivers/nfc, include/linux/nfc and Documentation/nfc.

I beefed up the changelog a bit, telling people what "nfc" is.

We really should tell more people that we're adding a new subsystem. 
Can you please resend the patchset, cc'ing linux-kernel?

> >> +/* sysfs interface */
> > 
> > OK, this is more serious.
> > 
> > You're proposing a permanent addition to the kernel ABI.  This is the
> > most important part of the driver because it is something we can never
> > change.  This interface is the very first thing we'll want to
> > understand and review, before we even look at the implementation.
> > 
> > And it isn't even described!  Not in the changelog, not in a
> > documentation file, not even in code comments.
> > 
> > Please, provide a description of this proposed interface.  Sufficient
> > for reviewers to understand it and for users to use it.  Pobably this
> > will require some description of the hardware functions as well.
> > 
> > Please also consider updating Documentation/ABI/
> 
> I've added a documentation file. But I didn't make changes to the interface
> yet.

So we can expect some updates?

> > 
> > And an ioctl interface as well!  An undocmented one.
> > 
> > ioctls are pretty unpopular for various reasons.  To a large extent,
> > people have been using sysfs interfaces as a repalcement for ioctl()s.
> > But this driver has both!
> 
> Some explanatory text written into the documentation file.

So, the sysfs interface is purely for running a device test?

And primary communication is via the /dev node, and that node supports
an ioctl() which changes the meaning of reads and writes to that node?

If so, that's a bit of a peculiar interface.  Perhaps there should have
been two /dev nodes.  Certainly it would be most popular if the ioctl()
interface were to simply disappear.

Please, do spell all of this out in some detail within the changelog
when resending the code for wider review.  There are people out there
(eg Greg, Alan) who are better at these things than I and we should
provide them with all the details up-front without going through
another question-and-answer session or expecting them to grovel through
code to reverse-engineer the interfaces.

Another consideration here is that if we do expect more NFC devices and
drivers for them, then we should aim for some standardisation of the
interface, from day one.  Some discussion of this would also be helpful
for reviewers.


One other thing: these messages which flow between userspace and the
device.  Are they documented or sufficiently well understood so that
non-Nokia people can use this driver?

Because we had a driver come up a couple of weeks ago.  It was a
simple, clean driver but all it did was to shuffle opaque data between
userspace and the device, and the contents of that data was not
publicly available.  I discussed the driver with Linus and he said "no".

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

* Re: [PATCH v2 1/1] NFC: Driver for NXP Semiconductors PN544 NFC chip.
       [not found]     ` <1288333569-19979-2-git-send-email-matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
@ 2010-10-29 21:35       ` Andrew Morton
       [not found]         ` <20101029143500.bc1cbc7d.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
  0 siblings, 1 reply; 9+ messages in thread
From: Andrew Morton @ 2010-10-29 21:35 UTC (permalink / raw)
  To: Matti J. Aaltonen; +Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA

On Fri, 29 Oct 2010 09:26:09 +0300
"Matti J. Aaltonen" <matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org> wrote:

> +static void __exit pn544_exit(void)
> +{
> +	flush_scheduled_work();

You said this had been removed.  Did you send the correct version?

> +	i2c_del_driver(&pn544_driver);
> +	pr_info(DRIVER_DESC ", Exiting.\n");
> +}

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

* Re: [PATCH v2 0/1] PN544 NFC driver.
       [not found]     ` <20101029143333.db43953b.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
@ 2010-10-29 22:50       ` Mark Brown
       [not found]         ` <20101029225008.GA17654-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
  2010-11-01  8:10       ` Matti J. Aaltonen
  1 sibling, 1 reply; 9+ messages in thread
From: Mark Brown @ 2010-10-29 22:50 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Matti J. Aaltonen, linux-i2c-u79uwXL29TY76Z2rM5mHXA

On Fri, Oct 29, 2010 at 02:33:33PM -0700, Andrew Morton wrote:

> Another consideration here is that if we do expect more NFC devices and
> drivers for them, then we should aim for some standardisation of the
> interface, from day one.  Some discussion of this would also be helpful
> for reviewers.

There's other NFC devices out there being used with Linux.

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

* Re: [PATCH v2 0/1] PN544 NFC driver.
       [not found]     ` <20101029143333.db43953b.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
  2010-10-29 22:50       ` Mark Brown
@ 2010-11-01  8:10       ` Matti J. Aaltonen
  1 sibling, 0 replies; 9+ messages in thread
From: Matti J. Aaltonen @ 2010-11-01  8:10 UTC (permalink / raw)
  To: ext Andrew Morton; +Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA

Hi.

On Fri, 2010-10-29 at 14:33 -0700, ext Andrew Morton wrote:
> On Fri, 29 Oct 2010 09:26:08 +0300
> "Matti J. Aaltonen" <matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org> wrote:
> 
> > Hello.
> > 
> > And thanks to Andrew for the comments.
> > 
> > >> include/linux/pn544.h |   99 ++++++
> > > 
> > > Is drivers/misc/ the best place for this?
> > > 
> > > Don't be afraid to create a new drivers/nfc/ even if it has only one
> > > driver in it.  If someone later comes in and adds a new NFC driver then
> > > things will all fall into place.
> > 
> > OK. Now I've created directories drivers/nfc, include/linux/nfc and Documentation/nfc.
> 
> I beefed up the changelog a bit, telling people what "nfc" is.
> 
> We really should tell more people that we're adding a new subsystem. 
> Can you please resend the patchset, cc'ing linux-kernel?

OK...

> > >> +/* sysfs interface */
> > > 
> > > OK, this is more serious.
> > > 
> > > You're proposing a permanent addition to the kernel ABI.  This is the
> > > most important part of the driver because it is something we can never
> > > change.  This interface is the very first thing we'll want to
> > > understand and review, before we even look at the implementation.
> > > 
> > > And it isn't even described!  Not in the changelog, not in a
> > > documentation file, not even in code comments.
> > > 
> > > Please, provide a description of this proposed interface.  Sufficient
> > > for reviewers to understand it and for users to use it.  Pobably this
> > > will require some description of the hardware functions as well.
> > > 
> > > Please also consider updating Documentation/ABI/
> > 
> > I've added a documentation file. But I didn't make changes to the interface
> > yet.
> 
> So we can expect some updates?

Yes in the sense that I'm not yet sure what the community wants and so
making a big leap could just go in the wrong direction... 

> > > 
> > > And an ioctl interface as well!  An undocmented one.
> > > 
> > > ioctls are pretty unpopular for various reasons.  To a large extent,
> > > people have been using sysfs interfaces as a repalcement for ioctl()s.
> > > But this driver has both!
> > 
> > Some explanatory text written into the documentation file.
> 
> So, the sysfs interface is purely for running a device test?

Yes, and if the board data doesn't contain the test the sysfs interface
doesn't appear.

> And primary communication is via the /dev node, and that node supports
> an ioctl() which changes the meaning of reads and writes to that node?

There is the "normal" mode, which is practice is used something like 99%
of the time and there the special firmware upload mode.

> If so, that's a bit of a peculiar interface.  Perhaps there should have
> been two /dev nodes.  Certainly it would be most popular if the ioctl()
> interface were to simply disappear.

What would be the most popular choice?

> Please, do spell all of this out in some detail within the changelog
> when resending the code for wider review.  There are people out there
> (eg Greg, Alan) who are better at these things than I and we should
> provide them with all the details up-front without going through
> another question-and-answer session or expecting them to grovel through
> code to reverse-engineer the interfaces.

OK I'll try to do that, but I really thought the driver was simple and
the documentation clear enough...

> Another consideration here is that if we do expect more NFC devices and
> drivers for them, then we should aim for some standardisation of the
> interface, from day one.  Some discussion of this would also be helpful
> for reviewers.

I personally think we should aim for standardization.

> One other thing: these messages which flow between userspace and the
> device.  Are they documented or sufficiently well understood so that
> non-Nokia people can use this driver?

You can get the documentation from www.etsi.org as I said in the
document file.

> Because we had a driver come up a couple of weeks ago.  It was a
> simple, clean driver but all it did was to shuffle opaque data between
> userspace and the device, and the contents of that data was not
> publicly available.  I discussed the driver with Linus and he said "no".

Yes I remember, I am the contact person for that driver as well. And I
also though that these two drivers were very similar - except for the
message protocol: "simple and clean". 

Cheers,
Matti

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

* Re: [PATCH v2 1/1] NFC: Driver for NXP Semiconductors PN544 NFC chip.
       [not found]         ` <20101029143500.bc1cbc7d.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
@ 2010-11-01  8:17           ` Matti J. Aaltonen
  0 siblings, 0 replies; 9+ messages in thread
From: Matti J. Aaltonen @ 2010-11-01  8:17 UTC (permalink / raw)
  To: ext Andrew Morton; +Cc: linux-i2c-u79uwXL29TY76Z2rM5mHXA

On Fri, 2010-10-29 at 14:35 -0700, ext Andrew Morton wrote:
> On Fri, 29 Oct 2010 09:26:09 +0300
> "Matti J. Aaltonen" <matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org> wrote:
> 
> > +static void __exit pn544_exit(void)
> > +{
> > +	flush_scheduled_work();
> 
> You said this had been removed.  Did you send the correct version?

I was the "correct" version but I clearly made some kind of mistake when
preparing it, sorry...

Cheers,
Matti

> 
> > +	i2c_del_driver(&pn544_driver);
> > +	pr_info(DRIVER_DESC ", Exiting.\n");
> > +}

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

* Re: [PATCH v2 0/1] PN544 NFC driver.
       [not found]         ` <20101029225008.GA17654-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
@ 2010-11-01 12:25           ` Matti J. Aaltonen
       [not found]             ` <1288614325.1603.96.camel-U1ola594hmgZeDAa2SinrdBPR1lH4CV8@public.gmane.org>
  0 siblings, 1 reply; 9+ messages in thread
From: Matti J. Aaltonen @ 2010-11-01 12:25 UTC (permalink / raw)
  To: ext Mark Brown; +Cc: Andrew Morton, linux-i2c-u79uwXL29TY76Z2rM5mHXA

On Fri, 2010-10-29 at 23:50 +0100, ext Mark Brown wrote:
> On Fri, Oct 29, 2010 at 02:33:33PM -0700, Andrew Morton wrote:
> 
> > Another consideration here is that if we do expect more NFC devices and
> > drivers for them, then we should aim for some standardisation of the
> > interface, from day one.  Some discussion of this would also be helpful
> > for reviewers.
> 
> There's other NFC devices out there being used with Linux.

But NFC drivers are not easy to find. In the kernel code
drivers/parisc/pdc_stable.c contains the following line:

{ USB_DEVICE(0x10C4, 0x8115) }, /* Arygon NFC/Mifare Reader */

That's the only reference to NFC I found.

The NFC/Mifare DDS product datasheet claims that "The Linux driver is
already distributed with recent 2.6 series kernels" but it doesn't seem
to be there...

B.R.
Matti

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

* Re: [PATCH v2 0/1] PN544 NFC driver.
       [not found]             ` <1288614325.1603.96.camel-U1ola594hmgZeDAa2SinrdBPR1lH4CV8@public.gmane.org>
@ 2010-11-01 17:54               ` Mark Brown
  0 siblings, 0 replies; 9+ messages in thread
From: Mark Brown @ 2010-11-01 17:54 UTC (permalink / raw)
  To: Matti J. Aaltonen; +Cc: Andrew Morton, linux-i2c-u79uwXL29TY76Z2rM5mHXA

On Mon, Nov 01, 2010 at 02:25:25PM +0200, Matti J. Aaltonen wrote:
> On Fri, 2010-10-29 at 23:50 +0100, ext Mark Brown wrote:

> > There's other NFC devices out there being used with Linux.

> But NFC drivers are not easy to find. In the kernel code
> drivers/parisc/pdc_stable.c contains the following line:

...

> The NFC/Mifare DDS product datasheet claims that "The Linux driver is
> already distributed with recent 2.6 series kernels" but it doesn't seem
> to be there...

I said nothing about mainline; I've not noticing anything there.  I was
commenting on the question of needing to have an interface which can be
reused by other devices.  I've never actually worked with such parts so
I've no idea what that would look like.

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

end of thread, other threads:[~2010-11-01 17:54 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-10-29  6:26 [PATCH v2 0/1] PN544 NFC driver Matti J. Aaltonen
     [not found] ` <1288333569-19979-1-git-send-email-matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
2010-10-29  6:26   ` [PATCH v2 1/1] NFC: Driver for NXP Semiconductors PN544 NFC chip Matti J. Aaltonen
     [not found]     ` <1288333569-19979-2-git-send-email-matti.j.aaltonen-xNZwKgViW5gAvxtiuMwx3w@public.gmane.org>
2010-10-29 21:35       ` Andrew Morton
     [not found]         ` <20101029143500.bc1cbc7d.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
2010-11-01  8:17           ` Matti J. Aaltonen
2010-10-29 21:33   ` [PATCH v2 0/1] PN544 NFC driver Andrew Morton
     [not found]     ` <20101029143333.db43953b.akpm-de/tnXTf+JLsfHDXvbKv3WD2FQJk+8+b@public.gmane.org>
2010-10-29 22:50       ` Mark Brown
     [not found]         ` <20101029225008.GA17654-GFdadSzt00ze9xe1eoZjHA@public.gmane.org>
2010-11-01 12:25           ` Matti J. Aaltonen
     [not found]             ` <1288614325.1603.96.camel-U1ola594hmgZeDAa2SinrdBPR1lH4CV8@public.gmane.org>
2010-11-01 17:54               ` Mark Brown
2010-11-01  8:10       ` Matti J. Aaltonen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.