summaryrefslogtreecommitdiffstats
path: root/drivers/nfc
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/nfc')
-rw-r--r--drivers/nfc/Kconfig10
-rw-r--r--drivers/nfc/Makefile1
-rw-r--r--drivers/nfc/mei_phy.c6
-rw-r--r--drivers/nfc/microread/microread.c6
-rw-r--r--drivers/nfc/nfcsim.c541
-rw-r--r--drivers/nfc/nfcwilink.c18
-rw-r--r--drivers/nfc/pn533.c31
-rw-r--r--drivers/nfc/pn544/pn544.c40
8 files changed, 604 insertions, 49 deletions
diff --git a/drivers/nfc/Kconfig b/drivers/nfc/Kconfig
index 74a852e4e41f..b0b64ccb7d7d 100644
--- a/drivers/nfc/Kconfig
+++ b/drivers/nfc/Kconfig
@@ -36,6 +36,16 @@ config NFC_MEI_PHY
If unsure, say N.
+config NFC_SIM
+ tristate "NFC hardware simulator driver"
+ help
+ This driver declares two virtual NFC devices supporting NFC-DEP
+ protocol. An LLCP connection can be established between them and
+ all packets sent from one device is sent back to the other, acting as
+ loopback devices.
+
+ If unsure, say N.
+
source "drivers/nfc/pn544/Kconfig"
source "drivers/nfc/microread/Kconfig"
diff --git a/drivers/nfc/Makefile b/drivers/nfc/Makefile
index aa6bd657ef40..be7636abcb3f 100644
--- a/drivers/nfc/Makefile
+++ b/drivers/nfc/Makefile
@@ -7,5 +7,6 @@ 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
+obj-$(CONFIG_NFC_SIM) += nfcsim.o
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
diff --git a/drivers/nfc/mei_phy.c b/drivers/nfc/mei_phy.c
index 1201bdbfb791..606bf55e76ec 100644
--- a/drivers/nfc/mei_phy.c
+++ b/drivers/nfc/mei_phy.c
@@ -30,7 +30,7 @@ struct mei_nfc_hdr {
u16 req_id;
u32 reserved;
u16 data_size;
-} __attribute__((packed));
+} __packed;
#define MEI_NFC_MAX_READ (MEI_NFC_HEADER_SIZE + MEI_NFC_MAX_HCI_PAYLOAD)
@@ -60,8 +60,8 @@ int nfc_mei_phy_enable(void *phy_id)
r = mei_cl_enable_device(phy->device);
if (r < 0) {
- pr_err("MEI_PHY: Could not enable device\n");
- return r;
+ pr_err("MEI_PHY: Could not enable device\n");
+ return r;
}
r = mei_cl_register_event_cb(phy->device, nfc_mei_event_cb, phy);
diff --git a/drivers/nfc/microread/microread.c b/drivers/nfc/microread/microread.c
index 3420d833db17..cdb9f6de132a 100644
--- a/drivers/nfc/microread/microread.c
+++ b/drivers/nfc/microread/microread.c
@@ -650,7 +650,7 @@ int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
{
struct microread_info *info;
unsigned long quirks = 0;
- u32 protocols, se;
+ u32 protocols;
struct nfc_hci_init_data init_data;
int r;
@@ -678,10 +678,8 @@ int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
NFC_PROTO_ISO14443_B_MASK |
NFC_PROTO_NFC_DEP_MASK;
- se = NFC_SE_UICC | NFC_SE_EMBEDDED;
-
info->hdev = nfc_hci_allocate_device(&microread_hci_ops, &init_data,
- quirks, protocols, se, llc_name,
+ quirks, protocols, llc_name,
phy_headroom +
MICROREAD_CMDS_HEADROOM,
phy_tailroom +
diff --git a/drivers/nfc/nfcsim.c b/drivers/nfc/nfcsim.c
new file mode 100644
index 000000000000..c5c30fb1d7bf
--- /dev/null
+++ b/drivers/nfc/nfcsim.c
@@ -0,0 +1,541 @@
+/*
+ * NFC hardware simulation driver
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * 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 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.
+ *
+ */
+
+#include <linux/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/nfc.h>
+#include <net/nfc/nfc.h>
+
+#define DEV_ERR(_dev, fmt, args...) nfc_dev_err(&_dev->nfc_dev->dev, \
+ "%s: " fmt, __func__, ## args)
+
+#define DEV_DBG(_dev, fmt, args...) nfc_dev_dbg(&_dev->nfc_dev->dev, \
+ "%s: " fmt, __func__, ## args)
+
+#define NFCSIM_VERSION "0.1"
+
+#define NFCSIM_POLL_NONE 0
+#define NFCSIM_POLL_INITIATOR 1
+#define NFCSIM_POLL_TARGET 2
+#define NFCSIM_POLL_DUAL (NFCSIM_POLL_INITIATOR | NFCSIM_POLL_TARGET)
+
+struct nfcsim {
+ struct nfc_dev *nfc_dev;
+
+ struct mutex lock;
+
+ struct delayed_work recv_work;
+
+ struct sk_buff *clone_skb;
+
+ struct delayed_work poll_work;
+ u8 polling_mode;
+ u8 curr_polling_mode;
+
+ u8 shutting_down;
+
+ u8 up;
+
+ u8 initiator;
+
+ data_exchange_cb_t cb;
+ void *cb_context;
+
+ struct nfcsim *peer_dev;
+};
+
+static struct nfcsim *dev0;
+static struct nfcsim *dev1;
+
+struct workqueue_struct *wq;
+
+static void nfcsim_cleanup_dev(struct nfcsim *dev, u8 shutdown)
+{
+ DEV_DBG(dev, "shutdown=%d", shutdown);
+
+ mutex_lock(&dev->lock);
+
+ dev->polling_mode = NFCSIM_POLL_NONE;
+ dev->shutting_down = shutdown;
+ dev->cb = NULL;
+ dev_kfree_skb(dev->clone_skb);
+ dev->clone_skb = NULL;
+
+ mutex_unlock(&dev->lock);
+
+ cancel_delayed_work_sync(&dev->poll_work);
+ cancel_delayed_work_sync(&dev->recv_work);
+}
+
+static int nfcsim_target_found(struct nfcsim *dev)
+{
+ struct nfc_target nfc_tgt;
+
+ DEV_DBG(dev, "");
+
+ memset(&nfc_tgt, 0, sizeof(struct nfc_target));
+
+ nfc_tgt.supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+ nfc_targets_found(dev->nfc_dev, &nfc_tgt, 1);
+
+ return 0;
+}
+
+static int nfcsim_dev_up(struct nfc_dev *nfc_dev)
+{
+ struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
+
+ DEV_DBG(dev, "");
+
+ mutex_lock(&dev->lock);
+
+ dev->up = 1;
+
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+static int nfcsim_dev_down(struct nfc_dev *nfc_dev)
+{
+ struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
+
+ DEV_DBG(dev, "");
+
+ mutex_lock(&dev->lock);
+
+ dev->up = 0;
+
+ mutex_unlock(&dev->lock);
+
+ return 0;
+}
+
+static int nfcsim_dep_link_up(struct nfc_dev *nfc_dev,
+ struct nfc_target *target,
+ u8 comm_mode, u8 *gb, size_t gb_len)
+{
+ int rc;
+ struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
+ struct nfcsim *peer = dev->peer_dev;
+ u8 *remote_gb;
+ size_t remote_gb_len;
+
+ DEV_DBG(dev, "target_idx: %d, comm_mode: %d\n", target->idx, comm_mode);
+
+ mutex_lock(&peer->lock);
+
+ nfc_tm_activated(peer->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
+ NFC_COMM_ACTIVE, gb, gb_len);
+
+ remote_gb = nfc_get_local_general_bytes(peer->nfc_dev, &remote_gb_len);
+ if (!remote_gb) {
+ DEV_ERR(peer, "Can't get remote general bytes");
+
+ mutex_unlock(&peer->lock);
+ return -EINVAL;
+ }
+
+ mutex_unlock(&peer->lock);
+
+ mutex_lock(&dev->lock);
+
+ rc = nfc_set_remote_general_bytes(nfc_dev, remote_gb, remote_gb_len);
+ if (rc) {
+ DEV_ERR(dev, "Can't set remote general bytes");
+ mutex_unlock(&dev->lock);
+ return rc;
+ }
+
+ rc = nfc_dep_link_is_up(nfc_dev, target->idx, NFC_COMM_ACTIVE,
+ NFC_RF_INITIATOR);
+
+ mutex_unlock(&dev->lock);
+
+ return rc;
+}
+
+static int nfcsim_dep_link_down(struct nfc_dev *nfc_dev)
+{
+ struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
+
+ DEV_DBG(dev, "");
+
+ nfcsim_cleanup_dev(dev, 0);
+
+ return 0;
+}
+
+static int nfcsim_start_poll(struct nfc_dev *nfc_dev,
+ u32 im_protocols, u32 tm_protocols)
+{
+ struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
+ int rc;
+
+ mutex_lock(&dev->lock);
+
+ if (dev->polling_mode != NFCSIM_POLL_NONE) {
+ DEV_ERR(dev, "Already in polling mode");
+ rc = -EBUSY;
+ goto exit;
+ }
+
+ if (im_protocols & NFC_PROTO_NFC_DEP_MASK)
+ dev->polling_mode |= NFCSIM_POLL_INITIATOR;
+
+ if (tm_protocols & NFC_PROTO_NFC_DEP_MASK)
+ dev->polling_mode |= NFCSIM_POLL_TARGET;
+
+ if (dev->polling_mode == NFCSIM_POLL_NONE) {
+ DEV_ERR(dev, "Unsupported polling mode");
+ rc = -EINVAL;
+ goto exit;
+ }
+
+ dev->initiator = 0;
+ dev->curr_polling_mode = NFCSIM_POLL_NONE;
+
+ queue_delayed_work(wq, &dev->poll_work, 0);
+
+ DEV_DBG(dev, "Start polling: im: 0x%X, tm: 0x%X", im_protocols,
+ tm_protocols);
+
+ rc = 0;
+exit:
+ mutex_unlock(&dev->lock);
+
+ return rc;
+}
+
+static void nfcsim_stop_poll(struct nfc_dev *nfc_dev)
+{
+ struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
+
+ DEV_DBG(dev, "Stop poll");
+
+ mutex_lock(&dev->lock);
+
+ dev->polling_mode = NFCSIM_POLL_NONE;
+
+ mutex_unlock(&dev->lock);
+
+ cancel_delayed_work_sync(&dev->poll_work);
+}
+
+static int nfcsim_activate_target(struct nfc_dev *nfc_dev,
+ struct nfc_target *target, u32 protocol)
+{
+ struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
+
+ DEV_DBG(dev, "");
+
+ return -ENOTSUPP;
+}
+
+static void nfcsim_deactivate_target(struct nfc_dev *nfc_dev,
+ struct nfc_target *target)
+{
+ struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
+
+ DEV_DBG(dev, "");
+}
+
+static void nfcsim_wq_recv(struct work_struct *work)
+{
+ struct nfcsim *dev = container_of(work, struct nfcsim,
+ recv_work.work);
+
+ mutex_lock(&dev->lock);
+
+ if (dev->shutting_down || !dev->up || !dev->clone_skb) {
+ dev_kfree_skb(dev->clone_skb);
+ goto exit;
+ }
+
+ if (dev->initiator) {
+ if (!dev->cb) {
+ DEV_ERR(dev, "Null recv callback");
+ dev_kfree_skb(dev->clone_skb);
+ goto exit;
+ }
+
+ dev->cb(dev->cb_context, dev->clone_skb, 0);
+ dev->cb = NULL;
+ } else {
+ nfc_tm_data_received(dev->nfc_dev, dev->clone_skb);
+ }
+
+exit:
+ dev->clone_skb = NULL;
+
+ mutex_unlock(&dev->lock);
+}
+
+static int nfcsim_tx(struct nfc_dev *nfc_dev, struct nfc_target *target,
+ struct sk_buff *skb, data_exchange_cb_t cb,
+ void *cb_context)
+{
+ struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
+ struct nfcsim *peer = dev->peer_dev;
+ int err;
+
+ mutex_lock(&dev->lock);
+
+ if (dev->shutting_down || !dev->up) {
+ mutex_unlock(&dev->lock);
+ err = -ENODEV;
+ goto exit;
+ }
+
+ dev->cb = cb;
+ dev->cb_context = cb_context;
+
+ mutex_unlock(&dev->lock);
+
+ mutex_lock(&peer->lock);
+
+ peer->clone_skb = skb_clone(skb, GFP_KERNEL);
+
+ if (!peer->clone_skb) {
+ DEV_ERR(dev, "skb_clone failed");
+ mutex_unlock(&peer->lock);
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ /* This simulates an arbitrary transmission delay between the 2 devices.
+ * If packet transmission occurs immediately between them, we have a
+ * non-stop flow of several tens of thousands SYMM packets per second
+ * and a burning cpu.
+ *
+ * TODO: Add support for a sysfs entry to control this delay.
+ */
+ queue_delayed_work(wq, &peer->recv_work, msecs_to_jiffies(5));
+
+ mutex_unlock(&peer->lock);
+
+ err = 0;
+exit:
+ dev_kfree_skb(skb);
+
+ return err;
+}
+
+static int nfcsim_im_transceive(struct nfc_dev *nfc_dev,
+ struct nfc_target *target, struct sk_buff *skb,
+ data_exchange_cb_t cb, void *cb_context)
+{
+ return nfcsim_tx(nfc_dev, target, skb, cb, cb_context);
+}
+
+static int nfcsim_tm_send(struct nfc_dev *nfc_dev, struct sk_buff *skb)
+{
+ return nfcsim_tx(nfc_dev, NULL, skb, NULL, NULL);
+}
+
+static struct nfc_ops nfcsim_nfc_ops = {
+ .dev_up = nfcsim_dev_up,
+ .dev_down = nfcsim_dev_down,
+ .dep_link_up = nfcsim_dep_link_up,
+ .dep_link_down = nfcsim_dep_link_down,
+ .start_poll = nfcsim_start_poll,
+ .stop_poll = nfcsim_stop_poll,
+ .activate_target = nfcsim_activate_target,
+ .deactivate_target = nfcsim_deactivate_target,
+ .im_transceive = nfcsim_im_transceive,
+ .tm_send = nfcsim_tm_send,
+};
+
+static void nfcsim_set_polling_mode(struct nfcsim *dev)
+{
+ if (dev->polling_mode == NFCSIM_POLL_NONE) {
+ dev->curr_polling_mode = NFCSIM_POLL_NONE;
+ return;
+ }
+
+ if (dev->curr_polling_mode == NFCSIM_POLL_NONE) {
+ if (dev->polling_mode & NFCSIM_POLL_INITIATOR)
+ dev->curr_polling_mode = NFCSIM_POLL_INITIATOR;
+ else
+ dev->curr_polling_mode = NFCSIM_POLL_TARGET;
+
+ return;
+ }
+
+ if (dev->polling_mode == NFCSIM_POLL_DUAL) {
+ if (dev->curr_polling_mode == NFCSIM_POLL_TARGET)
+ dev->curr_polling_mode = NFCSIM_POLL_INITIATOR;
+ else
+ dev->curr_polling_mode = NFCSIM_POLL_TARGET;
+ }
+}
+
+static void nfcsim_wq_poll(struct work_struct *work)
+{
+ struct nfcsim *dev = container_of(work, struct nfcsim, poll_work.work);
+ struct nfcsim *peer = dev->peer_dev;
+
+ /* These work items run on an ordered workqueue and are therefore
+ * serialized. So we can take both mutexes without being dead locked.
+ */
+ mutex_lock(&dev->lock);
+ mutex_lock(&peer->lock);
+
+ nfcsim_set_polling_mode(dev);
+
+ if (dev->curr_polling_mode == NFCSIM_POLL_NONE) {
+ DEV_DBG(dev, "Not polling");
+ goto unlock;
+ }
+
+ DEV_DBG(dev, "Polling as %s",
+ dev->curr_polling_mode == NFCSIM_POLL_INITIATOR ?
+ "initiator" : "target");
+
+ if (dev->curr_polling_mode == NFCSIM_POLL_TARGET)
+ goto sched_work;
+
+ if (peer->curr_polling_mode == NFCSIM_POLL_TARGET) {
+ peer->polling_mode = NFCSIM_POLL_NONE;
+ dev->polling_mode = NFCSIM_POLL_NONE;
+
+ dev->initiator = 1;
+
+ nfcsim_target_found(dev);
+
+ goto unlock;
+ }
+
+sched_work:
+ /* This defines the delay for an initiator to check if the other device
+ * is polling in target mode.
+ * If the device starts in dual mode polling, it switches between
+ * initiator and target at every round.
+ * Because the wq is ordered and only 1 work item is executed at a time,
+ * we'll always have one device polling as initiator and the other as
+ * target at some point, even if both are started in dual mode.
+ */
+ queue_delayed_work(wq, &dev->poll_work, msecs_to_jiffies(200));
+
+unlock:
+ mutex_unlock(&peer->lock);
+ mutex_unlock(&dev->lock);
+}
+
+static struct nfcsim *nfcsim_init_dev(void)
+{
+ struct nfcsim *dev;
+ int rc = -ENOMEM;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ mutex_init(&dev->lock);
+
+ INIT_DELAYED_WORK(&dev->recv_work, nfcsim_wq_recv);
+ INIT_DELAYED_WORK(&dev->poll_work, nfcsim_wq_poll);
+
+ dev->nfc_dev = nfc_allocate_device(&nfcsim_nfc_ops,
+ NFC_PROTO_NFC_DEP_MASK,
+ 0, 0);
+ if (!dev->nfc_dev)
+ goto error;
+
+ nfc_set_drvdata(dev->nfc_dev, dev);
+
+ rc = nfc_register_device(dev->nfc_dev);
+ if (rc)
+ goto free_nfc_dev;
+
+ return dev;
+
+free_nfc_dev:
+ nfc_free_device(dev->nfc_dev);
+
+error:
+ kfree(dev);
+
+ return ERR_PTR(rc);
+}
+
+static void nfcsim_free_device(struct nfcsim *dev)
+{
+ nfc_unregister_device(dev->nfc_dev);
+
+ nfc_free_device(dev->nfc_dev);
+
+ kfree(dev);
+}
+
+int __init nfcsim_init(void)
+{
+ int rc;
+
+ /* We need an ordered wq to ensure that poll_work items are executed
+ * one at a time.
+ */
+ wq = alloc_ordered_workqueue("nfcsim", 0);
+ if (!wq) {
+ rc = -ENOMEM;
+ goto exit;
+ }
+
+ dev0 = nfcsim_init_dev();
+ if (IS_ERR(dev0)) {
+ rc = PTR_ERR(dev0);
+ goto exit;
+ }
+
+ dev1 = nfcsim_init_dev();
+ if (IS_ERR(dev1)) {
+ kfree(dev0);
+
+ rc = PTR_ERR(dev1);
+ goto exit;
+ }
+
+ dev0->peer_dev = dev1;
+ dev1->peer_dev = dev0;
+
+ pr_debug("NFCsim " NFCSIM_VERSION " initialized\n");
+
+ rc = 0;
+exit:
+ if (rc)
+ pr_err("Failed to initialize nfcsim driver (%d)\n",
+ rc);
+
+ return rc;
+}
+
+void __exit nfcsim_exit(void)
+{
+ nfcsim_cleanup_dev(dev0, 1);
+ nfcsim_cleanup_dev(dev1, 1);
+
+ nfcsim_free_device(dev0);
+ nfcsim_free_device(dev1);
+
+ destroy_workqueue(wq);
+}
+
+module_init(nfcsim_init);
+module_exit(nfcsim_exit);
+
+MODULE_DESCRIPTION("NFCSim driver ver " NFCSIM_VERSION);
+MODULE_VERSION(NFCSIM_VERSION);
+MODULE_LICENSE("GPL");
diff --git a/drivers/nfc/nfcwilink.c b/drivers/nfc/nfcwilink.c
index 3b731acbc408..59f95d8fc98c 100644
--- a/drivers/nfc/nfcwilink.c
+++ b/drivers/nfc/nfcwilink.c
@@ -109,7 +109,7 @@ enum {
NFCWILINK_FW_DOWNLOAD,
};
-static int nfcwilink_send(struct sk_buff *skb);
+static int nfcwilink_send(struct nci_dev *ndev, struct sk_buff *skb);
static inline struct sk_buff *nfcwilink_skb_alloc(unsigned int len, gfp_t how)
{
@@ -156,8 +156,6 @@ static int nfcwilink_get_bts_file_name(struct nfcwilink *drv, char *file_name)
return -ENOMEM;
}
- skb->dev = (void *)drv->ndev;
-
cmd = (struct nci_vs_nfcc_info_cmd *)
skb_put(skb, sizeof(struct nci_vs_nfcc_info_cmd));
cmd->gid = NCI_VS_NFCC_INFO_CMD_GID;
@@ -166,7 +164,7 @@ static int nfcwilink_get_bts_file_name(struct nfcwilink *drv, char *file_name)
drv->nfcc_info.plen = 0;
- rc = nfcwilink_send(skb);
+ rc = nfcwilink_send(drv->ndev, skb);
if (rc)
return rc;
@@ -232,11 +230,9 @@ static int nfcwilink_send_bts_cmd(struct nfcwilink *drv, __u8 *data, int len)
return -ENOMEM;
}
- skb->dev = (void *)drv->ndev;
-
memcpy(skb_put(skb, len), data, len);
- rc = nfcwilink_send(skb);
+ rc = nfcwilink_send(drv->ndev, skb);
if (rc)
return rc;
@@ -371,10 +367,8 @@ static long nfcwilink_receive(void *priv_data, struct sk_buff *skb)
return 0;
}
- skb->dev = (void *) drv->ndev;
-
/* Forward skb to NCI core layer */
- rc = nci_recv_frame(skb);
+ rc = nci_recv_frame(drv->ndev, skb);
if (rc < 0) {
nfc_dev_err(&drv->pdev->dev, "nci_recv_frame failed %d", rc);
return rc;
@@ -480,9 +474,8 @@ static int nfcwilink_close(struct nci_dev *ndev)
return rc;
}
-static int nfcwilink_send(struct sk_buff *skb)
+static int nfcwilink_send(struct nci_dev *ndev, struct sk_buff *skb)
{
- struct nci_dev *ndev = (struct nci_dev *)skb->dev;
struct nfcwilink *drv = nci_get_drvdata(ndev);
struct nfcwilink_hdr hdr = {NFCWILINK_CHNL, NFCWILINK_OPCODE, 0x0000};
long len;
@@ -542,7 +535,6 @@ static int nfcwilink_probe(struct platform_device *pdev)
drv->ndev = nci_allocate_device(&nfcwilink_ops,
protocols,
- NFC_SE_NONE,
NFCWILINK_HDR_LEN,
0);
if (!drv->ndev) {
diff --git a/drivers/nfc/pn533.c b/drivers/nfc/pn533.c
index ec269e6f0375..daf92ac209f8 100644
--- a/drivers/nfc/pn533.c
+++ b/drivers/nfc/pn533.c
@@ -258,7 +258,7 @@ static const struct pn533_poll_modulations poll_mod[] = {
.opcode = PN533_FELICA_OPC_SENSF_REQ,
.sc = PN533_FELICA_SENSF_SC_ALL,
.rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE,
- .tsn = 0,
+ .tsn = 0x03,
},
},
.len = 7,
@@ -271,7 +271,7 @@ static const struct pn533_poll_modulations poll_mod[] = {
.opcode = PN533_FELICA_OPC_SENSF_REQ,
.sc = PN533_FELICA_SENSF_SC_ALL,
.rc = PN533_FELICA_SENSF_RC_NO_SYSTEM_CODE,
- .tsn = 0,
+ .tsn = 0x03,
},
},
.len = 7,
@@ -1235,7 +1235,7 @@ static int pn533_target_found_type_a(struct nfc_target *nfc_tgt, u8 *tgt_data,
struct pn533_target_felica {
u8 pol_res;
u8 opcode;
- u8 nfcid2[8];
+ u8 nfcid2[NFC_NFCID2_MAXSIZE];
u8 pad[8];
/* optional */
u8 syst_code[];
@@ -1275,6 +1275,9 @@ static int pn533_target_found_felica(struct nfc_target *nfc_tgt, u8 *tgt_data,
memcpy(nfc_tgt->sensf_res, &tgt_felica->opcode, 9);
nfc_tgt->sensf_res_len = 9;
+ memcpy(nfc_tgt->nfcid2, tgt_felica->nfcid2, NFC_NFCID2_MAXSIZE);
+ nfc_tgt->nfcid2_len = NFC_NFCID2_MAXSIZE;
+
return 0;
}
@@ -2084,6 +2087,9 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
if (comm_mode == NFC_COMM_PASSIVE)
skb_len += PASSIVE_DATA_LEN;
+ if (target && target->nfcid2_len)
+ skb_len += NFC_NFCID3_MAXSIZE;
+
skb = pn533_alloc_skb(dev, skb_len);
if (!skb)
return -ENOMEM;
@@ -2100,6 +2106,12 @@ static int pn533_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
*next |= 1;
}
+ if (target && target->nfcid2_len) {
+ memcpy(skb_put(skb, NFC_NFCID3_MAXSIZE), target->nfcid2,
+ target->nfcid2_len);
+ *next |= 2;
+ }
+
if (gb != NULL && gb_len > 0) {
memcpy(skb_put(skb, gb_len), gb, gb_len);
*next |= 4; /* We have some Gi */
@@ -2489,7 +2501,7 @@ static void pn533_acr122_poweron_rdr_resp(struct urb *urb)
nfc_dev_dbg(&urb->dev->dev, "%s", __func__);
- print_hex_dump(KERN_ERR, "ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1,
+ print_hex_dump_debug("ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1,
urb->transfer_buffer, urb->transfer_buffer_length,
false);
@@ -2520,7 +2532,7 @@ static int pn533_acr122_poweron_rdr(struct pn533 *dev)
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,
+ print_hex_dump_debug("ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1,
cmd, sizeof(cmd), false);
rc = usb_submit_urb(dev->out_urb, GFP_KERNEL);
@@ -2774,17 +2786,18 @@ static int pn533_probe(struct usb_interface *interface,
goto destroy_wq;
nfc_dev_info(&dev->interface->dev,
- "NXP PN533 firmware ver %d.%d now attached",
- fw_ver.ver, fw_ver.rev);
+ "NXP PN5%02X firmware ver %d.%d now attached",
+ fw_ver.ic, fw_ver.ver, fw_ver.rev);
dev->nfc_dev = nfc_allocate_device(&pn533_nfc_ops, protocols,
- NFC_SE_NONE,
dev->ops->tx_header_len +
PN533_CMD_DATAEXCH_HEAD_LEN,
dev->ops->tx_tail_len);
- if (!dev->nfc_dev)
+ if (!dev->nfc_dev) {
+ rc = -ENOMEM;
goto destroy_wq;
+ }
nfc_set_parent_dev(dev->nfc_dev, &interface->dev);
nfc_set_drvdata(dev->nfc_dev, dev);
diff --git a/drivers/nfc/pn544/pn544.c b/drivers/nfc/pn544/pn544.c
index 9c5f16e7baef..0d17da7675b7 100644
--- a/drivers/nfc/pn544/pn544.c
+++ b/drivers/nfc/pn544/pn544.c
@@ -551,20 +551,25 @@ static int pn544_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
return -EPROTO;
}
- r = nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE,
- PN544_RF_READER_CMD_ACTIVATE_NEXT,
- uid_skb->data, uid_skb->len, NULL);
- kfree_skb(uid_skb);
-
- r = nfc_hci_send_cmd(hdev,
+ /* Type F NFC-DEP IDm has prefix 0x01FE */
+ if ((uid_skb->data[0] == 0x01) && (uid_skb->data[1] == 0xfe)) {
+ kfree_skb(uid_skb);
+ r = nfc_hci_send_cmd(hdev,
PN544_RF_READER_NFCIP1_INITIATOR_GATE,
PN544_HCI_CMD_CONTINUE_ACTIVATION,
NULL, 0, NULL);
- if (r < 0)
- return r;
+ if (r < 0)
+ return r;
- target->hci_reader_gate = PN544_RF_READER_NFCIP1_INITIATOR_GATE;
- target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+ target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+ target->hci_reader_gate =
+ PN544_RF_READER_NFCIP1_INITIATOR_GATE;
+ } else {
+ r = nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE,
+ PN544_RF_READER_CMD_ACTIVATE_NEXT,
+ uid_skb->data, uid_skb->len, NULL);
+ kfree_skb(uid_skb);
+ }
} else if (target->supported_protocols & NFC_PROTO_ISO14443_MASK) {
/*
* TODO: maybe other ISO 14443 require some kind of continue
@@ -706,12 +711,9 @@ static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
return nfc_hci_send_cmd(hdev, NFC_HCI_RF_READER_A_GATE,
PN544_RF_READER_CMD_ACTIVATE_NEXT,
target->nfcid1, target->nfcid1_len, NULL);
- } else if (target->supported_protocols & NFC_PROTO_JEWEL_MASK) {
- return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
- PN544_JEWEL_RAW_CMD, NULL, 0, NULL);
- } else if (target->supported_protocols & NFC_PROTO_FELICA_MASK) {
- return nfc_hci_send_cmd(hdev, PN544_RF_READER_F_GATE,
- PN544_FELICA_RAW, NULL, 0, NULL);
+ } else if (target->supported_protocols & (NFC_PROTO_JEWEL_MASK |
+ NFC_PROTO_FELICA_MASK)) {
+ return -EOPNOTSUPP;
} else if (target->supported_protocols & NFC_PROTO_NFC_DEP_MASK) {
return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
PN544_HCI_CMD_ATTREQUEST,
@@ -801,7 +803,7 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
struct nfc_hci_dev **hdev)
{
struct pn544_hci_info *info;
- u32 protocols, se;
+ u32 protocols;
struct nfc_hci_init_data init_data;
int r;
@@ -834,10 +836,8 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
NFC_PROTO_ISO14443_B_MASK |
NFC_PROTO_NFC_DEP_MASK;
- se = NFC_SE_UICC | NFC_SE_EMBEDDED;
-
info->hdev = nfc_hci_allocate_device(&pn544_hci_ops, &init_data, 0,
- protocols, se, llc_name,
+ protocols, llc_name,
phy_headroom + PN544_CMDS_HEADROOM,
phy_tailroom, phy_payload);
if (!info->hdev) {