浏览代码

Merge tag 'nfc-next-3.14-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next

Samuel Ortiz <sameo@linux.intel.com> says:

"This is the first NFC pull request for 3.14

It includes:

* A new NFC driver for Marvell's 8897, and a few NCI fixes and
  improvements needed to support this chipset.

* An LLCP fix for how we were setting the default MIU on a p2p link. If
  there is no explicit MIU extension announced at connection time, we
  must use the default one and not the one announced at LLCP link
  establishement time.

* A pn544 EEPROM config update. Some of the currently EEPROM configured
  values are overwriting the firmware ones while other should not be set
  by the driver itself.

* Some NFC digital stack fixes and improvements. Asynchronous functions
  are better documented, RF technologies and CRC functions are set upon
  PSL_REQ reception, and a few minor bugs are fixed.

* Minor and miscelaneous pn533, mei_phy and port100 fixes."

Signed-off-by: John W. Linville <linville@tuxdriver.com>
John W. Linville 11 年之前
父节点
当前提交
ec665facde

+ 1 - 0
drivers/nfc/Kconfig

@@ -58,5 +58,6 @@ config NFC_PORT100
 
 source "drivers/nfc/pn544/Kconfig"
 source "drivers/nfc/microread/Kconfig"
+source "drivers/nfc/nfcmrvl/Kconfig"
 
 endmenu

+ 1 - 0
drivers/nfc/Makefile

@@ -9,5 +9,6 @@ obj-$(CONFIG_NFC_WILINK)	+= nfcwilink.o
 obj-$(CONFIG_NFC_MEI_PHY)	+= mei_phy.o
 obj-$(CONFIG_NFC_SIM)		+= nfcsim.o
 obj-$(CONFIG_NFC_PORT100)	+= port100.o
+obj-$(CONFIG_NFC_MRVL)		+= nfcmrvl/
 
 ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG

+ 1 - 1
drivers/nfc/mei_phy.c

@@ -127,7 +127,7 @@ void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context)
 
 		reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
 		if (reply_size < MEI_NFC_HEADER_SIZE) {
-			kfree(skb);
+			kfree_skb(skb);
 			return;
 		}
 

+ 23 - 0
drivers/nfc/nfcmrvl/Kconfig

@@ -0,0 +1,23 @@
+config NFC_MRVL
+	tristate "Marvell NFC driver support"
+	depends on NFC_NCI
+	help
+	  The core driver to support Marvell NFC devices.
+
+	  This driver is required if you want to support
+	  Marvell NFC device 8897.
+
+	  Say Y here to compile Marvell NFC driver into the kernel or
+	  say M to compile it as module.
+
+config NFC_MRVL_USB
+	tristate "Marvell NFC-over-USB driver"
+	depends on NFC_MRVL && USB
+	help
+	  Marvell NFC-over-USB driver.
+
+	  This driver provides support for Marvell NFC-over-USB devices:
+          8897.
+
+	  Say Y here to compile support for Marvell NFC-over-USB driver
+	  into the kernel or say M to compile it as module.

+ 9 - 0
drivers/nfc/nfcmrvl/Makefile

@@ -0,0 +1,9 @@
+#
+# Makefile for NFCMRVL NCI based NFC driver
+#
+
+nfcmrvl-y += main.o
+obj-$(CONFIG_NFC_MRVL) += nfcmrvl.o
+
+nfcmrvl_usb-y += usb.o
+obj-$(CONFIG_NFC_MRVL_USB) += nfcmrvl_usb.o

+ 165 - 0
drivers/nfc/nfcmrvl/main.c

@@ -0,0 +1,165 @@
+/*
+ * Marvell NFC driver: major functions
+ *
+ * Copyright (C) 2014, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available on the worldwide web at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ */
+
+#include <linux/module.h>
+#include <linux/nfc.h>
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include "nfcmrvl.h"
+
+#define VERSION "1.0"
+
+static int nfcmrvl_nci_open(struct nci_dev *ndev)
+{
+	struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
+	int err;
+
+	if (test_and_set_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
+		return 0;
+
+	err = priv->if_ops->nci_open(priv);
+
+	if (err)
+		clear_bit(NFCMRVL_NCI_RUNNING, &priv->flags);
+
+	return err;
+}
+
+static int nfcmrvl_nci_close(struct nci_dev *ndev)
+{
+	struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
+
+	if (!test_and_clear_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
+		return 0;
+
+	priv->if_ops->nci_close(priv);
+
+	return 0;
+}
+
+static int nfcmrvl_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
+{
+	struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
+
+	nfc_info(priv->dev, "send entry, len %d\n", skb->len);
+
+	skb->dev = (void *)ndev;
+
+	if (!test_bit(NFCMRVL_NCI_RUNNING, &priv->flags))
+		return -EBUSY;
+
+	return priv->if_ops->nci_send(priv, skb);
+}
+
+static int nfcmrvl_nci_setup(struct nci_dev *ndev)
+{
+	__u8 val;
+
+	val = NFCMRVL_GPIO_PIN_NFC_NOT_ALLOWED;
+	nci_set_config(ndev, NFCMRVL_NOT_ALLOWED_ID, 1, &val);
+	val = NFCMRVL_GPIO_PIN_NFC_ACTIVE;
+	nci_set_config(ndev, NFCMRVL_ACTIVE_ID, 1, &val);
+	val = NFCMRVL_EXT_COEX_ENABLE;
+	nci_set_config(ndev, NFCMRVL_EXT_COEX_ID, 1, &val);
+
+	return 0;
+}
+
+static struct nci_ops nfcmrvl_nci_ops = {
+	.open = nfcmrvl_nci_open,
+	.close = nfcmrvl_nci_close,
+	.send = nfcmrvl_nci_send,
+	.setup = nfcmrvl_nci_setup,
+};
+
+struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
+						 struct nfcmrvl_if_ops *ops,
+						 struct device *dev)
+{
+	struct nfcmrvl_private *priv;
+	int rc;
+	u32 protocols;
+
+	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+	if (!priv)
+		return ERR_PTR(-ENOMEM);
+
+	priv->drv_data = drv_data;
+	priv->if_ops = ops;
+	priv->dev = dev;
+
+	protocols = NFC_PROTO_JEWEL_MASK
+		| NFC_PROTO_MIFARE_MASK | NFC_PROTO_FELICA_MASK
+		| NFC_PROTO_ISO14443_MASK
+		| NFC_PROTO_ISO14443_B_MASK
+		| NFC_PROTO_NFC_DEP_MASK;
+
+	priv->ndev = nci_allocate_device(&nfcmrvl_nci_ops, protocols, 0, 0);
+	if (!priv->ndev) {
+		nfc_err(dev, "nci_allocate_device failed");
+		rc = -ENOMEM;
+		goto error;
+	}
+
+	nci_set_drvdata(priv->ndev, priv);
+
+	rc = nci_register_device(priv->ndev);
+	if (rc) {
+		nfc_err(dev, "nci_register_device failed %d", rc);
+		nci_free_device(priv->ndev);
+		goto error;
+	}
+
+	nfc_info(dev, "registered with nci successfully\n");
+	return priv;
+
+error:
+	kfree(priv);
+	return ERR_PTR(rc);
+}
+EXPORT_SYMBOL_GPL(nfcmrvl_nci_register_dev);
+
+void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv)
+{
+	struct nci_dev *ndev = priv->ndev;
+
+	nci_unregister_device(ndev);
+	nci_free_device(ndev);
+	kfree(priv);
+}
+EXPORT_SYMBOL_GPL(nfcmrvl_nci_unregister_dev);
+
+int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count)
+{
+	struct sk_buff *skb;
+
+	skb = nci_skb_alloc(priv->ndev, count, GFP_ATOMIC);
+	if (!skb)
+		return -ENOMEM;
+
+	memcpy(skb_put(skb, count), data, count);
+	nci_recv_frame(priv->ndev, skb);
+
+	return count;
+}
+EXPORT_SYMBOL_GPL(nfcmrvl_nci_recv_frame);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell NFC driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL v2");

+ 48 - 0
drivers/nfc/nfcmrvl/nfcmrvl.h

@@ -0,0 +1,48 @@
+/**
+ * Marvell NFC driver
+ *
+ * Copyright (C) 2014, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available on the worldwide web at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ **/
+
+/* Define private flags: */
+#define NFCMRVL_NCI_RUNNING			1
+
+#define NFCMRVL_EXT_COEX_ID			0xE0
+#define NFCMRVL_NOT_ALLOWED_ID			0xE1
+#define NFCMRVL_ACTIVE_ID			0xE2
+#define NFCMRVL_EXT_COEX_ENABLE			1
+#define NFCMRVL_GPIO_PIN_NFC_NOT_ALLOWED	0xA
+#define NFCMRVL_GPIO_PIN_NFC_ACTIVE		0xB
+#define NFCMRVL_NCI_MAX_EVENT_SIZE		260
+
+struct nfcmrvl_private {
+	struct nci_dev *ndev;
+	unsigned long flags;
+	void *drv_data;
+	struct device *dev;
+	struct nfcmrvl_if_ops *if_ops;
+};
+
+struct nfcmrvl_if_ops {
+	int (*nci_open) (struct nfcmrvl_private *priv);
+	int (*nci_close) (struct nfcmrvl_private *priv);
+	int (*nci_send) (struct nfcmrvl_private *priv, struct sk_buff *skb);
+};
+
+void nfcmrvl_nci_unregister_dev(struct nfcmrvl_private *priv);
+int nfcmrvl_nci_recv_frame(struct nfcmrvl_private *priv, void *data, int count);
+struct nfcmrvl_private *nfcmrvl_nci_register_dev(void *drv_data,
+						 struct nfcmrvl_if_ops *ops,
+						 struct device *dev);

+ 459 - 0
drivers/nfc/nfcmrvl/usb.c

@@ -0,0 +1,459 @@
+/**
+ * Marvell NFC-over-USB driver: USB interface related functions
+ *
+ * Copyright (C) 2014, Marvell International Ltd.
+ *
+ * This software file (the "File") is distributed by Marvell International
+ * Ltd. under the terms of the GNU General Public License Version 2, June 1991
+ * (the "License").  You may use, redistribute and/or modify this File in
+ * accordance with the terms and conditions of the License, a copy of which
+ * is available on the worldwide web at
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
+ *
+ * THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
+ * ARE EXPRESSLY DISCLAIMED.  The License provides additional details about
+ * this warranty disclaimer.
+ **/
+
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/nfc.h>
+#include <net/nfc/nci.h>
+#include <net/nfc/nci_core.h>
+#include "nfcmrvl.h"
+
+#define VERSION "1.0"
+
+static struct usb_device_id nfcmrvl_table[] = {
+	{ USB_DEVICE_INTERFACE_CLASS(0x1286, 0x2046, 0xff) },
+	{ }	/* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, nfcmrvl_table);
+
+#define NFCMRVL_USB_BULK_RUNNING	1
+#define NFCMRVL_USB_SUSPENDING		2
+
+struct nfcmrvl_usb_drv_data {
+	struct usb_device *udev;
+	struct usb_interface *intf;
+	unsigned long flags;
+	struct work_struct waker;
+	struct usb_anchor tx_anchor;
+	struct usb_anchor bulk_anchor;
+	struct usb_anchor deferred;
+	int tx_in_flight;
+	/* protects tx_in_flight */
+	spinlock_t txlock;
+	struct usb_endpoint_descriptor *bulk_tx_ep;
+	struct usb_endpoint_descriptor *bulk_rx_ep;
+	int suspend_count;
+	struct nfcmrvl_private *priv;
+};
+
+static int nfcmrvl_inc_tx(struct nfcmrvl_usb_drv_data *drv_data)
+{
+	unsigned long flags;
+	int rv;
+
+	spin_lock_irqsave(&drv_data->txlock, flags);
+	rv = test_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
+	if (!rv)
+		drv_data->tx_in_flight++;
+	spin_unlock_irqrestore(&drv_data->txlock, flags);
+
+	return rv;
+}
+
+static void nfcmrvl_bulk_complete(struct urb *urb)
+{
+	struct nfcmrvl_usb_drv_data *drv_data = urb->context;
+	int err;
+
+	dev_dbg(&drv_data->udev->dev, "urb %p status %d count %d",
+		urb, urb->status, urb->actual_length);
+
+	if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
+		return;
+
+	if (!urb->status) {
+		if (nfcmrvl_nci_recv_frame(drv_data->priv, urb->transfer_buffer,
+					   urb->actual_length) < 0)
+			nfc_err(&drv_data->udev->dev, "corrupted Rx packet");
+	}
+
+	if (!test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags))
+		return;
+
+	usb_anchor_urb(urb, &drv_data->bulk_anchor);
+	usb_mark_last_busy(drv_data->udev);
+
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err) {
+		/* -EPERM: urb is being killed;
+		 * -ENODEV: device got disconnected
+		 */
+		if (err != -EPERM && err != -ENODEV)
+			nfc_err(&drv_data->udev->dev,
+				"urb %p failed to resubmit (%d)", urb, -err);
+		usb_unanchor_urb(urb);
+	}
+}
+
+static int
+nfcmrvl_submit_bulk_urb(struct nfcmrvl_usb_drv_data *drv_data, gfp_t mem_flags)
+{
+	struct urb *urb;
+	unsigned char *buf;
+	unsigned int pipe;
+	int err, size = NFCMRVL_NCI_MAX_EVENT_SIZE;
+
+	if (!drv_data->bulk_rx_ep)
+		return -ENODEV;
+
+	urb = usb_alloc_urb(0, mem_flags);
+	if (!urb)
+		return -ENOMEM;
+
+	buf = kmalloc(size, mem_flags);
+	if (!buf) {
+		usb_free_urb(urb);
+		return -ENOMEM;
+	}
+
+	pipe = usb_rcvbulkpipe(drv_data->udev,
+			       drv_data->bulk_rx_ep->bEndpointAddress);
+
+	usb_fill_bulk_urb(urb, drv_data->udev, pipe, buf, size,
+			  nfcmrvl_bulk_complete, drv_data);
+
+	urb->transfer_flags |= URB_FREE_BUFFER;
+
+	usb_mark_last_busy(drv_data->udev);
+	usb_anchor_urb(urb, &drv_data->bulk_anchor);
+
+	err = usb_submit_urb(urb, mem_flags);
+	if (err) {
+		if (err != -EPERM && err != -ENODEV)
+			nfc_err(&drv_data->udev->dev,
+				"urb %p submission failed (%d)", urb, -err);
+		usb_unanchor_urb(urb);
+	}
+
+	usb_free_urb(urb);
+
+	return err;
+}
+
+static void nfcmrvl_tx_complete(struct urb *urb)
+{
+	struct sk_buff *skb = urb->context;
+	struct nci_dev *ndev = (struct nci_dev *)skb->dev;
+	struct nfcmrvl_private *priv = nci_get_drvdata(ndev);
+	struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
+
+	nfc_info(priv->dev, "urb %p status %d count %d",
+		 urb, urb->status, urb->actual_length);
+
+	spin_lock(&drv_data->txlock);
+	drv_data->tx_in_flight--;
+	spin_unlock(&drv_data->txlock);
+
+	kfree(urb->setup_packet);
+	kfree_skb(skb);
+}
+
+static int nfcmrvl_usb_nci_open(struct nfcmrvl_private *priv)
+{
+	struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
+	int err;
+
+	err = usb_autopm_get_interface(drv_data->intf);
+	if (err)
+		return err;
+
+	drv_data->intf->needs_remote_wakeup = 1;
+
+	err = nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL);
+	if (err)
+		goto failed;
+
+	set_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
+	nfcmrvl_submit_bulk_urb(drv_data, GFP_KERNEL);
+
+	usb_autopm_put_interface(drv_data->intf);
+	return 0;
+
+failed:
+	usb_autopm_put_interface(drv_data->intf);
+	return err;
+}
+
+static void nfcmrvl_usb_stop_traffic(struct nfcmrvl_usb_drv_data *drv_data)
+{
+	usb_kill_anchored_urbs(&drv_data->bulk_anchor);
+}
+
+static int nfcmrvl_usb_nci_close(struct nfcmrvl_private *priv)
+{
+	struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
+	int err;
+
+	cancel_work_sync(&drv_data->waker);
+
+	clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
+
+	nfcmrvl_usb_stop_traffic(drv_data);
+	usb_kill_anchored_urbs(&drv_data->tx_anchor);
+	err = usb_autopm_get_interface(drv_data->intf);
+	if (err)
+		goto failed;
+
+	drv_data->intf->needs_remote_wakeup = 0;
+	usb_autopm_put_interface(drv_data->intf);
+
+failed:
+	usb_scuttle_anchored_urbs(&drv_data->deferred);
+	return 0;
+}
+
+static int nfcmrvl_usb_nci_send(struct nfcmrvl_private *priv,
+				struct sk_buff *skb)
+{
+	struct nfcmrvl_usb_drv_data *drv_data = priv->drv_data;
+	struct urb *urb;
+	unsigned int pipe;
+	int err;
+
+	if (!drv_data->bulk_tx_ep)
+		return -ENODEV;
+
+	urb = usb_alloc_urb(0, GFP_ATOMIC);
+	if (!urb)
+		return -ENOMEM;
+
+	pipe = usb_sndbulkpipe(drv_data->udev,
+				drv_data->bulk_tx_ep->bEndpointAddress);
+
+	usb_fill_bulk_urb(urb, drv_data->udev, pipe, skb->data, skb->len,
+			  nfcmrvl_tx_complete, skb);
+
+	err = nfcmrvl_inc_tx(drv_data);
+	if (err) {
+		usb_anchor_urb(urb, &drv_data->deferred);
+		schedule_work(&drv_data->waker);
+		err = 0;
+		goto done;
+	}
+
+	usb_anchor_urb(urb, &drv_data->tx_anchor);
+
+	err = usb_submit_urb(urb, GFP_ATOMIC);
+	if (err) {
+		if (err != -EPERM && err != -ENODEV)
+			nfc_err(&drv_data->udev->dev,
+				"urb %p submission failed (%d)", urb, -err);
+		kfree(urb->setup_packet);
+		usb_unanchor_urb(urb);
+	} else {
+		usb_mark_last_busy(drv_data->udev);
+	}
+
+done:
+	usb_free_urb(urb);
+	return err;
+}
+
+static struct nfcmrvl_if_ops usb_ops = {
+	.nci_open = nfcmrvl_usb_nci_open,
+	.nci_close = nfcmrvl_usb_nci_close,
+	.nci_send = nfcmrvl_usb_nci_send,
+};
+
+static void nfcmrvl_waker(struct work_struct *work)
+{
+	struct nfcmrvl_usb_drv_data *drv_data =
+			container_of(work, struct nfcmrvl_usb_drv_data, waker);
+	int err;
+
+	err = usb_autopm_get_interface(drv_data->intf);
+	if (err)
+		return;
+
+	usb_autopm_put_interface(drv_data->intf);
+}
+
+static int nfcmrvl_probe(struct usb_interface *intf,
+			 const struct usb_device_id *id)
+{
+	struct usb_endpoint_descriptor *ep_desc;
+	struct nfcmrvl_usb_drv_data *drv_data;
+	struct nfcmrvl_private *priv;
+	int i;
+	struct usb_device *udev = interface_to_usbdev(intf);
+
+	nfc_info(&udev->dev, "intf %p id %p", intf, id);
+
+	drv_data = devm_kzalloc(&intf->dev, sizeof(*drv_data), GFP_KERNEL);
+	if (!drv_data)
+		return -ENOMEM;
+
+	for (i = 0; i < intf->cur_altsetting->desc.bNumEndpoints; i++) {
+		ep_desc = &intf->cur_altsetting->endpoint[i].desc;
+
+		if (!drv_data->bulk_tx_ep &&
+		    usb_endpoint_is_bulk_out(ep_desc)) {
+			drv_data->bulk_tx_ep = ep_desc;
+			continue;
+		}
+
+		if (!drv_data->bulk_rx_ep &&
+		    usb_endpoint_is_bulk_in(ep_desc)) {
+			drv_data->bulk_rx_ep = ep_desc;
+			continue;
+		}
+	}
+
+	if (!drv_data->bulk_tx_ep || !drv_data->bulk_rx_ep)
+		return -ENODEV;
+
+	drv_data->udev = udev;
+	drv_data->intf = intf;
+
+	INIT_WORK(&drv_data->waker, nfcmrvl_waker);
+	spin_lock_init(&drv_data->txlock);
+
+	init_usb_anchor(&drv_data->tx_anchor);
+	init_usb_anchor(&drv_data->bulk_anchor);
+	init_usb_anchor(&drv_data->deferred);
+
+	priv = nfcmrvl_nci_register_dev(drv_data, &usb_ops,
+					&drv_data->udev->dev);
+	if (IS_ERR(priv))
+		return PTR_ERR(priv);
+
+	drv_data->priv = priv;
+	priv->dev = &drv_data->udev->dev;
+
+	usb_set_intfdata(intf, drv_data);
+
+	return 0;
+}
+
+static void nfcmrvl_disconnect(struct usb_interface *intf)
+{
+	struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
+
+	if (!drv_data)
+		return;
+
+	nfc_info(&drv_data->udev->dev, "intf %p", intf);
+
+	nfcmrvl_nci_unregister_dev(drv_data->priv);
+
+	usb_set_intfdata(drv_data->intf, NULL);
+}
+
+#ifdef CONFIG_PM
+static int nfcmrvl_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
+
+	nfc_info(&drv_data->udev->dev, "intf %p", intf);
+
+	if (drv_data->suspend_count++)
+		return 0;
+
+	spin_lock_irq(&drv_data->txlock);
+	if (!(PMSG_IS_AUTO(message) && drv_data->tx_in_flight)) {
+		set_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
+		spin_unlock_irq(&drv_data->txlock);
+	} else {
+		spin_unlock_irq(&drv_data->txlock);
+		drv_data->suspend_count--;
+		return -EBUSY;
+	}
+
+	nfcmrvl_usb_stop_traffic(drv_data);
+	usb_kill_anchored_urbs(&drv_data->tx_anchor);
+
+	return 0;
+}
+
+static void nfcmrvl_play_deferred(struct nfcmrvl_usb_drv_data *drv_data)
+{
+	struct urb *urb;
+	int err;
+
+	while ((urb = usb_get_from_anchor(&drv_data->deferred))) {
+		err = usb_submit_urb(urb, GFP_ATOMIC);
+		if (err)
+			break;
+
+		drv_data->tx_in_flight++;
+	}
+	usb_scuttle_anchored_urbs(&drv_data->deferred);
+}
+
+static int nfcmrvl_resume(struct usb_interface *intf)
+{
+	struct nfcmrvl_usb_drv_data *drv_data = usb_get_intfdata(intf);
+	int err = 0;
+
+	nfc_info(&drv_data->udev->dev, "intf %p", intf);
+
+	if (--drv_data->suspend_count)
+		return 0;
+
+	if (!test_bit(NFCMRVL_NCI_RUNNING, &drv_data->flags))
+		goto done;
+
+	if (test_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags)) {
+		err = nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO);
+		if (err) {
+			clear_bit(NFCMRVL_USB_BULK_RUNNING, &drv_data->flags);
+			goto failed;
+		}
+
+		nfcmrvl_submit_bulk_urb(drv_data, GFP_NOIO);
+	}
+
+	spin_lock_irq(&drv_data->txlock);
+	nfcmrvl_play_deferred(drv_data);
+	clear_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
+	spin_unlock_irq(&drv_data->txlock);
+
+	return 0;
+
+failed:
+	usb_scuttle_anchored_urbs(&drv_data->deferred);
+done:
+	spin_lock_irq(&drv_data->txlock);
+	clear_bit(NFCMRVL_USB_SUSPENDING, &drv_data->flags);
+	spin_unlock_irq(&drv_data->txlock);
+
+	return err;
+}
+#endif
+
+static struct usb_driver nfcmrvl_usb_driver = {
+	.name		= "nfcmrvl",
+	.probe		= nfcmrvl_probe,
+	.disconnect	= nfcmrvl_disconnect,
+#ifdef CONFIG_PM
+	.suspend	= nfcmrvl_suspend,
+	.resume		= nfcmrvl_resume,
+	.reset_resume	= nfcmrvl_resume,
+#endif
+	.id_table	= nfcmrvl_table,
+	.supports_autosuspend = 1,
+	.disable_hub_initiated_lpm = 1,
+	.soft_unbind = 1,
+};
+module_usb_driver(nfcmrvl_usb_driver);
+
+MODULE_AUTHOR("Marvell International Ltd.");
+MODULE_DESCRIPTION("Marvell NFC-over-USB driver ver " VERSION);
+MODULE_VERSION(VERSION);
+MODULE_LICENSE("GPL v2");

+ 3 - 0
drivers/nfc/pn533.c

@@ -521,6 +521,9 @@ static bool pn533_acr122_is_rx_frame_valid(void *_frame, struct pn533 *dev)
 	if (frame->ccid.type != 0x83)
 		return false;
 
+	if (!frame->ccid.datalen)
+		return false;
+
 	if (frame->data[frame->ccid.datalen - 2] == 0x63)
 		return false;
 

+ 24 - 24
drivers/nfc/pn544/pn544.c

@@ -195,42 +195,42 @@ static int pn544_hci_ready(struct nfc_hci_dev *hdev)
 
 		{{0x9e, 0xaa}, 0x01},
 
-		{{0x9b, 0xd1}, 0x0d},
-		{{0x9b, 0xd2}, 0x24},
-		{{0x9b, 0xd3}, 0x0a},
-		{{0x9b, 0xd4}, 0x22},
-		{{0x9b, 0xd5}, 0x08},
-		{{0x9b, 0xd6}, 0x1e},
-		{{0x9b, 0xdd}, 0x1c},
-
-		{{0x9b, 0x84}, 0x13},
-		{{0x99, 0x81}, 0x7f},
-		{{0x99, 0x31}, 0x70},
+		{{0x9b, 0xd1}, 0x17},
+		{{0x9b, 0xd2}, 0x58},
+		{{0x9b, 0xd3}, 0x10},
+		{{0x9b, 0xd4}, 0x47},
+		{{0x9b, 0xd5}, 0x0c},
+		{{0x9b, 0xd6}, 0x37},
+		{{0x9b, 0xdd}, 0x33},
+
+		{{0x9b, 0x84}, 0x00},
+		{{0x99, 0x81}, 0x79},
+		{{0x99, 0x31}, 0x79},
 
 		{{0x98, 0x00}, 0x3f},
 
-		{{0x9f, 0x09}, 0x00},
+		{{0x9f, 0x09}, 0x02},
 
 		{{0x9f, 0x0a}, 0x05},
 
 		{{0x9e, 0xd1}, 0xa1},
-		{{0x99, 0x23}, 0x00},
-
-		{{0x9e, 0x74}, 0x80},
+		{{0x99, 0x23}, 0x01},
 
+		{{0x9e, 0x74}, 0x00},
+		{{0x9e, 0x90}, 0x00},
 		{{0x9f, 0x28}, 0x10},
 
-		{{0x9f, 0x35}, 0x14},
+		{{0x9f, 0x35}, 0x04},
 
-		{{0x9f, 0x36}, 0x60},
+		{{0x9f, 0x36}, 0x11},
 
 		{{0x9c, 0x31}, 0x00},
 
-		{{0x9c, 0x32}, 0xc8},
+		{{0x9c, 0x32}, 0x00},
 
-		{{0x9c, 0x19}, 0x40},
+		{{0x9c, 0x19}, 0x0a},
 
-		{{0x9c, 0x1a}, 0x40},
+		{{0x9c, 0x1a}, 0x0a},
 
 		{{0x9c, 0x0c}, 0x00},
 
@@ -240,13 +240,13 @@ static int pn544_hci_ready(struct nfc_hci_dev *hdev)
 
 		{{0x9c, 0x13}, 0x00},
 
-		{{0x98, 0xa2}, 0x0e},
+		{{0x98, 0xa2}, 0x09},
 
-		{{0x98, 0x93}, 0x40},
+		{{0x98, 0x93}, 0x00},
 
-		{{0x98, 0x7d}, 0x02},
+		{{0x98, 0x7d}, 0x08},
 		{{0x98, 0x7e}, 0x00},
-		{{0x9f, 0xc8}, 0x01},
+		{{0x9f, 0xc8}, 0x00},
 	};
 	struct hw_config *p = hw_config;
 	int count = ARRAY_SIZE(hw_config);

+ 1 - 0
drivers/nfc/port100.c

@@ -1509,6 +1509,7 @@ static void port100_disconnect(struct usb_interface *interface)
 
 	usb_free_urb(dev->in_urb);
 	usb_free_urb(dev->out_urb);
+	usb_put_dev(dev->udev);
 
 	kfree(dev->cmd);
 

+ 10 - 0
include/net/nfc/digital.h

@@ -122,6 +122,16 @@ typedef void (*nfc_digital_cmd_complete_t)(struct nfc_digital_dev *ddev,
  *	switch_rf to turn the radio on. A call to in|tg_configure_hw must turn
  *	the device radio on.
  * @abort_cmd: Discard the last sent command.
+ *
+ * Notes: Asynchronous functions have a timeout parameter. It is the driver
+ *	responsibility to call the digital stack back through the
+ *	nfc_digital_cmd_complete_t callback when no RF respsonse has been
+ *	received within the specified time (in milliseconds). In that case the
+ *	driver must set the resp sk_buff to ERR_PTR(-ETIMEDOUT).
+ *	Since the digital stack serializes commands to be sent, it's mandatory
+ *	for the driver to handle the timeout correctly. Otherwise the stack
+ *	would not be able to send new commands, waiting for the reply of the
+ *	current one.
  */
 struct nfc_digital_ops {
 	int (*in_configure_hw)(struct nfc_digital_dev *ddev, int type,

+ 2 - 0
include/net/nfc/nci_core.h

@@ -68,6 +68,7 @@ struct nci_ops {
 	int (*open)(struct nci_dev *ndev);
 	int (*close)(struct nci_dev *ndev);
 	int (*send)(struct nci_dev *ndev, struct sk_buff *skb);
+	int (*setup)(struct nci_dev *ndev);
 };
 
 #define NCI_MAX_SUPPORTED_RF_INTERFACES		4
@@ -154,6 +155,7 @@ void nci_free_device(struct nci_dev *ndev);
 int nci_register_device(struct nci_dev *ndev);
 void nci_unregister_device(struct nci_dev *ndev);
 int nci_recv_frame(struct nci_dev *ndev, struct sk_buff *skb);
+int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val);
 
 static inline struct sk_buff *nci_skb_alloc(struct nci_dev *ndev,
 					    unsigned int len,

+ 2 - 5
net/nfc/core.c

@@ -133,11 +133,8 @@ int nfc_dev_up(struct nfc_dev *dev)
 		dev->dev_up = true;
 
 	/* We have to enable the device before discovering SEs */
-	if (dev->ops->discover_se) {
-		rc = dev->ops->discover_se(dev);
-		if (rc)
-			pr_warn("SE discovery failed\n");
-	}
+	if (dev->ops->discover_se && dev->ops->discover_se(dev))
+		pr_err("SE discovery failed\n");
 
 error:
 	device_unlock(&dev->dev);

+ 26 - 2
net/nfc/digital_core.c

@@ -339,7 +339,6 @@ int digital_target_found(struct nfc_digital_dev *ddev,
 	pr_debug("rf_tech=%d, protocol=%d\n", rf_tech, protocol);
 
 	ddev->curr_rf_tech = rf_tech;
-	ddev->curr_protocol = protocol;
 
 	if (DIGITAL_DRV_CAPS_IN_CRC(ddev)) {
 		ddev->skb_add_crc = digital_skb_add_crc_none;
@@ -541,8 +540,14 @@ static int digital_dep_link_up(struct nfc_dev *nfc_dev,
 			       __u8 comm_mode, __u8 *gb, size_t gb_len)
 {
 	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
+	int rc;
+
+	rc = digital_in_send_atr_req(ddev, target, comm_mode, gb, gb_len);
 
-	return digital_in_send_atr_req(ddev, target, comm_mode, gb, gb_len);
+	if (!rc)
+		ddev->curr_protocol = NFC_PROTO_NFC_DEP;
+
+	return rc;
 }
 
 static int digital_dep_link_down(struct nfc_dev *nfc_dev)
@@ -557,6 +562,20 @@ static int digital_dep_link_down(struct nfc_dev *nfc_dev)
 static int digital_activate_target(struct nfc_dev *nfc_dev,
 				   struct nfc_target *target, __u32 protocol)
 {
+	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
+
+	if (ddev->poll_tech_count) {
+		pr_err("Can't activate a target while polling\n");
+		return -EBUSY;
+	}
+
+	if (ddev->curr_protocol) {
+		pr_err("A target is already active\n");
+		return -EBUSY;
+	}
+
+	ddev->curr_protocol = protocol;
+
 	return 0;
 }
 
@@ -565,6 +584,11 @@ static void digital_deactivate_target(struct nfc_dev *nfc_dev,
 {
 	struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
 
+	if (!ddev->curr_protocol) {
+		pr_err("No active target\n");
+		return;
+	}
+
 	ddev->curr_protocol = 0;
 }
 

+ 36 - 18
net/nfc/digital_dep.c

@@ -32,7 +32,6 @@
 #define DIGITAL_ATR_REQ_MIN_SIZE 16
 #define DIGITAL_ATR_REQ_MAX_SIZE 64
 
-#define DIGITAL_NFCID3_LEN ((u8)8)
 #define DIGITAL_LR_BITS_PAYLOAD_SIZE_254B 0x30
 #define DIGITAL_GB_BIT	0x02
 
@@ -206,10 +205,9 @@ int digital_in_send_atr_req(struct nfc_digital_dev *ddev,
 	atr_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT;
 	atr_req->cmd = DIGITAL_CMD_ATR_REQ;
 	if (target->nfcid2_len)
-		memcpy(atr_req->nfcid3, target->nfcid2,
-		       max(target->nfcid2_len, DIGITAL_NFCID3_LEN));
+		memcpy(atr_req->nfcid3, target->nfcid2, NFC_NFCID2_MAXSIZE);
 	else
-		get_random_bytes(atr_req->nfcid3, DIGITAL_NFCID3_LEN);
+		get_random_bytes(atr_req->nfcid3, NFC_NFCID3_MAXSIZE);
 
 	atr_req->did = 0;
 	atr_req->bs = 0;
@@ -382,6 +380,33 @@ int digital_in_send_dep_req(struct nfc_digital_dev *ddev,
 				   data_exch);
 }
 
+static void digital_tg_set_rf_tech(struct nfc_digital_dev *ddev, u8 rf_tech)
+{
+	ddev->curr_rf_tech = rf_tech;
+
+	ddev->skb_add_crc = digital_skb_add_crc_none;
+	ddev->skb_check_crc = digital_skb_check_crc_none;
+
+	if (DIGITAL_DRV_CAPS_TG_CRC(ddev))
+		return;
+
+	switch (ddev->curr_rf_tech) {
+	case NFC_DIGITAL_RF_TECH_106A:
+		ddev->skb_add_crc = digital_skb_add_crc_a;
+		ddev->skb_check_crc = digital_skb_check_crc_a;
+		break;
+
+	case NFC_DIGITAL_RF_TECH_212F:
+	case NFC_DIGITAL_RF_TECH_424F:
+		ddev->skb_add_crc = digital_skb_add_crc_f;
+		ddev->skb_check_crc = digital_skb_check_crc_f;
+		break;
+
+	default:
+		break;
+	}
+}
+
 static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg,
 				    struct sk_buff *resp)
 {
@@ -472,11 +497,13 @@ int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb)
 static void digital_tg_send_psl_res_complete(struct nfc_digital_dev *ddev,
 					     void *arg, struct sk_buff *resp)
 {
-	u8 rf_tech = PTR_ERR(arg);
+	u8 rf_tech = (unsigned long)arg;
 
 	if (IS_ERR(resp))
 		return;
 
+	digital_tg_set_rf_tech(ddev, rf_tech);
+
 	digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech);
 
 	digital_tg_listen(ddev, 1500, digital_tg_recv_dep_req, NULL);
@@ -508,7 +535,7 @@ static int digital_tg_send_psl_res(struct nfc_digital_dev *ddev, u8 did,
 	ddev->skb_add_crc(skb);
 
 	rc = digital_tg_send_cmd(ddev, skb, 0, digital_tg_send_psl_res_complete,
-				 ERR_PTR(rf_tech));
+				 (void *)(unsigned long)rf_tech);
 
 	if (rc)
 		kfree_skb(skb);
@@ -661,16 +688,10 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg,
 
 	if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) {
 		min_size = DIGITAL_ATR_REQ_MIN_SIZE + 2;
-
-		ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_106A;
-		ddev->skb_add_crc = digital_skb_add_crc_a;
-		ddev->skb_check_crc = digital_skb_check_crc_a;
+		digital_tg_set_rf_tech(ddev, NFC_DIGITAL_RF_TECH_106A);
 	} else {
 		min_size = DIGITAL_ATR_REQ_MIN_SIZE + 1;
-
-		ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_212F;
-		ddev->skb_add_crc = digital_skb_add_crc_f;
-		ddev->skb_check_crc = digital_skb_check_crc_f;
+		digital_tg_set_rf_tech(ddev, NFC_DIGITAL_RF_TECH_212F);
 	}
 
 	if (resp->len < min_size) {
@@ -678,10 +699,7 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg,
 		goto exit;
 	}
 
-	if (DIGITAL_DRV_CAPS_TG_CRC(ddev)) {
-		ddev->skb_add_crc = digital_skb_add_crc_none;
-		ddev->skb_check_crc = digital_skb_check_crc_none;
-	}
+	ddev->curr_protocol = NFC_PROTO_NFC_DEP_MASK;
 
 	rc = ddev->skb_check_crc(resp);
 	if (rc) {

+ 2 - 5
net/nfc/hci/core.c

@@ -335,11 +335,8 @@ exit:
 	kfree_skb(skb);
 
 exit_noskb:
-	if (r) {
-		/* TODO: There was an error dispatching the event,
-		 * how to propagate up to nfc core?
-		 */
-	}
+	if (r)
+		nfc_hci_driver_failure(hdev, r);
 }
 
 static void nfc_hci_cmd_timeout(unsigned long data)

+ 4 - 2
net/nfc/llcp_commands.c

@@ -675,7 +675,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 
 	do {
 		remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
-				local->remote_miu : sock->remote_miu;
+				LLCP_DEFAULT_MIU : sock->remote_miu;
 
 		frag_len = min_t(size_t, remote_miu, remaining_len);
 
@@ -684,8 +684,10 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 
 		pdu = llcp_allocate_pdu(sock, LLCP_PDU_I,
 					frag_len + LLCP_SEQUENCE_SIZE);
-		if (pdu == NULL)
+		if (pdu == NULL) {
+			kfree(msg_data);
 			return -ENOMEM;
+		}
 
 		skb_put(pdu, LLCP_SEQUENCE_SIZE);
 

+ 0 - 1
net/nfc/llcp_core.c

@@ -943,7 +943,6 @@ static void nfc_llcp_recv_connect(struct nfc_llcp_local *local,
 	new_sock->local = nfc_llcp_local_get(local);
 	new_sock->rw = sock->rw;
 	new_sock->miux = sock->miux;
-	new_sock->remote_miu = local->remote_miu;
 	new_sock->nfc_protocol = sock->nfc_protocol;
 	new_sock->dsap = ssap;
 	new_sock->target_idx = local->target_idx;

+ 0 - 1
net/nfc/llcp_sock.c

@@ -700,7 +700,6 @@ static int llcp_sock_connect(struct socket *sock, struct sockaddr *_addr,
 
 	llcp_sock->dev = dev;
 	llcp_sock->local = nfc_llcp_local_get(local);
-	llcp_sock->remote_miu = llcp_sock->local->remote_miu;
 	llcp_sock->ssap = nfc_llcp_get_local_ssap(local);
 	if (llcp_sock->ssap == LLCP_SAP_MAX) {
 		ret = -ENOMEM;

+ 21 - 6
net/nfc/nci/core.c

@@ -301,6 +301,9 @@ static int nci_open_device(struct nci_dev *ndev)
 	rc = __nci_request(ndev, nci_reset_req, 0,
 			   msecs_to_jiffies(NCI_RESET_TIMEOUT));
 
+	if (ndev->ops->setup(ndev))
+		ndev->ops->setup(ndev);
+
 	if (!rc) {
 		rc = __nci_request(ndev, nci_init_req, 0,
 				   msecs_to_jiffies(NCI_INIT_TIMEOUT));
@@ -361,6 +364,8 @@ static int nci_close_device(struct nci_dev *ndev)
 		      msecs_to_jiffies(NCI_RESET_TIMEOUT));
 	clear_bit(NCI_INIT, &ndev->flags);
 
+	del_timer_sync(&ndev->cmd_timer);
+
 	/* Flush cmd wq */
 	flush_workqueue(ndev->cmd_wq);
 
@@ -408,12 +413,26 @@ static int nci_dev_down(struct nfc_dev *nfc_dev)
 	return nci_close_device(ndev);
 }
 
+int nci_set_config(struct nci_dev *ndev, __u8 id, size_t len, __u8 *val)
+{
+	struct nci_set_config_param param;
+
+	if (!val || !len)
+		return 0;
+
+	param.id = id;
+	param.len = len;
+	param.val = val;
+
+	return __nci_request(ndev, nci_set_config_req, (unsigned long)&param,
+			     msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));
+}
+EXPORT_SYMBOL(nci_set_config);
+
 static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)
 {
 	struct nci_dev *ndev = nfc_get_drvdata(nfc_dev);
 	struct nci_set_config_param param;
-	__u8 local_gb[NFC_MAX_GT_LEN];
-	int i;
 
 	param.val = nfc_get_local_general_bytes(nfc_dev, &param.len);
 	if ((param.val == NULL) || (param.len == 0))
@@ -422,11 +441,7 @@ static int nci_set_local_general_bytes(struct nfc_dev *nfc_dev)
 	if (param.len > NFC_MAX_GT_LEN)
 		return -EINVAL;
 
-	for (i = 0; i < param.len; i++)
-		local_gb[param.len-1-i] = param.val[i];
-
 	param.id = NCI_PN_ATR_REQ_GEN_BYTES;
-	param.val = local_gb;
 
 	return nci_request(ndev, nci_set_config_req, (unsigned long)&param,
 			   msecs_to_jiffies(NCI_SET_CONFIG_TIMEOUT));