mirror of
https://github.com/torvalds/linux.git
synced 2024-11-01 09:41:44 +00:00
This is the first NFC pull request for the 3.13 kernel.
It's a fairly big one, with the following highlights: - NFC digital layer implementation: Most NFC chipsets implement the NFC digital layer in firmware, but others have more basic functionalities and expect the host to implement the digital layer. This layer sits below the NFC core. - Sony's port100 support: This is "soft" NFC USB dongle that expects the digital layer to be implemented on the host. This is the first user of our NFC digital stack implementation. - Secure element API: We now provide a netlink API for enabling, disabling and discovering NFC attached (embedded or UICC ones) secure elements. With some userspace help, this allows us to support NFC payments. Only the pn544 driver currently supports that API. - NCI SPI fixes and improvements: In order to support NCI devices over SPI, we fixed and improved our NCI/SPI implementation. The currently most deployed NFC NCI chipset, Broadcom's bcm2079x, supports that mode and we're planning to use our NCI/SPI framework to implement a driver for it. - pn533 fragmentation support in target mode: This was the only missing feature from our pn533 impementation. We now support fragmentation in both Tx and Rx modes, in target mode. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.14 (GNU/Linux) iQIcBAABAgAGBQJSUqvzAAoJEIqAPN1PVmxKKHEP/1mK8kWx9ZZ8egkrkzaTw4lW J9uJq2kTGv5tfEfWjuigAhz5kHB6qLTJLx8FEBZAHazLfa4Az0Zm2G7I7+GTQAMV Mw+uAAI22GGnNgdTNzXDAqgS76Eul2PiWf2UwAbKFZWiyEj5Vf/eZBJAS9nTKLM3 En37wBjvMpVgj6ZwOHKsqPR801NSa3HiM653tkmgSsk3QVL3b7s+kynSuAtshsmA twzymUoJFfYePVnQNRnT3PVPR6w0tRNs4vdq8j5UUuoj1vgKC0/h6nIz2aCURwyE j1pQlSy4ykASM8QZNI2jv3VaOFxmASig2GOgzvCeBZOmCBdlNq13ZY/T0SmmiYES LTbg6Pmh5BXID95GqcFcJaC+iS+QNZK+RWhNYmj+JWCuqZ9Qcja3++IoQ7m/pAip WfyQsO7lD7wPhXUu4IMxfyKNu8u4nCiHdBMp7TBVXiWIVUMxIcoM0auNW4O1qSvW eLq0f1oqQXE9hIrJ4oYUZmn9D5CKRLIXr9SVcmat+VxmV/+jFgV5cMQIGRdDAEUq 4g5g7Avbpkkccn9wdFaIm0VpxMebaNFSWVfBOw4L7PF56lqns6shBcq3W3OvDf60 /Tn0oe9Qqvr17xarJackFkF8beBkJaKOJv9M5+KjlVgGexcNMMTIiwj8aPl6+mqC t5n6tCp0g941jB3qAV2G =K1A5 -----END PGP SIGNATURE----- Merge tag 'nfc-next-3.13-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next Samuel Ortiz <sameo@linux.intel.com> says: "This is the first NFC pull request for the 3.13 kernel. It's a fairly big one, with the following highlights: - NFC digital layer implementation: Most NFC chipsets implement the NFC digital layer in firmware, but others have more basic functionalities and expect the host to implement the digital layer. This layer sits below the NFC core. - Sony's port100 support: This is "soft" NFC USB dongle that expects the digital layer to be implemented on the host. This is the first user of our NFC digital stack implementation. - Secure element API: We now provide a netlink API for enabling, disabling and discovering NFC attached (embedded or UICC ones) secure elements. With some userspace help, this allows us to support NFC payments. Only the pn544 driver currently supports that API. - NCI SPI fixes and improvements: In order to support NCI devices over SPI, we fixed and improved our NCI/SPI implementation. The currently most deployed NFC NCI chipset, Broadcom's bcm2079x, supports that mode and we're planning to use our NCI/SPI framework to implement a driver for it. - pn533 fragmentation support in target mode: This was the only missing feature from our pn533 impementation. We now support fragmentation in both Tx and Rx modes, in target mode." Signed-off-by: John W. Linville <linville@tuxdriver.com>
This commit is contained in:
commit
df3c2adea4
@ -46,6 +46,16 @@ config NFC_SIM
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config NFC_PORT100
|
||||
tristate "Sony NFC Port-100 Series USB device support"
|
||||
depends on USB
|
||||
depends on NFC_DIGITAL
|
||||
help
|
||||
This adds support for Sony Port-100 chip based USB devices such as the
|
||||
RC-S380 dongle.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
source "drivers/nfc/pn544/Kconfig"
|
||||
source "drivers/nfc/microread/Kconfig"
|
||||
|
||||
|
@ -8,5 +8,6 @@ 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
|
||||
obj-$(CONFIG_NFC_PORT100) += port100.o
|
||||
|
||||
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
|
||||
|
@ -18,6 +18,8 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/nfc.h>
|
||||
@ -60,13 +62,13 @@ 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");
|
||||
pr_err("Could not enable device\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
r = mei_cl_register_event_cb(phy->device, nfc_mei_event_cb, phy);
|
||||
if (r) {
|
||||
pr_err("MEY_PHY: Event cb registration failed\n");
|
||||
pr_err("Event cb registration failed\n");
|
||||
mei_cl_disable_device(phy->device);
|
||||
phy->powered = 0;
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/delay.h>
|
||||
@ -95,12 +97,8 @@ static int check_crc(struct sk_buff *skb)
|
||||
crc = crc ^ skb->data[i];
|
||||
|
||||
if (crc != skb->data[skb->len-1]) {
|
||||
pr_err(MICROREAD_I2C_DRIVER_NAME
|
||||
": CRC error 0x%x != 0x%x\n",
|
||||
crc, skb->data[skb->len-1]);
|
||||
|
||||
pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__);
|
||||
|
||||
pr_err("CRC error 0x%x != 0x%x\n", crc, skb->data[skb->len-1]);
|
||||
pr_info("%s: BAD CRC\n", __func__);
|
||||
return -EPERM;
|
||||
}
|
||||
|
||||
@ -160,18 +158,15 @@ static int microread_i2c_read(struct microread_i2c_phy *phy,
|
||||
u8 tmp[MICROREAD_I2C_LLC_MAX_SIZE - 1];
|
||||
struct i2c_client *client = phy->i2c_dev;
|
||||
|
||||
pr_debug("%s\n", __func__);
|
||||
|
||||
r = i2c_master_recv(client, &len, 1);
|
||||
if (r != 1) {
|
||||
dev_err(&client->dev, "cannot read len byte\n");
|
||||
nfc_err(&client->dev, "cannot read len byte\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
if ((len < MICROREAD_I2C_LLC_MIN_SIZE) ||
|
||||
(len > MICROREAD_I2C_LLC_MAX_SIZE)) {
|
||||
dev_err(&client->dev, "invalid len byte\n");
|
||||
pr_err("invalid len byte\n");
|
||||
nfc_err(&client->dev, "invalid len byte\n");
|
||||
r = -EBADMSG;
|
||||
goto flush;
|
||||
}
|
||||
@ -228,7 +223,6 @@ static irqreturn_t microread_i2c_irq_thread_fn(int irq, void *phy_id)
|
||||
}
|
||||
|
||||
client = phy->i2c_dev;
|
||||
dev_dbg(&client->dev, "IRQ\n");
|
||||
|
||||
if (phy->hard_fault != 0)
|
||||
return IRQ_HANDLED;
|
||||
@ -263,20 +257,18 @@ static int microread_i2c_probe(struct i2c_client *client,
|
||||
dev_get_platdata(&client->dev);
|
||||
int r;
|
||||
|
||||
dev_dbg(&client->dev, "client %p", client);
|
||||
dev_dbg(&client->dev, "client %p\n", client);
|
||||
|
||||
if (!pdata) {
|
||||
dev_err(&client->dev, "client %p: missing platform data",
|
||||
nfc_err(&client->dev, "client %p: missing platform data\n",
|
||||
client);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
phy = devm_kzalloc(&client->dev, sizeof(struct microread_i2c_phy),
|
||||
GFP_KERNEL);
|
||||
if (!phy) {
|
||||
dev_err(&client->dev, "Can't allocate microread phy");
|
||||
if (!phy)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
i2c_set_clientdata(client, phy);
|
||||
phy->i2c_dev = client;
|
||||
@ -285,7 +277,7 @@ static int microread_i2c_probe(struct i2c_client *client,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
MICROREAD_I2C_DRIVER_NAME, phy);
|
||||
if (r) {
|
||||
dev_err(&client->dev, "Unable to register IRQ handler");
|
||||
nfc_err(&client->dev, "Unable to register IRQ handler\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -296,7 +288,7 @@ static int microread_i2c_probe(struct i2c_client *client,
|
||||
if (r < 0)
|
||||
goto err_irq;
|
||||
|
||||
dev_info(&client->dev, "Probed");
|
||||
nfc_info(&client->dev, "Probed");
|
||||
|
||||
return 0;
|
||||
|
||||
@ -310,8 +302,6 @@ static int microread_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct microread_i2c_phy *phy = i2c_get_clientdata(client);
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
microread_remove(phy->hdev);
|
||||
|
||||
free_irq(client->irq, phy);
|
||||
|
@ -18,6 +18,8 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/mod_devicetable.h>
|
||||
#include <linux/nfc.h>
|
||||
@ -59,8 +61,6 @@ static int microread_mei_remove(struct mei_cl_device *device)
|
||||
{
|
||||
struct nfc_mei_phy *phy = mei_cl_get_drvdata(device);
|
||||
|
||||
pr_info("Removing microread\n");
|
||||
|
||||
microread_remove(phy->hdev);
|
||||
|
||||
nfc_mei_phy_free(phy);
|
||||
|
@ -18,6 +18,8 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
@ -546,7 +548,7 @@ exit:
|
||||
kfree_skb(skb);
|
||||
|
||||
if (r)
|
||||
pr_err("Failed to handle discovered target err=%d", r);
|
||||
pr_err("Failed to handle discovered target err=%d\n", r);
|
||||
}
|
||||
|
||||
static int microread_event_received(struct nfc_hci_dev *hdev, u8 gate,
|
||||
@ -656,7 +658,6 @@ int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
|
||||
|
||||
info = kzalloc(sizeof(struct microread_info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
pr_err("Cannot allocate memory for microread_info.\n");
|
||||
r = -ENOMEM;
|
||||
goto err_info_alloc;
|
||||
}
|
||||
@ -686,7 +687,7 @@ int microread_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
|
||||
MICROREAD_CMD_TAILROOM,
|
||||
phy_payload);
|
||||
if (!info->hdev) {
|
||||
pr_err("Cannot allocate nfc hdev.\n");
|
||||
pr_err("Cannot allocate nfc hdev\n");
|
||||
r = -ENOMEM;
|
||||
goto err_alloc_hdev;
|
||||
}
|
||||
|
@ -19,10 +19,10 @@
|
||||
#include <linux/nfc.h>
|
||||
#include <net/nfc/nfc.h>
|
||||
|
||||
#define DEV_ERR(_dev, fmt, args...) nfc_dev_err(&_dev->nfc_dev->dev, \
|
||||
#define DEV_ERR(_dev, fmt, args...) nfc_err(&_dev->nfc_dev->dev, \
|
||||
"%s: " fmt, __func__, ## args)
|
||||
|
||||
#define DEV_DBG(_dev, fmt, args...) nfc_dev_dbg(&_dev->nfc_dev->dev, \
|
||||
#define DEV_DBG(_dev, fmt, args...) dev_dbg(&_dev->nfc_dev->dev, \
|
||||
"%s: " fmt, __func__, ## args)
|
||||
|
||||
#define NFCSIM_VERSION "0.1"
|
||||
@ -64,7 +64,7 @@ static struct workqueue_struct *wq;
|
||||
|
||||
static void nfcsim_cleanup_dev(struct nfcsim *dev, u8 shutdown)
|
||||
{
|
||||
DEV_DBG(dev, "shutdown=%d", shutdown);
|
||||
DEV_DBG(dev, "shutdown=%d\n", shutdown);
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
|
||||
@ -84,7 +84,7 @@ static int nfcsim_target_found(struct nfcsim *dev)
|
||||
{
|
||||
struct nfc_target nfc_tgt;
|
||||
|
||||
DEV_DBG(dev, "");
|
||||
DEV_DBG(dev, "\n");
|
||||
|
||||
memset(&nfc_tgt, 0, sizeof(struct nfc_target));
|
||||
|
||||
@ -98,7 +98,7 @@ static int nfcsim_dev_up(struct nfc_dev *nfc_dev)
|
||||
{
|
||||
struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
|
||||
|
||||
DEV_DBG(dev, "");
|
||||
DEV_DBG(dev, "\n");
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
|
||||
@ -113,7 +113,7 @@ static int nfcsim_dev_down(struct nfc_dev *nfc_dev)
|
||||
{
|
||||
struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
|
||||
|
||||
DEV_DBG(dev, "");
|
||||
DEV_DBG(dev, "\n");
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
|
||||
@ -143,7 +143,7 @@ static int nfcsim_dep_link_up(struct nfc_dev *nfc_dev,
|
||||
|
||||
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");
|
||||
DEV_ERR(peer, "Can't get remote general bytes\n");
|
||||
|
||||
mutex_unlock(&peer->lock);
|
||||
return -EINVAL;
|
||||
@ -155,7 +155,7 @@ static int nfcsim_dep_link_up(struct nfc_dev *nfc_dev,
|
||||
|
||||
rc = nfc_set_remote_general_bytes(nfc_dev, remote_gb, remote_gb_len);
|
||||
if (rc) {
|
||||
DEV_ERR(dev, "Can't set remote general bytes");
|
||||
DEV_ERR(dev, "Can't set remote general bytes\n");
|
||||
mutex_unlock(&dev->lock);
|
||||
return rc;
|
||||
}
|
||||
@ -172,7 +172,7 @@ static int nfcsim_dep_link_down(struct nfc_dev *nfc_dev)
|
||||
{
|
||||
struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
|
||||
|
||||
DEV_DBG(dev, "");
|
||||
DEV_DBG(dev, "\n");
|
||||
|
||||
nfcsim_cleanup_dev(dev, 0);
|
||||
|
||||
@ -188,7 +188,7 @@ static int nfcsim_start_poll(struct nfc_dev *nfc_dev,
|
||||
mutex_lock(&dev->lock);
|
||||
|
||||
if (dev->polling_mode != NFCSIM_POLL_NONE) {
|
||||
DEV_ERR(dev, "Already in polling mode");
|
||||
DEV_ERR(dev, "Already in polling mode\n");
|
||||
rc = -EBUSY;
|
||||
goto exit;
|
||||
}
|
||||
@ -200,7 +200,7 @@ static int nfcsim_start_poll(struct nfc_dev *nfc_dev,
|
||||
dev->polling_mode |= NFCSIM_POLL_TARGET;
|
||||
|
||||
if (dev->polling_mode == NFCSIM_POLL_NONE) {
|
||||
DEV_ERR(dev, "Unsupported polling mode");
|
||||
DEV_ERR(dev, "Unsupported polling mode\n");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
@ -210,7 +210,7 @@ static int nfcsim_start_poll(struct nfc_dev *nfc_dev,
|
||||
|
||||
queue_delayed_work(wq, &dev->poll_work, 0);
|
||||
|
||||
DEV_DBG(dev, "Start polling: im: 0x%X, tm: 0x%X", im_protocols,
|
||||
DEV_DBG(dev, "Start polling: im: 0x%X, tm: 0x%X\n", im_protocols,
|
||||
tm_protocols);
|
||||
|
||||
rc = 0;
|
||||
@ -224,7 +224,7 @@ static void nfcsim_stop_poll(struct nfc_dev *nfc_dev)
|
||||
{
|
||||
struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
|
||||
|
||||
DEV_DBG(dev, "Stop poll");
|
||||
DEV_DBG(dev, "Stop poll\n");
|
||||
|
||||
mutex_lock(&dev->lock);
|
||||
|
||||
@ -240,7 +240,7 @@ static int nfcsim_activate_target(struct nfc_dev *nfc_dev,
|
||||
{
|
||||
struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
|
||||
|
||||
DEV_DBG(dev, "");
|
||||
DEV_DBG(dev, "\n");
|
||||
|
||||
return -ENOTSUPP;
|
||||
}
|
||||
@ -250,7 +250,7 @@ static void nfcsim_deactivate_target(struct nfc_dev *nfc_dev,
|
||||
{
|
||||
struct nfcsim *dev = nfc_get_drvdata(nfc_dev);
|
||||
|
||||
DEV_DBG(dev, "");
|
||||
DEV_DBG(dev, "\n");
|
||||
}
|
||||
|
||||
static void nfcsim_wq_recv(struct work_struct *work)
|
||||
@ -267,7 +267,7 @@ static void nfcsim_wq_recv(struct work_struct *work)
|
||||
|
||||
if (dev->initiator) {
|
||||
if (!dev->cb) {
|
||||
DEV_ERR(dev, "Null recv callback");
|
||||
DEV_ERR(dev, "Null recv callback\n");
|
||||
dev_kfree_skb(dev->clone_skb);
|
||||
goto exit;
|
||||
}
|
||||
@ -310,7 +310,7 @@ static int nfcsim_tx(struct nfc_dev *nfc_dev, struct nfc_target *target,
|
||||
peer->clone_skb = skb_clone(skb, GFP_KERNEL);
|
||||
|
||||
if (!peer->clone_skb) {
|
||||
DEV_ERR(dev, "skb_clone failed");
|
||||
DEV_ERR(dev, "skb_clone failed\n");
|
||||
mutex_unlock(&peer->lock);
|
||||
err = -ENOMEM;
|
||||
goto exit;
|
||||
@ -397,13 +397,13 @@ static void nfcsim_wq_poll(struct work_struct *work)
|
||||
nfcsim_set_polling_mode(dev);
|
||||
|
||||
if (dev->curr_polling_mode == NFCSIM_POLL_NONE) {
|
||||
DEV_DBG(dev, "Not polling");
|
||||
DEV_DBG(dev, "Not polling\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
DEV_DBG(dev, "Polling as %s",
|
||||
dev->curr_polling_mode == NFCSIM_POLL_INITIATOR ?
|
||||
"initiator" : "target");
|
||||
"initiator\n" : "target\n");
|
||||
|
||||
if (dev->curr_polling_mode == NFCSIM_POLL_TARGET)
|
||||
goto sched_work;
|
||||
|
@ -146,13 +146,11 @@ static int nfcwilink_get_bts_file_name(struct nfcwilink *drv, char *file_name)
|
||||
unsigned long comp_ret;
|
||||
int rc;
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev, "get_bts_file_name entry");
|
||||
|
||||
skb = nfcwilink_skb_alloc(sizeof(struct nci_vs_nfcc_info_cmd),
|
||||
GFP_KERNEL);
|
||||
if (!skb) {
|
||||
nfc_dev_err(&drv->pdev->dev,
|
||||
"no memory for nci_vs_nfcc_info_cmd");
|
||||
nfc_err(&drv->pdev->dev,
|
||||
"no memory for nci_vs_nfcc_info_cmd\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -170,21 +168,19 @@ static int nfcwilink_get_bts_file_name(struct nfcwilink *drv, char *file_name)
|
||||
|
||||
comp_ret = wait_for_completion_timeout(&drv->completed,
|
||||
msecs_to_jiffies(NFCWILINK_CMD_TIMEOUT));
|
||||
nfc_dev_dbg(&drv->pdev->dev, "wait_for_completion_timeout returned %ld",
|
||||
comp_ret);
|
||||
dev_dbg(&drv->pdev->dev, "wait_for_completion_timeout returned %ld\n",
|
||||
comp_ret);
|
||||
if (comp_ret == 0) {
|
||||
nfc_dev_err(&drv->pdev->dev,
|
||||
"timeout on wait_for_completion_timeout");
|
||||
nfc_err(&drv->pdev->dev,
|
||||
"timeout on wait_for_completion_timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev, "nci_vs_nfcc_info_rsp: plen %d, status %d",
|
||||
drv->nfcc_info.plen,
|
||||
drv->nfcc_info.status);
|
||||
dev_dbg(&drv->pdev->dev, "nci_vs_nfcc_info_rsp: plen %d, status %d\n",
|
||||
drv->nfcc_info.plen, drv->nfcc_info.status);
|
||||
|
||||
if ((drv->nfcc_info.plen != 5) || (drv->nfcc_info.status != 0)) {
|
||||
nfc_dev_err(&drv->pdev->dev,
|
||||
"invalid nci_vs_nfcc_info_rsp");
|
||||
nfc_err(&drv->pdev->dev, "invalid nci_vs_nfcc_info_rsp\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
@ -195,7 +191,7 @@ static int nfcwilink_get_bts_file_name(struct nfcwilink *drv, char *file_name)
|
||||
drv->nfcc_info.sw_ver_z,
|
||||
drv->nfcc_info.patch_id);
|
||||
|
||||
nfc_dev_info(&drv->pdev->dev, "nfcwilink FW file name: %s", file_name);
|
||||
nfc_info(&drv->pdev->dev, "nfcwilink FW file name: %s\n", file_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -207,15 +203,13 @@ static int nfcwilink_send_bts_cmd(struct nfcwilink *drv, __u8 *data, int len)
|
||||
unsigned long comp_ret;
|
||||
int rc;
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev, "send_bts_cmd entry");
|
||||
|
||||
/* verify valid cmd for the NFC channel */
|
||||
if ((len <= sizeof(struct nfcwilink_hdr)) ||
|
||||
(len > BTS_FILE_CMD_MAX_LEN) ||
|
||||
(hdr->chnl != NFCWILINK_CHNL) ||
|
||||
(hdr->opcode != NFCWILINK_OPCODE)) {
|
||||
nfc_dev_err(&drv->pdev->dev,
|
||||
"ignoring invalid bts cmd, len %d, chnl %d, opcode %d",
|
||||
nfc_err(&drv->pdev->dev,
|
||||
"ignoring invalid bts cmd, len %d, chnl %d, opcode %d\n",
|
||||
len, hdr->chnl, hdr->opcode);
|
||||
return 0;
|
||||
}
|
||||
@ -226,7 +220,7 @@ static int nfcwilink_send_bts_cmd(struct nfcwilink *drv, __u8 *data, int len)
|
||||
|
||||
skb = nfcwilink_skb_alloc(len, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
nfc_dev_err(&drv->pdev->dev, "no memory for bts cmd");
|
||||
nfc_err(&drv->pdev->dev, "no memory for bts cmd\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
@ -238,11 +232,11 @@ static int nfcwilink_send_bts_cmd(struct nfcwilink *drv, __u8 *data, int len)
|
||||
|
||||
comp_ret = wait_for_completion_timeout(&drv->completed,
|
||||
msecs_to_jiffies(NFCWILINK_CMD_TIMEOUT));
|
||||
nfc_dev_dbg(&drv->pdev->dev, "wait_for_completion_timeout returned %ld",
|
||||
comp_ret);
|
||||
dev_dbg(&drv->pdev->dev, "wait_for_completion_timeout returned %ld\n",
|
||||
comp_ret);
|
||||
if (comp_ret == 0) {
|
||||
nfc_dev_err(&drv->pdev->dev,
|
||||
"timeout on wait_for_completion_timeout");
|
||||
nfc_err(&drv->pdev->dev,
|
||||
"timeout on wait_for_completion_timeout\n");
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
@ -257,8 +251,6 @@ static int nfcwilink_download_fw(struct nfcwilink *drv)
|
||||
__u8 *ptr;
|
||||
int len, rc;
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev, "download_fw entry");
|
||||
|
||||
set_bit(NFCWILINK_FW_DOWNLOAD, &drv->flags);
|
||||
|
||||
rc = nfcwilink_get_bts_file_name(drv, file_name);
|
||||
@ -267,7 +259,7 @@ static int nfcwilink_download_fw(struct nfcwilink *drv)
|
||||
|
||||
rc = request_firmware(&fw, file_name, &drv->pdev->dev);
|
||||
if (rc) {
|
||||
nfc_dev_err(&drv->pdev->dev, "request_firmware failed %d", rc);
|
||||
nfc_err(&drv->pdev->dev, "request_firmware failed %d\n", rc);
|
||||
|
||||
/* if the file is not found, don't exit with failure */
|
||||
if (rc == -ENOENT)
|
||||
@ -280,14 +272,14 @@ static int nfcwilink_download_fw(struct nfcwilink *drv)
|
||||
ptr = (__u8 *)fw->data;
|
||||
|
||||
if ((len == 0) || (ptr == NULL)) {
|
||||
nfc_dev_dbg(&drv->pdev->dev,
|
||||
"request_firmware returned size %d", len);
|
||||
dev_dbg(&drv->pdev->dev,
|
||||
"request_firmware returned size %d\n", len);
|
||||
goto release_fw;
|
||||
}
|
||||
|
||||
if (__le32_to_cpu(((struct bts_file_hdr *)ptr)->magic) !=
|
||||
BTS_FILE_HDR_MAGIC) {
|
||||
nfc_dev_err(&drv->pdev->dev, "wrong bts magic number");
|
||||
nfc_err(&drv->pdev->dev, "wrong bts magic number\n");
|
||||
rc = -EINVAL;
|
||||
goto release_fw;
|
||||
}
|
||||
@ -302,8 +294,8 @@ static int nfcwilink_download_fw(struct nfcwilink *drv)
|
||||
action_len =
|
||||
__le16_to_cpu(((struct bts_file_action *)ptr)->len);
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev, "bts_file_action type %d, len %d",
|
||||
action_type, action_len);
|
||||
dev_dbg(&drv->pdev->dev, "bts_file_action type %d, len %d\n",
|
||||
action_type, action_len);
|
||||
|
||||
switch (action_type) {
|
||||
case BTS_FILE_ACTION_TYPE_SEND_CMD:
|
||||
@ -333,8 +325,6 @@ static void nfcwilink_register_complete(void *priv_data, char data)
|
||||
{
|
||||
struct nfcwilink *drv = priv_data;
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev, "register_complete entry");
|
||||
|
||||
/* store ST registration status */
|
||||
drv->st_register_cb_status = data;
|
||||
|
||||
@ -356,7 +346,7 @@ static long nfcwilink_receive(void *priv_data, struct sk_buff *skb)
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev, "receive entry, len %d", skb->len);
|
||||
dev_dbg(&drv->pdev->dev, "receive entry, len %d\n", skb->len);
|
||||
|
||||
/* strip the ST header
|
||||
(apart for the chnl byte, which is not received in the hdr) */
|
||||
@ -370,7 +360,7 @@ static long nfcwilink_receive(void *priv_data, struct sk_buff *skb)
|
||||
/* Forward skb to NCI core layer */
|
||||
rc = nci_recv_frame(drv->ndev, skb);
|
||||
if (rc < 0) {
|
||||
nfc_dev_err(&drv->pdev->dev, "nci_recv_frame failed %d", rc);
|
||||
nfc_err(&drv->pdev->dev, "nci_recv_frame failed %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@ -396,8 +386,6 @@ static int nfcwilink_open(struct nci_dev *ndev)
|
||||
unsigned long comp_ret;
|
||||
int rc;
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev, "open entry");
|
||||
|
||||
if (test_and_set_bit(NFCWILINK_RUNNING, &drv->flags)) {
|
||||
rc = -EBUSY;
|
||||
goto exit;
|
||||
@ -415,9 +403,9 @@ static int nfcwilink_open(struct nci_dev *ndev)
|
||||
&drv->completed,
|
||||
msecs_to_jiffies(NFCWILINK_REGISTER_TIMEOUT));
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev,
|
||||
"wait_for_completion_timeout returned %ld",
|
||||
comp_ret);
|
||||
dev_dbg(&drv->pdev->dev,
|
||||
"wait_for_completion_timeout returned %ld\n",
|
||||
comp_ret);
|
||||
|
||||
if (comp_ret == 0) {
|
||||
/* timeout */
|
||||
@ -425,13 +413,12 @@ static int nfcwilink_open(struct nci_dev *ndev)
|
||||
goto clear_exit;
|
||||
} else if (drv->st_register_cb_status != 0) {
|
||||
rc = drv->st_register_cb_status;
|
||||
nfc_dev_err(&drv->pdev->dev,
|
||||
"st_register_cb failed %d", rc);
|
||||
nfc_err(&drv->pdev->dev,
|
||||
"st_register_cb failed %d\n", rc);
|
||||
goto clear_exit;
|
||||
}
|
||||
} else {
|
||||
nfc_dev_err(&drv->pdev->dev,
|
||||
"st_register failed %d", rc);
|
||||
nfc_err(&drv->pdev->dev, "st_register failed %d\n", rc);
|
||||
goto clear_exit;
|
||||
}
|
||||
}
|
||||
@ -441,8 +428,8 @@ static int nfcwilink_open(struct nci_dev *ndev)
|
||||
drv->st_write = nfcwilink_proto.write;
|
||||
|
||||
if (nfcwilink_download_fw(drv)) {
|
||||
nfc_dev_err(&drv->pdev->dev, "nfcwilink_download_fw failed %d",
|
||||
rc);
|
||||
nfc_err(&drv->pdev->dev, "nfcwilink_download_fw failed %d\n",
|
||||
rc);
|
||||
/* open should succeed, even if the FW download failed */
|
||||
}
|
||||
|
||||
@ -460,14 +447,12 @@ static int nfcwilink_close(struct nci_dev *ndev)
|
||||
struct nfcwilink *drv = nci_get_drvdata(ndev);
|
||||
int rc;
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev, "close entry");
|
||||
|
||||
if (!test_and_clear_bit(NFCWILINK_RUNNING, &drv->flags))
|
||||
return 0;
|
||||
|
||||
rc = st_unregister(&nfcwilink_proto);
|
||||
if (rc)
|
||||
nfc_dev_err(&drv->pdev->dev, "st_unregister failed %d", rc);
|
||||
nfc_err(&drv->pdev->dev, "st_unregister failed %d\n", rc);
|
||||
|
||||
drv->st_write = NULL;
|
||||
|
||||
@ -480,7 +465,7 @@ static int nfcwilink_send(struct nci_dev *ndev, struct sk_buff *skb)
|
||||
struct nfcwilink_hdr hdr = {NFCWILINK_CHNL, NFCWILINK_OPCODE, 0x0000};
|
||||
long len;
|
||||
|
||||
nfc_dev_dbg(&drv->pdev->dev, "send entry, len %d", skb->len);
|
||||
dev_dbg(&drv->pdev->dev, "send entry, len %d\n", skb->len);
|
||||
|
||||
if (!test_bit(NFCWILINK_RUNNING, &drv->flags)) {
|
||||
kfree_skb(skb);
|
||||
@ -498,7 +483,7 @@ static int nfcwilink_send(struct nci_dev *ndev, struct sk_buff *skb)
|
||||
len = drv->st_write(skb);
|
||||
if (len < 0) {
|
||||
kfree_skb(skb);
|
||||
nfc_dev_err(&drv->pdev->dev, "st_write failed %ld", len);
|
||||
nfc_err(&drv->pdev->dev, "st_write failed %ld\n", len);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
@ -517,8 +502,6 @@ static int nfcwilink_probe(struct platform_device *pdev)
|
||||
int rc;
|
||||
__u32 protocols;
|
||||
|
||||
nfc_dev_dbg(&pdev->dev, "probe entry");
|
||||
|
||||
drv = devm_kzalloc(&pdev->dev, sizeof(struct nfcwilink), GFP_KERNEL);
|
||||
if (!drv) {
|
||||
rc = -ENOMEM;
|
||||
@ -538,7 +521,7 @@ static int nfcwilink_probe(struct platform_device *pdev)
|
||||
NFCWILINK_HDR_LEN,
|
||||
0);
|
||||
if (!drv->ndev) {
|
||||
nfc_dev_err(&pdev->dev, "nci_allocate_device failed");
|
||||
nfc_err(&pdev->dev, "nci_allocate_device failed\n");
|
||||
rc = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
@ -548,7 +531,7 @@ static int nfcwilink_probe(struct platform_device *pdev)
|
||||
|
||||
rc = nci_register_device(drv->ndev);
|
||||
if (rc < 0) {
|
||||
nfc_dev_err(&pdev->dev, "nci_register_device failed %d", rc);
|
||||
nfc_err(&pdev->dev, "nci_register_device failed %d\n", rc);
|
||||
goto free_dev_exit;
|
||||
}
|
||||
|
||||
@ -568,8 +551,6 @@ static int nfcwilink_remove(struct platform_device *pdev)
|
||||
struct nfcwilink *drv = dev_get_drvdata(&pdev->dev);
|
||||
struct nci_dev *ndev;
|
||||
|
||||
nfc_dev_dbg(&pdev->dev, "remove entry");
|
||||
|
||||
if (!drv)
|
||||
return -EFAULT;
|
||||
|
||||
@ -578,8 +559,6 @@ static int nfcwilink_remove(struct platform_device *pdev)
|
||||
nci_unregister_device(ndev);
|
||||
nci_free_device(ndev);
|
||||
|
||||
dev_set_drvdata(&pdev->dev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -18,6 +18,8 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/crc-ccitt.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/i2c.h>
|
||||
@ -151,8 +153,7 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
|
||||
char rset_cmd[] = { 0x05, 0xF9, 0x04, 0x00, 0xC3, 0xE5 };
|
||||
int count = sizeof(rset_cmd);
|
||||
|
||||
pr_info(DRIVER_DESC ": %s\n", __func__);
|
||||
dev_info(&phy->i2c_dev->dev, "Detecting nfc_en polarity\n");
|
||||
nfc_info(&phy->i2c_dev->dev, "Detecting nfc_en polarity\n");
|
||||
|
||||
/* Disable fw download */
|
||||
gpio_set_value(phy->gpio_fw, 0);
|
||||
@ -173,7 +174,7 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
|
||||
dev_dbg(&phy->i2c_dev->dev, "Sending reset cmd\n");
|
||||
ret = i2c_master_send(phy->i2c_dev, rset_cmd, count);
|
||||
if (ret == count) {
|
||||
dev_info(&phy->i2c_dev->dev,
|
||||
nfc_info(&phy->i2c_dev->dev,
|
||||
"nfc_en polarity : active %s\n",
|
||||
(polarity == 0 ? "low" : "high"));
|
||||
goto out;
|
||||
@ -181,7 +182,7 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
|
||||
}
|
||||
}
|
||||
|
||||
dev_err(&phy->i2c_dev->dev,
|
||||
nfc_err(&phy->i2c_dev->dev,
|
||||
"Could not detect nfc_en polarity, fallback to active high\n");
|
||||
|
||||
out:
|
||||
@ -201,7 +202,7 @@ static int pn544_hci_i2c_enable(void *phy_id)
|
||||
{
|
||||
struct pn544_i2c_phy *phy = phy_id;
|
||||
|
||||
pr_info(DRIVER_DESC ": %s\n", __func__);
|
||||
pr_info("%s\n", __func__);
|
||||
|
||||
pn544_hci_i2c_enable_mode(phy, PN544_HCI_MODE);
|
||||
|
||||
@ -214,8 +215,6 @@ static void pn544_hci_i2c_disable(void *phy_id)
|
||||
{
|
||||
struct pn544_i2c_phy *phy = phy_id;
|
||||
|
||||
pr_info(DRIVER_DESC ": %s\n", __func__);
|
||||
|
||||
gpio_set_value(phy->gpio_fw, 0);
|
||||
gpio_set_value(phy->gpio_en, !phy->en_polarity);
|
||||
usleep_range(10000, 15000);
|
||||
@ -298,11 +297,9 @@ static int check_crc(u8 *buf, int buflen)
|
||||
crc = ~crc;
|
||||
|
||||
if (buf[len - 2] != (crc & 0xff) || buf[len - 1] != (crc >> 8)) {
|
||||
pr_err(PN544_HCI_I2C_DRIVER_NAME
|
||||
": CRC error 0x%x != 0x%x 0x%x\n",
|
||||
pr_err("CRC error 0x%x != 0x%x 0x%x\n",
|
||||
crc, buf[len - 1], buf[len - 2]);
|
||||
|
||||
pr_info(DRIVER_DESC ": %s : BAD CRC\n", __func__);
|
||||
pr_info("%s: BAD CRC\n", __func__);
|
||||
print_hex_dump(KERN_DEBUG, "crc: ", DUMP_PREFIX_NONE,
|
||||
16, 2, buf, buflen, false);
|
||||
return -EPERM;
|
||||
@ -328,13 +325,13 @@ static int pn544_hci_i2c_read(struct pn544_i2c_phy *phy, struct sk_buff **skb)
|
||||
|
||||
r = i2c_master_recv(client, &len, 1);
|
||||
if (r != 1) {
|
||||
dev_err(&client->dev, "cannot read len byte\n");
|
||||
nfc_err(&client->dev, "cannot read len byte\n");
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
if ((len < (PN544_HCI_I2C_LLC_MIN_SIZE - 1)) ||
|
||||
(len > (PN544_HCI_I2C_LLC_MAX_SIZE - 1))) {
|
||||
dev_err(&client->dev, "invalid len byte\n");
|
||||
nfc_err(&client->dev, "invalid len byte\n");
|
||||
r = -EBADMSG;
|
||||
goto flush;
|
||||
}
|
||||
@ -386,7 +383,7 @@ static int pn544_hci_i2c_fw_read_status(struct pn544_i2c_phy *phy)
|
||||
|
||||
r = i2c_master_recv(client, (char *) &response, sizeof(response));
|
||||
if (r != sizeof(response)) {
|
||||
dev_err(&client->dev, "cannot read fw status\n");
|
||||
nfc_err(&client->dev, "cannot read fw status\n");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
@ -478,8 +475,7 @@ static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name)
|
||||
{
|
||||
struct pn544_i2c_phy *phy = phy_id;
|
||||
|
||||
pr_info(DRIVER_DESC ": Starting Firmware Download (%s)\n",
|
||||
firmware_name);
|
||||
pr_info("Starting Firmware Download (%s)\n", firmware_name);
|
||||
|
||||
strcpy(phy->firmware_name, firmware_name);
|
||||
|
||||
@ -493,7 +489,7 @@ static int pn544_hci_i2c_fw_download(void *phy_id, const char *firmware_name)
|
||||
static void pn544_hci_i2c_fw_work_complete(struct pn544_i2c_phy *phy,
|
||||
int result)
|
||||
{
|
||||
pr_info(DRIVER_DESC ": Firmware Download Complete, result=%d\n", result);
|
||||
pr_info("Firmware Download Complete, result=%d\n", result);
|
||||
|
||||
pn544_hci_i2c_disable(phy);
|
||||
|
||||
@ -694,14 +690,14 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
|
||||
dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
dev_err(&client->dev, "Need I2C_FUNC_I2C\n");
|
||||
nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
phy = devm_kzalloc(&client->dev, sizeof(struct pn544_i2c_phy),
|
||||
GFP_KERNEL);
|
||||
if (!phy) {
|
||||
dev_err(&client->dev,
|
||||
nfc_err(&client->dev,
|
||||
"Cannot allocate memory for pn544 i2c phy.\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
@ -714,18 +710,18 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
|
||||
|
||||
pdata = client->dev.platform_data;
|
||||
if (pdata == NULL) {
|
||||
dev_err(&client->dev, "No platform data\n");
|
||||
nfc_err(&client->dev, "No platform data\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (pdata->request_resources == NULL) {
|
||||
dev_err(&client->dev, "request_resources() missing\n");
|
||||
nfc_err(&client->dev, "request_resources() missing\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
r = pdata->request_resources(client);
|
||||
if (r) {
|
||||
dev_err(&client->dev, "Cannot get platform resources\n");
|
||||
nfc_err(&client->dev, "Cannot get platform resources\n");
|
||||
return r;
|
||||
}
|
||||
|
||||
@ -739,7 +735,7 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
|
||||
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
|
||||
PN544_HCI_I2C_DRIVER_NAME, phy);
|
||||
if (r < 0) {
|
||||
dev_err(&client->dev, "Unable to register IRQ handler\n");
|
||||
nfc_err(&client->dev, "Unable to register IRQ handler\n");
|
||||
goto err_rti;
|
||||
}
|
||||
|
||||
|
@ -18,6 +18,8 @@
|
||||
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/delay.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
@ -41,6 +43,7 @@ enum pn544_state {
|
||||
|
||||
/* Proprietary commands */
|
||||
#define PN544_WRITE 0x3f
|
||||
#define PN544_TEST_SWP 0x21
|
||||
|
||||
/* Proprietary gates, events, commands and registers */
|
||||
|
||||
@ -81,14 +84,17 @@ enum pn544_state {
|
||||
#define PN544_PL_NFCT_DEACTIVATED 0x09
|
||||
|
||||
#define PN544_SWP_MGMT_GATE 0xA0
|
||||
#define PN544_SWP_DEFAULT_MODE 0x01
|
||||
|
||||
#define PN544_NFC_WI_MGMT_GATE 0xA1
|
||||
#define PN544_NFC_ESE_DEFAULT_MODE 0x01
|
||||
|
||||
#define PN544_HCI_EVT_SND_DATA 0x01
|
||||
#define PN544_HCI_EVT_ACTIVATED 0x02
|
||||
#define PN544_HCI_EVT_DEACTIVATED 0x03
|
||||
#define PN544_HCI_EVT_RCV_DATA 0x04
|
||||
#define PN544_HCI_EVT_CONTINUE_MI 0x05
|
||||
#define PN544_HCI_EVT_SWITCH_MODE 0x03
|
||||
|
||||
#define PN544_HCI_CMD_ATTREQUEST 0x12
|
||||
#define PN544_HCI_CMD_CONTINUE_ACTIVATION 0x13
|
||||
@ -187,13 +193,6 @@ static int pn544_hci_ready(struct nfc_hci_dev *hdev)
|
||||
|
||||
{{0x9e, 0xb4}, 0x00},
|
||||
|
||||
{{0x9e, 0xd9}, 0xff},
|
||||
{{0x9e, 0xda}, 0xff},
|
||||
{{0x9e, 0xdb}, 0x23},
|
||||
{{0x9e, 0xdc}, 0x21},
|
||||
{{0x9e, 0xdd}, 0x22},
|
||||
{{0x9e, 0xde}, 0x24},
|
||||
|
||||
{{0x9c, 0x01}, 0x08},
|
||||
|
||||
{{0x9e, 0xaa}, 0x01},
|
||||
@ -394,7 +393,7 @@ static int pn544_hci_start_poll(struct nfc_hci_dev *hdev,
|
||||
if ((im_protocols | tm_protocols) & NFC_PROTO_NFC_DEP_MASK) {
|
||||
hdev->gb = nfc_get_local_general_bytes(hdev->ndev,
|
||||
&hdev->gb_len);
|
||||
pr_debug("generate local bytes %p", hdev->gb);
|
||||
pr_debug("generate local bytes %p\n", hdev->gb);
|
||||
if (hdev->gb == NULL || hdev->gb_len == 0) {
|
||||
im_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
|
||||
tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
|
||||
@ -696,7 +695,7 @@ static int pn544_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
|
||||
static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
|
||||
struct nfc_target *target)
|
||||
{
|
||||
pr_debug("supported protocol %d", target->supported_protocols);
|
||||
pr_debug("supported protocol %d\b", target->supported_protocols);
|
||||
if (target->supported_protocols & (NFC_PROTO_ISO14443_MASK |
|
||||
NFC_PROTO_ISO14443_B_MASK)) {
|
||||
return nfc_hci_send_cmd(hdev, target->hci_reader_gate,
|
||||
@ -733,7 +732,7 @@ static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event,
|
||||
struct sk_buff *rgb_skb = NULL;
|
||||
int r;
|
||||
|
||||
pr_debug("hci event %d", event);
|
||||
pr_debug("hci event %d\n", event);
|
||||
switch (event) {
|
||||
case PN544_HCI_EVT_ACTIVATED:
|
||||
if (gate == PN544_RF_READER_NFCIP1_INITIATOR_GATE) {
|
||||
@ -764,7 +763,7 @@ static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event,
|
||||
}
|
||||
|
||||
if (skb->data[0] != 0) {
|
||||
pr_debug("data0 %d", skb->data[0]);
|
||||
pr_debug("data0 %d\n", skb->data[0]);
|
||||
r = -EPROTO;
|
||||
goto exit;
|
||||
}
|
||||
@ -792,6 +791,108 @@ static int pn544_hci_fw_download(struct nfc_hci_dev *hdev,
|
||||
return info->fw_download(info->phy_id, firmware_name);
|
||||
}
|
||||
|
||||
static int pn544_hci_discover_se(struct nfc_hci_dev *hdev)
|
||||
{
|
||||
u32 se_idx = 0;
|
||||
u8 ese_mode = 0x01; /* Default mode */
|
||||
struct sk_buff *res_skb;
|
||||
int r;
|
||||
|
||||
r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE, PN544_TEST_SWP,
|
||||
NULL, 0, &res_skb);
|
||||
|
||||
if (r == 0) {
|
||||
if (res_skb->len == 2 && res_skb->data[0] == 0x00)
|
||||
nfc_add_se(hdev->ndev, se_idx++, NFC_SE_UICC);
|
||||
|
||||
kfree_skb(res_skb);
|
||||
}
|
||||
|
||||
r = nfc_hci_send_event(hdev, PN544_NFC_WI_MGMT_GATE,
|
||||
PN544_HCI_EVT_SWITCH_MODE,
|
||||
&ese_mode, 1);
|
||||
if (r == 0)
|
||||
nfc_add_se(hdev->ndev, se_idx++, NFC_SE_EMBEDDED);
|
||||
|
||||
return !se_idx;
|
||||
}
|
||||
|
||||
#define PN544_SE_MODE_OFF 0x00
|
||||
#define PN544_SE_MODE_ON 0x01
|
||||
static int pn544_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx)
|
||||
{
|
||||
struct nfc_se *se;
|
||||
u8 enable = PN544_SE_MODE_ON;
|
||||
static struct uicc_gatelist {
|
||||
u8 head;
|
||||
u8 adr[2];
|
||||
u8 value;
|
||||
} uicc_gatelist[] = {
|
||||
{0x00, {0x9e, 0xd9}, 0x23},
|
||||
{0x00, {0x9e, 0xda}, 0x21},
|
||||
{0x00, {0x9e, 0xdb}, 0x22},
|
||||
{0x00, {0x9e, 0xdc}, 0x24},
|
||||
};
|
||||
struct uicc_gatelist *p = uicc_gatelist;
|
||||
int count = ARRAY_SIZE(uicc_gatelist);
|
||||
struct sk_buff *res_skb;
|
||||
int r;
|
||||
|
||||
se = nfc_find_se(hdev->ndev, se_idx);
|
||||
|
||||
switch (se->type) {
|
||||
case NFC_SE_UICC:
|
||||
while (count--) {
|
||||
r = nfc_hci_send_cmd(hdev, PN544_SYS_MGMT_GATE,
|
||||
PN544_WRITE, (u8 *)p, 4, &res_skb);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (res_skb->len != 1) {
|
||||
kfree_skb(res_skb);
|
||||
return -EPROTO;
|
||||
}
|
||||
|
||||
if (res_skb->data[0] != p->value) {
|
||||
kfree_skb(res_skb);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
kfree_skb(res_skb);
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
return nfc_hci_set_param(hdev, PN544_SWP_MGMT_GATE,
|
||||
PN544_SWP_DEFAULT_MODE, &enable, 1);
|
||||
case NFC_SE_EMBEDDED:
|
||||
return nfc_hci_set_param(hdev, PN544_NFC_WI_MGMT_GATE,
|
||||
PN544_NFC_ESE_DEFAULT_MODE, &enable, 1);
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static int pn544_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx)
|
||||
{
|
||||
struct nfc_se *se;
|
||||
u8 disable = PN544_SE_MODE_OFF;
|
||||
|
||||
se = nfc_find_se(hdev->ndev, se_idx);
|
||||
|
||||
switch (se->type) {
|
||||
case NFC_SE_UICC:
|
||||
return nfc_hci_set_param(hdev, PN544_SWP_MGMT_GATE,
|
||||
PN544_SWP_DEFAULT_MODE, &disable, 1);
|
||||
case NFC_SE_EMBEDDED:
|
||||
return nfc_hci_set_param(hdev, PN544_NFC_WI_MGMT_GATE,
|
||||
PN544_NFC_ESE_DEFAULT_MODE, &disable, 1);
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static struct nfc_hci_ops pn544_hci_ops = {
|
||||
.open = pn544_hci_open,
|
||||
.close = pn544_hci_close,
|
||||
@ -807,6 +908,9 @@ static struct nfc_hci_ops pn544_hci_ops = {
|
||||
.check_presence = pn544_hci_check_presence,
|
||||
.event_received = pn544_hci_event_received,
|
||||
.fw_download = pn544_hci_fw_download,
|
||||
.discover_se = pn544_hci_discover_se,
|
||||
.enable_se = pn544_hci_enable_se,
|
||||
.disable_se = pn544_hci_disable_se,
|
||||
};
|
||||
|
||||
int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
|
||||
@ -820,7 +924,6 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
|
||||
|
||||
info = kzalloc(sizeof(struct pn544_hci_info), GFP_KERNEL);
|
||||
if (!info) {
|
||||
pr_err("Cannot allocate memory for pn544_hci_info.\n");
|
||||
r = -ENOMEM;
|
||||
goto err_info_alloc;
|
||||
}
|
||||
@ -853,7 +956,7 @@ int pn544_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, char *llc_name,
|
||||
phy_headroom + PN544_CMDS_HEADROOM,
|
||||
phy_tailroom, phy_payload);
|
||||
if (!info->hdev) {
|
||||
pr_err("Cannot allocate nfc hdev.\n");
|
||||
pr_err("Cannot allocate nfc hdev\n");
|
||||
r = -ENOMEM;
|
||||
goto err_alloc_hdev;
|
||||
}
|
||||
|
1529
drivers/nfc/port100.c
Normal file
1529
drivers/nfc/port100.c
Normal file
File diff suppressed because it is too large
Load Diff
227
include/net/nfc/digital.h
Normal file
227
include/net/nfc/digital.h
Normal file
@ -0,0 +1,227 @@
|
||||
/*
|
||||
* NFC Digital Protocol stack
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __NFC_DIGITAL_H
|
||||
#define __NFC_DIGITAL_H
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <net/nfc/nfc.h>
|
||||
|
||||
/**
|
||||
* Configuration types for in_configure_hw and tg_configure_hw.
|
||||
*/
|
||||
enum {
|
||||
NFC_DIGITAL_CONFIG_RF_TECH = 0,
|
||||
NFC_DIGITAL_CONFIG_FRAMING,
|
||||
};
|
||||
|
||||
/**
|
||||
* RF technology values passed as param argument to in_configure_hw and
|
||||
* tg_configure_hw for NFC_DIGITAL_CONFIG_RF_TECH configuration type.
|
||||
*/
|
||||
enum {
|
||||
NFC_DIGITAL_RF_TECH_106A = 0,
|
||||
NFC_DIGITAL_RF_TECH_212F,
|
||||
NFC_DIGITAL_RF_TECH_424F,
|
||||
|
||||
NFC_DIGITAL_RF_TECH_LAST,
|
||||
};
|
||||
|
||||
/**
|
||||
* Framing configuration passed as param argument to in_configure_hw and
|
||||
* tg_configure_hw for NFC_DIGITAL_CONFIG_FRAMING configuration type.
|
||||
*/
|
||||
enum {
|
||||
NFC_DIGITAL_FRAMING_NFCA_SHORT = 0,
|
||||
NFC_DIGITAL_FRAMING_NFCA_STANDARD,
|
||||
NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A,
|
||||
|
||||
NFC_DIGITAL_FRAMING_NFCA_T1T,
|
||||
NFC_DIGITAL_FRAMING_NFCA_T2T,
|
||||
NFC_DIGITAL_FRAMING_NFCA_NFC_DEP,
|
||||
|
||||
NFC_DIGITAL_FRAMING_NFCF,
|
||||
NFC_DIGITAL_FRAMING_NFCF_T3T,
|
||||
NFC_DIGITAL_FRAMING_NFCF_NFC_DEP,
|
||||
NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED,
|
||||
|
||||
NFC_DIGITAL_FRAMING_LAST,
|
||||
};
|
||||
|
||||
#define DIGITAL_MDAA_NFCID1_SIZE 3
|
||||
|
||||
struct digital_tg_mdaa_params {
|
||||
u16 sens_res;
|
||||
u8 nfcid1[DIGITAL_MDAA_NFCID1_SIZE];
|
||||
u8 sel_res;
|
||||
|
||||
u8 nfcid2[NFC_NFCID2_MAXSIZE];
|
||||
u16 sc;
|
||||
};
|
||||
|
||||
struct nfc_digital_dev;
|
||||
|
||||
/**
|
||||
* nfc_digital_cmd_complete_t - Definition of command result callback
|
||||
*
|
||||
* @ddev: nfc_digital_device ref
|
||||
* @arg: user data
|
||||
* @resp: response data
|
||||
*
|
||||
* resp pointer can be an error code and will be checked with IS_ERR() macro.
|
||||
* The callback is responsible for freeing resp sk_buff.
|
||||
*/
|
||||
typedef void (*nfc_digital_cmd_complete_t)(struct nfc_digital_dev *ddev,
|
||||
void *arg, struct sk_buff *resp);
|
||||
|
||||
/**
|
||||
* Device side NFC Digital operations
|
||||
*
|
||||
* Initiator mode:
|
||||
* @in_configure_hw: Hardware configuration for RF technology and communication
|
||||
* framing in initiator mode. This is a synchronous function.
|
||||
* @in_send_cmd: Initiator mode data exchange using RF technology and framing
|
||||
* previously set with in_configure_hw. The peer response is returned
|
||||
* through callback cb. If an io error occurs or the peer didn't reply
|
||||
* within the specified timeout (ms), the error code is passed back through
|
||||
* the resp pointer. This is an asynchronous function.
|
||||
*
|
||||
* Target mode: Only NFC-DEP protocol is supported in target mode.
|
||||
* @tg_configure_hw: Hardware configuration for RF technology and communication
|
||||
* framing in target mode. This is a synchronous function.
|
||||
* @tg_send_cmd: Target mode data exchange using RF technology and framing
|
||||
* previously set with tg_configure_hw. The peer next command is returned
|
||||
* through callback cb. If an io error occurs or the peer didn't reply
|
||||
* within the specified timeout (ms), the error code is passed back through
|
||||
* the resp pointer. This is an asynchronous function.
|
||||
* @tg_listen: Put the device in listen mode waiting for data from the peer
|
||||
* device. This is an asynchronous function.
|
||||
* @tg_listen_mdaa: If supported, put the device in automatic listen mode with
|
||||
* mode detection and automatic anti-collision. In this mode, the device
|
||||
* automatically detects the RF technology and executes the anti-collision
|
||||
* detection using the command responses specified in mdaa_params. The
|
||||
* mdaa_params structure contains SENS_RES, NFCID1, and SEL_RES for 106A RF
|
||||
* tech. NFCID2 and system code (sc) for 212F and 424F. The driver returns
|
||||
* the NFC-DEP ATR_REQ command through cb. The digital stack deducts the RF
|
||||
* tech by analyzing the SoD of the frame containing the ATR_REQ command.
|
||||
* This is an asynchronous function.
|
||||
*
|
||||
* @switch_rf: Turns device radio on or off. The stack does not call explicitly
|
||||
* switch_rf to turn the radio on. A call to in|tg_configure_hw must turn
|
||||
* the device radio on.
|
||||
* @abort_cmd: Discard the last sent command.
|
||||
*/
|
||||
struct nfc_digital_ops {
|
||||
int (*in_configure_hw)(struct nfc_digital_dev *ddev, int type,
|
||||
int param);
|
||||
int (*in_send_cmd)(struct nfc_digital_dev *ddev, struct sk_buff *skb,
|
||||
u16 timeout, nfc_digital_cmd_complete_t cb,
|
||||
void *arg);
|
||||
|
||||
int (*tg_configure_hw)(struct nfc_digital_dev *ddev, int type,
|
||||
int param);
|
||||
int (*tg_send_cmd)(struct nfc_digital_dev *ddev, struct sk_buff *skb,
|
||||
u16 timeout, nfc_digital_cmd_complete_t cb,
|
||||
void *arg);
|
||||
int (*tg_listen)(struct nfc_digital_dev *ddev, u16 timeout,
|
||||
nfc_digital_cmd_complete_t cb, void *arg);
|
||||
int (*tg_listen_mdaa)(struct nfc_digital_dev *ddev,
|
||||
struct digital_tg_mdaa_params *mdaa_params,
|
||||
u16 timeout, nfc_digital_cmd_complete_t cb,
|
||||
void *arg);
|
||||
|
||||
int (*switch_rf)(struct nfc_digital_dev *ddev, bool on);
|
||||
void (*abort_cmd)(struct nfc_digital_dev *ddev);
|
||||
};
|
||||
|
||||
#define NFC_DIGITAL_POLL_MODE_COUNT_MAX 6 /* 106A, 212F, and 424F in & tg */
|
||||
|
||||
typedef int (*digital_poll_t)(struct nfc_digital_dev *ddev, u8 rf_tech);
|
||||
|
||||
struct digital_poll_tech {
|
||||
u8 rf_tech;
|
||||
digital_poll_t poll_func;
|
||||
};
|
||||
|
||||
/**
|
||||
* Driver capabilities - bit mask made of the following values
|
||||
*
|
||||
* @NFC_DIGITAL_DRV_CAPS_IN_CRC: The driver handles CRC calculation in initiator
|
||||
* mode.
|
||||
* @NFC_DIGITAL_DRV_CAPS_TG_CRC: The driver handles CRC calculation in target
|
||||
* mode.
|
||||
*/
|
||||
#define NFC_DIGITAL_DRV_CAPS_IN_CRC 0x0001
|
||||
#define NFC_DIGITAL_DRV_CAPS_TG_CRC 0x0002
|
||||
|
||||
struct nfc_digital_dev {
|
||||
struct nfc_dev *nfc_dev;
|
||||
struct nfc_digital_ops *ops;
|
||||
|
||||
u32 protocols;
|
||||
|
||||
int tx_headroom;
|
||||
int tx_tailroom;
|
||||
|
||||
u32 driver_capabilities;
|
||||
void *driver_data;
|
||||
|
||||
struct digital_poll_tech poll_techs[NFC_DIGITAL_POLL_MODE_COUNT_MAX];
|
||||
u8 poll_tech_count;
|
||||
u8 poll_tech_index;
|
||||
struct mutex poll_lock;
|
||||
|
||||
struct work_struct cmd_work;
|
||||
struct work_struct cmd_complete_work;
|
||||
struct list_head cmd_queue;
|
||||
struct mutex cmd_lock;
|
||||
|
||||
struct work_struct poll_work;
|
||||
|
||||
u8 curr_protocol;
|
||||
u8 curr_rf_tech;
|
||||
u8 curr_nfc_dep_pni;
|
||||
|
||||
int (*skb_check_crc)(struct sk_buff *skb);
|
||||
void (*skb_add_crc)(struct sk_buff *skb);
|
||||
};
|
||||
|
||||
struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops,
|
||||
__u32 supported_protocols,
|
||||
__u32 driver_capabilities,
|
||||
int tx_headroom,
|
||||
int tx_tailroom);
|
||||
void nfc_digital_free_device(struct nfc_digital_dev *ndev);
|
||||
int nfc_digital_register_device(struct nfc_digital_dev *ndev);
|
||||
void nfc_digital_unregister_device(struct nfc_digital_dev *ndev);
|
||||
|
||||
static inline void nfc_digital_set_parent_dev(struct nfc_digital_dev *ndev,
|
||||
struct device *dev)
|
||||
{
|
||||
nfc_set_parent_dev(ndev->nfc_dev, dev);
|
||||
}
|
||||
|
||||
static inline void nfc_digital_set_drvdata(struct nfc_digital_dev *dev,
|
||||
void *data)
|
||||
{
|
||||
dev->driver_data = data;
|
||||
}
|
||||
|
||||
static inline void *nfc_digital_get_drvdata(struct nfc_digital_dev *dev)
|
||||
{
|
||||
return dev->driver_data;
|
||||
}
|
||||
|
||||
#endif /* __NFC_DIGITAL_H */
|
@ -24,12 +24,6 @@
|
||||
|
||||
#include <net/nfc/nfc.h>
|
||||
|
||||
struct nfc_phy_ops {
|
||||
int (*write)(void *dev_id, struct sk_buff *skb);
|
||||
int (*enable)(void *dev_id);
|
||||
void (*disable)(void *dev_id);
|
||||
};
|
||||
|
||||
struct nfc_hci_dev;
|
||||
|
||||
struct nfc_hci_ops {
|
||||
|
@ -166,6 +166,10 @@
|
||||
#define NCI_GID_NFCEE_MGMT 0x2
|
||||
#define NCI_GID_PROPRIETARY 0xf
|
||||
|
||||
/* ----- NCI over SPI head/crc(tail) room needed for outgoing frames ----- */
|
||||
#define NCI_SPI_HDR_LEN 4
|
||||
#define NCI_SPI_CRC_LEN 2
|
||||
|
||||
/* ---- NCI Packet structures ---- */
|
||||
#define NCI_CTRL_HDR_SIZE 3
|
||||
#define NCI_DATA_HDR_SIZE 3
|
||||
|
@ -207,19 +207,9 @@ int nci_to_errno(__u8 code);
|
||||
#define NCI_SPI_CRC_ENABLED 0x01
|
||||
|
||||
/* ----- NCI SPI structures ----- */
|
||||
struct nci_spi_dev;
|
||||
|
||||
struct nci_spi_ops {
|
||||
int (*open)(struct nci_spi_dev *ndev);
|
||||
int (*close)(struct nci_spi_dev *ndev);
|
||||
void (*assert_int)(struct nci_spi_dev *ndev);
|
||||
void (*deassert_int)(struct nci_spi_dev *ndev);
|
||||
};
|
||||
|
||||
struct nci_spi_dev {
|
||||
struct nci_dev *nci_dev;
|
||||
struct nci_spi {
|
||||
struct nci_dev *ndev;
|
||||
struct spi_device *spi;
|
||||
struct nci_spi_ops *ops;
|
||||
|
||||
unsigned int xfer_udelay; /* microseconds delay between
|
||||
transactions */
|
||||
@ -227,31 +217,15 @@ struct nci_spi_dev {
|
||||
|
||||
struct completion req_completion;
|
||||
u8 req_result;
|
||||
|
||||
void *driver_data;
|
||||
};
|
||||
|
||||
/* ----- NCI SPI Devices ----- */
|
||||
struct nci_spi_dev *nci_spi_allocate_device(struct spi_device *spi,
|
||||
struct nci_spi_ops *ops,
|
||||
u32 supported_protocols,
|
||||
u32 supported_se,
|
||||
u8 acknowledge_mode,
|
||||
unsigned int delay);
|
||||
void nci_spi_free_device(struct nci_spi_dev *ndev);
|
||||
int nci_spi_register_device(struct nci_spi_dev *ndev);
|
||||
void nci_spi_unregister_device(struct nci_spi_dev *ndev);
|
||||
int nci_spi_recv_frame(struct nci_spi_dev *ndev);
|
||||
|
||||
static inline void nci_spi_set_drvdata(struct nci_spi_dev *ndev,
|
||||
void *data)
|
||||
{
|
||||
ndev->driver_data = data;
|
||||
}
|
||||
|
||||
static inline void *nci_spi_get_drvdata(struct nci_spi_dev *ndev)
|
||||
{
|
||||
return ndev->driver_data;
|
||||
}
|
||||
/* ----- NCI SPI ----- */
|
||||
struct nci_spi *nci_spi_allocate_spi(struct spi_device *spi,
|
||||
u8 acknowledge_mode, unsigned int delay,
|
||||
struct nci_dev *ndev);
|
||||
int nci_spi_send(struct nci_spi *nspi,
|
||||
struct completion *write_handshake_completion,
|
||||
struct sk_buff *skb);
|
||||
struct sk_buff *nci_spi_read(struct nci_spi *nspi);
|
||||
|
||||
#endif /* __NCI_CORE_H */
|
||||
|
@ -28,9 +28,14 @@
|
||||
#include <linux/device.h>
|
||||
#include <linux/skbuff.h>
|
||||
|
||||
#define nfc_dev_info(dev, fmt, arg...) dev_info((dev), "NFC: " fmt "\n", ## arg)
|
||||
#define nfc_dev_err(dev, fmt, arg...) dev_err((dev), "NFC: " fmt "\n", ## arg)
|
||||
#define nfc_dev_dbg(dev, fmt, arg...) dev_dbg((dev), fmt "\n", ## arg)
|
||||
#define nfc_info(dev, fmt, ...) dev_info((dev), "NFC: " fmt, ##__VA_ARGS__)
|
||||
#define nfc_err(dev, fmt, ...) dev_err((dev), "NFC: " fmt, ##__VA_ARGS__)
|
||||
|
||||
struct nfc_phy_ops {
|
||||
int (*write)(void *dev_id, struct sk_buff *skb);
|
||||
int (*enable)(void *dev_id);
|
||||
void (*disable)(void *dev_id);
|
||||
};
|
||||
|
||||
struct nfc_dev;
|
||||
|
||||
@ -48,6 +53,8 @@ struct nfc_dev;
|
||||
typedef void (*data_exchange_cb_t)(void *context, struct sk_buff *skb,
|
||||
int err);
|
||||
|
||||
typedef void (*se_io_cb_t)(void *context, u8 *apdu, size_t apdu_len, int err);
|
||||
|
||||
struct nfc_target;
|
||||
|
||||
struct nfc_ops {
|
||||
@ -74,12 +81,23 @@ struct nfc_ops {
|
||||
int (*discover_se)(struct nfc_dev *dev);
|
||||
int (*enable_se)(struct nfc_dev *dev, u32 se_idx);
|
||||
int (*disable_se)(struct nfc_dev *dev, u32 se_idx);
|
||||
int (*se_io) (struct nfc_dev *dev, u32 se_idx,
|
||||
u8 *apdu, size_t apdu_length,
|
||||
se_io_cb_t cb, void *cb_context);
|
||||
};
|
||||
|
||||
#define NFC_TARGET_IDX_ANY -1
|
||||
#define NFC_MAX_GT_LEN 48
|
||||
#define NFC_ATR_RES_GT_OFFSET 15
|
||||
|
||||
/**
|
||||
* struct nfc_target - NFC target descriptiom
|
||||
*
|
||||
* @sens_res: 2 bytes describing the target SENS_RES response, if the target
|
||||
* is a type A one. The %sens_res most significant byte must be byte 2
|
||||
* as described by the NFC Forum digital specification (i.e. the platform
|
||||
* configuration one) while %sens_res least significant byte is byte 1.
|
||||
*/
|
||||
struct nfc_target {
|
||||
u32 idx;
|
||||
u32 supported_protocols;
|
||||
@ -243,5 +261,6 @@ void nfc_driver_failure(struct nfc_dev *dev, int err);
|
||||
|
||||
int nfc_add_se(struct nfc_dev *dev, u32 se_idx, u16 type);
|
||||
int nfc_remove_se(struct nfc_dev *dev, u32 se_idx);
|
||||
struct nfc_se *nfc_find_se(struct nfc_dev *dev, u32 se_idx);
|
||||
|
||||
#endif /* __NET_NFC_H */
|
||||
|
@ -85,6 +85,7 @@
|
||||
* a specific SE notifies us about the end of a transaction. The parameter
|
||||
* for this event is the application ID (AID).
|
||||
* @NFC_CMD_GET_SE: Dump all discovered secure elements from an NFC controller.
|
||||
* @NFC_CMD_SE_IO: Send/Receive APDUs to/from the selected secure element.
|
||||
*/
|
||||
enum nfc_commands {
|
||||
NFC_CMD_UNSPEC,
|
||||
@ -114,6 +115,7 @@ enum nfc_commands {
|
||||
NFC_EVENT_SE_CONNECTIVITY,
|
||||
NFC_EVENT_SE_TRANSACTION,
|
||||
NFC_CMD_GET_SE,
|
||||
NFC_CMD_SE_IO,
|
||||
/* private: internal use only */
|
||||
__NFC_CMD_AFTER_LAST
|
||||
};
|
||||
@ -147,6 +149,7 @@ enum nfc_commands {
|
||||
* @NFC_ATTR_SE_INDEX: Secure element index
|
||||
* @NFC_ATTR_SE_TYPE: Secure element type (UICC or EMBEDDED)
|
||||
* @NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS: Firmware download operation status
|
||||
* @NFC_ATTR_APDU: Secure element APDU
|
||||
*/
|
||||
enum nfc_attrs {
|
||||
NFC_ATTR_UNSPEC,
|
||||
@ -174,6 +177,7 @@ enum nfc_attrs {
|
||||
NFC_ATTR_SE_TYPE,
|
||||
NFC_ATTR_SE_AID,
|
||||
NFC_ATTR_FIRMWARE_DOWNLOAD_STATUS,
|
||||
NFC_ATTR_SE_APDU,
|
||||
/* private: internal use only */
|
||||
__NFC_ATTR_AFTER_LAST
|
||||
};
|
||||
|
@ -14,6 +14,20 @@ menuconfig NFC
|
||||
To compile this support as a module, choose M here: the module will
|
||||
be called nfc.
|
||||
|
||||
config NFC_DIGITAL
|
||||
depends on NFC
|
||||
select CRC_CCITT
|
||||
select CRC_ITU_T
|
||||
tristate "NFC Digital Protocol stack support"
|
||||
default n
|
||||
help
|
||||
Say Y if you want to build NFC digital protocol stack support.
|
||||
This is needed by NFC chipsets whose firmware only implement
|
||||
the NFC analog layer.
|
||||
|
||||
To compile this support as a module, choose M here: the module will
|
||||
be called nfc_digital.
|
||||
|
||||
source "net/nfc/nci/Kconfig"
|
||||
source "net/nfc/hci/Kconfig"
|
||||
|
||||
|
@ -5,7 +5,9 @@
|
||||
obj-$(CONFIG_NFC) += nfc.o
|
||||
obj-$(CONFIG_NFC_NCI) += nci/
|
||||
obj-$(CONFIG_NFC_HCI) += hci/
|
||||
obj-$(CONFIG_NFC_DIGITAL) += nfc_digital.o
|
||||
|
||||
nfc-objs := core.o netlink.o af_nfc.o rawsock.o llcp_core.o llcp_commands.o \
|
||||
llcp_sock.o
|
||||
|
||||
nfc_digital-objs := digital_core.o digital_technology.o digital_dep.o
|
||||
|
@ -384,6 +384,19 @@ int nfc_dep_link_is_up(struct nfc_dev *dev, u32 target_idx,
|
||||
{
|
||||
dev->dep_link_up = true;
|
||||
|
||||
if (!dev->active_target) {
|
||||
struct nfc_target *target;
|
||||
|
||||
target = nfc_find_target(dev, target_idx);
|
||||
if (target == NULL)
|
||||
return -ENOTCONN;
|
||||
|
||||
dev->active_target = target;
|
||||
}
|
||||
|
||||
dev->polling = false;
|
||||
dev->rf_mode = rf_mode;
|
||||
|
||||
nfc_llcp_mac_is_up(dev, target_idx, comm_mode, rf_mode);
|
||||
|
||||
return nfc_genl_dep_link_up_event(dev, target_idx, comm_mode, rf_mode);
|
||||
@ -536,7 +549,7 @@ error:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static struct nfc_se *find_se(struct nfc_dev *dev, u32 se_idx)
|
||||
struct nfc_se *nfc_find_se(struct nfc_dev *dev, u32 se_idx)
|
||||
{
|
||||
struct nfc_se *se, *n;
|
||||
|
||||
@ -546,6 +559,7 @@ static struct nfc_se *find_se(struct nfc_dev *dev, u32 se_idx)
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(nfc_find_se);
|
||||
|
||||
int nfc_enable_se(struct nfc_dev *dev, u32 se_idx)
|
||||
{
|
||||
@ -577,7 +591,7 @@ int nfc_enable_se(struct nfc_dev *dev, u32 se_idx)
|
||||
goto error;
|
||||
}
|
||||
|
||||
se = find_se(dev, se_idx);
|
||||
se = nfc_find_se(dev, se_idx);
|
||||
if (!se) {
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
@ -622,7 +636,7 @@ int nfc_disable_se(struct nfc_dev *dev, u32 se_idx)
|
||||
goto error;
|
||||
}
|
||||
|
||||
se = find_se(dev, se_idx);
|
||||
se = nfc_find_se(dev, se_idx);
|
||||
if (!se) {
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
@ -881,7 +895,7 @@ int nfc_add_se(struct nfc_dev *dev, u32 se_idx, u16 type)
|
||||
|
||||
pr_debug("%s se index %d\n", dev_name(&dev->dev), se_idx);
|
||||
|
||||
se = find_se(dev, se_idx);
|
||||
se = nfc_find_se(dev, se_idx);
|
||||
if (se)
|
||||
return -EALREADY;
|
||||
|
||||
|
170
net/nfc/digital.h
Normal file
170
net/nfc/digital.h
Normal file
@ -0,0 +1,170 @@
|
||||
/*
|
||||
* NFC Digital Protocol stack
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __DIGITAL_H
|
||||
#define __DIGITAL_H
|
||||
|
||||
#include <net/nfc/nfc.h>
|
||||
#include <net/nfc/digital.h>
|
||||
|
||||
#include <linux/crc-ccitt.h>
|
||||
#include <linux/crc-itu-t.h>
|
||||
|
||||
#define PROTOCOL_ERR(req) pr_err("%d: NFC Digital Protocol error: %s\n", \
|
||||
__LINE__, req)
|
||||
|
||||
#define DIGITAL_CMD_IN_SEND 0
|
||||
#define DIGITAL_CMD_TG_SEND 1
|
||||
#define DIGITAL_CMD_TG_LISTEN 2
|
||||
#define DIGITAL_CMD_TG_LISTEN_MDAA 3
|
||||
|
||||
#define DIGITAL_MAX_HEADER_LEN 7
|
||||
#define DIGITAL_CRC_LEN 2
|
||||
|
||||
#define DIGITAL_SENSF_NFCID2_NFC_DEP_B1 0x01
|
||||
#define DIGITAL_SENSF_NFCID2_NFC_DEP_B2 0xFE
|
||||
|
||||
#define DIGITAL_SENS_RES_NFC_DEP 0x0100
|
||||
#define DIGITAL_SEL_RES_NFC_DEP 0x40
|
||||
#define DIGITAL_SENSF_FELICA_SC 0xFFFF
|
||||
|
||||
#define DIGITAL_DRV_CAPS_IN_CRC(ddev) \
|
||||
((ddev)->driver_capabilities & NFC_DIGITAL_DRV_CAPS_IN_CRC)
|
||||
#define DIGITAL_DRV_CAPS_TG_CRC(ddev) \
|
||||
((ddev)->driver_capabilities & NFC_DIGITAL_DRV_CAPS_TG_CRC)
|
||||
|
||||
struct digital_data_exch {
|
||||
data_exchange_cb_t cb;
|
||||
void *cb_context;
|
||||
};
|
||||
|
||||
struct sk_buff *digital_skb_alloc(struct nfc_digital_dev *ddev,
|
||||
unsigned int len);
|
||||
|
||||
int digital_send_cmd(struct nfc_digital_dev *ddev, u8 cmd_type,
|
||||
struct sk_buff *skb, struct digital_tg_mdaa_params *params,
|
||||
u16 timeout, nfc_digital_cmd_complete_t cmd_cb,
|
||||
void *cb_context);
|
||||
|
||||
int digital_in_configure_hw(struct nfc_digital_dev *ddev, int type, int param);
|
||||
static inline int digital_in_send_cmd(struct nfc_digital_dev *ddev,
|
||||
struct sk_buff *skb, u16 timeout,
|
||||
nfc_digital_cmd_complete_t cmd_cb,
|
||||
void *cb_context)
|
||||
{
|
||||
return digital_send_cmd(ddev, DIGITAL_CMD_IN_SEND, skb, NULL, timeout,
|
||||
cmd_cb, cb_context);
|
||||
}
|
||||
|
||||
void digital_poll_next_tech(struct nfc_digital_dev *ddev);
|
||||
|
||||
int digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech);
|
||||
int digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech);
|
||||
|
||||
int digital_target_found(struct nfc_digital_dev *ddev,
|
||||
struct nfc_target *target, u8 protocol);
|
||||
|
||||
int digital_in_recv_mifare_res(struct sk_buff *resp);
|
||||
|
||||
int digital_in_send_atr_req(struct nfc_digital_dev *ddev,
|
||||
struct nfc_target *target, __u8 comm_mode, __u8 *gb,
|
||||
size_t gb_len);
|
||||
int digital_in_send_dep_req(struct nfc_digital_dev *ddev,
|
||||
struct nfc_target *target, struct sk_buff *skb,
|
||||
struct digital_data_exch *data_exch);
|
||||
|
||||
int digital_tg_configure_hw(struct nfc_digital_dev *ddev, int type, int param);
|
||||
static inline int digital_tg_send_cmd(struct nfc_digital_dev *ddev,
|
||||
struct sk_buff *skb, u16 timeout,
|
||||
nfc_digital_cmd_complete_t cmd_cb, void *cb_context)
|
||||
{
|
||||
return digital_send_cmd(ddev, DIGITAL_CMD_TG_SEND, skb, NULL, timeout,
|
||||
cmd_cb, cb_context);
|
||||
}
|
||||
|
||||
void digital_tg_recv_sens_req(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp);
|
||||
|
||||
void digital_tg_recv_sensf_req(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp);
|
||||
|
||||
static inline int digital_tg_listen(struct nfc_digital_dev *ddev, u16 timeout,
|
||||
nfc_digital_cmd_complete_t cb, void *arg)
|
||||
{
|
||||
return digital_send_cmd(ddev, DIGITAL_CMD_TG_LISTEN, NULL, NULL,
|
||||
timeout, cb, arg);
|
||||
}
|
||||
|
||||
void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp);
|
||||
|
||||
int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb);
|
||||
|
||||
int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech);
|
||||
int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech);
|
||||
|
||||
typedef u16 (*crc_func_t)(u16, const u8 *, size_t);
|
||||
|
||||
#define CRC_A_INIT 0x6363
|
||||
#define CRC_B_INIT 0xFFFF
|
||||
#define CRC_F_INIT 0x0000
|
||||
|
||||
void digital_skb_add_crc(struct sk_buff *skb, crc_func_t crc_func, u16 init,
|
||||
u8 bitwise_inv, u8 msb_first);
|
||||
|
||||
static inline void digital_skb_add_crc_a(struct sk_buff *skb)
|
||||
{
|
||||
digital_skb_add_crc(skb, crc_ccitt, CRC_A_INIT, 0, 0);
|
||||
}
|
||||
|
||||
static inline void digital_skb_add_crc_b(struct sk_buff *skb)
|
||||
{
|
||||
digital_skb_add_crc(skb, crc_ccitt, CRC_B_INIT, 1, 0);
|
||||
}
|
||||
|
||||
static inline void digital_skb_add_crc_f(struct sk_buff *skb)
|
||||
{
|
||||
digital_skb_add_crc(skb, crc_itu_t, CRC_F_INIT, 0, 1);
|
||||
}
|
||||
|
||||
static inline void digital_skb_add_crc_none(struct sk_buff *skb)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int digital_skb_check_crc(struct sk_buff *skb, crc_func_t crc_func,
|
||||
u16 crc_init, u8 bitwise_inv, u8 msb_first);
|
||||
|
||||
static inline int digital_skb_check_crc_a(struct sk_buff *skb)
|
||||
{
|
||||
return digital_skb_check_crc(skb, crc_ccitt, CRC_A_INIT, 0, 0);
|
||||
}
|
||||
|
||||
static inline int digital_skb_check_crc_b(struct sk_buff *skb)
|
||||
{
|
||||
return digital_skb_check_crc(skb, crc_ccitt, CRC_B_INIT, 1, 0);
|
||||
}
|
||||
|
||||
static inline int digital_skb_check_crc_f(struct sk_buff *skb)
|
||||
{
|
||||
return digital_skb_check_crc(skb, crc_itu_t, CRC_F_INIT, 0, 1);
|
||||
}
|
||||
|
||||
static inline int digital_skb_check_crc_none(struct sk_buff *skb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* __DIGITAL_H */
|
737
net/nfc/digital_core.c
Normal file
737
net/nfc/digital_core.c
Normal file
@ -0,0 +1,737 @@
|
||||
/*
|
||||
* NFC Digital Protocol stack
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "digital: %s: " fmt, __func__
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include "digital.h"
|
||||
|
||||
#define DIGITAL_PROTO_NFCA_RF_TECH \
|
||||
(NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK | NFC_PROTO_NFC_DEP_MASK)
|
||||
|
||||
#define DIGITAL_PROTO_NFCF_RF_TECH \
|
||||
(NFC_PROTO_FELICA_MASK | NFC_PROTO_NFC_DEP_MASK)
|
||||
|
||||
struct digital_cmd {
|
||||
struct list_head queue;
|
||||
|
||||
u8 type;
|
||||
u8 pending;
|
||||
|
||||
u16 timeout;
|
||||
struct sk_buff *req;
|
||||
struct sk_buff *resp;
|
||||
struct digital_tg_mdaa_params *mdaa_params;
|
||||
|
||||
nfc_digital_cmd_complete_t cmd_cb;
|
||||
void *cb_context;
|
||||
};
|
||||
|
||||
struct sk_buff *digital_skb_alloc(struct nfc_digital_dev *ddev,
|
||||
unsigned int len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
skb = alloc_skb(len + ddev->tx_headroom + ddev->tx_tailroom,
|
||||
GFP_KERNEL);
|
||||
if (skb)
|
||||
skb_reserve(skb, ddev->tx_headroom);
|
||||
|
||||
return skb;
|
||||
}
|
||||
|
||||
void digital_skb_add_crc(struct sk_buff *skb, crc_func_t crc_func, u16 init,
|
||||
u8 bitwise_inv, u8 msb_first)
|
||||
{
|
||||
u16 crc;
|
||||
|
||||
crc = crc_func(init, skb->data, skb->len);
|
||||
|
||||
if (bitwise_inv)
|
||||
crc = ~crc;
|
||||
|
||||
if (msb_first)
|
||||
crc = __fswab16(crc);
|
||||
|
||||
*skb_put(skb, 1) = crc & 0xFF;
|
||||
*skb_put(skb, 1) = (crc >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
int digital_skb_check_crc(struct sk_buff *skb, crc_func_t crc_func,
|
||||
u16 crc_init, u8 bitwise_inv, u8 msb_first)
|
||||
{
|
||||
int rc;
|
||||
u16 crc;
|
||||
|
||||
if (skb->len <= 2)
|
||||
return -EIO;
|
||||
|
||||
crc = crc_func(crc_init, skb->data, skb->len - 2);
|
||||
|
||||
if (bitwise_inv)
|
||||
crc = ~crc;
|
||||
|
||||
if (msb_first)
|
||||
crc = __swab16(crc);
|
||||
|
||||
rc = (skb->data[skb->len - 2] - (crc & 0xFF)) +
|
||||
(skb->data[skb->len - 1] - ((crc >> 8) & 0xFF));
|
||||
|
||||
if (rc)
|
||||
return -EIO;
|
||||
|
||||
skb_trim(skb, skb->len - 2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void digital_switch_rf(struct nfc_digital_dev *ddev, bool on)
|
||||
{
|
||||
ddev->ops->switch_rf(ddev, on);
|
||||
}
|
||||
|
||||
static inline void digital_abort_cmd(struct nfc_digital_dev *ddev)
|
||||
{
|
||||
ddev->ops->abort_cmd(ddev);
|
||||
}
|
||||
|
||||
static void digital_wq_cmd_complete(struct work_struct *work)
|
||||
{
|
||||
struct digital_cmd *cmd;
|
||||
struct nfc_digital_dev *ddev = container_of(work,
|
||||
struct nfc_digital_dev,
|
||||
cmd_complete_work);
|
||||
|
||||
mutex_lock(&ddev->cmd_lock);
|
||||
|
||||
cmd = list_first_entry_or_null(&ddev->cmd_queue, struct digital_cmd,
|
||||
queue);
|
||||
if (!cmd) {
|
||||
mutex_unlock(&ddev->cmd_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
list_del(&cmd->queue);
|
||||
|
||||
mutex_unlock(&ddev->cmd_lock);
|
||||
|
||||
if (!IS_ERR(cmd->resp))
|
||||
print_hex_dump_debug("DIGITAL RX: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
cmd->resp->data, cmd->resp->len, false);
|
||||
|
||||
cmd->cmd_cb(ddev, cmd->cb_context, cmd->resp);
|
||||
|
||||
kfree(cmd->mdaa_params);
|
||||
kfree(cmd);
|
||||
|
||||
schedule_work(&ddev->cmd_work);
|
||||
}
|
||||
|
||||
static void digital_send_cmd_complete(struct nfc_digital_dev *ddev,
|
||||
void *arg, struct sk_buff *resp)
|
||||
{
|
||||
struct digital_cmd *cmd = arg;
|
||||
|
||||
cmd->resp = resp;
|
||||
|
||||
schedule_work(&ddev->cmd_complete_work);
|
||||
}
|
||||
|
||||
static void digital_wq_cmd(struct work_struct *work)
|
||||
{
|
||||
int rc;
|
||||
struct digital_cmd *cmd;
|
||||
struct digital_tg_mdaa_params *params;
|
||||
struct nfc_digital_dev *ddev = container_of(work,
|
||||
struct nfc_digital_dev,
|
||||
cmd_work);
|
||||
|
||||
mutex_lock(&ddev->cmd_lock);
|
||||
|
||||
cmd = list_first_entry_or_null(&ddev->cmd_queue, struct digital_cmd,
|
||||
queue);
|
||||
if (!cmd || cmd->pending) {
|
||||
mutex_unlock(&ddev->cmd_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_unlock(&ddev->cmd_lock);
|
||||
|
||||
if (cmd->req)
|
||||
print_hex_dump_debug("DIGITAL TX: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
cmd->req->data, cmd->req->len, false);
|
||||
|
||||
switch (cmd->type) {
|
||||
case DIGITAL_CMD_IN_SEND:
|
||||
rc = ddev->ops->in_send_cmd(ddev, cmd->req, cmd->timeout,
|
||||
digital_send_cmd_complete, cmd);
|
||||
break;
|
||||
|
||||
case DIGITAL_CMD_TG_SEND:
|
||||
rc = ddev->ops->tg_send_cmd(ddev, cmd->req, cmd->timeout,
|
||||
digital_send_cmd_complete, cmd);
|
||||
break;
|
||||
|
||||
case DIGITAL_CMD_TG_LISTEN:
|
||||
rc = ddev->ops->tg_listen(ddev, cmd->timeout,
|
||||
digital_send_cmd_complete, cmd);
|
||||
break;
|
||||
|
||||
case DIGITAL_CMD_TG_LISTEN_MDAA:
|
||||
params = cmd->mdaa_params;
|
||||
|
||||
rc = ddev->ops->tg_listen_mdaa(ddev, params, cmd->timeout,
|
||||
digital_send_cmd_complete, cmd);
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_err("Unknown cmd type %d\n", cmd->type);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!rc)
|
||||
return;
|
||||
|
||||
pr_err("in_send_command returned err %d\n", rc);
|
||||
|
||||
mutex_lock(&ddev->cmd_lock);
|
||||
list_del(&cmd->queue);
|
||||
mutex_unlock(&ddev->cmd_lock);
|
||||
|
||||
kfree_skb(cmd->req);
|
||||
kfree(cmd->mdaa_params);
|
||||
kfree(cmd);
|
||||
|
||||
schedule_work(&ddev->cmd_work);
|
||||
}
|
||||
|
||||
int digital_send_cmd(struct nfc_digital_dev *ddev, u8 cmd_type,
|
||||
struct sk_buff *skb, struct digital_tg_mdaa_params *params,
|
||||
u16 timeout, nfc_digital_cmd_complete_t cmd_cb,
|
||||
void *cb_context)
|
||||
{
|
||||
struct digital_cmd *cmd;
|
||||
|
||||
cmd = kzalloc(sizeof(struct digital_cmd), GFP_KERNEL);
|
||||
if (!cmd)
|
||||
return -ENOMEM;
|
||||
|
||||
cmd->type = cmd_type;
|
||||
cmd->timeout = timeout;
|
||||
cmd->req = skb;
|
||||
cmd->mdaa_params = params;
|
||||
cmd->cmd_cb = cmd_cb;
|
||||
cmd->cb_context = cb_context;
|
||||
INIT_LIST_HEAD(&cmd->queue);
|
||||
|
||||
mutex_lock(&ddev->cmd_lock);
|
||||
list_add_tail(&cmd->queue, &ddev->cmd_queue);
|
||||
mutex_unlock(&ddev->cmd_lock);
|
||||
|
||||
schedule_work(&ddev->cmd_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int digital_in_configure_hw(struct nfc_digital_dev *ddev, int type, int param)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ddev->ops->in_configure_hw(ddev, type, param);
|
||||
if (rc)
|
||||
pr_err("in_configure_hw failed: %d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int digital_tg_configure_hw(struct nfc_digital_dev *ddev, int type, int param)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = ddev->ops->tg_configure_hw(ddev, type, param);
|
||||
if (rc)
|
||||
pr_err("tg_configure_hw failed: %d\n", rc);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int digital_tg_listen_mdaa(struct nfc_digital_dev *ddev, u8 rf_tech)
|
||||
{
|
||||
struct digital_tg_mdaa_params *params;
|
||||
|
||||
params = kzalloc(sizeof(struct digital_tg_mdaa_params), GFP_KERNEL);
|
||||
if (!params)
|
||||
return -ENOMEM;
|
||||
|
||||
params->sens_res = DIGITAL_SENS_RES_NFC_DEP;
|
||||
get_random_bytes(params->nfcid1, sizeof(params->nfcid1));
|
||||
params->sel_res = DIGITAL_SEL_RES_NFC_DEP;
|
||||
|
||||
params->nfcid2[0] = DIGITAL_SENSF_NFCID2_NFC_DEP_B1;
|
||||
params->nfcid2[1] = DIGITAL_SENSF_NFCID2_NFC_DEP_B2;
|
||||
get_random_bytes(params->nfcid2 + 2, NFC_NFCID2_MAXSIZE - 2);
|
||||
params->sc = DIGITAL_SENSF_FELICA_SC;
|
||||
|
||||
return digital_send_cmd(ddev, DIGITAL_CMD_TG_LISTEN_MDAA, NULL, params,
|
||||
500, digital_tg_recv_atr_req, NULL);
|
||||
}
|
||||
|
||||
int digital_target_found(struct nfc_digital_dev *ddev,
|
||||
struct nfc_target *target, u8 protocol)
|
||||
{
|
||||
int rc;
|
||||
u8 framing;
|
||||
u8 rf_tech;
|
||||
int (*check_crc)(struct sk_buff *skb);
|
||||
void (*add_crc)(struct sk_buff *skb);
|
||||
|
||||
rf_tech = ddev->poll_techs[ddev->poll_tech_index].rf_tech;
|
||||
|
||||
switch (protocol) {
|
||||
case NFC_PROTO_JEWEL:
|
||||
framing = NFC_DIGITAL_FRAMING_NFCA_T1T;
|
||||
check_crc = digital_skb_check_crc_b;
|
||||
add_crc = digital_skb_add_crc_b;
|
||||
break;
|
||||
|
||||
case NFC_PROTO_MIFARE:
|
||||
framing = NFC_DIGITAL_FRAMING_NFCA_T2T;
|
||||
check_crc = digital_skb_check_crc_a;
|
||||
add_crc = digital_skb_add_crc_a;
|
||||
break;
|
||||
|
||||
case NFC_PROTO_FELICA:
|
||||
framing = NFC_DIGITAL_FRAMING_NFCF_T3T;
|
||||
check_crc = digital_skb_check_crc_f;
|
||||
add_crc = digital_skb_add_crc_f;
|
||||
break;
|
||||
|
||||
case NFC_PROTO_NFC_DEP:
|
||||
if (rf_tech == NFC_DIGITAL_RF_TECH_106A) {
|
||||
framing = NFC_DIGITAL_FRAMING_NFCA_NFC_DEP;
|
||||
check_crc = digital_skb_check_crc_a;
|
||||
add_crc = digital_skb_add_crc_a;
|
||||
} else {
|
||||
framing = NFC_DIGITAL_FRAMING_NFCF_NFC_DEP;
|
||||
check_crc = digital_skb_check_crc_f;
|
||||
add_crc = digital_skb_add_crc_f;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_err("Invalid protocol %d\n", protocol);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
pr_debug("rf_tech=%d, protocol=%d\n", rf_tech, protocol);
|
||||
|
||||
ddev->curr_rf_tech = rf_tech;
|
||||
ddev->curr_protocol = protocol;
|
||||
|
||||
if (DIGITAL_DRV_CAPS_IN_CRC(ddev)) {
|
||||
ddev->skb_add_crc = digital_skb_add_crc_none;
|
||||
ddev->skb_check_crc = digital_skb_check_crc_none;
|
||||
} else {
|
||||
ddev->skb_add_crc = add_crc;
|
||||
ddev->skb_check_crc = check_crc;
|
||||
}
|
||||
|
||||
rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING, framing);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
target->supported_protocols = (1 << protocol);
|
||||
rc = nfc_targets_found(ddev->nfc_dev, target, 1);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
ddev->poll_tech_count = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void digital_poll_next_tech(struct nfc_digital_dev *ddev)
|
||||
{
|
||||
digital_switch_rf(ddev, 0);
|
||||
|
||||
mutex_lock(&ddev->poll_lock);
|
||||
|
||||
if (!ddev->poll_tech_count) {
|
||||
mutex_unlock(&ddev->poll_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
ddev->poll_tech_index = (ddev->poll_tech_index + 1) %
|
||||
ddev->poll_tech_count;
|
||||
|
||||
mutex_unlock(&ddev->poll_lock);
|
||||
|
||||
schedule_work(&ddev->poll_work);
|
||||
}
|
||||
|
||||
static void digital_wq_poll(struct work_struct *work)
|
||||
{
|
||||
int rc;
|
||||
struct digital_poll_tech *poll_tech;
|
||||
struct nfc_digital_dev *ddev = container_of(work,
|
||||
struct nfc_digital_dev,
|
||||
poll_work);
|
||||
mutex_lock(&ddev->poll_lock);
|
||||
|
||||
if (!ddev->poll_tech_count) {
|
||||
mutex_unlock(&ddev->poll_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
poll_tech = &ddev->poll_techs[ddev->poll_tech_index];
|
||||
|
||||
mutex_unlock(&ddev->poll_lock);
|
||||
|
||||
rc = poll_tech->poll_func(ddev, poll_tech->rf_tech);
|
||||
if (rc)
|
||||
digital_poll_next_tech(ddev);
|
||||
}
|
||||
|
||||
static void digital_add_poll_tech(struct nfc_digital_dev *ddev, u8 rf_tech,
|
||||
digital_poll_t poll_func)
|
||||
{
|
||||
struct digital_poll_tech *poll_tech;
|
||||
|
||||
if (ddev->poll_tech_count >= NFC_DIGITAL_POLL_MODE_COUNT_MAX)
|
||||
return;
|
||||
|
||||
poll_tech = &ddev->poll_techs[ddev->poll_tech_count++];
|
||||
|
||||
poll_tech->rf_tech = rf_tech;
|
||||
poll_tech->poll_func = poll_func;
|
||||
}
|
||||
|
||||
/**
|
||||
* start_poll operation
|
||||
*
|
||||
* For every supported protocol, the corresponding polling function is added
|
||||
* to the table of polling technologies (ddev->poll_techs[]) using
|
||||
* digital_add_poll_tech().
|
||||
* When a polling function fails (by timeout or protocol error) the next one is
|
||||
* schedule by digital_poll_next_tech() on the poll workqueue (ddev->poll_work).
|
||||
*/
|
||||
static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols,
|
||||
__u32 tm_protocols)
|
||||
{
|
||||
struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
|
||||
u32 matching_im_protocols, matching_tm_protocols;
|
||||
|
||||
pr_debug("protocols: im 0x%x, tm 0x%x, supported 0x%x\n", im_protocols,
|
||||
tm_protocols, ddev->protocols);
|
||||
|
||||
matching_im_protocols = ddev->protocols & im_protocols;
|
||||
matching_tm_protocols = ddev->protocols & tm_protocols;
|
||||
|
||||
if (!matching_im_protocols && !matching_tm_protocols) {
|
||||
pr_err("Unknown protocol\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (ddev->poll_tech_count) {
|
||||
pr_err("Already polling\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
if (ddev->curr_protocol) {
|
||||
pr_err("A target is already active\n");
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
ddev->poll_tech_count = 0;
|
||||
ddev->poll_tech_index = 0;
|
||||
|
||||
if (matching_im_protocols & DIGITAL_PROTO_NFCA_RF_TECH)
|
||||
digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A,
|
||||
digital_in_send_sens_req);
|
||||
|
||||
if (im_protocols & DIGITAL_PROTO_NFCF_RF_TECH) {
|
||||
digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_212F,
|
||||
digital_in_send_sensf_req);
|
||||
|
||||
digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_424F,
|
||||
digital_in_send_sensf_req);
|
||||
}
|
||||
|
||||
if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
|
||||
if (ddev->ops->tg_listen_mdaa) {
|
||||
digital_add_poll_tech(ddev, 0,
|
||||
digital_tg_listen_mdaa);
|
||||
} else {
|
||||
digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A,
|
||||
digital_tg_listen_nfca);
|
||||
|
||||
digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_212F,
|
||||
digital_tg_listen_nfcf);
|
||||
|
||||
digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_424F,
|
||||
digital_tg_listen_nfcf);
|
||||
}
|
||||
}
|
||||
|
||||
if (!ddev->poll_tech_count) {
|
||||
pr_err("Unsupported protocols: im=0x%x, tm=0x%x\n",
|
||||
matching_im_protocols, matching_tm_protocols);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
schedule_work(&ddev->poll_work);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void digital_stop_poll(struct nfc_dev *nfc_dev)
|
||||
{
|
||||
struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
|
||||
|
||||
mutex_lock(&ddev->poll_lock);
|
||||
|
||||
if (!ddev->poll_tech_count) {
|
||||
pr_err("Polling operation was not running\n");
|
||||
mutex_unlock(&ddev->poll_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
ddev->poll_tech_count = 0;
|
||||
|
||||
mutex_unlock(&ddev->poll_lock);
|
||||
|
||||
cancel_work_sync(&ddev->poll_work);
|
||||
|
||||
digital_abort_cmd(ddev);
|
||||
}
|
||||
|
||||
static int digital_dev_up(struct nfc_dev *nfc_dev)
|
||||
{
|
||||
struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
|
||||
|
||||
digital_switch_rf(ddev, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int digital_dev_down(struct nfc_dev *nfc_dev)
|
||||
{
|
||||
struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
|
||||
|
||||
digital_switch_rf(ddev, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int digital_dep_link_up(struct nfc_dev *nfc_dev,
|
||||
struct nfc_target *target,
|
||||
__u8 comm_mode, __u8 *gb, size_t gb_len)
|
||||
{
|
||||
struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
|
||||
|
||||
return digital_in_send_atr_req(ddev, target, comm_mode, gb, gb_len);
|
||||
}
|
||||
|
||||
static int digital_dep_link_down(struct nfc_dev *nfc_dev)
|
||||
{
|
||||
struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
|
||||
|
||||
ddev->curr_protocol = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int digital_activate_target(struct nfc_dev *nfc_dev,
|
||||
struct nfc_target *target, __u32 protocol)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void digital_deactivate_target(struct nfc_dev *nfc_dev,
|
||||
struct nfc_target *target)
|
||||
{
|
||||
struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
|
||||
|
||||
ddev->curr_protocol = 0;
|
||||
}
|
||||
|
||||
static int digital_tg_send(struct nfc_dev *dev, struct sk_buff *skb)
|
||||
{
|
||||
struct nfc_digital_dev *ddev = nfc_get_drvdata(dev);
|
||||
|
||||
return digital_tg_send_dep_res(ddev, skb);
|
||||
}
|
||||
|
||||
static void digital_in_send_complete(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
struct digital_data_exch *data_exch = arg;
|
||||
int rc;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ddev->curr_protocol == NFC_PROTO_MIFARE)
|
||||
rc = digital_in_recv_mifare_res(resp);
|
||||
else
|
||||
rc = ddev->skb_check_crc(resp);
|
||||
|
||||
if (rc) {
|
||||
kfree_skb(resp);
|
||||
resp = NULL;
|
||||
}
|
||||
|
||||
done:
|
||||
data_exch->cb(data_exch->cb_context, resp, rc);
|
||||
|
||||
kfree(data_exch);
|
||||
}
|
||||
|
||||
static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target,
|
||||
struct sk_buff *skb, data_exchange_cb_t cb,
|
||||
void *cb_context)
|
||||
{
|
||||
struct nfc_digital_dev *ddev = nfc_get_drvdata(nfc_dev);
|
||||
struct digital_data_exch *data_exch;
|
||||
|
||||
data_exch = kzalloc(sizeof(struct digital_data_exch), GFP_KERNEL);
|
||||
if (!data_exch) {
|
||||
pr_err("Failed to allocate data_exch struct\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
data_exch->cb = cb;
|
||||
data_exch->cb_context = cb_context;
|
||||
|
||||
if (ddev->curr_protocol == NFC_PROTO_NFC_DEP)
|
||||
return digital_in_send_dep_req(ddev, target, skb, data_exch);
|
||||
|
||||
ddev->skb_add_crc(skb);
|
||||
|
||||
return digital_in_send_cmd(ddev, skb, 500, digital_in_send_complete,
|
||||
data_exch);
|
||||
}
|
||||
|
||||
static struct nfc_ops digital_nfc_ops = {
|
||||
.dev_up = digital_dev_up,
|
||||
.dev_down = digital_dev_down,
|
||||
.start_poll = digital_start_poll,
|
||||
.stop_poll = digital_stop_poll,
|
||||
.dep_link_up = digital_dep_link_up,
|
||||
.dep_link_down = digital_dep_link_down,
|
||||
.activate_target = digital_activate_target,
|
||||
.deactivate_target = digital_deactivate_target,
|
||||
.tm_send = digital_tg_send,
|
||||
.im_transceive = digital_in_send,
|
||||
};
|
||||
|
||||
struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops,
|
||||
__u32 supported_protocols,
|
||||
__u32 driver_capabilities,
|
||||
int tx_headroom, int tx_tailroom)
|
||||
{
|
||||
struct nfc_digital_dev *ddev;
|
||||
|
||||
if (!ops->in_configure_hw || !ops->in_send_cmd || !ops->tg_listen ||
|
||||
!ops->tg_configure_hw || !ops->tg_send_cmd || !ops->abort_cmd ||
|
||||
!ops->switch_rf)
|
||||
return NULL;
|
||||
|
||||
ddev = kzalloc(sizeof(struct nfc_digital_dev), GFP_KERNEL);
|
||||
if (!ddev)
|
||||
return NULL;
|
||||
|
||||
ddev->driver_capabilities = driver_capabilities;
|
||||
ddev->ops = ops;
|
||||
|
||||
mutex_init(&ddev->cmd_lock);
|
||||
INIT_LIST_HEAD(&ddev->cmd_queue);
|
||||
|
||||
INIT_WORK(&ddev->cmd_work, digital_wq_cmd);
|
||||
INIT_WORK(&ddev->cmd_complete_work, digital_wq_cmd_complete);
|
||||
|
||||
mutex_init(&ddev->poll_lock);
|
||||
INIT_WORK(&ddev->poll_work, digital_wq_poll);
|
||||
|
||||
if (supported_protocols & NFC_PROTO_JEWEL_MASK)
|
||||
ddev->protocols |= NFC_PROTO_JEWEL_MASK;
|
||||
if (supported_protocols & NFC_PROTO_MIFARE_MASK)
|
||||
ddev->protocols |= NFC_PROTO_MIFARE_MASK;
|
||||
if (supported_protocols & NFC_PROTO_FELICA_MASK)
|
||||
ddev->protocols |= NFC_PROTO_FELICA_MASK;
|
||||
if (supported_protocols & NFC_PROTO_NFC_DEP_MASK)
|
||||
ddev->protocols |= NFC_PROTO_NFC_DEP_MASK;
|
||||
|
||||
ddev->tx_headroom = tx_headroom + DIGITAL_MAX_HEADER_LEN;
|
||||
ddev->tx_tailroom = tx_tailroom + DIGITAL_CRC_LEN;
|
||||
|
||||
ddev->nfc_dev = nfc_allocate_device(&digital_nfc_ops, ddev->protocols,
|
||||
ddev->tx_headroom,
|
||||
ddev->tx_tailroom);
|
||||
if (!ddev->nfc_dev) {
|
||||
pr_err("nfc_allocate_device failed\n");
|
||||
goto free_dev;
|
||||
}
|
||||
|
||||
nfc_set_drvdata(ddev->nfc_dev, ddev);
|
||||
|
||||
return ddev;
|
||||
|
||||
free_dev:
|
||||
kfree(ddev);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(nfc_digital_allocate_device);
|
||||
|
||||
void nfc_digital_free_device(struct nfc_digital_dev *ddev)
|
||||
{
|
||||
nfc_free_device(ddev->nfc_dev);
|
||||
kfree(ddev);
|
||||
}
|
||||
EXPORT_SYMBOL(nfc_digital_free_device);
|
||||
|
||||
int nfc_digital_register_device(struct nfc_digital_dev *ddev)
|
||||
{
|
||||
return nfc_register_device(ddev->nfc_dev);
|
||||
}
|
||||
EXPORT_SYMBOL(nfc_digital_register_device);
|
||||
|
||||
void nfc_digital_unregister_device(struct nfc_digital_dev *ddev)
|
||||
{
|
||||
struct digital_cmd *cmd, *n;
|
||||
|
||||
nfc_unregister_device(ddev->nfc_dev);
|
||||
|
||||
mutex_lock(&ddev->poll_lock);
|
||||
ddev->poll_tech_count = 0;
|
||||
mutex_unlock(&ddev->poll_lock);
|
||||
|
||||
cancel_work_sync(&ddev->poll_work);
|
||||
cancel_work_sync(&ddev->cmd_work);
|
||||
cancel_work_sync(&ddev->cmd_complete_work);
|
||||
|
||||
list_for_each_entry_safe(cmd, n, &ddev->cmd_queue, queue) {
|
||||
list_del(&cmd->queue);
|
||||
kfree(cmd->mdaa_params);
|
||||
kfree(cmd);
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL(nfc_digital_unregister_device);
|
||||
|
||||
MODULE_LICENSE("GPL");
|
729
net/nfc/digital_dep.c
Normal file
729
net/nfc/digital_dep.c
Normal file
@ -0,0 +1,729 @@
|
||||
/*
|
||||
* NFC Digital Protocol stack
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "digital: %s: " fmt, __func__
|
||||
|
||||
#include "digital.h"
|
||||
|
||||
#define DIGITAL_NFC_DEP_FRAME_DIR_OUT 0xD4
|
||||
#define DIGITAL_NFC_DEP_FRAME_DIR_IN 0xD5
|
||||
|
||||
#define DIGITAL_NFC_DEP_NFCA_SOD_SB 0xF0
|
||||
|
||||
#define DIGITAL_CMD_ATR_REQ 0x00
|
||||
#define DIGITAL_CMD_ATR_RES 0x01
|
||||
#define DIGITAL_CMD_PSL_REQ 0x04
|
||||
#define DIGITAL_CMD_PSL_RES 0x05
|
||||
#define DIGITAL_CMD_DEP_REQ 0x06
|
||||
#define DIGITAL_CMD_DEP_RES 0x07
|
||||
|
||||
#define DIGITAL_ATR_REQ_MIN_SIZE 16
|
||||
#define DIGITAL_ATR_REQ_MAX_SIZE 64
|
||||
|
||||
#define DIGITAL_NFCID3_LEN ((u8)8)
|
||||
#define DIGITAL_LR_BITS_PAYLOAD_SIZE_254B 0x30
|
||||
#define DIGITAL_GB_BIT 0x02
|
||||
|
||||
#define DIGITAL_NFC_DEP_PFB_TYPE(pfb) ((pfb) & 0xE0)
|
||||
|
||||
#define DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT 0x10
|
||||
|
||||
#define DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb) \
|
||||
((pfb) & DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT)
|
||||
#define DIGITAL_NFC_DEP_MI_BIT_SET(pfb) ((pfb) & 0x10)
|
||||
#define DIGITAL_NFC_DEP_NAD_BIT_SET(pfb) ((pfb) & 0x08)
|
||||
#define DIGITAL_NFC_DEP_DID_BIT_SET(pfb) ((pfb) & 0x04)
|
||||
#define DIGITAL_NFC_DEP_PFB_PNI(pfb) ((pfb) & 0x03)
|
||||
|
||||
#define DIGITAL_NFC_DEP_PFB_I_PDU 0x00
|
||||
#define DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU 0x40
|
||||
#define DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU 0x80
|
||||
|
||||
struct digital_atr_req {
|
||||
u8 dir;
|
||||
u8 cmd;
|
||||
u8 nfcid3[10];
|
||||
u8 did;
|
||||
u8 bs;
|
||||
u8 br;
|
||||
u8 pp;
|
||||
u8 gb[0];
|
||||
} __packed;
|
||||
|
||||
struct digital_atr_res {
|
||||
u8 dir;
|
||||
u8 cmd;
|
||||
u8 nfcid3[10];
|
||||
u8 did;
|
||||
u8 bs;
|
||||
u8 br;
|
||||
u8 to;
|
||||
u8 pp;
|
||||
u8 gb[0];
|
||||
} __packed;
|
||||
|
||||
struct digital_psl_req {
|
||||
u8 dir;
|
||||
u8 cmd;
|
||||
u8 did;
|
||||
u8 brs;
|
||||
u8 fsl;
|
||||
} __packed;
|
||||
|
||||
struct digital_psl_res {
|
||||
u8 dir;
|
||||
u8 cmd;
|
||||
u8 did;
|
||||
} __packed;
|
||||
|
||||
struct digital_dep_req_res {
|
||||
u8 dir;
|
||||
u8 cmd;
|
||||
u8 pfb;
|
||||
} __packed;
|
||||
|
||||
static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp);
|
||||
|
||||
static void digital_skb_push_dep_sod(struct nfc_digital_dev *ddev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
skb_push(skb, sizeof(u8));
|
||||
|
||||
skb->data[0] = skb->len;
|
||||
|
||||
if (ddev->curr_rf_tech == NFC_DIGITAL_RF_TECH_106A)
|
||||
*skb_push(skb, sizeof(u8)) = DIGITAL_NFC_DEP_NFCA_SOD_SB;
|
||||
}
|
||||
|
||||
static int digital_skb_pull_dep_sod(struct nfc_digital_dev *ddev,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
u8 size;
|
||||
|
||||
if (skb->len < 2)
|
||||
return -EIO;
|
||||
|
||||
if (ddev->curr_rf_tech == NFC_DIGITAL_RF_TECH_106A)
|
||||
skb_pull(skb, sizeof(u8));
|
||||
|
||||
size = skb->data[0];
|
||||
if (size != skb->len)
|
||||
return -EIO;
|
||||
|
||||
skb_pull(skb, sizeof(u8));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void digital_in_recv_atr_res(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
struct nfc_target *target = arg;
|
||||
struct digital_atr_res *atr_res;
|
||||
u8 gb_len;
|
||||
int rc;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = ddev->skb_check_crc(resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("14.4.1.6");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = digital_skb_pull_dep_sod(ddev, resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("14.4.1.2");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (resp->len < sizeof(struct digital_atr_res)) {
|
||||
rc = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
gb_len = resp->len - sizeof(struct digital_atr_res);
|
||||
|
||||
atr_res = (struct digital_atr_res *)resp->data;
|
||||
|
||||
rc = nfc_set_remote_general_bytes(ddev->nfc_dev, atr_res->gb, gb_len);
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
rc = nfc_dep_link_is_up(ddev->nfc_dev, target->idx, NFC_COMM_ACTIVE,
|
||||
NFC_RF_INITIATOR);
|
||||
|
||||
ddev->curr_nfc_dep_pni = 0;
|
||||
|
||||
exit:
|
||||
dev_kfree_skb(resp);
|
||||
|
||||
if (rc)
|
||||
ddev->curr_protocol = 0;
|
||||
}
|
||||
|
||||
int digital_in_send_atr_req(struct nfc_digital_dev *ddev,
|
||||
struct nfc_target *target, __u8 comm_mode, __u8 *gb,
|
||||
size_t gb_len)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct digital_atr_req *atr_req;
|
||||
uint size;
|
||||
|
||||
size = DIGITAL_ATR_REQ_MIN_SIZE + gb_len;
|
||||
|
||||
if (size > DIGITAL_ATR_REQ_MAX_SIZE) {
|
||||
PROTOCOL_ERR("14.6.1.1");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
skb = digital_skb_alloc(ddev, size);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_put(skb, sizeof(struct digital_atr_req));
|
||||
|
||||
atr_req = (struct digital_atr_req *)skb->data;
|
||||
memset(atr_req, 0, sizeof(struct digital_atr_req));
|
||||
|
||||
atr_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT;
|
||||
atr_req->cmd = DIGITAL_CMD_ATR_REQ;
|
||||
if (target->nfcid2_len)
|
||||
memcpy(atr_req->nfcid3, target->nfcid2,
|
||||
max(target->nfcid2_len, DIGITAL_NFCID3_LEN));
|
||||
else
|
||||
get_random_bytes(atr_req->nfcid3, DIGITAL_NFCID3_LEN);
|
||||
|
||||
atr_req->did = 0;
|
||||
atr_req->bs = 0;
|
||||
atr_req->br = 0;
|
||||
|
||||
atr_req->pp = DIGITAL_LR_BITS_PAYLOAD_SIZE_254B;
|
||||
|
||||
if (gb_len) {
|
||||
atr_req->pp |= DIGITAL_GB_BIT;
|
||||
memcpy(skb_put(skb, gb_len), gb, gb_len);
|
||||
}
|
||||
|
||||
digital_skb_push_dep_sod(ddev, skb);
|
||||
|
||||
ddev->skb_add_crc(skb);
|
||||
|
||||
digital_in_send_cmd(ddev, skb, 500, digital_in_recv_atr_res, target);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int digital_in_send_rtox(struct nfc_digital_dev *ddev,
|
||||
struct digital_data_exch *data_exch, u8 rtox)
|
||||
{
|
||||
struct digital_dep_req_res *dep_req;
|
||||
struct sk_buff *skb;
|
||||
int rc;
|
||||
|
||||
skb = digital_skb_alloc(ddev, 1);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
*skb_put(skb, 1) = rtox;
|
||||
|
||||
skb_push(skb, sizeof(struct digital_dep_req_res));
|
||||
|
||||
dep_req = (struct digital_dep_req_res *)skb->data;
|
||||
|
||||
dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT;
|
||||
dep_req->cmd = DIGITAL_CMD_DEP_REQ;
|
||||
dep_req->pfb = DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU |
|
||||
DIGITAL_NFC_DEP_PFB_TIMEOUT_BIT;
|
||||
|
||||
digital_skb_push_dep_sod(ddev, skb);
|
||||
|
||||
ddev->skb_add_crc(skb);
|
||||
|
||||
rc = digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res,
|
||||
data_exch);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void digital_in_recv_dep_res(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
struct digital_data_exch *data_exch = arg;
|
||||
struct digital_dep_req_res *dep_res;
|
||||
u8 pfb;
|
||||
uint size;
|
||||
int rc;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = ddev->skb_check_crc(resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("14.4.1.6");
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = digital_skb_pull_dep_sod(ddev, resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("14.4.1.2");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dep_res = (struct digital_dep_req_res *)resp->data;
|
||||
|
||||
if (resp->len < sizeof(struct digital_dep_req_res) ||
|
||||
dep_res->dir != DIGITAL_NFC_DEP_FRAME_DIR_IN ||
|
||||
dep_res->cmd != DIGITAL_CMD_DEP_RES) {
|
||||
rc = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
pfb = dep_res->pfb;
|
||||
|
||||
switch (DIGITAL_NFC_DEP_PFB_TYPE(pfb)) {
|
||||
case DIGITAL_NFC_DEP_PFB_I_PDU:
|
||||
if (DIGITAL_NFC_DEP_PFB_PNI(pfb) != ddev->curr_nfc_dep_pni) {
|
||||
PROTOCOL_ERR("14.12.3.3");
|
||||
rc = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
ddev->curr_nfc_dep_pni =
|
||||
DIGITAL_NFC_DEP_PFB_PNI(ddev->curr_nfc_dep_pni + 1);
|
||||
rc = 0;
|
||||
break;
|
||||
|
||||
case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU:
|
||||
pr_err("Received a ACK/NACK PDU\n");
|
||||
rc = -EIO;
|
||||
goto error;
|
||||
|
||||
case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU:
|
||||
if (!DIGITAL_NFC_DEP_PFB_IS_TIMEOUT(pfb)) {
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
rc = digital_in_send_rtox(ddev, data_exch, resp->data[3]);
|
||||
if (rc)
|
||||
goto error;
|
||||
|
||||
kfree_skb(resp);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DIGITAL_NFC_DEP_MI_BIT_SET(pfb)) {
|
||||
pr_err("MI bit set. Chained PDU not supported\n");
|
||||
rc = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
size = sizeof(struct digital_dep_req_res);
|
||||
|
||||
if (DIGITAL_NFC_DEP_DID_BIT_SET(pfb))
|
||||
size++;
|
||||
|
||||
if (size > resp->len) {
|
||||
rc = -EIO;
|
||||
goto error;
|
||||
}
|
||||
|
||||
skb_pull(resp, size);
|
||||
|
||||
exit:
|
||||
data_exch->cb(data_exch->cb_context, resp, rc);
|
||||
|
||||
error:
|
||||
kfree(data_exch);
|
||||
|
||||
if (rc)
|
||||
kfree_skb(resp);
|
||||
}
|
||||
|
||||
int digital_in_send_dep_req(struct nfc_digital_dev *ddev,
|
||||
struct nfc_target *target, struct sk_buff *skb,
|
||||
struct digital_data_exch *data_exch)
|
||||
{
|
||||
struct digital_dep_req_res *dep_req;
|
||||
|
||||
skb_push(skb, sizeof(struct digital_dep_req_res));
|
||||
|
||||
dep_req = (struct digital_dep_req_res *)skb->data;
|
||||
dep_req->dir = DIGITAL_NFC_DEP_FRAME_DIR_OUT;
|
||||
dep_req->cmd = DIGITAL_CMD_DEP_REQ;
|
||||
dep_req->pfb = ddev->curr_nfc_dep_pni;
|
||||
|
||||
digital_skb_push_dep_sod(ddev, skb);
|
||||
|
||||
ddev->skb_add_crc(skb);
|
||||
|
||||
return digital_in_send_cmd(ddev, skb, 1500, digital_in_recv_dep_res,
|
||||
data_exch);
|
||||
}
|
||||
|
||||
static void digital_tg_recv_dep_req(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
int rc;
|
||||
struct digital_dep_req_res *dep_req;
|
||||
size_t size;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = ddev->skb_check_crc(resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("14.4.1.6");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = digital_skb_pull_dep_sod(ddev, resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("14.4.1.2");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
size = sizeof(struct digital_dep_req_res);
|
||||
dep_req = (struct digital_dep_req_res *)resp->data;
|
||||
|
||||
if (resp->len < size || dep_req->dir != DIGITAL_NFC_DEP_FRAME_DIR_OUT ||
|
||||
dep_req->cmd != DIGITAL_CMD_DEP_REQ) {
|
||||
rc = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (DIGITAL_NFC_DEP_DID_BIT_SET(dep_req->pfb))
|
||||
size++;
|
||||
|
||||
if (resp->len < size) {
|
||||
rc = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
switch (DIGITAL_NFC_DEP_PFB_TYPE(dep_req->pfb)) {
|
||||
case DIGITAL_NFC_DEP_PFB_I_PDU:
|
||||
pr_debug("DIGITAL_NFC_DEP_PFB_I_PDU\n");
|
||||
ddev->curr_nfc_dep_pni = DIGITAL_NFC_DEP_PFB_PNI(dep_req->pfb);
|
||||
break;
|
||||
case DIGITAL_NFC_DEP_PFB_ACK_NACK_PDU:
|
||||
pr_err("Received a ACK/NACK PDU\n");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
break;
|
||||
case DIGITAL_NFC_DEP_PFB_SUPERVISOR_PDU:
|
||||
pr_err("Received a SUPERVISOR PDU\n");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
break;
|
||||
}
|
||||
|
||||
skb_pull(resp, size);
|
||||
|
||||
rc = nfc_tm_data_received(ddev->nfc_dev, resp);
|
||||
|
||||
exit:
|
||||
if (rc)
|
||||
kfree_skb(resp);
|
||||
}
|
||||
|
||||
int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb)
|
||||
{
|
||||
struct digital_dep_req_res *dep_res;
|
||||
|
||||
skb_push(skb, sizeof(struct digital_dep_req_res));
|
||||
dep_res = (struct digital_dep_req_res *)skb->data;
|
||||
|
||||
dep_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN;
|
||||
dep_res->cmd = DIGITAL_CMD_DEP_RES;
|
||||
dep_res->pfb = ddev->curr_nfc_dep_pni;
|
||||
|
||||
digital_skb_push_dep_sod(ddev, skb);
|
||||
|
||||
ddev->skb_add_crc(skb);
|
||||
|
||||
return digital_tg_send_cmd(ddev, skb, 1500, digital_tg_recv_dep_req,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void digital_tg_send_psl_res_complete(struct nfc_digital_dev *ddev,
|
||||
void *arg, struct sk_buff *resp)
|
||||
{
|
||||
u8 rf_tech = PTR_ERR(arg);
|
||||
|
||||
if (IS_ERR(resp))
|
||||
return;
|
||||
|
||||
digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech);
|
||||
|
||||
digital_tg_listen(ddev, 1500, digital_tg_recv_dep_req, NULL);
|
||||
|
||||
dev_kfree_skb(resp);
|
||||
}
|
||||
|
||||
static int digital_tg_send_psl_res(struct nfc_digital_dev *ddev, u8 did,
|
||||
u8 rf_tech)
|
||||
{
|
||||
struct digital_psl_res *psl_res;
|
||||
struct sk_buff *skb;
|
||||
int rc;
|
||||
|
||||
skb = digital_skb_alloc(ddev, sizeof(struct digital_psl_res));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_put(skb, sizeof(struct digital_psl_res));
|
||||
|
||||
psl_res = (struct digital_psl_res *)skb->data;
|
||||
|
||||
psl_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN;
|
||||
psl_res->cmd = DIGITAL_CMD_PSL_RES;
|
||||
psl_res->did = did;
|
||||
|
||||
digital_skb_push_dep_sod(ddev, skb);
|
||||
|
||||
ddev->skb_add_crc(skb);
|
||||
|
||||
rc = digital_tg_send_cmd(ddev, skb, 0, digital_tg_send_psl_res_complete,
|
||||
ERR_PTR(rf_tech));
|
||||
|
||||
if (rc)
|
||||
kfree_skb(skb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void digital_tg_recv_psl_req(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
int rc;
|
||||
struct digital_psl_req *psl_req;
|
||||
u8 rf_tech;
|
||||
u8 dsi;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = ddev->skb_check_crc(resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("14.4.1.6");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = digital_skb_pull_dep_sod(ddev, resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("14.4.1.2");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
psl_req = (struct digital_psl_req *)resp->data;
|
||||
|
||||
if (resp->len != sizeof(struct digital_psl_req) ||
|
||||
psl_req->dir != DIGITAL_NFC_DEP_FRAME_DIR_OUT ||
|
||||
psl_req->cmd != DIGITAL_CMD_PSL_REQ) {
|
||||
rc = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
dsi = (psl_req->brs >> 3) & 0x07;
|
||||
switch (dsi) {
|
||||
case 0:
|
||||
rf_tech = NFC_DIGITAL_RF_TECH_106A;
|
||||
break;
|
||||
case 1:
|
||||
rf_tech = NFC_DIGITAL_RF_TECH_212F;
|
||||
break;
|
||||
case 2:
|
||||
rf_tech = NFC_DIGITAL_RF_TECH_424F;
|
||||
break;
|
||||
default:
|
||||
pr_err("Unsuported dsi value %d\n", dsi);
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = digital_tg_send_psl_res(ddev, psl_req->did, rf_tech);
|
||||
|
||||
exit:
|
||||
kfree_skb(resp);
|
||||
}
|
||||
|
||||
static void digital_tg_send_atr_res_complete(struct nfc_digital_dev *ddev,
|
||||
void *arg, struct sk_buff *resp)
|
||||
{
|
||||
int offset;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
digital_poll_next_tech(ddev);
|
||||
return;
|
||||
}
|
||||
|
||||
offset = 2;
|
||||
if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB)
|
||||
offset++;
|
||||
|
||||
if (resp->data[offset] == DIGITAL_CMD_PSL_REQ)
|
||||
digital_tg_recv_psl_req(ddev, arg, resp);
|
||||
else
|
||||
digital_tg_recv_dep_req(ddev, arg, resp);
|
||||
}
|
||||
|
||||
static int digital_tg_send_atr_res(struct nfc_digital_dev *ddev,
|
||||
struct digital_atr_req *atr_req)
|
||||
{
|
||||
struct digital_atr_res *atr_res;
|
||||
struct sk_buff *skb;
|
||||
u8 *gb;
|
||||
size_t gb_len;
|
||||
int rc;
|
||||
|
||||
gb = nfc_get_local_general_bytes(ddev->nfc_dev, &gb_len);
|
||||
if (!gb)
|
||||
gb_len = 0;
|
||||
|
||||
skb = digital_skb_alloc(ddev, sizeof(struct digital_atr_res) + gb_len);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_put(skb, sizeof(struct digital_atr_res));
|
||||
atr_res = (struct digital_atr_res *)skb->data;
|
||||
|
||||
memset(atr_res, 0, sizeof(struct digital_atr_res));
|
||||
|
||||
atr_res->dir = DIGITAL_NFC_DEP_FRAME_DIR_IN;
|
||||
atr_res->cmd = DIGITAL_CMD_ATR_RES;
|
||||
memcpy(atr_res->nfcid3, atr_req->nfcid3, sizeof(atr_req->nfcid3));
|
||||
atr_res->to = 8;
|
||||
atr_res->pp = DIGITAL_LR_BITS_PAYLOAD_SIZE_254B;
|
||||
if (gb_len) {
|
||||
skb_put(skb, gb_len);
|
||||
|
||||
atr_res->pp |= DIGITAL_GB_BIT;
|
||||
memcpy(atr_res->gb, gb, gb_len);
|
||||
}
|
||||
|
||||
digital_skb_push_dep_sod(ddev, skb);
|
||||
|
||||
ddev->skb_add_crc(skb);
|
||||
|
||||
rc = digital_tg_send_cmd(ddev, skb, 999,
|
||||
digital_tg_send_atr_res_complete, NULL);
|
||||
if (rc) {
|
||||
kfree_skb(skb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
int rc;
|
||||
struct digital_atr_req *atr_req;
|
||||
size_t gb_len, min_size;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!resp->len) {
|
||||
rc = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (resp->data[0] == DIGITAL_NFC_DEP_NFCA_SOD_SB) {
|
||||
min_size = DIGITAL_ATR_REQ_MIN_SIZE + 2;
|
||||
|
||||
ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_106A;
|
||||
ddev->skb_add_crc = digital_skb_add_crc_a;
|
||||
ddev->skb_check_crc = digital_skb_check_crc_a;
|
||||
} else {
|
||||
min_size = DIGITAL_ATR_REQ_MIN_SIZE + 1;
|
||||
|
||||
ddev->curr_rf_tech = NFC_DIGITAL_RF_TECH_212F;
|
||||
ddev->skb_add_crc = digital_skb_add_crc_f;
|
||||
ddev->skb_check_crc = digital_skb_check_crc_f;
|
||||
}
|
||||
|
||||
if (resp->len < min_size) {
|
||||
rc = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (DIGITAL_DRV_CAPS_TG_CRC(ddev)) {
|
||||
ddev->skb_add_crc = digital_skb_add_crc_none;
|
||||
ddev->skb_check_crc = digital_skb_check_crc_none;
|
||||
}
|
||||
|
||||
rc = ddev->skb_check_crc(resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("14.4.1.6");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = digital_skb_pull_dep_sod(ddev, resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("14.4.1.2");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
atr_req = (struct digital_atr_req *)resp->data;
|
||||
|
||||
if (atr_req->dir != DIGITAL_NFC_DEP_FRAME_DIR_OUT ||
|
||||
atr_req->cmd != DIGITAL_CMD_ATR_REQ) {
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
|
||||
NFC_DIGITAL_FRAMING_NFC_DEP_ACTIVATED);
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
rc = digital_tg_send_atr_res(ddev, atr_req);
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
gb_len = resp->len - sizeof(struct digital_atr_req);
|
||||
rc = nfc_tm_activated(ddev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
|
||||
NFC_COMM_PASSIVE, atr_req->gb, gb_len);
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
ddev->poll_tech_count = 0;
|
||||
|
||||
rc = 0;
|
||||
exit:
|
||||
if (rc)
|
||||
digital_poll_next_tech(ddev);
|
||||
|
||||
dev_kfree_skb(resp);
|
||||
}
|
770
net/nfc/digital_technology.c
Normal file
770
net/nfc/digital_technology.c
Normal file
@ -0,0 +1,770 @@
|
||||
/*
|
||||
* NFC Digital Protocol stack
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) "digital: %s: " fmt, __func__
|
||||
|
||||
#include "digital.h"
|
||||
|
||||
#define DIGITAL_CMD_SENS_REQ 0x26
|
||||
#define DIGITAL_CMD_ALL_REQ 0x52
|
||||
#define DIGITAL_CMD_SEL_REQ_CL1 0x93
|
||||
#define DIGITAL_CMD_SEL_REQ_CL2 0x95
|
||||
#define DIGITAL_CMD_SEL_REQ_CL3 0x97
|
||||
|
||||
#define DIGITAL_SDD_REQ_SEL_PAR 0x20
|
||||
|
||||
#define DIGITAL_SDD_RES_CT 0x88
|
||||
#define DIGITAL_SDD_RES_LEN 5
|
||||
|
||||
#define DIGITAL_SEL_RES_NFCID1_COMPLETE(sel_res) (!((sel_res) & 0x04))
|
||||
#define DIGITAL_SEL_RES_IS_T2T(sel_res) (!((sel_res) & 0x60))
|
||||
#define DIGITAL_SEL_RES_IS_NFC_DEP(sel_res) ((sel_res) & 0x40)
|
||||
|
||||
#define DIGITAL_SENS_RES_IS_T1T(sens_res) (((sens_res) & 0x0C00) == 0x0C00)
|
||||
#define DIGITAL_SENS_RES_IS_VALID(sens_res) \
|
||||
((!((sens_res) & 0x001F) && (((sens_res) & 0x0C00) == 0x0C00)) || \
|
||||
(((sens_res) & 0x001F) && ((sens_res) & 0x0C00) != 0x0C00))
|
||||
|
||||
#define DIGITAL_MIFARE_READ_RES_LEN 16
|
||||
#define DIGITAL_MIFARE_ACK_RES 0x0A
|
||||
|
||||
#define DIGITAL_CMD_SENSF_REQ 0x00
|
||||
#define DIGITAL_CMD_SENSF_RES 0x01
|
||||
|
||||
#define DIGITAL_SENSF_RES_MIN_LENGTH 17
|
||||
#define DIGITAL_SENSF_RES_RD_AP_B1 0x00
|
||||
#define DIGITAL_SENSF_RES_RD_AP_B2 0x8F
|
||||
|
||||
#define DIGITAL_SENSF_REQ_RC_NONE 0
|
||||
#define DIGITAL_SENSF_REQ_RC_SC 1
|
||||
#define DIGITAL_SENSF_REQ_RC_AP 2
|
||||
|
||||
struct digital_sdd_res {
|
||||
u8 nfcid1[4];
|
||||
u8 bcc;
|
||||
} __packed;
|
||||
|
||||
struct digital_sel_req {
|
||||
u8 sel_cmd;
|
||||
u8 b2;
|
||||
u8 nfcid1[4];
|
||||
u8 bcc;
|
||||
} __packed;
|
||||
|
||||
struct digital_sensf_req {
|
||||
u8 cmd;
|
||||
u8 sc1;
|
||||
u8 sc2;
|
||||
u8 rc;
|
||||
u8 tsn;
|
||||
} __packed;
|
||||
|
||||
struct digital_sensf_res {
|
||||
u8 cmd;
|
||||
u8 nfcid2[8];
|
||||
u8 pad0[2];
|
||||
u8 pad1[3];
|
||||
u8 mrti_check;
|
||||
u8 mrti_update;
|
||||
u8 pad2;
|
||||
u8 rd[2];
|
||||
} __packed;
|
||||
|
||||
static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev,
|
||||
struct nfc_target *target);
|
||||
|
||||
static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
struct nfc_target *target = arg;
|
||||
int rc;
|
||||
u8 sel_res;
|
||||
u8 nfc_proto;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!DIGITAL_DRV_CAPS_IN_CRC(ddev)) {
|
||||
rc = digital_skb_check_crc_a(resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("4.4.1.3");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (!resp->len) {
|
||||
rc = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sel_res = resp->data[0];
|
||||
|
||||
if (!DIGITAL_SEL_RES_NFCID1_COMPLETE(sel_res)) {
|
||||
rc = digital_in_send_sdd_req(ddev, target);
|
||||
if (rc)
|
||||
goto exit;
|
||||
|
||||
goto exit_free_skb;
|
||||
}
|
||||
|
||||
if (DIGITAL_SEL_RES_IS_T2T(sel_res)) {
|
||||
nfc_proto = NFC_PROTO_MIFARE;
|
||||
} else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) {
|
||||
nfc_proto = NFC_PROTO_NFC_DEP;
|
||||
} else {
|
||||
rc = -EOPNOTSUPP;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
target->sel_res = sel_res;
|
||||
|
||||
rc = digital_target_found(ddev, target, nfc_proto);
|
||||
|
||||
exit:
|
||||
kfree(target);
|
||||
|
||||
exit_free_skb:
|
||||
dev_kfree_skb(resp);
|
||||
|
||||
if (rc)
|
||||
digital_poll_next_tech(ddev);
|
||||
}
|
||||
|
||||
static int digital_in_send_sel_req(struct nfc_digital_dev *ddev,
|
||||
struct nfc_target *target,
|
||||
struct digital_sdd_res *sdd_res)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct digital_sel_req *sel_req;
|
||||
u8 sel_cmd;
|
||||
int rc;
|
||||
|
||||
skb = digital_skb_alloc(ddev, sizeof(struct digital_sel_req));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_put(skb, sizeof(struct digital_sel_req));
|
||||
sel_req = (struct digital_sel_req *)skb->data;
|
||||
|
||||
if (target->nfcid1_len <= 4)
|
||||
sel_cmd = DIGITAL_CMD_SEL_REQ_CL1;
|
||||
else if (target->nfcid1_len < 10)
|
||||
sel_cmd = DIGITAL_CMD_SEL_REQ_CL2;
|
||||
else
|
||||
sel_cmd = DIGITAL_CMD_SEL_REQ_CL3;
|
||||
|
||||
sel_req->sel_cmd = sel_cmd;
|
||||
sel_req->b2 = 0x70;
|
||||
memcpy(sel_req->nfcid1, sdd_res->nfcid1, 4);
|
||||
sel_req->bcc = sdd_res->bcc;
|
||||
|
||||
if (DIGITAL_DRV_CAPS_IN_CRC(ddev)) {
|
||||
rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
|
||||
NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A);
|
||||
if (rc)
|
||||
goto exit;
|
||||
} else {
|
||||
digital_skb_add_crc_a(skb);
|
||||
}
|
||||
|
||||
rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sel_res,
|
||||
target);
|
||||
exit:
|
||||
if (rc)
|
||||
kfree_skb(skb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void digital_in_recv_sdd_res(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
struct nfc_target *target = arg;
|
||||
struct digital_sdd_res *sdd_res;
|
||||
int rc;
|
||||
u8 offset, size;
|
||||
u8 i, bcc;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (resp->len < DIGITAL_SDD_RES_LEN) {
|
||||
PROTOCOL_ERR("4.7.2.8");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sdd_res = (struct digital_sdd_res *)resp->data;
|
||||
|
||||
for (i = 0, bcc = 0; i < 4; i++)
|
||||
bcc ^= sdd_res->nfcid1[i];
|
||||
|
||||
if (bcc != sdd_res->bcc) {
|
||||
PROTOCOL_ERR("4.7.2.6");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (sdd_res->nfcid1[0] == DIGITAL_SDD_RES_CT) {
|
||||
offset = 1;
|
||||
size = 3;
|
||||
} else {
|
||||
offset = 0;
|
||||
size = 4;
|
||||
}
|
||||
|
||||
memcpy(target->nfcid1 + target->nfcid1_len, sdd_res->nfcid1 + offset,
|
||||
size);
|
||||
target->nfcid1_len += size;
|
||||
|
||||
rc = digital_in_send_sel_req(ddev, target, sdd_res);
|
||||
|
||||
exit:
|
||||
dev_kfree_skb(resp);
|
||||
|
||||
if (rc) {
|
||||
kfree(target);
|
||||
digital_poll_next_tech(ddev);
|
||||
}
|
||||
}
|
||||
|
||||
static int digital_in_send_sdd_req(struct nfc_digital_dev *ddev,
|
||||
struct nfc_target *target)
|
||||
{
|
||||
int rc;
|
||||
struct sk_buff *skb;
|
||||
u8 sel_cmd;
|
||||
|
||||
rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
|
||||
NFC_DIGITAL_FRAMING_NFCA_STANDARD);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
skb = digital_skb_alloc(ddev, 2);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
if (target->nfcid1_len == 0)
|
||||
sel_cmd = DIGITAL_CMD_SEL_REQ_CL1;
|
||||
else if (target->nfcid1_len == 3)
|
||||
sel_cmd = DIGITAL_CMD_SEL_REQ_CL2;
|
||||
else
|
||||
sel_cmd = DIGITAL_CMD_SEL_REQ_CL3;
|
||||
|
||||
*skb_put(skb, sizeof(u8)) = sel_cmd;
|
||||
*skb_put(skb, sizeof(u8)) = DIGITAL_SDD_REQ_SEL_PAR;
|
||||
|
||||
return digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sdd_res,
|
||||
target);
|
||||
}
|
||||
|
||||
static void digital_in_recv_sens_res(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
struct nfc_target *target = NULL;
|
||||
int rc;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (resp->len < sizeof(u16)) {
|
||||
rc = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
target = kzalloc(sizeof(struct nfc_target), GFP_KERNEL);
|
||||
if (!target) {
|
||||
rc = -ENOMEM;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
target->sens_res = __le16_to_cpu(*(__le16 *)resp->data);
|
||||
|
||||
if (!DIGITAL_SENS_RES_IS_VALID(target->sens_res)) {
|
||||
PROTOCOL_ERR("4.6.3.3");
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (DIGITAL_SENS_RES_IS_T1T(target->sens_res))
|
||||
rc = digital_target_found(ddev, target, NFC_PROTO_JEWEL);
|
||||
else
|
||||
rc = digital_in_send_sdd_req(ddev, target);
|
||||
|
||||
exit:
|
||||
dev_kfree_skb(resp);
|
||||
|
||||
if (rc) {
|
||||
kfree(target);
|
||||
digital_poll_next_tech(ddev);
|
||||
}
|
||||
}
|
||||
|
||||
int digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int rc;
|
||||
|
||||
rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH,
|
||||
NFC_DIGITAL_RF_TECH_106A);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
|
||||
NFC_DIGITAL_FRAMING_NFCA_SHORT);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
skb = digital_skb_alloc(ddev, 1);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
*skb_put(skb, sizeof(u8)) = DIGITAL_CMD_SENS_REQ;
|
||||
|
||||
rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sens_res, NULL);
|
||||
if (rc)
|
||||
kfree_skb(skb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int digital_in_recv_mifare_res(struct sk_buff *resp)
|
||||
{
|
||||
/* Successful READ command response is 16 data bytes + 2 CRC bytes long.
|
||||
* Since the driver can't differentiate a ACK/NACK response from a valid
|
||||
* READ response, the CRC calculation must be handled at digital level
|
||||
* even if the driver supports it for this technology.
|
||||
*/
|
||||
if (resp->len == DIGITAL_MIFARE_READ_RES_LEN + DIGITAL_CRC_LEN) {
|
||||
if (digital_skb_check_crc_a(resp)) {
|
||||
PROTOCOL_ERR("9.4.1.2");
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ACK response (i.e. successful WRITE). */
|
||||
if (resp->len == 1 && resp->data[0] == DIGITAL_MIFARE_ACK_RES) {
|
||||
resp->data[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* NACK and any other responses are treated as error. */
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void digital_in_recv_sensf_res(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
int rc;
|
||||
u8 proto;
|
||||
struct nfc_target target;
|
||||
struct digital_sensf_res *sensf_res;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (resp->len < DIGITAL_SENSF_RES_MIN_LENGTH) {
|
||||
rc = -EIO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!DIGITAL_DRV_CAPS_IN_CRC(ddev)) {
|
||||
rc = digital_skb_check_crc_f(resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("6.4.1.8");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
skb_pull(resp, 1);
|
||||
|
||||
memset(&target, 0, sizeof(struct nfc_target));
|
||||
|
||||
sensf_res = (struct digital_sensf_res *)resp->data;
|
||||
|
||||
memcpy(target.sensf_res, sensf_res, resp->len);
|
||||
target.sensf_res_len = resp->len;
|
||||
|
||||
memcpy(target.nfcid2, sensf_res->nfcid2, NFC_NFCID2_MAXSIZE);
|
||||
target.nfcid2_len = NFC_NFCID2_MAXSIZE;
|
||||
|
||||
if (target.nfcid2[0] == DIGITAL_SENSF_NFCID2_NFC_DEP_B1 &&
|
||||
target.nfcid2[1] == DIGITAL_SENSF_NFCID2_NFC_DEP_B2)
|
||||
proto = NFC_PROTO_NFC_DEP;
|
||||
else
|
||||
proto = NFC_PROTO_FELICA;
|
||||
|
||||
rc = digital_target_found(ddev, &target, proto);
|
||||
|
||||
exit:
|
||||
dev_kfree_skb(resp);
|
||||
|
||||
if (rc)
|
||||
digital_poll_next_tech(ddev);
|
||||
}
|
||||
|
||||
int digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech)
|
||||
{
|
||||
struct digital_sensf_req *sensf_req;
|
||||
struct sk_buff *skb;
|
||||
int rc;
|
||||
u8 size;
|
||||
|
||||
rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
|
||||
NFC_DIGITAL_FRAMING_NFCF);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
size = sizeof(struct digital_sensf_req);
|
||||
|
||||
skb = digital_skb_alloc(ddev, size);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_put(skb, size);
|
||||
|
||||
sensf_req = (struct digital_sensf_req *)skb->data;
|
||||
sensf_req->cmd = DIGITAL_CMD_SENSF_REQ;
|
||||
sensf_req->sc1 = 0xFF;
|
||||
sensf_req->sc2 = 0xFF;
|
||||
sensf_req->rc = 0;
|
||||
sensf_req->tsn = 0;
|
||||
|
||||
*skb_push(skb, 1) = size + 1;
|
||||
|
||||
if (!DIGITAL_DRV_CAPS_IN_CRC(ddev))
|
||||
digital_skb_add_crc_f(skb);
|
||||
|
||||
rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sensf_res,
|
||||
NULL);
|
||||
if (rc)
|
||||
kfree_skb(skb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int digital_tg_send_sel_res(struct nfc_digital_dev *ddev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int rc;
|
||||
|
||||
skb = digital_skb_alloc(ddev, 1);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
*skb_put(skb, 1) = DIGITAL_SEL_RES_NFC_DEP;
|
||||
|
||||
if (!DIGITAL_DRV_CAPS_TG_CRC(ddev))
|
||||
digital_skb_add_crc_a(skb);
|
||||
|
||||
rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_atr_req,
|
||||
NULL);
|
||||
if (rc)
|
||||
kfree_skb(skb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void digital_tg_recv_sel_req(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
int rc;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!DIGITAL_DRV_CAPS_TG_CRC(ddev)) {
|
||||
rc = digital_skb_check_crc_a(resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("4.4.1.3");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
/* Silently ignore SEL_REQ content and send a SEL_RES for NFC-DEP */
|
||||
|
||||
rc = digital_tg_send_sel_res(ddev);
|
||||
|
||||
exit:
|
||||
if (rc)
|
||||
digital_poll_next_tech(ddev);
|
||||
|
||||
dev_kfree_skb(resp);
|
||||
}
|
||||
|
||||
static int digital_tg_send_sdd_res(struct nfc_digital_dev *ddev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct digital_sdd_res *sdd_res;
|
||||
int rc, i;
|
||||
|
||||
skb = digital_skb_alloc(ddev, sizeof(struct digital_sdd_res));
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_put(skb, sizeof(struct digital_sdd_res));
|
||||
sdd_res = (struct digital_sdd_res *)skb->data;
|
||||
|
||||
sdd_res->nfcid1[0] = 0x08;
|
||||
get_random_bytes(sdd_res->nfcid1 + 1, 3);
|
||||
|
||||
sdd_res->bcc = 0;
|
||||
for (i = 0; i < 4; i++)
|
||||
sdd_res->bcc ^= sdd_res->nfcid1[i];
|
||||
|
||||
rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sel_req,
|
||||
NULL);
|
||||
if (rc)
|
||||
kfree_skb(skb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void digital_tg_recv_sdd_req(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
u8 *sdd_req;
|
||||
int rc;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sdd_req = resp->data;
|
||||
|
||||
if (resp->len < 2 || sdd_req[0] != DIGITAL_CMD_SEL_REQ_CL1 ||
|
||||
sdd_req[1] != DIGITAL_SDD_REQ_SEL_PAR) {
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = digital_tg_send_sdd_res(ddev);
|
||||
|
||||
exit:
|
||||
if (rc)
|
||||
digital_poll_next_tech(ddev);
|
||||
|
||||
dev_kfree_skb(resp);
|
||||
}
|
||||
|
||||
static int digital_tg_send_sens_res(struct nfc_digital_dev *ddev)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u8 *sens_res;
|
||||
int rc;
|
||||
|
||||
skb = digital_skb_alloc(ddev, 2);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
sens_res = skb_put(skb, 2);
|
||||
|
||||
sens_res[0] = (DIGITAL_SENS_RES_NFC_DEP >> 8) & 0xFF;
|
||||
sens_res[1] = DIGITAL_SENS_RES_NFC_DEP & 0xFF;
|
||||
|
||||
rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sdd_req,
|
||||
NULL);
|
||||
if (rc)
|
||||
kfree_skb(skb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void digital_tg_recv_sens_req(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
u8 sens_req;
|
||||
int rc;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
sens_req = resp->data[0];
|
||||
|
||||
if (!resp->len || (sens_req != DIGITAL_CMD_SENS_REQ &&
|
||||
sens_req != DIGITAL_CMD_ALL_REQ)) {
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = digital_tg_send_sens_res(ddev);
|
||||
|
||||
exit:
|
||||
if (rc)
|
||||
digital_poll_next_tech(ddev);
|
||||
|
||||
dev_kfree_skb(resp);
|
||||
}
|
||||
|
||||
static int digital_tg_send_sensf_res(struct nfc_digital_dev *ddev,
|
||||
struct digital_sensf_req *sensf_req)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
u8 size;
|
||||
int rc;
|
||||
struct digital_sensf_res *sensf_res;
|
||||
|
||||
size = sizeof(struct digital_sensf_res);
|
||||
|
||||
if (sensf_req->rc != DIGITAL_SENSF_REQ_RC_NONE)
|
||||
size -= sizeof(sensf_res->rd);
|
||||
|
||||
skb = digital_skb_alloc(ddev, size);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_put(skb, size);
|
||||
|
||||
sensf_res = (struct digital_sensf_res *)skb->data;
|
||||
|
||||
memset(sensf_res, 0, size);
|
||||
|
||||
sensf_res->cmd = DIGITAL_CMD_SENSF_RES;
|
||||
sensf_res->nfcid2[0] = DIGITAL_SENSF_NFCID2_NFC_DEP_B1;
|
||||
sensf_res->nfcid2[1] = DIGITAL_SENSF_NFCID2_NFC_DEP_B2;
|
||||
get_random_bytes(&sensf_res->nfcid2[2], 6);
|
||||
|
||||
switch (sensf_req->rc) {
|
||||
case DIGITAL_SENSF_REQ_RC_SC:
|
||||
sensf_res->rd[0] = sensf_req->sc1;
|
||||
sensf_res->rd[1] = sensf_req->sc2;
|
||||
break;
|
||||
case DIGITAL_SENSF_REQ_RC_AP:
|
||||
sensf_res->rd[0] = DIGITAL_SENSF_RES_RD_AP_B1;
|
||||
sensf_res->rd[1] = DIGITAL_SENSF_RES_RD_AP_B2;
|
||||
break;
|
||||
}
|
||||
|
||||
*skb_push(skb, sizeof(u8)) = size + 1;
|
||||
|
||||
if (!DIGITAL_DRV_CAPS_TG_CRC(ddev))
|
||||
digital_skb_add_crc_f(skb);
|
||||
|
||||
rc = digital_tg_send_cmd(ddev, skb, 300,
|
||||
digital_tg_recv_atr_req, NULL);
|
||||
if (rc)
|
||||
kfree_skb(skb);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
void digital_tg_recv_sensf_req(struct nfc_digital_dev *ddev, void *arg,
|
||||
struct sk_buff *resp)
|
||||
{
|
||||
struct digital_sensf_req *sensf_req;
|
||||
int rc;
|
||||
|
||||
if (IS_ERR(resp)) {
|
||||
rc = PTR_ERR(resp);
|
||||
resp = NULL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if (!DIGITAL_DRV_CAPS_TG_CRC(ddev)) {
|
||||
rc = digital_skb_check_crc_f(resp);
|
||||
if (rc) {
|
||||
PROTOCOL_ERR("6.4.1.8");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
|
||||
if (resp->len != sizeof(struct digital_sensf_req) + 1) {
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
skb_pull(resp, 1);
|
||||
sensf_req = (struct digital_sensf_req *)resp->data;
|
||||
|
||||
if (sensf_req->cmd != DIGITAL_CMD_SENSF_REQ) {
|
||||
rc = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
rc = digital_tg_send_sensf_res(ddev, sensf_req);
|
||||
|
||||
exit:
|
||||
if (rc)
|
||||
digital_poll_next_tech(ddev);
|
||||
|
||||
dev_kfree_skb(resp);
|
||||
}
|
||||
|
||||
int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech)
|
||||
{
|
||||
int rc;
|
||||
|
||||
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
|
||||
NFC_DIGITAL_FRAMING_NFCA_NFC_DEP);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
return digital_tg_listen(ddev, 300, digital_tg_recv_sens_req, NULL);
|
||||
}
|
||||
|
||||
int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech)
|
||||
{
|
||||
int rc;
|
||||
u8 *nfcid2;
|
||||
|
||||
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
|
||||
NFC_DIGITAL_FRAMING_NFCF_NFC_DEP);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
nfcid2 = kzalloc(NFC_NFCID2_MAXSIZE, GFP_KERNEL);
|
||||
if (!nfcid2)
|
||||
return -ENOMEM;
|
||||
|
||||
nfcid2[0] = DIGITAL_SENSF_NFCID2_NFC_DEP_B1;
|
||||
nfcid2[1] = DIGITAL_SENSF_NFCID2_NFC_DEP_B2;
|
||||
get_random_bytes(nfcid2 + 2, NFC_NFCID2_MAXSIZE - 2);
|
||||
|
||||
return digital_tg_listen(ddev, 300, digital_tg_recv_sensf_req, nfcid2);
|
||||
}
|
@ -21,11 +21,8 @@
|
||||
#include <linux/export.h>
|
||||
#include <linux/spi/spi.h>
|
||||
#include <linux/crc-ccitt.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <net/nfc/nci_core.h>
|
||||
|
||||
#define NCI_SPI_HDR_LEN 4
|
||||
#define NCI_SPI_CRC_LEN 2
|
||||
#define NCI_SPI_ACK_SHIFT 6
|
||||
#define NCI_SPI_MSB_PAYLOAD_MASK 0x3F
|
||||
|
||||
@ -41,54 +38,48 @@
|
||||
|
||||
#define CRC_INIT 0xFFFF
|
||||
|
||||
static int nci_spi_open(struct nci_dev *nci_dev)
|
||||
{
|
||||
struct nci_spi_dev *ndev = nci_get_drvdata(nci_dev);
|
||||
|
||||
return ndev->ops->open(ndev);
|
||||
}
|
||||
|
||||
static int nci_spi_close(struct nci_dev *nci_dev)
|
||||
{
|
||||
struct nci_spi_dev *ndev = nci_get_drvdata(nci_dev);
|
||||
|
||||
return ndev->ops->close(ndev);
|
||||
}
|
||||
|
||||
static int __nci_spi_send(struct nci_spi_dev *ndev, struct sk_buff *skb)
|
||||
static int __nci_spi_send(struct nci_spi *nspi, struct sk_buff *skb,
|
||||
int cs_change)
|
||||
{
|
||||
struct spi_message m;
|
||||
struct spi_transfer t;
|
||||
|
||||
t.tx_buf = skb->data;
|
||||
t.len = skb->len;
|
||||
t.cs_change = 0;
|
||||
t.delay_usecs = ndev->xfer_udelay;
|
||||
memset(&t, 0, sizeof(struct spi_transfer));
|
||||
/* a NULL skb means we just want the SPI chip select line to raise */
|
||||
if (skb) {
|
||||
t.tx_buf = skb->data;
|
||||
t.len = skb->len;
|
||||
} else {
|
||||
/* still set tx_buf non NULL to make the driver happy */
|
||||
t.tx_buf = &t;
|
||||
t.len = 0;
|
||||
}
|
||||
t.cs_change = cs_change;
|
||||
t.delay_usecs = nspi->xfer_udelay;
|
||||
|
||||
spi_message_init(&m);
|
||||
spi_message_add_tail(&t, &m);
|
||||
|
||||
return spi_sync(ndev->spi, &m);
|
||||
return spi_sync(nspi->spi, &m);
|
||||
}
|
||||
|
||||
static int nci_spi_send(struct nci_dev *nci_dev, struct sk_buff *skb)
|
||||
int nci_spi_send(struct nci_spi *nspi,
|
||||
struct completion *write_handshake_completion,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct nci_spi_dev *ndev = nci_get_drvdata(nci_dev);
|
||||
unsigned int payload_len = skb->len;
|
||||
unsigned char *hdr;
|
||||
int ret;
|
||||
long completion_rc;
|
||||
|
||||
ndev->ops->deassert_int(ndev);
|
||||
|
||||
/* add the NCI SPI header to the start of the buffer */
|
||||
hdr = skb_push(skb, NCI_SPI_HDR_LEN);
|
||||
hdr[0] = NCI_SPI_DIRECT_WRITE;
|
||||
hdr[1] = ndev->acknowledge_mode;
|
||||
hdr[1] = nspi->acknowledge_mode;
|
||||
hdr[2] = payload_len >> 8;
|
||||
hdr[3] = payload_len & 0xFF;
|
||||
|
||||
if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
|
||||
if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
|
||||
u16 crc;
|
||||
|
||||
crc = crc_ccitt(CRC_INIT, skb->data, skb->len);
|
||||
@ -96,123 +87,77 @@ static int nci_spi_send(struct nci_dev *nci_dev, struct sk_buff *skb)
|
||||
*skb_put(skb, 1) = crc & 0xFF;
|
||||
}
|
||||
|
||||
ret = __nci_spi_send(ndev, skb);
|
||||
if (write_handshake_completion) {
|
||||
/* Trick SPI driver to raise chip select */
|
||||
ret = __nci_spi_send(nspi, NULL, 1);
|
||||
if (ret)
|
||||
goto done;
|
||||
|
||||
kfree_skb(skb);
|
||||
ndev->ops->assert_int(ndev);
|
||||
/* wait for NFC chip hardware handshake to complete */
|
||||
if (wait_for_completion_timeout(write_handshake_completion,
|
||||
msecs_to_jiffies(1000)) == 0) {
|
||||
ret = -ETIME;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret != 0 || ndev->acknowledge_mode == NCI_SPI_CRC_DISABLED)
|
||||
ret = __nci_spi_send(nspi, skb, 0);
|
||||
if (ret != 0 || nspi->acknowledge_mode == NCI_SPI_CRC_DISABLED)
|
||||
goto done;
|
||||
|
||||
init_completion(&ndev->req_completion);
|
||||
completion_rc =
|
||||
wait_for_completion_interruptible_timeout(&ndev->req_completion,
|
||||
NCI_SPI_SEND_TIMEOUT);
|
||||
init_completion(&nspi->req_completion);
|
||||
completion_rc = wait_for_completion_interruptible_timeout(
|
||||
&nspi->req_completion,
|
||||
NCI_SPI_SEND_TIMEOUT);
|
||||
|
||||
if (completion_rc <= 0 || ndev->req_result == ACKNOWLEDGE_NACK)
|
||||
if (completion_rc <= 0 || nspi->req_result == ACKNOWLEDGE_NACK)
|
||||
ret = -EIO;
|
||||
|
||||
done:
|
||||
kfree_skb(skb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct nci_ops nci_spi_ops = {
|
||||
.open = nci_spi_open,
|
||||
.close = nci_spi_close,
|
||||
.send = nci_spi_send,
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(nci_spi_send);
|
||||
|
||||
/* ---- Interface to NCI SPI drivers ---- */
|
||||
|
||||
/**
|
||||
* nci_spi_allocate_device - allocate a new nci spi device
|
||||
* nci_spi_allocate_spi - allocate a new nci spi
|
||||
*
|
||||
* @spi: SPI device
|
||||
* @ops: device operations
|
||||
* @supported_protocols: NFC protocols supported by the device
|
||||
* @supported_se: NFC Secure Elements supported by the device
|
||||
* @acknowledge_mode: Acknowledge mode used by the device
|
||||
* @acknowledge_mode: Acknowledge mode used by the NFC device
|
||||
* @delay: delay between transactions in us
|
||||
* @ndev: nci dev to send incoming nci frames to
|
||||
*/
|
||||
struct nci_spi_dev *nci_spi_allocate_device(struct spi_device *spi,
|
||||
struct nci_spi_ops *ops,
|
||||
u32 supported_protocols,
|
||||
u32 supported_se,
|
||||
u8 acknowledge_mode,
|
||||
unsigned int delay)
|
||||
struct nci_spi *nci_spi_allocate_spi(struct spi_device *spi,
|
||||
u8 acknowledge_mode, unsigned int delay,
|
||||
struct nci_dev *ndev)
|
||||
{
|
||||
struct nci_spi_dev *ndev;
|
||||
int tailroom = 0;
|
||||
struct nci_spi *nspi;
|
||||
|
||||
if (!ops->open || !ops->close || !ops->assert_int || !ops->deassert_int)
|
||||
nspi = devm_kzalloc(&spi->dev, sizeof(struct nci_spi), GFP_KERNEL);
|
||||
if (!nspi)
|
||||
return NULL;
|
||||
|
||||
if (!supported_protocols)
|
||||
return NULL;
|
||||
nspi->acknowledge_mode = acknowledge_mode;
|
||||
nspi->xfer_udelay = delay;
|
||||
|
||||
ndev = devm_kzalloc(&spi->dev, sizeof(struct nci_dev), GFP_KERNEL);
|
||||
if (!ndev)
|
||||
return NULL;
|
||||
nspi->spi = spi;
|
||||
nspi->ndev = ndev;
|
||||
|
||||
ndev->ops = ops;
|
||||
ndev->acknowledge_mode = acknowledge_mode;
|
||||
ndev->xfer_udelay = delay;
|
||||
|
||||
if (acknowledge_mode == NCI_SPI_CRC_ENABLED)
|
||||
tailroom += NCI_SPI_CRC_LEN;
|
||||
|
||||
ndev->nci_dev = nci_allocate_device(&nci_spi_ops, supported_protocols,
|
||||
NCI_SPI_HDR_LEN, tailroom);
|
||||
if (!ndev->nci_dev)
|
||||
return NULL;
|
||||
|
||||
nci_set_drvdata(ndev->nci_dev, ndev);
|
||||
|
||||
return ndev;
|
||||
return nspi;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nci_spi_allocate_device);
|
||||
EXPORT_SYMBOL_GPL(nci_spi_allocate_spi);
|
||||
|
||||
/**
|
||||
* nci_spi_free_device - deallocate nci spi device
|
||||
*
|
||||
* @ndev: The nci spi device to deallocate
|
||||
*/
|
||||
void nci_spi_free_device(struct nci_spi_dev *ndev)
|
||||
{
|
||||
nci_free_device(ndev->nci_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nci_spi_free_device);
|
||||
|
||||
/**
|
||||
* nci_spi_register_device - register a nci spi device in the nfc subsystem
|
||||
*
|
||||
* @pdev: The nci spi device to register
|
||||
*/
|
||||
int nci_spi_register_device(struct nci_spi_dev *ndev)
|
||||
{
|
||||
return nci_register_device(ndev->nci_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nci_spi_register_device);
|
||||
|
||||
/**
|
||||
* nci_spi_unregister_device - unregister a nci spi device in the nfc subsystem
|
||||
*
|
||||
* @dev: The nci spi device to unregister
|
||||
*/
|
||||
void nci_spi_unregister_device(struct nci_spi_dev *ndev)
|
||||
{
|
||||
nci_unregister_device(ndev->nci_dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nci_spi_unregister_device);
|
||||
|
||||
static int send_acknowledge(struct nci_spi_dev *ndev, u8 acknowledge)
|
||||
static int send_acknowledge(struct nci_spi *nspi, u8 acknowledge)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
unsigned char *hdr;
|
||||
u16 crc;
|
||||
int ret;
|
||||
|
||||
skb = nci_skb_alloc(ndev->nci_dev, 0, GFP_KERNEL);
|
||||
skb = nci_skb_alloc(nspi->ndev, 0, GFP_KERNEL);
|
||||
|
||||
/* add the NCI SPI header to the start of the buffer */
|
||||
hdr = skb_push(skb, NCI_SPI_HDR_LEN);
|
||||
@ -225,14 +170,14 @@ static int send_acknowledge(struct nci_spi_dev *ndev, u8 acknowledge)
|
||||
*skb_put(skb, 1) = crc >> 8;
|
||||
*skb_put(skb, 1) = crc & 0xFF;
|
||||
|
||||
ret = __nci_spi_send(ndev, skb);
|
||||
ret = __nci_spi_send(nspi, skb, 0);
|
||||
|
||||
kfree_skb(skb);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct sk_buff *__nci_spi_recv_frame(struct nci_spi_dev *ndev)
|
||||
static struct sk_buff *__nci_spi_read(struct nci_spi *nspi)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct spi_message m;
|
||||
@ -242,43 +187,49 @@ static struct sk_buff *__nci_spi_recv_frame(struct nci_spi_dev *ndev)
|
||||
int ret;
|
||||
|
||||
spi_message_init(&m);
|
||||
|
||||
memset(&tx, 0, sizeof(struct spi_transfer));
|
||||
req[0] = NCI_SPI_DIRECT_READ;
|
||||
req[1] = ndev->acknowledge_mode;
|
||||
req[1] = nspi->acknowledge_mode;
|
||||
tx.tx_buf = req;
|
||||
tx.len = 2;
|
||||
tx.cs_change = 0;
|
||||
spi_message_add_tail(&tx, &m);
|
||||
|
||||
memset(&rx, 0, sizeof(struct spi_transfer));
|
||||
rx.rx_buf = resp_hdr;
|
||||
rx.len = 2;
|
||||
rx.cs_change = 1;
|
||||
spi_message_add_tail(&rx, &m);
|
||||
ret = spi_sync(ndev->spi, &m);
|
||||
|
||||
ret = spi_sync(nspi->spi, &m);
|
||||
if (ret)
|
||||
return NULL;
|
||||
|
||||
if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED)
|
||||
if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
|
||||
rx_len = ((resp_hdr[0] & NCI_SPI_MSB_PAYLOAD_MASK) << 8) +
|
||||
resp_hdr[1] + NCI_SPI_CRC_LEN;
|
||||
else
|
||||
rx_len = (resp_hdr[0] << 8) | resp_hdr[1];
|
||||
|
||||
skb = nci_skb_alloc(ndev->nci_dev, rx_len, GFP_KERNEL);
|
||||
skb = nci_skb_alloc(nspi->ndev, rx_len, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return NULL;
|
||||
|
||||
spi_message_init(&m);
|
||||
|
||||
memset(&rx, 0, sizeof(struct spi_transfer));
|
||||
rx.rx_buf = skb_put(skb, rx_len);
|
||||
rx.len = rx_len;
|
||||
rx.cs_change = 0;
|
||||
rx.delay_usecs = ndev->xfer_udelay;
|
||||
rx.delay_usecs = nspi->xfer_udelay;
|
||||
spi_message_add_tail(&rx, &m);
|
||||
ret = spi_sync(ndev->spi, &m);
|
||||
|
||||
ret = spi_sync(nspi->spi, &m);
|
||||
if (ret)
|
||||
goto receive_error;
|
||||
|
||||
if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
|
||||
if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
|
||||
*skb_push(skb, 1) = resp_hdr[1];
|
||||
*skb_push(skb, 1) = resp_hdr[0];
|
||||
}
|
||||
@ -318,61 +269,53 @@ static u8 nci_spi_get_ack(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
/**
|
||||
* nci_spi_recv_frame - receive frame from NCI SPI drivers
|
||||
* nci_spi_read - read frame from NCI SPI drivers
|
||||
*
|
||||
* @ndev: The nci spi device
|
||||
* @nspi: The nci spi
|
||||
* Context: can sleep
|
||||
*
|
||||
* This call may only be used from a context that may sleep. The sleep
|
||||
* is non-interruptible, and has no timeout.
|
||||
*
|
||||
* It returns zero on success, else a negative error code.
|
||||
* It returns an allocated skb containing the frame on success, or NULL.
|
||||
*/
|
||||
int nci_spi_recv_frame(struct nci_spi_dev *ndev)
|
||||
struct sk_buff *nci_spi_read(struct nci_spi *nspi)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
int ret = 0;
|
||||
|
||||
ndev->ops->deassert_int(ndev);
|
||||
|
||||
/* Retrieve frame from SPI */
|
||||
skb = __nci_spi_recv_frame(ndev);
|
||||
if (!skb) {
|
||||
ret = -EIO;
|
||||
skb = __nci_spi_read(nspi);
|
||||
if (!skb)
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
|
||||
if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED) {
|
||||
if (!nci_spi_check_crc(skb)) {
|
||||
send_acknowledge(ndev, ACKNOWLEDGE_NACK);
|
||||
send_acknowledge(nspi, ACKNOWLEDGE_NACK);
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* In case of acknowledged mode: if ACK or NACK received,
|
||||
* unblock completion of latest frame sent.
|
||||
*/
|
||||
ndev->req_result = nci_spi_get_ack(skb);
|
||||
if (ndev->req_result)
|
||||
complete(&ndev->req_completion);
|
||||
nspi->req_result = nci_spi_get_ack(skb);
|
||||
if (nspi->req_result)
|
||||
complete(&nspi->req_completion);
|
||||
}
|
||||
|
||||
/* If there is no payload (ACK/NACK only frame),
|
||||
* free the socket buffer
|
||||
*/
|
||||
if (skb->len == 0) {
|
||||
if (!skb->len) {
|
||||
kfree_skb(skb);
|
||||
skb = NULL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (ndev->acknowledge_mode == NCI_SPI_CRC_ENABLED)
|
||||
send_acknowledge(ndev, ACKNOWLEDGE_ACK);
|
||||
|
||||
/* Forward skb to NCI core layer */
|
||||
ret = nci_recv_frame(ndev->nci_dev, skb);
|
||||
if (nspi->acknowledge_mode == NCI_SPI_CRC_ENABLED)
|
||||
send_acknowledge(nspi, ACKNOWLEDGE_ACK);
|
||||
|
||||
done:
|
||||
ndev->ops->assert_int(ndev);
|
||||
|
||||
return ret;
|
||||
return skb;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(nci_spi_recv_frame);
|
||||
EXPORT_SYMBOL_GPL(nci_spi_read);
|
||||
|
@ -58,6 +58,7 @@ static const struct nla_policy nfc_genl_policy[NFC_ATTR_MAX + 1] = {
|
||||
[NFC_ATTR_LLC_SDP] = { .type = NLA_NESTED },
|
||||
[NFC_ATTR_FIRMWARE_NAME] = { .type = NLA_STRING,
|
||||
.len = NFC_FIRMWARE_NAME_MAXSIZE },
|
||||
[NFC_ATTR_SE_APDU] = { .type = NLA_BINARY },
|
||||
};
|
||||
|
||||
static const struct nla_policy nfc_sdp_genl_policy[NFC_SDP_ATTR_MAX + 1] = {
|
||||
@ -1278,6 +1279,91 @@ static int nfc_genl_dump_ses_done(struct netlink_callback *cb)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct se_io_ctx {
|
||||
u32 dev_idx;
|
||||
u32 se_idx;
|
||||
};
|
||||
|
||||
static void se_io_cb(void *context, u8 *apdu, size_t apdu_len, int err)
|
||||
{
|
||||
struct se_io_ctx *ctx = context;
|
||||
struct sk_buff *msg;
|
||||
void *hdr;
|
||||
|
||||
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
|
||||
if (!msg) {
|
||||
kfree(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
|
||||
NFC_CMD_SE_IO);
|
||||
if (!hdr)
|
||||
goto free_msg;
|
||||
|
||||
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, ctx->dev_idx) ||
|
||||
nla_put_u32(msg, NFC_ATTR_SE_INDEX, ctx->se_idx) ||
|
||||
nla_put(msg, NFC_ATTR_SE_APDU, apdu_len, apdu))
|
||||
goto nla_put_failure;
|
||||
|
||||
genlmsg_end(msg, hdr);
|
||||
|
||||
genlmsg_multicast(msg, 0, nfc_genl_event_mcgrp.id, GFP_KERNEL);
|
||||
|
||||
kfree(ctx);
|
||||
|
||||
return;
|
||||
|
||||
nla_put_failure:
|
||||
genlmsg_cancel(msg, hdr);
|
||||
free_msg:
|
||||
nlmsg_free(msg);
|
||||
kfree(ctx);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static int nfc_genl_se_io(struct sk_buff *skb, struct genl_info *info)
|
||||
{
|
||||
struct nfc_dev *dev;
|
||||
struct se_io_ctx *ctx;
|
||||
u32 dev_idx, se_idx;
|
||||
u8 *apdu;
|
||||
size_t apdu_len;
|
||||
|
||||
if (!info->attrs[NFC_ATTR_DEVICE_INDEX] ||
|
||||
!info->attrs[NFC_ATTR_SE_INDEX] ||
|
||||
!info->attrs[NFC_ATTR_SE_APDU])
|
||||
return -EINVAL;
|
||||
|
||||
dev_idx = nla_get_u32(info->attrs[NFC_ATTR_DEVICE_INDEX]);
|
||||
se_idx = nla_get_u32(info->attrs[NFC_ATTR_SE_INDEX]);
|
||||
|
||||
dev = nfc_get_device(dev_idx);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
if (!dev->ops || !dev->ops->se_io)
|
||||
return -ENOTSUPP;
|
||||
|
||||
apdu_len = nla_len(info->attrs[NFC_ATTR_SE_APDU]);
|
||||
if (apdu_len == 0)
|
||||
return -EINVAL;
|
||||
|
||||
apdu = nla_data(info->attrs[NFC_ATTR_SE_APDU]);
|
||||
if (!apdu)
|
||||
return -EINVAL;
|
||||
|
||||
ctx = kzalloc(sizeof(struct se_io_ctx), GFP_KERNEL);
|
||||
if (!ctx)
|
||||
return -ENOMEM;
|
||||
|
||||
ctx->dev_idx = dev_idx;
|
||||
ctx->se_idx = se_idx;
|
||||
|
||||
return dev->ops->se_io(dev, se_idx, apdu, apdu_len, se_io_cb, ctx);
|
||||
}
|
||||
|
||||
static struct genl_ops nfc_genl_ops[] = {
|
||||
{
|
||||
.cmd = NFC_CMD_GET_DEVICE,
|
||||
@ -1358,6 +1444,11 @@ static struct genl_ops nfc_genl_ops[] = {
|
||||
.done = nfc_genl_dump_ses_done,
|
||||
.policy = nfc_genl_policy,
|
||||
},
|
||||
{
|
||||
.cmd = NFC_CMD_SE_IO,
|
||||
.doit = nfc_genl_se_io,
|
||||
.policy = nfc_genl_policy,
|
||||
},
|
||||
};
|
||||
|
||||
|
||||
|
@ -142,11 +142,11 @@ static void rawsock_data_exchange_complete(void *context, struct sk_buff *skb,
|
||||
|
||||
err = rawsock_add_header(skb);
|
||||
if (err)
|
||||
goto error;
|
||||
goto error_skb;
|
||||
|
||||
err = sock_queue_rcv_skb(sk, skb);
|
||||
if (err)
|
||||
goto error;
|
||||
goto error_skb;
|
||||
|
||||
spin_lock_bh(&sk->sk_write_queue.lock);
|
||||
if (!skb_queue_empty(&sk->sk_write_queue))
|
||||
@ -158,6 +158,9 @@ static void rawsock_data_exchange_complete(void *context, struct sk_buff *skb,
|
||||
sock_put(sk);
|
||||
return;
|
||||
|
||||
error_skb:
|
||||
kfree_skb(skb);
|
||||
|
||||
error:
|
||||
rawsock_report_error(sk, err);
|
||||
sock_put(sk);
|
||||
|
Loading…
Reference in New Issue
Block a user