Przeglądaj źródła

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

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

"This is the 2nd NFC pull request for 3.10.

With this one we have:

- A major pn533 update. The pn533 framing support has been changed in order to
  easily support all pn533 derivatives. For example we now support the ACR122
  USB dongle.

- An NFC MEI physical layer code factorization through the mei_phy NFC API.
  Both the microread and the pn544 drivers now use it.

- LLCP aggregation support. This allows NFC p2p devices to send aggregated
  frames containing all sort of LLCP frames except SYMM and aggregation
  frames.

- More LLCP socket options for getting the remote device link parameters.

- Fixes for the LLCP socket option code added with the first pull request for
  3.10.

- Some support for LLCP corner cases like 0 length SDUs and general DISC
  (tagged with a 0,0 dsap ssap couple) handling.

- RFKILL support for NFC."

Signed-off-by: John W. Linville <linville@tuxdriver.com>
John W. Linville 12 lat temu
rodzic
commit
197bbf0aed

+ 10 - 0
drivers/nfc/Kconfig

@@ -26,6 +26,16 @@ config NFC_WILINK
 	  Say Y here to compile support for Texas Instrument's NFC WiLink driver
 	  into the kernel or say M to compile it as module.
 
+config NFC_MEI_PHY
+	tristate "MEI bus NFC device support"
+	depends on INTEL_MEI_BUS_NFC && NFC_HCI
+	help
+	  This adds support to use an mei bus nfc device. Select this if you
+	  will use an HCI NFC driver for an NFC chip connected behind an
+	  Intel's Management Engine chip.
+
+	  If unsure, say N.
+
 source "drivers/nfc/pn544/Kconfig"
 source "drivers/nfc/microread/Kconfig"
 

+ 1 - 0
drivers/nfc/Makefile

@@ -6,5 +6,6 @@ obj-$(CONFIG_NFC_PN544)		+= pn544/
 obj-$(CONFIG_NFC_MICROREAD)	+= microread/
 obj-$(CONFIG_NFC_PN533)		+= pn533.o
 obj-$(CONFIG_NFC_WILINK)	+= nfcwilink.o
+obj-$(CONFIG_NFC_MEI_PHY)	+= mei_phy.o
 
 ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG

+ 164 - 0
drivers/nfc/mei_phy.c

@@ -0,0 +1,164 @@
+/*
+ * MEI Library for mei bus nfc device access
+ *
+ * Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions 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/module.h>
+#include <linux/slab.h>
+#include <linux/nfc.h>
+
+#include "mei_phy.h"
+
+struct mei_nfc_hdr {
+	u8 cmd;
+	u8 status;
+	u16 req_id;
+	u32 reserved;
+	u16 data_size;
+} __attribute__((packed));
+
+#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
+
+#define MEI_DUMP_SKB_IN(info, skb)				\
+do {								\
+	pr_debug("%s:\n", info);				\
+	print_hex_dump_debug("mei in : ", DUMP_PREFIX_OFFSET,	\
+			16, 1, (skb)->data, (skb)->len, false);	\
+} while (0)
+
+#define MEI_DUMP_SKB_OUT(info, skb)				\
+do {								\
+	pr_debug("%s:\n", info);				\
+	print_hex_dump_debug("mei out: ", DUMP_PREFIX_OFFSET,	\
+		       16, 1, (skb)->data, (skb)->len, false);	\
+} while (0)
+
+int nfc_mei_phy_enable(void *phy_id)
+{
+	int r;
+	struct nfc_mei_phy *phy = phy_id;
+
+	pr_info("%s\n", __func__);
+
+	if (phy->powered == 1)
+		return 0;
+
+	r = mei_cl_enable_device(phy->device);
+	if (r < 0) {
+                pr_err("MEI_PHY: Could not enable device\n");
+                return r;
+	}
+
+	phy->powered = 1;
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(nfc_mei_phy_enable);
+
+void nfc_mei_phy_disable(void *phy_id)
+{
+	struct nfc_mei_phy *phy = phy_id;
+
+	pr_info("%s\n", __func__);
+
+	mei_cl_disable_device(phy->device);
+
+	phy->powered = 0;
+}
+EXPORT_SYMBOL_GPL(nfc_mei_phy_disable);
+
+/*
+ * Writing a frame must not return the number of written bytes.
+ * It must return either zero for success, or <0 for error.
+ * In addition, it must not alter the skb
+ */
+static int nfc_mei_phy_write(void *phy_id, struct sk_buff *skb)
+{
+	struct nfc_mei_phy *phy = phy_id;
+	int r;
+
+	MEI_DUMP_SKB_OUT("mei frame sent", skb);
+
+	r = mei_cl_send(phy->device, skb->data, skb->len);
+	if (r > 0)
+		r = 0;
+
+	return r;
+}
+
+void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context)
+{
+	struct nfc_mei_phy *phy = context;
+
+	if (phy->hard_fault != 0)
+		return;
+
+	if (events & BIT(MEI_CL_EVENT_RX)) {
+		struct sk_buff *skb;
+		int reply_size;
+
+		skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
+		if (!skb)
+			return;
+
+		reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
+		if (reply_size < MEI_NFC_HEADER_SIZE) {
+			kfree(skb);
+			return;
+		}
+
+		skb_put(skb, reply_size);
+		skb_pull(skb, MEI_NFC_HEADER_SIZE);
+
+		MEI_DUMP_SKB_IN("mei frame read", skb);
+
+		nfc_hci_recv_frame(phy->hdev, skb);
+	}
+}
+EXPORT_SYMBOL_GPL(nfc_mei_event_cb);
+
+struct nfc_phy_ops mei_phy_ops = {
+	.write = nfc_mei_phy_write,
+	.enable = nfc_mei_phy_enable,
+	.disable = nfc_mei_phy_disable,
+};
+EXPORT_SYMBOL_GPL(mei_phy_ops);
+
+struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device)
+{
+	struct nfc_mei_phy *phy;
+
+	phy = kzalloc(sizeof(struct nfc_mei_phy), GFP_KERNEL);
+	if (!phy)
+		return NULL;
+
+	phy->device = device;
+	mei_cl_set_drvdata(device, phy);
+
+	return phy;
+}
+EXPORT_SYMBOL_GPL(nfc_mei_phy_alloc);
+
+void nfc_mei_phy_free(struct nfc_mei_phy *phy)
+{
+	kfree(phy);
+}
+EXPORT_SYMBOL_GPL(nfc_mei_phy_free);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("mei bus NFC device interface");

+ 30 - 0
drivers/nfc/mei_phy.h

@@ -0,0 +1,30 @@
+#ifndef __LOCAL_MEI_PHY_H_
+#define __LOCAL_MEI_PHY_H_
+
+#include <linux/mei_cl_bus.h>
+#include <net/nfc/hci.h>
+
+#define MEI_NFC_HEADER_SIZE 10
+#define MEI_NFC_MAX_HCI_PAYLOAD 300
+
+struct nfc_mei_phy {
+	struct mei_cl_device *device;
+	struct nfc_hci_dev *hdev;
+
+	int powered;
+
+	int hard_fault;		/*
+				 * < 0 if hardware error occured
+				 * and prevents normal operation.
+				 */
+};
+
+extern struct nfc_phy_ops mei_phy_ops;
+
+int nfc_mei_phy_enable(void *phy_id);
+void nfc_mei_phy_disable(void *phy_id);
+void nfc_mei_event_cb(struct mei_cl_device *device, u32 events, void *context);
+struct nfc_mei_phy *nfc_mei_phy_alloc(struct mei_cl_device *device);
+void nfc_mei_phy_free(struct nfc_mei_phy *phy);
+
+#endif /* __LOCAL_MEI_PHY_H_ */

+ 1 - 1
drivers/nfc/microread/Kconfig

@@ -25,7 +25,7 @@ config NFC_MICROREAD_I2C
 
 config NFC_MICROREAD_MEI
 	tristate "NFC Microread MEI support"
-	depends on NFC_MICROREAD && INTEL_MEI_BUS_NFC
+	depends on NFC_MICROREAD && NFC_MEI_PHY
 	---help---
 	  This module adds support for the mei interface of adapters using
 	  Inside microread chipsets.  Select this if your microread chipset

+ 9 - 130
drivers/nfc/microread/mei.c

@@ -19,151 +19,31 @@
  */
 
 #include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/gpio.h>
-#include <linux/mei_cl_bus.h>
-
+#include <linux/mod_devicetable.h>
 #include <linux/nfc.h>
 #include <net/nfc/hci.h>
 #include <net/nfc/llc.h>
 
+#include "../mei_phy.h"
 #include "microread.h"
 
 #define MICROREAD_DRIVER_NAME "microread"
 
-struct mei_nfc_hdr {
-	u8 cmd;
-	u8 status;
-	u16 req_id;
-	u32 reserved;
-	u16 data_size;
-} __attribute__((packed));
-
-#define MEI_NFC_HEADER_SIZE 10
-#define MEI_NFC_MAX_HCI_PAYLOAD 300
-#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
-
-struct microread_mei_phy {
-	struct mei_cl_device *device;
-	struct nfc_hci_dev *hdev;
-
-	int powered;
-
-	int hard_fault;		/*
-				 * < 0 if hardware error occured (e.g. i2c err)
-				 * and prevents normal operation.
-				 */
-};
-
-#define MEI_DUMP_SKB_IN(info, skb)					\
-do {								\
-	pr_debug("%s:\n", info);				\
-	print_hex_dump(KERN_DEBUG, "mei in : ", DUMP_PREFIX_OFFSET,	\
-		       16, 1, (skb)->data, (skb)->len, 0);	\
-} while (0)
-
-#define MEI_DUMP_SKB_OUT(info, skb)					\
-do {								\
-	pr_debug("%s:\n", info);				\
-	print_hex_dump(KERN_DEBUG, "mei out: ", DUMP_PREFIX_OFFSET,	\
-		       16, 1, (skb)->data, (skb)->len, 0);	\
-} while (0)
-
-static int microread_mei_enable(void *phy_id)
-{
-	struct microread_mei_phy *phy = phy_id;
-
-	pr_info(DRIVER_DESC ": %s\n", __func__);
-
-	phy->powered = 1;
-
-	return 0;
-}
-
-static void microread_mei_disable(void *phy_id)
-{
-	struct microread_mei_phy *phy = phy_id;
-
-	pr_info(DRIVER_DESC ": %s\n", __func__);
-
-	phy->powered = 0;
-}
-
-/*
- * Writing a frame must not return the number of written bytes.
- * It must return either zero for success, or <0 for error.
- * In addition, it must not alter the skb
- */
-static int microread_mei_write(void *phy_id, struct sk_buff *skb)
-{
-	struct microread_mei_phy *phy = phy_id;
-	int r;
-
-	MEI_DUMP_SKB_OUT("mei frame sent", skb);
-
-	r = mei_cl_send(phy->device, skb->data, skb->len);
-	if (r > 0)
-		r = 0;
-
-	return r;
-}
-
-static void microread_event_cb(struct mei_cl_device *device, u32 events,
-			       void *context)
-{
-	struct microread_mei_phy *phy = context;
-
-	if (phy->hard_fault != 0)
-		return;
-
-	if (events & BIT(MEI_CL_EVENT_RX)) {
-		struct sk_buff *skb;
-		int reply_size;
-
-		skb = alloc_skb(MEI_NFC_MAX_READ, GFP_KERNEL);
-		if (!skb)
-			return;
-
-		reply_size = mei_cl_recv(device, skb->data, MEI_NFC_MAX_READ);
-		if (reply_size < MEI_NFC_HEADER_SIZE) {
-			kfree(skb);
-			return;
-		}
-
-		skb_put(skb, reply_size);
-		skb_pull(skb, MEI_NFC_HEADER_SIZE);
-
-		MEI_DUMP_SKB_IN("mei frame read", skb);
-
-		nfc_hci_recv_frame(phy->hdev, skb);
-	}
-}
-
-static struct nfc_phy_ops mei_phy_ops = {
-	.write = microread_mei_write,
-	.enable = microread_mei_enable,
-	.disable = microread_mei_disable,
-};
-
 static int microread_mei_probe(struct mei_cl_device *device,
 			       const struct mei_cl_device_id *id)
 {
-	struct microread_mei_phy *phy;
+	struct nfc_mei_phy *phy;
 	int r;
 
 	pr_info("Probing NFC microread\n");
 
-	phy = kzalloc(sizeof(struct microread_mei_phy), GFP_KERNEL);
+	phy = nfc_mei_phy_alloc(device);
 	if (!phy) {
 		pr_err("Cannot allocate memory for microread mei phy.\n");
 		return -ENOMEM;
 	}
 
-	phy->device = device;
-	mei_cl_set_drvdata(device, phy);
-
-	r = mei_cl_register_event_cb(device, microread_event_cb, phy);
+	r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
 	if (r) {
 		pr_err(MICROREAD_DRIVER_NAME ": event cb registration failed\n");
 		goto err_out;
@@ -178,23 +58,22 @@ static int microread_mei_probe(struct mei_cl_device *device,
 	return 0;
 
 err_out:
-	kfree(phy);
+	nfc_mei_phy_free(phy);
 
 	return r;
 }
 
 static int microread_mei_remove(struct mei_cl_device *device)
 {
-	struct microread_mei_phy *phy = mei_cl_get_drvdata(device);
+	struct nfc_mei_phy *phy = mei_cl_get_drvdata(device);
 
 	pr_info("Removing microread\n");
 
 	microread_remove(phy->hdev);
 
-	if (phy->powered)
-		microread_mei_disable(phy);
+	nfc_mei_phy_disable(phy);
 
-	kfree(phy);
+	nfc_mei_phy_free(phy);
 
 	return 0;
 }

+ 455 - 198
drivers/nfc/pn533.c

@@ -1,9 +1,6 @@
 /*
  * Copyright (C) 2011 Instituto Nokia de Tecnologia
- *
- * Authors:
- *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
- *    Aloisio Almeida Jr <aloisio.almeida@openbossa.org>
+ * Copyright (C) 2012-2013 Tieto Poland
  *
  * 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
@@ -30,7 +27,7 @@
 #include <linux/netdevice.h>
 #include <net/nfc/nfc.h>
 
-#define VERSION "0.1"
+#define VERSION "0.2"
 
 #define PN533_VENDOR_ID 0x4CC
 #define PN533_PRODUCT_ID 0x2533
@@ -41,8 +38,12 @@
 #define SONY_VENDOR_ID         0x054c
 #define PASORI_PRODUCT_ID      0x02e1
 
-#define PN533_DEVICE_STD    0x1
-#define PN533_DEVICE_PASORI 0x2
+#define ACS_VENDOR_ID 0x072f
+#define ACR122U_PRODUCT_ID 0x2200
+
+#define PN533_DEVICE_STD     0x1
+#define PN533_DEVICE_PASORI  0x2
+#define PN533_DEVICE_ACR122U 0x3
 
 #define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\
 			     NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\
@@ -71,6 +72,11 @@ static const struct usb_device_id pn533_table[] = {
 	  .idProduct		= PASORI_PRODUCT_ID,
 	  .driver_info		= PN533_DEVICE_PASORI,
 	},
+	{ .match_flags		= USB_DEVICE_ID_MATCH_DEVICE,
+	  .idVendor		= ACS_VENDOR_ID,
+	  .idProduct		= ACR122U_PRODUCT_ID,
+	  .driver_info		= PN533_DEVICE_ACR122U,
+	},
 	{ }
 };
 MODULE_DEVICE_TABLE(usb, pn533_table);
@@ -78,32 +84,47 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
 /* How much time we spend listening for initiators */
 #define PN533_LISTEN_TIME 2
 
-/* frame definitions */
-#define PN533_FRAME_HEADER_LEN (sizeof(struct pn533_frame) \
+/* Standard pn533 frame definitions */
+#define PN533_STD_FRAME_HEADER_LEN (sizeof(struct pn533_std_frame) \
 					+ 2) /* data[0] TFI, data[1] CC */
-#define PN533_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/
+#define PN533_STD_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/
 
 /*
  * Max extended frame payload len, excluding TFI and CC
  * which are already in PN533_FRAME_HEADER_LEN.
  */
-#define PN533_FRAME_MAX_PAYLOAD_LEN 263
+#define PN533_STD_FRAME_MAX_PAYLOAD_LEN 263
 
-#define PN533_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2),
+#define PN533_STD_FRAME_ACK_SIZE 6 /* Preamble (1), SoPC (2), ACK Code (2),
 				  Postamble (1) */
-#define PN533_FRAME_CHECKSUM(f) (f->data[f->datalen])
-#define PN533_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
+#define PN533_STD_FRAME_CHECKSUM(f) (f->data[f->datalen])
+#define PN533_STD_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
 
 /* start of frame */
-#define PN533_SOF 0x00FF
+#define PN533_STD_FRAME_SOF 0x00FF
+
+/* standard frame identifier: in/out/error */
+#define PN533_STD_FRAME_IDENTIFIER(f) (f->data[0]) /* TFI */
+#define PN533_STD_FRAME_DIR_OUT 0xD4
+#define PN533_STD_FRAME_DIR_IN 0xD5
+
+/* ACS ACR122 pn533 frame definitions */
+#define PN533_ACR122_TX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_tx_frame) \
+					  + 2)
+#define PN533_ACR122_TX_FRAME_TAIL_LEN 0
+#define PN533_ACR122_RX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_rx_frame) \
+					  + 2)
+#define PN533_ACR122_RX_FRAME_TAIL_LEN 2
+#define PN533_ACR122_FRAME_MAX_PAYLOAD_LEN PN533_STD_FRAME_MAX_PAYLOAD_LEN
+
+/* CCID messages types */
+#define PN533_ACR122_PC_TO_RDR_ICCPOWERON 0x62
+#define PN533_ACR122_PC_TO_RDR_ESCAPE 0x6B
 
-/* frame identifier: in/out/error */
-#define PN533_FRAME_IDENTIFIER(f) (f->data[0])
-#define PN533_DIR_OUT 0xD4
-#define PN533_DIR_IN 0xD5
+#define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83
 
 /* PN533 Commands */
-#define PN533_FRAME_CMD(f) (f->data[1])
+#define PN533_STD_FRAME_CMD(f) (f->data[1])
 
 #define PN533_CMD_GET_FIRMWARE_VERSION 0x02
 #define PN533_CMD_RF_CONFIGURATION 0x32
@@ -128,8 +149,6 @@ MODULE_DEVICE_TABLE(usb, pn533_table);
 
 struct pn533;
 
-typedef int (*pn533_cmd_complete_t) (struct pn533 *dev, void *arg, int status);
-
 typedef int (*pn533_send_async_complete_t) (struct pn533 *dev, void *arg,
 					struct sk_buff *resp);
 
@@ -144,9 +163,13 @@ struct pn533_fw_version {
 };
 
 /* PN533_CMD_RF_CONFIGURATION */
-#define PN533_CFGITEM_TIMING 0x02
+#define PN533_CFGITEM_RF_FIELD    0x01
+#define PN533_CFGITEM_TIMING      0x02
 #define PN533_CFGITEM_MAX_RETRIES 0x05
-#define PN533_CFGITEM_PASORI 0x82
+#define PN533_CFGITEM_PASORI      0x82
+
+#define PN533_CFGITEM_RF_FIELD_ON  0x1
+#define PN533_CFGITEM_RF_FIELD_OFF 0x0
 
 #define PN533_CONFIG_TIMING_102 0xb
 #define PN533_CONFIG_TIMING_204 0xc
@@ -313,10 +336,17 @@ struct pn533_cmd_jump_dep_response {
 #define PN533_INIT_TARGET_RESP_ACTIVE     0x1
 #define PN533_INIT_TARGET_RESP_DEP        0x4
 
+enum  pn533_protocol_type {
+	PN533_PROTO_REQ_ACK_RESP = 0,
+	PN533_PROTO_REQ_RESP
+};
+
 struct pn533 {
 	struct usb_device *udev;
 	struct usb_interface *interface;
 	struct nfc_dev *nfc_dev;
+	u32 device_type;
+	enum pn533_protocol_type protocol_type;
 
 	struct urb *out_urb;
 	struct urb *in_urb;
@@ -329,21 +359,21 @@ struct pn533 {
 	struct work_struct poll_work;
 	struct work_struct mi_work;
 	struct work_struct tg_work;
-	struct timer_list listen_timer;
-	int wq_in_error;
-	int cancel_listen;
 
-	pn533_cmd_complete_t cmd_complete;
-	void *cmd_complete_arg;
+	struct list_head cmd_queue;
+	struct pn533_cmd *cmd;
+	u8 cmd_pending;
+	struct mutex cmd_lock;  /* protects cmd queue */
+
 	void *cmd_complete_mi_arg;
-	struct mutex 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;
 	u32 listen_protocols;
+	struct timer_list listen_timer;
+	int cancel_listen;
 
 	u8 *gb;
 	size_t gb_len;
@@ -352,24 +382,21 @@ struct pn533 {
 	u8 tgt_active_prot;
 	u8 tgt_mode;
 
-	u32 device_type;
-
-	struct list_head cmd_queue;
-	u8 cmd_pending;
-
 	struct pn533_frame_ops *ops;
 };
 
 struct pn533_cmd {
 	struct list_head queue;
-	u8 cmd_code;
+	u8 code;
+	int status;
 	struct sk_buff *req;
 	struct sk_buff *resp;
 	int resp_len;
-	void *arg;
+	pn533_send_async_complete_t  complete_cb;
+	void *complete_cb_context;
 };
 
-struct pn533_frame {
+struct pn533_std_frame {
 	u8 preamble;
 	__be16 start_frame;
 	u8 datalen;
@@ -393,14 +420,124 @@ struct pn533_frame_ops {
 	u8 (*get_cmd_code)(void *frame);
 };
 
+struct pn533_acr122_ccid_hdr {
+	u8 type;
+	u32 datalen;
+	u8 slot;
+	u8 seq;
+	u8 params[3]; /* 3 msg specific bytes or status, error and 1 specific
+			 byte for reposnse msg */
+	u8 data[]; /* payload */
+} __packed;
+
+struct pn533_acr122_apdu_hdr {
+	u8 class;
+	u8 ins;
+	u8 p1;
+	u8 p2;
+} __packed;
+
+struct pn533_acr122_tx_frame {
+	struct pn533_acr122_ccid_hdr ccid;
+	struct pn533_acr122_apdu_hdr apdu;
+	u8 datalen;
+	u8 data[]; /* pn533 frame: TFI ... */
+} __packed;
+
+struct pn533_acr122_rx_frame {
+	struct pn533_acr122_ccid_hdr ccid;
+	u8 data[]; /* pn533 frame : TFI ... */
+} __packed;
+
+static void pn533_acr122_tx_frame_init(void *_frame, u8 cmd_code)
+{
+	struct pn533_acr122_tx_frame *frame = _frame;
+
+	frame->ccid.type = PN533_ACR122_PC_TO_RDR_ESCAPE;
+	frame->ccid.datalen = sizeof(frame->apdu) + 1; /* sizeof(apdu_hdr) +
+							  sizeof(datalen) */
+	frame->ccid.slot = 0;
+	frame->ccid.seq = 0;
+	frame->ccid.params[0] = 0;
+	frame->ccid.params[1] = 0;
+	frame->ccid.params[2] = 0;
+
+	frame->data[0] = PN533_STD_FRAME_DIR_OUT;
+	frame->data[1] = cmd_code;
+	frame->datalen = 2;  /* data[0] + data[1] */
+
+	frame->apdu.class = 0xFF;
+	frame->apdu.ins = 0;
+	frame->apdu.p1 = 0;
+	frame->apdu.p2 = 0;
+}
+
+static void pn533_acr122_tx_frame_finish(void *_frame)
+{
+	struct pn533_acr122_tx_frame *frame = _frame;
+
+	frame->ccid.datalen += frame->datalen;
+}
+
+static void pn533_acr122_tx_update_payload_len(void *_frame, int len)
+{
+	struct pn533_acr122_tx_frame *frame = _frame;
+
+	frame->datalen += len;
+}
+
+static bool pn533_acr122_is_rx_frame_valid(void *_frame)
+{
+	struct pn533_acr122_rx_frame *frame = _frame;
+
+	if (frame->ccid.type != 0x83)
+		return false;
+
+	if (frame->data[frame->ccid.datalen - 2] == 0x63)
+		return false;
+
+	return true;
+}
+
+static int pn533_acr122_rx_frame_size(void *frame)
+{
+	struct pn533_acr122_rx_frame *f = frame;
+
+	/* f->ccid.datalen already includes tail length */
+	return sizeof(struct pn533_acr122_rx_frame) + f->ccid.datalen;
+}
+
+static u8 pn533_acr122_get_cmd_code(void *frame)
+{
+	struct pn533_acr122_rx_frame *f = frame;
+
+	return PN533_STD_FRAME_CMD(f);
+}
+
+static struct pn533_frame_ops pn533_acr122_frame_ops = {
+	.tx_frame_init = pn533_acr122_tx_frame_init,
+	.tx_frame_finish = pn533_acr122_tx_frame_finish,
+	.tx_update_payload_len = pn533_acr122_tx_update_payload_len,
+	.tx_header_len = PN533_ACR122_TX_FRAME_HEADER_LEN,
+	.tx_tail_len = PN533_ACR122_TX_FRAME_TAIL_LEN,
+
+	.rx_is_frame_valid = pn533_acr122_is_rx_frame_valid,
+	.rx_header_len = PN533_ACR122_RX_FRAME_HEADER_LEN,
+	.rx_tail_len = PN533_ACR122_RX_FRAME_TAIL_LEN,
+	.rx_frame_size = pn533_acr122_rx_frame_size,
+
+	.max_payload_len = PN533_ACR122_FRAME_MAX_PAYLOAD_LEN,
+	.get_cmd_code = pn533_acr122_get_cmd_code,
+};
+
 /* The rule: value + checksum = 0 */
-static inline u8 pn533_checksum(u8 value)
+static inline u8 pn533_std_checksum(u8 value)
 {
 	return ~value + 1;
 }
 
 /* The rule: sum(data elements) + checksum = 0 */
-static u8 pn533_data_checksum(u8 *data, int datalen)
+static u8 pn533_std_data_checksum(u8 *data, int datalen)
 {
 	u8 sum = 0;
 	int i;
@@ -408,61 +545,61 @@ static u8 pn533_data_checksum(u8 *data, int datalen)
 	for (i = 0; i < datalen; i++)
 		sum += data[i];
 
-	return pn533_checksum(sum);
+	return pn533_std_checksum(sum);
 }
 
-static void pn533_tx_frame_init(void *_frame, u8 cmd_code)
+static void pn533_std_tx_frame_init(void *_frame, u8 cmd_code)
 {
-	struct pn533_frame *frame = _frame;
+	struct pn533_std_frame *frame = _frame;
 
 	frame->preamble = 0;
-	frame->start_frame = cpu_to_be16(PN533_SOF);
-	PN533_FRAME_IDENTIFIER(frame) = PN533_DIR_OUT;
-	PN533_FRAME_CMD(frame) = cmd_code;
+	frame->start_frame = cpu_to_be16(PN533_STD_FRAME_SOF);
+	PN533_STD_FRAME_IDENTIFIER(frame) = PN533_STD_FRAME_DIR_OUT;
+	PN533_STD_FRAME_CMD(frame) = cmd_code;
 	frame->datalen = 2;
 }
 
-static void pn533_tx_frame_finish(void *_frame)
+static void pn533_std_tx_frame_finish(void *_frame)
 {
-	struct pn533_frame *frame = _frame;
+	struct pn533_std_frame *frame = _frame;
 
-	frame->datalen_checksum = pn533_checksum(frame->datalen);
+	frame->datalen_checksum = pn533_std_checksum(frame->datalen);
 
-	PN533_FRAME_CHECKSUM(frame) =
-		pn533_data_checksum(frame->data, frame->datalen);
+	PN533_STD_FRAME_CHECKSUM(frame) =
+		pn533_std_data_checksum(frame->data, frame->datalen);
 
-	PN533_FRAME_POSTAMBLE(frame) = 0;
+	PN533_STD_FRAME_POSTAMBLE(frame) = 0;
 }
 
-static void pn533_tx_update_payload_len(void *_frame, int len)
+static void pn533_std_tx_update_payload_len(void *_frame, int len)
 {
-	struct pn533_frame *frame = _frame;
+	struct pn533_std_frame *frame = _frame;
 
 	frame->datalen += len;
 }
 
-static bool pn533_rx_frame_is_valid(void *_frame)
+static bool pn533_std_rx_frame_is_valid(void *_frame)
 {
 	u8 checksum;
-	struct pn533_frame *frame = _frame;
+	struct pn533_std_frame *frame = _frame;
 
-	if (frame->start_frame != cpu_to_be16(PN533_SOF))
+	if (frame->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF))
 		return false;
 
-	checksum = pn533_checksum(frame->datalen);
+	checksum = pn533_std_checksum(frame->datalen);
 	if (checksum != frame->datalen_checksum)
 		return false;
 
-	checksum = pn533_data_checksum(frame->data, frame->datalen);
-	if (checksum != PN533_FRAME_CHECKSUM(frame))
+	checksum = pn533_std_data_checksum(frame->data, frame->datalen);
+	if (checksum != PN533_STD_FRAME_CHECKSUM(frame))
 		return false;
 
 	return true;
 }
 
-static bool pn533_rx_frame_is_ack(struct pn533_frame *frame)
+static bool pn533_std_rx_frame_is_ack(struct pn533_std_frame *frame)
 {
-	if (frame->start_frame != cpu_to_be16(PN533_SOF))
+	if (frame->start_frame != cpu_to_be16(PN533_STD_FRAME_SOF))
 		return false;
 
 	if (frame->datalen != 0 || frame->datalen_checksum != 0xFF)
@@ -471,57 +608,51 @@ static bool pn533_rx_frame_is_ack(struct pn533_frame *frame)
 	return true;
 }
 
-static inline int pn533_rx_frame_size(void *frame)
+static inline int pn533_std_rx_frame_size(void *frame)
 {
-	struct pn533_frame *f = frame;
+	struct pn533_std_frame *f = frame;
 
-	return sizeof(struct pn533_frame) + f->datalen + PN533_FRAME_TAIL_LEN;
+	return sizeof(struct pn533_std_frame) + f->datalen +
+	       PN533_STD_FRAME_TAIL_LEN;
 }
 
-static u8 pn533_get_cmd_code(void *frame)
+static u8 pn533_std_get_cmd_code(void *frame)
 {
-	struct pn533_frame *f = frame;
+	struct pn533_std_frame *f = frame;
 
-	return PN533_FRAME_CMD(f);
+	return PN533_STD_FRAME_CMD(f);
 }
 
 static struct pn533_frame_ops pn533_std_frame_ops = {
-	.tx_frame_init = pn533_tx_frame_init,
-	.tx_frame_finish = pn533_tx_frame_finish,
-	.tx_update_payload_len = pn533_tx_update_payload_len,
-	.tx_header_len = PN533_FRAME_HEADER_LEN,
-	.tx_tail_len = PN533_FRAME_TAIL_LEN,
-
-	.rx_is_frame_valid = pn533_rx_frame_is_valid,
-	.rx_frame_size = pn533_rx_frame_size,
-	.rx_header_len = PN533_FRAME_HEADER_LEN,
-	.rx_tail_len = PN533_FRAME_TAIL_LEN,
-
-	.max_payload_len =  PN533_FRAME_MAX_PAYLOAD_LEN,
-	.get_cmd_code = pn533_get_cmd_code,
+	.tx_frame_init = pn533_std_tx_frame_init,
+	.tx_frame_finish = pn533_std_tx_frame_finish,
+	.tx_update_payload_len = pn533_std_tx_update_payload_len,
+	.tx_header_len = PN533_STD_FRAME_HEADER_LEN,
+	.tx_tail_len = PN533_STD_FRAME_TAIL_LEN,
+
+	.rx_is_frame_valid = pn533_std_rx_frame_is_valid,
+	.rx_frame_size = pn533_std_rx_frame_size,
+	.rx_header_len = PN533_STD_FRAME_HEADER_LEN,
+	.rx_tail_len = PN533_STD_FRAME_TAIL_LEN,
+
+	.max_payload_len =  PN533_STD_FRAME_MAX_PAYLOAD_LEN,
+	.get_cmd_code = pn533_std_get_cmd_code,
 };
 
 static bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame)
 {
-	return (dev->ops->get_cmd_code(frame) == PN533_CMD_RESPONSE(dev->cmd));
-}
-
-
-static void pn533_wq_cmd_complete(struct work_struct *work)
-{
-	struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work);
-	int rc;
-
-	rc = dev->cmd_complete(dev, dev->cmd_complete_arg, dev->wq_in_error);
-	if (rc != -EINPROGRESS)
-		queue_work(dev->wq, &dev->cmd_work);
+	return (dev->ops->get_cmd_code(frame) ==
+				PN533_CMD_RESPONSE(dev->cmd->code));
 }
 
 static void pn533_recv_response(struct urb *urb)
 {
 	struct pn533 *dev = urb->context;
+	struct pn533_cmd *cmd = dev->cmd;
 	u8 *in_frame;
 
+	cmd->status = urb->status;
+
 	switch (urb->status) {
 	case 0:
 		break; /* success */
@@ -530,37 +661,33 @@ static void pn533_recv_response(struct urb *urb)
 		nfc_dev_dbg(&dev->interface->dev,
 			    "The urb has been canceled (status %d)",
 			    urb->status);
-		dev->wq_in_error = urb->status;
 		goto sched_wq;
 	case -ESHUTDOWN:
 	default:
 		nfc_dev_err(&dev->interface->dev,
 			    "Urb failure (status %d)", urb->status);
-		dev->wq_in_error = urb->status;
 		goto sched_wq;
 	}
 
 	in_frame = dev->in_urb->transfer_buffer;
 
 	nfc_dev_dbg(&dev->interface->dev, "Received a frame.");
-	print_hex_dump(KERN_DEBUG, "PN533 RX: ", DUMP_PREFIX_NONE, 16, 1,
-		       in_frame, dev->ops->rx_frame_size(in_frame), false);
+	print_hex_dump_debug("PN533 RX: ", DUMP_PREFIX_NONE, 16, 1, in_frame,
+			     dev->ops->rx_frame_size(in_frame), false);
 
 	if (!dev->ops->rx_is_frame_valid(in_frame)) {
 		nfc_dev_err(&dev->interface->dev, "Received an invalid frame");
-		dev->wq_in_error = -EIO;
+		cmd->status = -EIO;
 		goto sched_wq;
 	}
 
 	if (!pn533_rx_frame_is_cmd_response(dev, in_frame)) {
 		nfc_dev_err(&dev->interface->dev,
 			    "It it not the response to the last command");
-		dev->wq_in_error = -EIO;
+		cmd->status = -EIO;
 		goto sched_wq;
 	}
 
-	dev->wq_in_error = 0;
-
 sched_wq:
 	queue_work(dev->wq, &dev->cmd_complete_work);
 }
@@ -575,9 +702,12 @@ static int pn533_submit_urb_for_response(struct pn533 *dev, gfp_t flags)
 static void pn533_recv_ack(struct urb *urb)
 {
 	struct pn533 *dev = urb->context;
-	struct pn533_frame *in_frame;
+	struct pn533_cmd *cmd = dev->cmd;
+	struct pn533_std_frame *in_frame;
 	int rc;
 
+	cmd->status = urb->status;
+
 	switch (urb->status) {
 	case 0:
 		break; /* success */
@@ -586,21 +716,19 @@ static void pn533_recv_ack(struct urb *urb)
 		nfc_dev_dbg(&dev->interface->dev,
 			    "The urb has been stopped (status %d)",
 			    urb->status);
-		dev->wq_in_error = urb->status;
 		goto sched_wq;
 	case -ESHUTDOWN:
 	default:
 		nfc_dev_err(&dev->interface->dev,
 			    "Urb failure (status %d)", urb->status);
-		dev->wq_in_error = urb->status;
 		goto sched_wq;
 	}
 
 	in_frame = dev->in_urb->transfer_buffer;
 
-	if (!pn533_rx_frame_is_ack(in_frame)) {
+	if (!pn533_std_rx_frame_is_ack(in_frame)) {
 		nfc_dev_err(&dev->interface->dev, "Received an invalid ack");
-		dev->wq_in_error = -EIO;
+		cmd->status = -EIO;
 		goto sched_wq;
 	}
 
@@ -608,7 +736,7 @@ static void pn533_recv_ack(struct urb *urb)
 	if (rc) {
 		nfc_dev_err(&dev->interface->dev,
 			    "usb_submit_urb failed with result %d", rc);
-		dev->wq_in_error = rc;
+		cmd->status = rc;
 		goto sched_wq;
 	}
 
@@ -627,7 +755,7 @@ static int pn533_submit_urb_for_ack(struct pn533 *dev, gfp_t flags)
 
 static int pn533_send_ack(struct pn533 *dev, gfp_t flags)
 {
-	u8 ack[PN533_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
+	u8 ack[PN533_STD_FRAME_ACK_SIZE] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
 	/* spec 7.1.1.3:  Preamble, SoPC (2), ACK Code (2), Postamble */
 	int rc;
 
@@ -643,32 +771,34 @@ static int pn533_send_ack(struct pn533 *dev, gfp_t flags)
 static int __pn533_send_frame_async(struct pn533 *dev,
 					struct sk_buff *out,
 					struct sk_buff *in,
-					int in_len,
-					pn533_cmd_complete_t cmd_complete,
-					void *arg)
+					int in_len)
 {
 	int rc;
 
-	dev->cmd = dev->ops->get_cmd_code(out->data);
-	dev->cmd_complete = cmd_complete;
-	dev->cmd_complete_arg = arg;
-
 	dev->out_urb->transfer_buffer = out->data;
 	dev->out_urb->transfer_buffer_length = out->len;
 
 	dev->in_urb->transfer_buffer = in->data;
 	dev->in_urb->transfer_buffer_length = in_len;
 
-	print_hex_dump(KERN_DEBUG, "PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
-		       out->data, out->len, false);
+	print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
+			     out->data, out->len, false);
 
 	rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
 	if (rc)
 		return rc;
 
-	rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL);
-	if (rc)
-		goto error;
+	if (dev->protocol_type == PN533_PROTO_REQ_RESP) {
+		/* request for response for sent packet directly */
+		rc = pn533_submit_urb_for_response(dev, GFP_ATOMIC);
+		if (rc)
+			goto error;
+	} else if (dev->protocol_type == PN533_PROTO_REQ_ACK_RESP) {
+		/* request for ACK if that's the case */
+		rc = pn533_submit_urb_for_ack(dev, GFP_KERNEL);
+		if (rc)
+			goto error;
+	}
 
 	return 0;
 
@@ -693,39 +823,34 @@ static void pn533_build_cmd_frame(struct pn533 *dev, u8 cmd_code,
 	ops->tx_frame_finish(skb->data);
 }
 
-struct pn533_send_async_complete_arg {
-	pn533_send_async_complete_t  complete_cb;
-	void *complete_cb_context;
-	struct sk_buff *resp;
-	struct sk_buff *req;
-};
-
-static int pn533_send_async_complete(struct pn533 *dev, void *_arg, int status)
+static int pn533_send_async_complete(struct pn533 *dev)
 {
-	struct pn533_send_async_complete_arg *arg = _arg;
+	struct pn533_cmd *cmd = dev->cmd;
+	int status = cmd->status;
 
-	struct sk_buff *req = arg->req;
-	struct sk_buff *resp = arg->resp;
+	struct sk_buff *req = cmd->req;
+	struct sk_buff *resp = cmd->resp;
 
 	int rc;
 
 	dev_kfree_skb(req);
 
 	if (status < 0) {
-		arg->complete_cb(dev, arg->complete_cb_context,
-				 ERR_PTR(status));
+		rc = cmd->complete_cb(dev, cmd->complete_cb_context,
+				      ERR_PTR(status));
 		dev_kfree_skb(resp);
-		kfree(arg);
-		return status;
+		goto done;
 	}
 
 	skb_put(resp, dev->ops->rx_frame_size(resp->data));
 	skb_pull(resp, dev->ops->rx_header_len);
 	skb_trim(resp, resp->len - dev->ops->rx_tail_len);
 
-	rc = arg->complete_cb(dev, arg->complete_cb_context, resp);
+	rc = cmd->complete_cb(dev, cmd->complete_cb_context, resp);
 
-	kfree(arg);
+done:
+	kfree(cmd);
+	dev->cmd = NULL;
 	return rc;
 }
 
@@ -736,56 +861,45 @@ static int __pn533_send_async(struct pn533 *dev, u8 cmd_code,
 			      void *complete_cb_context)
 {
 	struct pn533_cmd *cmd;
-	struct pn533_send_async_complete_arg *arg;
 	int rc = 0;
 
 	nfc_dev_dbg(&dev->interface->dev, "Sending command 0x%x", cmd_code);
 
-	arg = kzalloc(sizeof(*arg), GFP_KERNEL);
-	if (!arg)
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd)
 		return -ENOMEM;
 
-	arg->complete_cb = complete_cb;
-	arg->complete_cb_context = complete_cb_context;
-	arg->resp = resp;
-	arg->req = req;
+	cmd->code = cmd_code;
+	cmd->req = req;
+	cmd->resp = resp;
+	cmd->resp_len = resp_len;
+	cmd->complete_cb = complete_cb;
+	cmd->complete_cb_context = complete_cb_context;
 
 	pn533_build_cmd_frame(dev, cmd_code, req);
 
 	mutex_lock(&dev->cmd_lock);
 
 	if (!dev->cmd_pending) {
-		rc = __pn533_send_frame_async(dev, req, resp, resp_len,
-					      pn533_send_async_complete, arg);
+		rc = __pn533_send_frame_async(dev, req, resp, resp_len);
 		if (rc)
 			goto error;
 
 		dev->cmd_pending = 1;
+		dev->cmd = cmd;
 		goto unlock;
 	}
 
 	nfc_dev_dbg(&dev->interface->dev, "%s Queueing command 0x%x", __func__,
 		    cmd_code);
 
-	cmd = kzalloc(sizeof(struct pn533_cmd), GFP_KERNEL);
-	if (!cmd) {
-		rc = -ENOMEM;
-		goto error;
-	}
-
 	INIT_LIST_HEAD(&cmd->queue);
-	cmd->cmd_code = cmd_code;
-	cmd->req = req;
-	cmd->resp = resp;
-	cmd->resp_len = resp_len;
-	cmd->arg = arg;
-
 	list_add_tail(&cmd->queue, &dev->cmd_queue);
 
 	goto unlock;
 
 error:
-	kfree(arg);
+	kfree(cmd);
 unlock:
 	mutex_unlock(&dev->cmd_lock);
 	return rc;
@@ -850,8 +964,8 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,
 				       pn533_send_async_complete_t complete_cb,
 				       void *complete_cb_context)
 {
-	struct pn533_send_async_complete_arg *arg;
 	struct sk_buff *resp;
+	struct pn533_cmd *cmd;
 	int rc;
 	int resp_len = dev->ops->rx_header_len +
 		       dev->ops->max_payload_len +
@@ -861,33 +975,47 @@ static int pn533_send_cmd_direct_async(struct pn533 *dev, u8 cmd_code,
 	if (!resp)
 		return -ENOMEM;
 
-	arg = kzalloc(sizeof(*arg), GFP_KERNEL);
-	if (!arg) {
+	cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+	if (!cmd) {
 		dev_kfree_skb(resp);
 		return -ENOMEM;
 	}
 
-	arg->complete_cb = complete_cb;
-	arg->complete_cb_context = complete_cb_context;
-	arg->resp = resp;
-	arg->req = req;
+	cmd->code = cmd_code;
+	cmd->req = req;
+	cmd->resp = resp;
+	cmd->resp_len = resp_len;
+	cmd->complete_cb = complete_cb;
+	cmd->complete_cb_context = complete_cb_context;
 
 	pn533_build_cmd_frame(dev, cmd_code, req);
 
-	rc = __pn533_send_frame_async(dev, req, resp, resp_len,
-				      pn533_send_async_complete, arg);
+	rc = __pn533_send_frame_async(dev, req, resp, resp_len);
 	if (rc < 0) {
 		dev_kfree_skb(resp);
-		kfree(arg);
+		kfree(cmd);
+	} else {
+		dev->cmd = cmd;
 	}
 
 	return rc;
 }
 
+static void pn533_wq_cmd_complete(struct work_struct *work)
+{
+	struct pn533 *dev = container_of(work, struct pn533, cmd_complete_work);
+	int rc;
+
+	rc = pn533_send_async_complete(dev);
+	if (rc != -EINPROGRESS)
+		queue_work(dev->wq, &dev->cmd_work);
+}
+
 static void pn533_wq_cmd(struct work_struct *work)
 {
 	struct pn533 *dev = container_of(work, struct pn533, cmd_work);
 	struct pn533_cmd *cmd;
+	int rc;
 
 	mutex_lock(&dev->cmd_lock);
 
@@ -903,10 +1031,15 @@ static void pn533_wq_cmd(struct work_struct *work)
 
 	mutex_unlock(&dev->cmd_lock);
 
-	__pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len,
-				 pn533_send_async_complete, cmd->arg);
+	rc = __pn533_send_frame_async(dev, cmd->req, cmd->resp, cmd->resp_len);
+	if (rc < 0) {
+		dev_kfree_skb(cmd->req);
+		dev_kfree_skb(cmd->resp);
+		kfree(cmd);
+		return;
+	}
 
-	kfree(cmd);
+	dev->cmd = cmd;
 }
 
 struct pn533_sync_cmd_response {
@@ -982,6 +1115,23 @@ static void pn533_send_complete(struct urb *urb)
 	}
 }
 
+static void pn533_abort_cmd(struct pn533 *dev, gfp_t flags)
+{
+	/* ACR122U does not support any command which aborts last
+	 * issued command i.e. as ACK for standard PN533. Additionally,
+	 * it behaves stange, sending broken or incorrect responses,
+	 * when we cancel urb before the chip will send response.
+	 */
+	if (dev->device_type == PN533_DEVICE_ACR122U)
+		return;
+
+	/* An ack will cancel the last issued command */
+	pn533_send_ack(dev, flags);
+
+	/* cancel the urb request */
+	usb_kill_urb(dev->in_urb);
+}
+
 static struct sk_buff *pn533_alloc_skb(struct pn533 *dev, unsigned int size)
 {
 	struct sk_buff *skb;
@@ -1500,9 +1650,6 @@ static void pn533_listen_mode_timer(unsigned long data)
 
 	nfc_dev_dbg(&dev->interface->dev, "Listen mode timeout");
 
-	/* An ack will cancel the last issued command (poll) */
-	pn533_send_ack(dev, GFP_ATOMIC);
-
 	dev->cancel_listen = 1;
 
 	pn533_poll_next_mod(dev);
@@ -1549,6 +1696,11 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg,
 	if (!rc)
 		goto done;
 
+	if (!dev->poll_mod_count) {
+		nfc_dev_dbg(&dev->interface->dev, "Polling has been stoped.");
+		goto done;
+	}
+
 	pn533_poll_next_mod(dev);
 	queue_work(dev->wq, &dev->poll_work);
 
@@ -1627,7 +1779,7 @@ static void pn533_wq_poll(struct work_struct *work)
 
 	if (dev->cancel_listen == 1) {
 		dev->cancel_listen = 0;
-		usb_kill_urb(dev->in_urb);
+		pn533_abort_cmd(dev, GFP_ATOMIC);
 	}
 
 	rc = pn533_send_poll_frame(dev);
@@ -1689,12 +1841,7 @@ static void pn533_stop_poll(struct nfc_dev *nfc_dev)
 		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);
-
+	pn533_abort_cmd(dev, GFP_KERNEL);
 	pn533_poll_reset_mod_list(dev);
 }
 
@@ -1723,6 +1870,8 @@ static int pn533_activate_target_nfcdep(struct pn533 *dev)
 	rsp = (struct pn533_cmd_activate_response *)resp->data;
 	rc = rsp->status & PN533_CMD_RET_MASK;
 	if (rc != PN533_CMD_RET_SUCCESS) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Target activation failed (error 0x%x)", rc);
 		dev_kfree_skb(resp);
 		return -EIO;
 	}
@@ -1850,7 +1999,7 @@ static int pn533_in_dep_link_up_complete(struct pn533 *dev, void *arg,
 	rc = rsp->status & PN533_CMD_RET_MASK;
 	if (rc != PN533_CMD_RET_SUCCESS) {
 		nfc_dev_err(&dev->interface->dev,
-			    "Bringing DEP link up failed %d", rc);
+			    "Bringing DEP link up failed (error 0x%x)", rc);
 		goto error;
 	}
 
@@ -1985,10 +2134,8 @@ static int pn533_dep_link_down(struct nfc_dev *nfc_dev)
 
 	pn533_poll_reset_mod_list(dev);
 
-	if (dev->tgt_mode || dev->tgt_active_prot) {
-		pn533_send_ack(dev, GFP_KERNEL);
-		usb_kill_urb(dev->in_urb);
-	}
+	if (dev->tgt_mode || dev->tgt_active_prot)
+		pn533_abort_cmd(dev, GFP_KERNEL);
 
 	dev->tgt_active_prot = 0;
 	dev->tgt_mode = 0;
@@ -2064,8 +2211,7 @@ static int pn533_data_exchange_complete(struct pn533 *dev, void *_arg,
 
 	if (ret != PN533_CMD_RET_SUCCESS) {
 		nfc_dev_err(&dev->interface->dev,
-			    "PN533 reported error %d when exchanging data",
-			    ret);
+			    "Exchanging data failed (error 0x%x)", ret);
 		rc = -EIO;
 		goto error;
 	}
@@ -2253,7 +2399,7 @@ static void pn533_wq_mi_recv(struct work_struct *work)
 		    "Error %d when trying to perform data_exchange", rc);
 
 	dev_kfree_skb(skb);
-	kfree(dev->cmd_complete_arg);
+	kfree(dev->cmd_complete_mi_arg);
 
 error:
 	pn533_send_ack(dev, GFP_KERNEL);
@@ -2310,7 +2456,7 @@ static int pn533_get_firmware_version(struct pn533 *dev,
 	return 0;
 }
 
-static int pn533_fw_reset(struct pn533 *dev)
+static int pn533_pasori_fw_reset(struct pn533 *dev)
 {
 	struct sk_buff *skb;
 	struct sk_buff *resp;
@@ -2332,9 +2478,102 @@ static int pn533_fw_reset(struct pn533 *dev)
 	return 0;
 }
 
+struct pn533_acr122_poweron_rdr_arg {
+	int rc;
+	struct completion done;
+};
+
+static void pn533_acr122_poweron_rdr_resp(struct urb *urb)
+{
+	struct pn533_acr122_poweron_rdr_arg *arg = urb->context;
+
+	nfc_dev_dbg(&urb->dev->dev, "%s", __func__);
+
+	print_hex_dump(KERN_ERR, "ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1,
+		       urb->transfer_buffer, urb->transfer_buffer_length,
+		       false);
+
+	arg->rc = urb->status;
+	complete(&arg->done);
+}
+
+static int pn533_acr122_poweron_rdr(struct pn533 *dev)
+{
+	/* Power on th reader (CCID cmd) */
+	u8 cmd[10] = {PN533_ACR122_PC_TO_RDR_ICCPOWERON,
+		      0, 0, 0, 0, 0, 0, 3, 0, 0};
+	u8 buf[255];
+	int rc;
+	void *cntx;
+	struct pn533_acr122_poweron_rdr_arg arg;
+
+	nfc_dev_dbg(&dev->interface->dev, "%s", __func__);
+
+	init_completion(&arg.done);
+	cntx = dev->in_urb->context;  /* backup context */
+
+	dev->in_urb->transfer_buffer = buf;
+	dev->in_urb->transfer_buffer_length = 255;
+	dev->in_urb->complete = pn533_acr122_poweron_rdr_resp;
+	dev->in_urb->context = &arg;
+
+	dev->out_urb->transfer_buffer = cmd;
+	dev->out_urb->transfer_buffer_length = sizeof(cmd);
+
+	print_hex_dump(KERN_ERR, "ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1,
+		       cmd, sizeof(cmd), false);
+
+	rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
+	if (rc) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Reader power on cmd error %d", rc);
+		return rc;
+	}
+
+	rc =  usb_submit_urb(dev->in_urb, GFP_KERNEL);
+	if (rc) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Can't submit for reader power on cmd response %d",
+			    rc);
+		return rc;
+	}
+
+	wait_for_completion(&arg.done);
+	dev->in_urb->context = cntx; /* restore context */
+
+	return arg.rc;
+}
+
+static int pn533_rf_field(struct nfc_dev *nfc_dev, u8 rf)
+{
+	struct pn533 *dev = nfc_get_drvdata(nfc_dev);
+	u8 rf_field = !!rf;
+	int rc;
+
+	rc = pn533_set_configuration(dev, PN533_CFGITEM_RF_FIELD,
+				     (u8 *)&rf_field, 1);
+	if (rc) {
+		nfc_dev_err(&dev->interface->dev,
+			    "Error on setting RF field");
+		return rc;
+	}
+
+	return rc;
+}
+
+int pn533_dev_up(struct nfc_dev *nfc_dev)
+{
+	return pn533_rf_field(nfc_dev, 1);
+}
+
+int pn533_dev_down(struct nfc_dev *nfc_dev)
+{
+	return pn533_rf_field(nfc_dev, 0);
+}
+
 static struct nfc_ops pn533_nfc_ops = {
-	.dev_up = NULL,
-	.dev_down = NULL,
+	.dev_up = pn533_dev_up,
+	.dev_down = pn533_dev_down,
 	.dep_link_up = pn533_dep_link_up,
 	.dep_link_down = pn533_dep_link_down,
 	.start_poll = pn533_start_poll,
@@ -2366,6 +2605,7 @@ static int pn533_setup(struct pn533 *dev)
 		break;
 
 	case PN533_DEVICE_PASORI:
+	case PN533_DEVICE_ACR122U:
 		max_retries.mx_rty_atr = 0x2;
 		max_retries.mx_rty_psl = 0x1;
 		max_retries.mx_rty_passive_act =
@@ -2405,7 +2645,7 @@ static int pn533_setup(struct pn533 *dev)
 		break;
 
 	case PN533_DEVICE_PASORI:
-		pn533_fw_reset(dev);
+		pn533_pasori_fw_reset(dev);
 
 		rc = pn533_set_configuration(dev, PN533_CFGITEM_PASORI,
 					     pasori_cfg, 3);
@@ -2415,7 +2655,7 @@ static int pn533_setup(struct pn533 *dev)
 			return rc;
 		}
 
-		pn533_fw_reset(dev);
+		pn533_pasori_fw_reset(dev);
 
 		break;
 	}
@@ -2496,6 +2736,7 @@ static int pn533_probe(struct usb_interface *interface,
 
 	dev->ops = &pn533_std_frame_ops;
 
+	dev->protocol_type = PN533_PROTO_REQ_ACK_RESP;
 	dev->device_type = id->driver_info;
 	switch (dev->device_type) {
 	case PN533_DEVICE_STD:
@@ -2506,6 +2747,20 @@ static int pn533_probe(struct usb_interface *interface,
 		protocols = PN533_NO_TYPE_B_PROTOCOLS;
 		break;
 
+	case PN533_DEVICE_ACR122U:
+		protocols = PN533_NO_TYPE_B_PROTOCOLS;
+		dev->ops = &pn533_acr122_frame_ops;
+		dev->protocol_type = PN533_PROTO_REQ_RESP,
+
+		rc = pn533_acr122_poweron_rdr(dev);
+		if (rc < 0) {
+			nfc_dev_err(&dev->interface->dev,
+				    "Couldn't poweron the reader (error %d)",
+				    rc);
+			goto destroy_wq;
+		}
+		break;
+
 	default:
 		nfc_dev_err(&dev->interface->dev, "Unknown device type %d\n",
 			    dev->device_type);
@@ -2555,6 +2810,7 @@ destroy_wq:
 error:
 	usb_free_urb(dev->in_urb);
 	usb_free_urb(dev->out_urb);
+	usb_put_dev(dev->udev);
 	kfree(dev);
 	return rc;
 }
@@ -2600,8 +2856,9 @@ static struct usb_driver pn533_driver = {
 
 module_usb_driver(pn533_driver);
 
-MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>,"
-			" Aloisio Almeida Jr <aloisio.almeida@openbossa.org>");
+MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>");
+MODULE_AUTHOR("Aloisio Almeida Jr <aloisio.almeida@openbossa.org>");
+MODULE_AUTHOR("Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>");
 MODULE_DESCRIPTION("PN533 usb driver ver " VERSION);
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");

+ 12 - 1
drivers/nfc/pn544/Kconfig

@@ -20,4 +20,15 @@ config NFC_PN544_I2C
 	  Select this if your platform is using the i2c bus.
 
 	  If you choose to build a module, it'll be called pn544_i2c.
-	  Say N if unsure.
+	  Say N if unsure.
+
+config NFC_PN544_MEI
+	tristate "NFC PN544 MEI support"
+	depends on NFC_PN544 && NFC_MEI_PHY
+	---help---
+	  This module adds support for the mei interface of adapters using
+	  NXP pn544 chipsets.  Select this if your pn544 chipset
+	  is handled by Intel's Management Engine Interface on your platform.
+
+	  If you choose to build a module, it'll be called pn544_mei.
+	  Say N if unsure.

+ 2 - 0
drivers/nfc/pn544/Makefile

@@ -3,6 +3,8 @@
 #
 
 pn544_i2c-objs  = i2c.o
+pn544_mei-objs  = mei.o
 
 obj-$(CONFIG_NFC_PN544)     += pn544.o
 obj-$(CONFIG_NFC_PN544_I2C) += pn544_i2c.o
+obj-$(CONFIG_NFC_PN544_MEI) += pn544_mei.o

+ 121 - 0
drivers/nfc/pn544/mei.c

@@ -0,0 +1,121 @@
+/*
+ * HCI based Driver for NXP pn544 NFC Chip
+ *
+ * Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions 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/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/nfc.h>
+#include <net/nfc/hci.h>
+#include <net/nfc/llc.h>
+
+#include "../mei_phy.h"
+#include "pn544.h"
+
+#define PN544_DRIVER_NAME "pn544"
+
+static int pn544_mei_probe(struct mei_cl_device *device,
+			       const struct mei_cl_device_id *id)
+{
+	struct nfc_mei_phy *phy;
+	int r;
+
+	pr_info("Probing NFC pn544\n");
+
+	phy = nfc_mei_phy_alloc(device);
+	if (!phy) {
+		pr_err("Cannot allocate memory for pn544 mei phy.\n");
+		return -ENOMEM;
+	}
+
+	r = mei_cl_register_event_cb(device, nfc_mei_event_cb, phy);
+	if (r) {
+		pr_err(PN544_DRIVER_NAME ": event cb registration failed\n");
+		goto err_out;
+	}
+
+	r = pn544_hci_probe(phy, &mei_phy_ops, LLC_NOP_NAME,
+			    MEI_NFC_HEADER_SIZE, 0, MEI_NFC_MAX_HCI_PAYLOAD,
+			    &phy->hdev);
+	if (r < 0)
+		goto err_out;
+
+	return 0;
+
+err_out:
+	nfc_mei_phy_free(phy);
+
+	return r;
+}
+
+static int pn544_mei_remove(struct mei_cl_device *device)
+{
+	struct nfc_mei_phy *phy = mei_cl_get_drvdata(device);
+
+	pr_info("Removing pn544\n");
+
+	pn544_hci_remove(phy->hdev);
+
+	nfc_mei_phy_disable(phy);
+
+	nfc_mei_phy_free(phy);
+
+	return 0;
+}
+
+static struct mei_cl_device_id pn544_mei_tbl[] = {
+	{ PN544_DRIVER_NAME },
+
+	/* required last entry */
+	{ }
+};
+MODULE_DEVICE_TABLE(mei, pn544_mei_tbl);
+
+static struct mei_cl_driver pn544_driver = {
+	.id_table = pn544_mei_tbl,
+	.name = PN544_DRIVER_NAME,
+
+	.probe = pn544_mei_probe,
+	.remove = pn544_mei_remove,
+};
+
+static int pn544_mei_init(void)
+{
+	int r;
+
+	pr_debug(DRIVER_DESC ": %s\n", __func__);
+
+	r = mei_cl_driver_register(&pn544_driver);
+	if (r) {
+		pr_err(PN544_DRIVER_NAME ": driver registration failed\n");
+		return r;
+	}
+
+	return 0;
+}
+
+static void pn544_mei_exit(void)
+{
+	mei_cl_driver_unregister(&pn544_driver);
+}
+
+module_init(pn544_mei_init);
+module_exit(pn544_mei_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);

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

@@ -122,6 +122,8 @@ struct nfc_dev {
 
 	bool shutting_down;
 
+	struct rfkill *rfkill;
+
 	struct nfc_ops *ops;
 };
 #define to_nfc_dev(_dev) container_of(_dev, struct nfc_dev, dev)

+ 5 - 2
include/uapi/linux/nfc.h

@@ -233,7 +233,10 @@ struct sockaddr_nfc_llcp {
 #define NFC_LLCP_DIRECTION_TX		0x01
 
 /* socket option names */
-#define NFC_LLCP_RW   0
-#define NFC_LLCP_MIUX 1
+#define NFC_LLCP_RW		0
+#define NFC_LLCP_MIUX		1
+#define NFC_LLCP_REMOTE_MIU	2
+#define NFC_LLCP_REMOTE_LTO	3
+#define NFC_LLCP_REMOTE_RW	4
 
 #endif /*__LINUX_NFC_H */

+ 2 - 0
include/uapi/linux/rfkill.h

@@ -37,6 +37,7 @@
  * @RFKILL_TYPE_WWAN: switch is on a wireless WAN device.
  * @RFKILL_TYPE_GPS: switch is on a GPS device.
  * @RFKILL_TYPE_FM: switch is on a FM radio device.
+ * @RFKILL_TYPE_NFC: switch is on an NFC device.
  * @NUM_RFKILL_TYPES: number of defined rfkill types
  */
 enum rfkill_type {
@@ -48,6 +49,7 @@ enum rfkill_type {
 	RFKILL_TYPE_WWAN,
 	RFKILL_TYPE_GPS,
 	RFKILL_TYPE_FM,
+	RFKILL_TYPE_NFC,
 	NUM_RFKILL_TYPES,
 };
 

+ 43 - 0
net/nfc/core.c

@@ -27,6 +27,7 @@
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
+#include <linux/rfkill.h>
 #include <linux/nfc.h>
 
 #include <net/genetlink.h>
@@ -58,6 +59,11 @@ int nfc_dev_up(struct nfc_dev *dev)
 
 	device_lock(&dev->dev);
 
+	if (dev->rfkill && rfkill_blocked(dev->rfkill)) {
+		rc = -ERFKILL;
+		goto error;
+	}
+
 	if (!device_is_registered(&dev->dev)) {
 		rc = -ENODEV;
 		goto error;
@@ -117,6 +123,24 @@ error:
 	return rc;
 }
 
+static int nfc_rfkill_set_block(void *data, bool blocked)
+{
+	struct nfc_dev *dev = data;
+
+	pr_debug("%s blocked %d", dev_name(&dev->dev), blocked);
+
+	if (!blocked)
+		return 0;
+
+	nfc_dev_down(dev);
+
+	return 0;
+}
+
+static const struct rfkill_ops nfc_rfkill_ops = {
+	.set_block = nfc_rfkill_set_block,
+};
+
 /**
  * nfc_start_poll - start polling for nfc targets
  *
@@ -143,6 +167,11 @@ int nfc_start_poll(struct nfc_dev *dev, u32 im_protocols, u32 tm_protocols)
 		goto error;
 	}
 
+	if (!dev->dev_up) {
+		rc = -ENODEV;
+		goto error;
+	}
+
 	if (dev->polling) {
 		rc = -EBUSY;
 		goto error;
@@ -835,6 +864,15 @@ int nfc_register_device(struct nfc_dev *dev)
 		pr_debug("The userspace won't be notified that the device %s was added\n",
 			 dev_name(&dev->dev));
 
+	dev->rfkill = rfkill_alloc(dev_name(&dev->dev), &dev->dev,
+				   RFKILL_TYPE_NFC, &nfc_rfkill_ops, dev);
+	if (dev->rfkill) {
+		if (rfkill_register(dev->rfkill) < 0) {
+			rfkill_destroy(dev->rfkill);
+			dev->rfkill = NULL;
+		}
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL(nfc_register_device);
@@ -852,6 +890,11 @@ void nfc_unregister_device(struct nfc_dev *dev)
 
 	id = dev->idx;
 
+	if (dev->rfkill) {
+		rfkill_unregister(dev->rfkill);
+		rfkill_destroy(dev->rfkill);
+	}
+
 	if (dev->ops->check_presence) {
 		device_lock(&dev->dev);
 		dev->shutting_down = true;

+ 20 - 10
net/nfc/llcp/commands.c

@@ -420,7 +420,8 @@ int nfc_llcp_send_connect(struct nfc_llcp_sock *sock)
 	}
 
 	/* If the socket parameters are not set, use the local ones */
-	miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux;
+	miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ?
+		local->miux : sock->miux;
 	rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
 
 	miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
@@ -475,7 +476,8 @@ int nfc_llcp_send_cc(struct nfc_llcp_sock *sock)
 		return -ENODEV;
 
 	/* If the socket parameters are not set, use the local ones */
-	miux = sock->miux > LLCP_MAX_MIUX ? local->miux : sock->miux;
+	miux = be16_to_cpu(sock->miux) > LLCP_MAX_MIUX ?
+		local->miux : sock->miux;
 	rw = sock->rw > LLCP_MAX_RW ? local->rw : sock->rw;
 
 	miux_tlv = nfc_llcp_build_tlv(LLCP_TLV_MIUX, (u8 *)&miux, 0,
@@ -656,6 +658,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 	struct nfc_llcp_local *local;
 	size_t frag_len = 0, remaining_len;
 	u8 *msg_data, *msg_ptr;
+	u16 remote_miu;
 
 	pr_debug("Send I frame len %zd\n", len);
 
@@ -692,9 +695,11 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 	remaining_len = len;
 	msg_ptr = msg_data;
 
-	while (remaining_len > 0) {
+	do {
+		remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
+				local->remote_miu : sock->remote_miu;
 
-		frag_len = min_t(size_t, sock->remote_miu, remaining_len);
+		frag_len = min_t(size_t, remote_miu, remaining_len);
 
 		pr_debug("Fragment %zd bytes remaining %zd",
 			 frag_len, remaining_len);
@@ -706,7 +711,8 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 
 		skb_put(pdu, LLCP_SEQUENCE_SIZE);
 
-		memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
+		if (likely(frag_len > 0))
+			memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
 
 		skb_queue_tail(&sock->tx_queue, pdu);
 
@@ -718,7 +724,7 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
 
 		remaining_len -= frag_len;
 		msg_ptr += frag_len;
-	}
+	} while (remaining_len > 0);
 
 	kfree(msg_data);
 
@@ -732,6 +738,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
 	struct nfc_llcp_local *local;
 	size_t frag_len = 0, remaining_len;
 	u8 *msg_ptr, *msg_data;
+	u16 remote_miu;
 	int err;
 
 	pr_debug("Send UI frame len %zd\n", len);
@@ -752,9 +759,11 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
 	remaining_len = len;
 	msg_ptr = msg_data;
 
-	while (remaining_len > 0) {
+	do {
+		remote_miu = sock->remote_miu > LLCP_MAX_MIU ?
+				local->remote_miu : sock->remote_miu;
 
-		frag_len = min_t(size_t, sock->remote_miu, remaining_len);
+		frag_len = min_t(size_t, remote_miu, remaining_len);
 
 		pr_debug("Fragment %zd bytes remaining %zd",
 			 frag_len, remaining_len);
@@ -768,14 +777,15 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
 
 		pdu = llcp_add_header(pdu, dsap, ssap, LLCP_PDU_UI);
 
-		memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
+		if (likely(frag_len > 0))
+			memcpy(skb_put(pdu, frag_len), msg_ptr, frag_len);
 
 		/* No need to check for the peer RW for UI frames */
 		skb_queue_tail(&local->tx_queue, pdu);
 
 		remaining_len -= frag_len;
 		msg_ptr += frag_len;
-	}
+	} while (remaining_len > 0);
 
 	kfree(msg_data);
 

+ 90 - 37
net/nfc/llcp/llcp.c

@@ -31,6 +31,8 @@ static u8 llcp_magic[3] = {0x46, 0x66, 0x6d};
 
 static struct list_head llcp_devices;
 
+static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb);
+
 void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *sk)
 {
 	write_lock(&l->lock);
@@ -45,6 +47,12 @@ void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *sk)
 	write_unlock(&l->lock);
 }
 
+void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock)
+{
+	sock->remote_rw = LLCP_DEFAULT_RW;
+	sock->remote_miu = LLCP_MAX_MIU + 1;
+}
+
 static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
 {
 	struct nfc_llcp_local *local = sock->local;
@@ -68,7 +76,7 @@ static void nfc_llcp_socket_purge(struct nfc_llcp_sock *sock)
 	}
 }
 
-static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
+static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool device,
 				    int err)
 {
 	struct sock *sk;
@@ -108,21 +116,6 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
 
 				bh_unlock_sock(accept_sk);
 			}
-
-			if (listen == true) {
-				bh_unlock_sock(sk);
-				continue;
-			}
-		}
-
-		/*
-		 * If we have a connection less socket bound, we keep it alive
-		 * if the device is still present.
-		 */
-		if (sk->sk_state == LLCP_BOUND && sk->sk_type == SOCK_DGRAM &&
-		    listen == true) {
-			bh_unlock_sock(sk);
-			continue;
 		}
 
 		if (err)
@@ -137,11 +130,8 @@ static void nfc_llcp_socket_release(struct nfc_llcp_local *local, bool listen,
 
 	write_unlock(&local->sockets.lock);
 
-	/*
-	 * If we want to keep the listening sockets alive,
-	 * we don't touch the RAW ones.
-	 */
-	if (listen == true)
+	/* If we still have a device, we keep the RAW sockets alive */
+	if (device == true)
 		return;
 
 	write_lock(&local->raw_sockets.lock);
@@ -173,9 +163,9 @@ struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local)
 	return local;
 }
 
-static void local_cleanup(struct nfc_llcp_local *local, bool listen)
+static void local_cleanup(struct nfc_llcp_local *local)
 {
-	nfc_llcp_socket_release(local, listen, ENXIO);
+	nfc_llcp_socket_release(local, false, ENXIO);
 	del_timer_sync(&local->link_timer);
 	skb_queue_purge(&local->tx_queue);
 	cancel_work_sync(&local->tx_work);
@@ -194,7 +184,7 @@ static void local_release(struct kref *ref)
 	local = container_of(ref, struct nfc_llcp_local, ref);
 
 	list_del(&local->list);
-	local_cleanup(local, false);
+	local_cleanup(local);
 	kfree(local);
 }
 
@@ -1116,6 +1106,12 @@ static void nfc_llcp_recv_disc(struct nfc_llcp_local *local,
 	dsap = nfc_llcp_dsap(skb);
 	ssap = nfc_llcp_ssap(skb);
 
+	if ((dsap == 0) && (ssap == 0)) {
+		pr_debug("Connection termination");
+		nfc_dep_link_down(local->dev);
+		return;
+	}
+
 	llcp_sock = nfc_llcp_sock_get(local, dsap, ssap);
 	if (llcp_sock == NULL) {
 		nfc_llcp_send_dm(local, dsap, ssap, LLCP_DM_NOCONN);
@@ -1349,19 +1345,54 @@ exit:
 		nfc_llcp_send_snl_sdres(local, &llc_sdres_list, sdres_tlvs_len);
 }
 
-static void nfc_llcp_rx_work(struct work_struct *work)
+static void nfc_llcp_recv_agf(struct nfc_llcp_local *local, struct sk_buff *skb)
 {
-	struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
-						    rx_work);
-	u8 dsap, ssap, ptype;
-	struct sk_buff *skb;
+	u8 ptype;
+	u16 pdu_len;
+	struct sk_buff *new_skb;
 
-	skb = local->rx_pending;
-	if (skb == NULL) {
-		pr_debug("No pending SKB\n");
+	if (skb->len <= LLCP_HEADER_SIZE) {
+		pr_err("Malformed AGF PDU\n");
 		return;
 	}
 
+	skb_pull(skb, LLCP_HEADER_SIZE);
+
+	while (skb->len > LLCP_AGF_PDU_HEADER_SIZE) {
+		pdu_len = skb->data[0] << 8 | skb->data[1];
+
+		skb_pull(skb, LLCP_AGF_PDU_HEADER_SIZE);
+
+		if (pdu_len < LLCP_HEADER_SIZE || pdu_len > skb->len) {
+			pr_err("Malformed AGF PDU\n");
+			return;
+		}
+
+		ptype = nfc_llcp_ptype(skb);
+
+		if (ptype == LLCP_PDU_SYMM || ptype == LLCP_PDU_AGF)
+			goto next;
+
+		new_skb = nfc_alloc_recv_skb(pdu_len, GFP_KERNEL);
+		if (new_skb == NULL) {
+			pr_err("Could not allocate PDU\n");
+			return;
+		}
+
+		memcpy(skb_put(new_skb, pdu_len), skb->data, pdu_len);
+
+		nfc_llcp_rx_skb(local, new_skb);
+
+		kfree_skb(new_skb);
+next:
+		skb_pull(skb, pdu_len);
+	}
+}
+
+static void nfc_llcp_rx_skb(struct nfc_llcp_local *local, struct sk_buff *skb)
+{
+	u8 dsap, ssap, ptype;
+
 	ptype = nfc_llcp_ptype(skb);
 	dsap = nfc_llcp_dsap(skb);
 	ssap = nfc_llcp_ssap(skb);
@@ -1372,10 +1403,6 @@ static void nfc_llcp_rx_work(struct work_struct *work)
 		print_hex_dump(KERN_DEBUG, "LLCP Rx: ", DUMP_PREFIX_OFFSET,
 			       16, 1, skb->data, skb->len, true);
 
-	__net_timestamp(skb);
-
-	nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
-
 	switch (ptype) {
 	case LLCP_PDU_SYMM:
 		pr_debug("SYMM\n");
@@ -1418,7 +1445,30 @@ static void nfc_llcp_rx_work(struct work_struct *work)
 		nfc_llcp_recv_hdlc(local, skb);
 		break;
 
+	case LLCP_PDU_AGF:
+		pr_debug("AGF frame\n");
+		nfc_llcp_recv_agf(local, skb);
+		break;
 	}
+}
+
+static void nfc_llcp_rx_work(struct work_struct *work)
+{
+	struct nfc_llcp_local *local = container_of(work, struct nfc_llcp_local,
+						    rx_work);
+	struct sk_buff *skb;
+
+	skb = local->rx_pending;
+	if (skb == NULL) {
+		pr_debug("No pending SKB\n");
+		return;
+	}
+
+	__net_timestamp(skb);
+
+	nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
+
+	nfc_llcp_rx_skb(local, skb);
 
 	schedule_work(&local->tx_work);
 	kfree_skb(local->rx_pending);
@@ -1466,6 +1516,9 @@ void nfc_llcp_mac_is_down(struct nfc_dev *dev)
 	if (local == NULL)
 		return;
 
+	local->remote_miu = LLCP_DEFAULT_MIU;
+	local->remote_lto = LLCP_DEFAULT_LTO;
+
 	/* Close and purge all existing sockets */
 	nfc_llcp_socket_release(local, true, 0);
 }
@@ -1553,7 +1606,7 @@ void nfc_llcp_unregister_device(struct nfc_dev *dev)
 		return;
 	}
 
-	local_cleanup(local, false);
+	local_cleanup(local);
 
 	nfc_llcp_local_put(local);
 }

+ 4 - 1
net/nfc/llcp/llcp.h

@@ -31,6 +31,7 @@ enum llcp_state {
 #define LLCP_MAX_LTO  0xff
 #define LLCP_MAX_RW   15
 #define LLCP_MAX_MIUX 0x7ff
+#define LLCP_MAX_MIU (LLCP_MAX_MIUX + 128)
 
 #define LLCP_WKS_NUM_SAP   16
 #define LLCP_SDP_NUM_SAP   16
@@ -124,7 +125,7 @@ struct nfc_llcp_sock {
 	char *service_name;
 	size_t service_name_len;
 	u8 rw;
-	u16 miux;
+	__be16 miux;
 
 
 	/* Remote link parameters */
@@ -162,6 +163,7 @@ struct nfc_llcp_ui_cb {
 
 #define LLCP_HEADER_SIZE   2
 #define LLCP_SEQUENCE_SIZE 1
+#define LLCP_AGF_PDU_HEADER_SIZE 2
 
 /* LLCP versions: 1.1 is 1.0 plus SDP */
 #define LLCP_VERSION_10 0x10
@@ -210,6 +212,7 @@ struct nfc_llcp_ui_cb {
 
 void nfc_llcp_sock_link(struct llcp_sock_list *l, struct sock *s);
 void nfc_llcp_sock_unlink(struct llcp_sock_list *l, struct sock *s);
+void nfc_llcp_socket_remote_param_init(struct nfc_llcp_sock *sock);
 struct nfc_llcp_local *nfc_llcp_find_local(struct nfc_dev *dev);
 struct nfc_llcp_local *nfc_llcp_local_get(struct nfc_llcp_local *local);
 int nfc_llcp_local_put(struct nfc_llcp_local *local);

+ 37 - 6
net/nfc/llcp/sock.c

@@ -279,7 +279,7 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
 			break;
 		}
 
-		llcp_sock->miux = (u16) opt;
+		llcp_sock->miux = cpu_to_be16((u16) opt);
 
 		break;
 
@@ -299,9 +299,12 @@ static int nfc_llcp_setsockopt(struct socket *sock, int level, int optname,
 static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
 			       char __user *optval, int __user *optlen)
 {
+	struct nfc_llcp_local *local;
 	struct sock *sk = sock->sk;
 	struct nfc_llcp_sock *llcp_sock = nfc_llcp_sock(sk);
 	int len, err = 0;
+	u16 miux, remote_miu;
+	u8 rw;
 
 	pr_debug("%p optname %d\n", sk, optname);
 
@@ -311,19 +314,48 @@ static int nfc_llcp_getsockopt(struct socket *sock, int level, int optname,
 	if (get_user(len, optlen))
 		return -EFAULT;
 
+	local = llcp_sock->local;
+	if (!local)
+		return -ENODEV;
+
 	len = min_t(u32, len, sizeof(u32));
 
 	lock_sock(sk);
 
 	switch (optname) {
 	case NFC_LLCP_RW:
-		if (put_user(llcp_sock->rw, (u32 __user *) optval))
+		rw = llcp_sock->rw > LLCP_MAX_RW ? local->rw : llcp_sock->rw;
+		if (put_user(rw, (u32 __user *) optval))
 			err = -EFAULT;
 
 		break;
 
 	case NFC_LLCP_MIUX:
-		if (put_user(llcp_sock->miux, (u32 __user *) optval))
+		miux = be16_to_cpu(llcp_sock->miux) > LLCP_MAX_MIUX ?
+			be16_to_cpu(local->miux) : be16_to_cpu(llcp_sock->miux);
+
+		if (put_user(miux, (u32 __user *) optval))
+			err = -EFAULT;
+
+		break;
+
+	case NFC_LLCP_REMOTE_MIU:
+		remote_miu = llcp_sock->remote_miu > LLCP_MAX_MIU ?
+				local->remote_miu : llcp_sock->remote_miu;
+
+		if (put_user(remote_miu, (u32 __user *) optval))
+			err = -EFAULT;
+
+		break;
+
+	case NFC_LLCP_REMOTE_LTO:
+		if (put_user(local->remote_lto / 10, (u32 __user *) optval))
+			err = -EFAULT;
+
+		break;
+
+	case NFC_LLCP_REMOTE_RW:
+		if (put_user(llcp_sock->remote_rw, (u32 __user *) optval))
 			err = -EFAULT;
 
 		break;
@@ -921,13 +953,12 @@ struct sock *nfc_llcp_sock_alloc(struct socket *sock, int type, gfp_t gfp)
 	llcp_sock->ssap = 0;
 	llcp_sock->dsap = LLCP_SAP_SDP;
 	llcp_sock->rw = LLCP_MAX_RW + 1;
-	llcp_sock->miux = LLCP_MAX_MIUX + 1;
-	llcp_sock->remote_rw = LLCP_DEFAULT_RW;
-	llcp_sock->remote_miu = LLCP_DEFAULT_MIU;
+	llcp_sock->miux = cpu_to_be16(LLCP_MAX_MIUX + 1);
 	llcp_sock->send_n = llcp_sock->send_ack_n = 0;
 	llcp_sock->recv_n = llcp_sock->recv_ack_n = 0;
 	llcp_sock->remote_ready = 1;
 	llcp_sock->reserved_ssap = LLCP_SAP_MAX;
+	nfc_llcp_socket_remote_param_init(llcp_sock);
 	skb_queue_head_init(&llcp_sock->tx_queue);
 	skb_queue_head_init(&llcp_sock->tx_pending_queue);
 	INIT_LIST_HEAD(&llcp_sock->accept_queue);

+ 3 - 1
net/rfkill/core.c

@@ -587,7 +587,7 @@ static ssize_t rfkill_name_show(struct device *dev,
 
 static const char *rfkill_get_type_str(enum rfkill_type type)
 {
-	BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_FM + 1);
+	BUILD_BUG_ON(NUM_RFKILL_TYPES != RFKILL_TYPE_NFC + 1);
 
 	switch (type) {
 	case RFKILL_TYPE_WLAN:
@@ -604,6 +604,8 @@ static const char *rfkill_get_type_str(enum rfkill_type type)
 		return "gps";
 	case RFKILL_TYPE_FM:
 		return "fm";
+	case RFKILL_TYPE_NFC:
+		return "nfc";
 	default:
 		BUG();
 	}