diff options
Diffstat (limited to 'drivers/nfc')
| -rw-r--r-- | drivers/nfc/Kconfig | 10 | ||||
| -rw-r--r-- | drivers/nfc/Makefile | 1 | ||||
| -rw-r--r-- | drivers/nfc/mei_phy.c | 6 | ||||
| -rw-r--r-- | drivers/nfc/microread/microread.c | 6 | ||||
| -rw-r--r-- | drivers/nfc/nfcsim.c | 541 | ||||
| -rw-r--r-- | drivers/nfc/nfcwilink.c | 18 | ||||
| -rw-r--r-- | drivers/nfc/pn533.c | 33 | ||||
| -rw-r--r-- | drivers/nfc/pn544/pn544.c | 40 | 
8 files changed, 605 insertions, 50 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(µread_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 8f6f2baa930d..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;  } @@ -1697,7 +1700,7 @@ static int pn533_poll_complete(struct pn533 *dev, void *arg,  		goto done;  	if (!dev->poll_mod_count) { -		nfc_dev_dbg(&dev->interface->dev, "Polling has been stoped."); +		nfc_dev_dbg(&dev->interface->dev, "Polling has been stopped.");  		goto done;  	} @@ -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) { |