mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 02:50:43 +00:00
NFC 4.7 pull request
This is the first NFC pull request for 4.7. With this one we mainly have: - Support for NXP's pn532 NFC chipset. The pn532 is based on the same microcontroller as the pn533, but it talks to the host through i2c instead of USB. By separating the pn533 driver into core and PHY parts, we can not add the i2c layer and support the pn532 chipset. - Support for NCI's loopback mode. This is a testing mode where each packet received by the NFCC is sent back to the DH, allowing the host to test that the controller can receive and send data. - A few ACPI related fixes for the STMicro drivers, in order to match the device tree naming scheme. - A bunch of cleanups for the st-nci and the st21nfca STMicro drivers. -----BEGIN PGP SIGNATURE----- Version: GnuPG v1 iQIcBAABAgAGBQJXMRA8AAoJEIqAPN1PVmxKknQP/2WyaVYD+jeRkM4pymRQ/6s6 V2+be68JlatvC53D6fbzo9FF8/QO7w++vTF+KI5nV6g/RvkPvKnxg2DC39fob0DA 6x7KaRuUrTwxBx4tfsvtNfUL4idRi3i6/hrYRJyzaNMHKAukDbjJQiCchveUhZeB NlfYSEcieNnRJkGpdVGny4tea0fFOY6v+Uz74h2HboKbSD3SGNK29v47AqxH/ssg Y9XycyYWWF1w2uOUfFzJFsvBAYcPlBDF4WqQ8SkamxhaPAB047Ysfp3y9vWGc8By pdXLNAALzlCIt2JeGsrXhLG+Zf3y3w3G7HlcVbkh5BcB6fN2FYpPZurY8Km8Z6SM ufgP8MwGOvOJa9NKapSm3FF6Tl1B3gCK3+SWT5N/lSNEFnaoZ6xMNGqXe1RhTght +oqfuHLNO0YulQG0/ixJJl08p4eb6hhUMO3LKan3AYub9kgk63I43XeKXhIlqmLJ tEh3xAPzbPyu+nwkrJF0B2tMeUdrCKZaucru/upYcZi7LDbQOvMjHgTS8YmX/aBk gCOjINs+U1Q9jN2B7fMJe1uP6DJOTVW+xqiaLBLwHawRBhQQPbg+pLK/sHgFWcaa bdUWASp7n5Bu5pY/rPHL+xvA8O5z5ngJ7ZPjqB2CvHr9XyQDna3Fo9jA/w3hgr/q DgvCHukjvkDlUochojQZ =zM22 -----END PGP SIGNATURE----- Merge tag 'nfc-next-4.7-1' of git://git.kernel.org/pub/scm/linux/kernel/git/sameo/nfc-next Samuel Ortiz says: ==================== NFC 4.7 pull request This is the first NFC pull request for 4.7. With this one we mainly have: - Support for NXP's pn532 NFC chipset. The pn532 is based on the same microcontroller as the pn533, but it talks to the host through i2c instead of USB. By separating the pn533 driver into core and PHY parts, we can not add the i2c layer and support the pn532 chipset. - Support for NCI's loopback mode. This is a testing mode where each packet received by the NFCC is sent back to the DH, allowing the host to test that the controller can receive and send data. - A few ACPI related fixes for the STMicro drivers, in order to match the device tree naming scheme. - A bunch of cleanups for the st-nci and the st21nfca STMicro drivers. ==================== Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
631ad4a3e7
24 changed files with 1692 additions and 1105 deletions
31
Documentation/devicetree/bindings/net/nfc/pn533-i2c.txt
Normal file
31
Documentation/devicetree/bindings/net/nfc/pn533-i2c.txt
Normal file
|
@ -0,0 +1,31 @@
|
|||
* NXP Semiconductors PN532 NFC Controller
|
||||
|
||||
Required properties:
|
||||
- compatible: Should be "nxp,pn532-i2c" or "nxp,pn533-i2c".
|
||||
- clock-frequency: I²C work frequency.
|
||||
- reg: address on the bus
|
||||
- interrupt-parent: phandle for the interrupt gpio controller
|
||||
- interrupts: GPIO interrupt to which the chip is connected
|
||||
|
||||
Optional SoC Specific Properties:
|
||||
- pinctrl-names: Contains only one value - "default".
|
||||
- pintctrl-0: Specifies the pin control groups used for this controller.
|
||||
|
||||
Example (for ARM-based BeagleBone with PN532 on I2C2):
|
||||
|
||||
&i2c2 {
|
||||
|
||||
status = "okay";
|
||||
|
||||
pn532: pn532@24 {
|
||||
|
||||
compatible = "nxp,pn532-i2c";
|
||||
|
||||
reg = <0x24>;
|
||||
clock-frequency = <400000>;
|
||||
|
||||
interrupt-parent = <&gpio1>;
|
||||
interrupts = <17 IRQ_TYPE_EDGE_FALLING>;
|
||||
|
||||
};
|
||||
};
|
|
@ -5,16 +5,6 @@
|
|||
menu "Near Field Communication (NFC) devices"
|
||||
depends on NFC
|
||||
|
||||
config NFC_PN533
|
||||
tristate "NXP PN533 USB driver"
|
||||
depends on USB
|
||||
help
|
||||
NXP PN533 USB driver.
|
||||
This driver provides support for NFC NXP PN533 devices.
|
||||
|
||||
Say Y here to compile support for PN533 devices into the
|
||||
kernel or say M to compile it as module (pn533).
|
||||
|
||||
config NFC_WILINK
|
||||
tristate "Texas Instruments NFC WiLink driver"
|
||||
depends on TI_ST && NFC_NCI
|
||||
|
@ -70,6 +60,7 @@ config NFC_PORT100
|
|||
|
||||
source "drivers/nfc/fdp/Kconfig"
|
||||
source "drivers/nfc/pn544/Kconfig"
|
||||
source "drivers/nfc/pn533/Kconfig"
|
||||
source "drivers/nfc/microread/Kconfig"
|
||||
source "drivers/nfc/nfcmrvl/Kconfig"
|
||||
source "drivers/nfc/st21nfca/Kconfig"
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
obj-$(CONFIG_NFC_FDP) += fdp/
|
||||
obj-$(CONFIG_NFC_PN544) += pn544/
|
||||
obj-$(CONFIG_NFC_MICROREAD) += microread/
|
||||
obj-$(CONFIG_NFC_PN533) += pn533.o
|
||||
obj-$(CONFIG_NFC_PN533) += pn533/
|
||||
obj-$(CONFIG_NFC_WILINK) += nfcwilink.o
|
||||
obj-$(CONFIG_NFC_MEI_PHY) += mei_phy.o
|
||||
obj-$(CONFIG_NFC_SIM) += nfcsim.o
|
||||
|
|
|
@ -102,7 +102,8 @@ static int fdp_nci_create_conn(struct nci_dev *ndev)
|
|||
if (r)
|
||||
return r;
|
||||
|
||||
return nci_get_conn_info_by_id(ndev, 0);
|
||||
return nci_get_conn_info_by_dest_type_params(ndev,
|
||||
FDP_PATCH_CONN_DEST, NULL);
|
||||
}
|
||||
|
||||
static inline int fdp_nci_get_versions(struct nci_dev *ndev)
|
||||
|
|
|
@ -418,7 +418,6 @@ MODULE_DEVICE_TABLE(acpi, acpi_id);
|
|||
static struct i2c_driver nxp_nci_i2c_driver = {
|
||||
.driver = {
|
||||
.name = NXP_NCI_I2C_DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.acpi_match_table = ACPI_PTR(acpi_id),
|
||||
.of_match_table = of_match_ptr(of_nxp_nci_i2c_match),
|
||||
},
|
||||
|
|
27
drivers/nfc/pn533/Kconfig
Normal file
27
drivers/nfc/pn533/Kconfig
Normal file
|
@ -0,0 +1,27 @@
|
|||
config NFC_PN533
|
||||
tristate
|
||||
help
|
||||
NXP PN533 core driver.
|
||||
This driver provides core functionality for NXP PN533 NFC devices.
|
||||
|
||||
config NFC_PN533_USB
|
||||
tristate "NFC PN533 device support (USB)"
|
||||
depends on USB
|
||||
select NFC_PN533
|
||||
---help---
|
||||
This module adds support for the NXP pn533 USB interface.
|
||||
Select this if your platform is using the USB bus.
|
||||
|
||||
If you choose to build a module, it'll be called pn533_usb.
|
||||
Say N if unsure.
|
||||
|
||||
config NFC_PN533_I2C
|
||||
tristate "NFC PN533 device support (I2C)"
|
||||
depends on I2C
|
||||
select NFC_PN533
|
||||
---help---
|
||||
This module adds support for the NXP pn533 I2C interface.
|
||||
Select this if your platform is using the I2C bus.
|
||||
|
||||
If you choose to build a module, it'll be called pn533_i2c.
|
||||
Say N if unsure.
|
9
drivers/nfc/pn533/Makefile
Normal file
9
drivers/nfc/pn533/Makefile
Normal file
|
@ -0,0 +1,9 @@
|
|||
#
|
||||
# Makefile for PN533 NFC driver
|
||||
#
|
||||
pn533_usb-objs = usb.o
|
||||
pn533_i2c-objs = i2c.o
|
||||
|
||||
obj-$(CONFIG_NFC_PN533) += pn533.o
|
||||
obj-$(CONFIG_NFC_PN533_USB) += pn533_usb.o
|
||||
obj-$(CONFIG_NFC_PN533_I2C) += pn533_i2c.o
|
281
drivers/nfc/pn533/i2c.c
Normal file
281
drivers/nfc/pn533/i2c.c
Normal file
|
@ -0,0 +1,281 @@
|
|||
/*
|
||||
* Driver for NXP PN533 NFC Chip - I2C transport layer
|
||||
*
|
||||
* Copyright (C) 2011 Instituto Nokia de Tecnologia
|
||||
* Copyright (C) 2012-2013 Tieto Poland
|
||||
* Copyright (C) 2016 HALE electronic
|
||||
*
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/i2c.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <net/nfc/nfc.h>
|
||||
#include "pn533.h"
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
#define PN533_I2C_DRIVER_NAME "pn533_i2c"
|
||||
|
||||
struct pn533_i2c_phy {
|
||||
struct i2c_client *i2c_dev;
|
||||
struct pn533 *priv;
|
||||
|
||||
bool aborted;
|
||||
|
||||
int hard_fault; /*
|
||||
* < 0 if hardware error occurred (e.g. i2c err)
|
||||
* and prevents normal operation.
|
||||
*/
|
||||
};
|
||||
|
||||
static int pn533_i2c_send_ack(struct pn533 *dev, gfp_t flags)
|
||||
{
|
||||
struct pn533_i2c_phy *phy = dev->phy;
|
||||
struct i2c_client *client = phy->i2c_dev;
|
||||
u8 ack[6] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
|
||||
/* spec 6.2.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */
|
||||
int rc;
|
||||
|
||||
rc = i2c_master_send(client, ack, 6);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pn533_i2c_send_frame(struct pn533 *dev,
|
||||
struct sk_buff *out)
|
||||
{
|
||||
struct pn533_i2c_phy *phy = dev->phy;
|
||||
struct i2c_client *client = phy->i2c_dev;
|
||||
int rc;
|
||||
|
||||
if (phy->hard_fault != 0)
|
||||
return phy->hard_fault;
|
||||
|
||||
if (phy->priv == NULL)
|
||||
phy->priv = dev;
|
||||
|
||||
phy->aborted = false;
|
||||
|
||||
print_hex_dump_debug("PN533_i2c TX: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
out->data, out->len, false);
|
||||
|
||||
rc = i2c_master_send(client, out->data, out->len);
|
||||
|
||||
if (rc == -EREMOTEIO) { /* Retry, chip was in power down */
|
||||
usleep_range(6000, 10000);
|
||||
rc = i2c_master_send(client, out->data, out->len);
|
||||
}
|
||||
|
||||
if (rc >= 0) {
|
||||
if (rc != out->len)
|
||||
rc = -EREMOTEIO;
|
||||
else
|
||||
rc = 0;
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void pn533_i2c_abort_cmd(struct pn533 *dev, gfp_t flags)
|
||||
{
|
||||
struct pn533_i2c_phy *phy = dev->phy;
|
||||
|
||||
phy->aborted = true;
|
||||
|
||||
/* An ack will cancel the last issued command */
|
||||
pn533_i2c_send_ack(dev, flags);
|
||||
|
||||
/* schedule cmd_complete_work to finish current command execution */
|
||||
pn533_recv_frame(phy->priv, NULL, -ENOENT);
|
||||
}
|
||||
|
||||
static int pn533_i2c_read(struct pn533_i2c_phy *phy, struct sk_buff **skb)
|
||||
{
|
||||
struct i2c_client *client = phy->i2c_dev;
|
||||
int len = PN533_EXT_FRAME_HEADER_LEN +
|
||||
PN533_STD_FRAME_MAX_PAYLOAD_LEN +
|
||||
PN533_STD_FRAME_TAIL_LEN + 1;
|
||||
int r;
|
||||
|
||||
*skb = alloc_skb(len, GFP_KERNEL);
|
||||
if (*skb == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
r = i2c_master_recv(client, skb_put(*skb, len), len);
|
||||
if (r != len) {
|
||||
nfc_err(&client->dev, "cannot read. r=%d len=%d\n", r, len);
|
||||
kfree_skb(*skb);
|
||||
return -EREMOTEIO;
|
||||
}
|
||||
|
||||
if (!((*skb)->data[0] & 0x01)) {
|
||||
nfc_err(&client->dev, "READY flag not set");
|
||||
kfree_skb(*skb);
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
/* remove READY byte */
|
||||
skb_pull(*skb, 1);
|
||||
/* trim to frame size */
|
||||
skb_trim(*skb, phy->priv->ops->rx_frame_size((*skb)->data));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static irqreturn_t pn533_i2c_irq_thread_fn(int irq, void *data)
|
||||
{
|
||||
struct pn533_i2c_phy *phy = data;
|
||||
struct i2c_client *client;
|
||||
struct sk_buff *skb = NULL;
|
||||
int r;
|
||||
|
||||
if (!phy || irq != phy->i2c_dev->irq) {
|
||||
WARN_ON_ONCE(1);
|
||||
return IRQ_NONE;
|
||||
}
|
||||
|
||||
client = phy->i2c_dev;
|
||||
dev_dbg(&client->dev, "IRQ\n");
|
||||
|
||||
if (phy->hard_fault != 0)
|
||||
return IRQ_HANDLED;
|
||||
|
||||
r = pn533_i2c_read(phy, &skb);
|
||||
if (r == -EREMOTEIO) {
|
||||
phy->hard_fault = r;
|
||||
|
||||
pn533_recv_frame(phy->priv, NULL, -EREMOTEIO);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
} else if ((r == -ENOMEM) || (r == -EBADMSG) || (r == -EBUSY)) {
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
if (!phy->aborted)
|
||||
pn533_recv_frame(phy->priv, skb, 0);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static struct pn533_phy_ops i2c_phy_ops = {
|
||||
.send_frame = pn533_i2c_send_frame,
|
||||
.send_ack = pn533_i2c_send_ack,
|
||||
.abort_cmd = pn533_i2c_abort_cmd,
|
||||
};
|
||||
|
||||
|
||||
static int pn533_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
struct pn533_i2c_phy *phy;
|
||||
struct pn533 *priv;
|
||||
int r = 0;
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
|
||||
|
||||
if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
|
||||
nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
phy = devm_kzalloc(&client->dev, sizeof(struct pn533_i2c_phy),
|
||||
GFP_KERNEL);
|
||||
if (!phy)
|
||||
return -ENOMEM;
|
||||
|
||||
phy->i2c_dev = client;
|
||||
i2c_set_clientdata(client, phy);
|
||||
|
||||
r = request_threaded_irq(client->irq, NULL, pn533_i2c_irq_thread_fn,
|
||||
IRQF_TRIGGER_FALLING |
|
||||
IRQF_SHARED | IRQF_ONESHOT,
|
||||
PN533_I2C_DRIVER_NAME, phy);
|
||||
|
||||
if (r < 0)
|
||||
nfc_err(&client->dev, "Unable to register IRQ handler\n");
|
||||
|
||||
priv = pn533_register_device(PN533_DEVICE_PN532,
|
||||
PN533_NO_TYPE_B_PROTOCOLS,
|
||||
PN533_PROTO_REQ_ACK_RESP,
|
||||
phy, &i2c_phy_ops, NULL,
|
||||
&phy->i2c_dev->dev,
|
||||
&client->dev);
|
||||
|
||||
if (IS_ERR(priv)) {
|
||||
r = PTR_ERR(priv);
|
||||
goto err_register;
|
||||
}
|
||||
|
||||
phy->priv = priv;
|
||||
|
||||
return 0;
|
||||
|
||||
err_register:
|
||||
free_irq(client->irq, phy);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int pn533_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct pn533_i2c_phy *phy = i2c_get_clientdata(client);
|
||||
|
||||
dev_dbg(&client->dev, "%s\n", __func__);
|
||||
|
||||
pn533_unregister_device(phy->priv);
|
||||
|
||||
free_irq(client->irq, phy);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_pn533_i2c_match[] = {
|
||||
{ .compatible = "nxp,pn533-i2c", },
|
||||
{ .compatible = "nxp,pn532-i2c", },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, of_pn533_i2c_match);
|
||||
|
||||
static struct i2c_device_id pn533_i2c_id_table[] = {
|
||||
{ PN533_I2C_DRIVER_NAME, 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(i2c, pn533_i2c_id_table);
|
||||
|
||||
static struct i2c_driver pn533_i2c_driver = {
|
||||
.driver = {
|
||||
.name = PN533_I2C_DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(of_pn533_i2c_match),
|
||||
},
|
||||
.probe = pn533_i2c_probe,
|
||||
.id_table = pn533_i2c_id_table,
|
||||
.remove = pn533_i2c_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(pn533_i2c_driver);
|
||||
|
||||
MODULE_AUTHOR("Michael Thalmeier <michael.thalmeier@hale.at>");
|
||||
MODULE_DESCRIPTION("PN533 I2C driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
File diff suppressed because it is too large
Load diff
238
drivers/nfc/pn533/pn533.h
Normal file
238
drivers/nfc/pn533/pn533.h
Normal file
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* Driver for NXP PN533 NFC Chip
|
||||
*
|
||||
* Copyright (C) 2011 Instituto Nokia de Tecnologia
|
||||
* Copyright (C) 2012-2013 Tieto Poland
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#define PN533_DEVICE_STD 0x1
|
||||
#define PN533_DEVICE_PASORI 0x2
|
||||
#define PN533_DEVICE_ACR122U 0x3
|
||||
#define PN533_DEVICE_PN532 0x4
|
||||
|
||||
#define PN533_ALL_PROTOCOLS (NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK |\
|
||||
NFC_PROTO_FELICA_MASK | NFC_PROTO_ISO14443_MASK |\
|
||||
NFC_PROTO_NFC_DEP_MASK |\
|
||||
NFC_PROTO_ISO14443_B_MASK)
|
||||
|
||||
#define PN533_NO_TYPE_B_PROTOCOLS (NFC_PROTO_JEWEL_MASK | \
|
||||
NFC_PROTO_MIFARE_MASK | \
|
||||
NFC_PROTO_FELICA_MASK | \
|
||||
NFC_PROTO_ISO14443_MASK | \
|
||||
NFC_PROTO_NFC_DEP_MASK)
|
||||
|
||||
/* Standard pn533 frame definitions (standard and extended)*/
|
||||
#define PN533_STD_FRAME_HEADER_LEN (sizeof(struct pn533_std_frame) \
|
||||
+ 2) /* data[0] TFI, data[1] CC */
|
||||
#define PN533_STD_FRAME_TAIL_LEN 2 /* data[len] DCS, data[len + 1] postamble*/
|
||||
|
||||
#define PN533_EXT_FRAME_HEADER_LEN (sizeof(struct pn533_ext_frame) \
|
||||
+ 2) /* data[0] TFI, data[1] CC */
|
||||
|
||||
#define PN533_CMD_DATAEXCH_HEAD_LEN 1
|
||||
#define PN533_CMD_DATAEXCH_DATA_MAXLEN 262
|
||||
#define PN533_CMD_DATAFRAME_MAXLEN 240 /* max data length (send) */
|
||||
|
||||
/*
|
||||
* Max extended frame payload len, excluding TFI and CC
|
||||
* which are already in PN533_FRAME_HEADER_LEN.
|
||||
*/
|
||||
#define PN533_STD_FRAME_MAX_PAYLOAD_LEN 263
|
||||
|
||||
|
||||
/* Preamble (1), SoPC (2), ACK Code (2), Postamble (1) */
|
||||
#define PN533_STD_FRAME_ACK_SIZE 6
|
||||
#define PN533_STD_FRAME_CHECKSUM(f) (f->data[f->datalen])
|
||||
#define PN533_STD_FRAME_POSTAMBLE(f) (f->data[f->datalen + 1])
|
||||
/* Half start code (3), LEN (4) should be 0xffff for extended frame */
|
||||
#define PN533_STD_IS_EXTENDED(hdr) ((hdr)->datalen == 0xFF \
|
||||
&& (hdr)->datalen_checksum == 0xFF)
|
||||
#define PN533_EXT_FRAME_CHECKSUM(f) (f->data[be16_to_cpu(f->datalen)])
|
||||
|
||||
/* start of frame */
|
||||
#define PN533_STD_FRAME_SOF 0x00FF
|
||||
|
||||
/* standard frame identifier: in/out/error */
|
||||
#define PN533_STD_FRAME_IDENTIFIER(f) (f->data[0]) /* TFI */
|
||||
#define PN533_STD_FRAME_DIR_OUT 0xD4
|
||||
#define PN533_STD_FRAME_DIR_IN 0xD5
|
||||
|
||||
/* PN533 Commands */
|
||||
#define PN533_FRAME_CMD(f) (f->data[1])
|
||||
|
||||
#define PN533_CMD_GET_FIRMWARE_VERSION 0x02
|
||||
#define PN533_CMD_SAM_CONFIGURATION 0x14
|
||||
#define PN533_CMD_RF_CONFIGURATION 0x32
|
||||
#define PN533_CMD_IN_DATA_EXCHANGE 0x40
|
||||
#define PN533_CMD_IN_COMM_THRU 0x42
|
||||
#define PN533_CMD_IN_LIST_PASSIVE_TARGET 0x4A
|
||||
#define PN533_CMD_IN_ATR 0x50
|
||||
#define PN533_CMD_IN_RELEASE 0x52
|
||||
#define PN533_CMD_IN_JUMP_FOR_DEP 0x56
|
||||
|
||||
#define PN533_CMD_TG_INIT_AS_TARGET 0x8c
|
||||
#define PN533_CMD_TG_GET_DATA 0x86
|
||||
#define PN533_CMD_TG_SET_DATA 0x8e
|
||||
#define PN533_CMD_TG_SET_META_DATA 0x94
|
||||
#define PN533_CMD_UNDEF 0xff
|
||||
|
||||
#define PN533_CMD_RESPONSE(cmd) (cmd + 1)
|
||||
|
||||
/* PN533 Return codes */
|
||||
#define PN533_CMD_RET_MASK 0x3F
|
||||
#define PN533_CMD_MI_MASK 0x40
|
||||
#define PN533_CMD_RET_SUCCESS 0x00
|
||||
|
||||
|
||||
enum pn533_protocol_type {
|
||||
PN533_PROTO_REQ_ACK_RESP = 0,
|
||||
PN533_PROTO_REQ_RESP
|
||||
};
|
||||
|
||||
/* Poll modulations */
|
||||
enum {
|
||||
PN533_POLL_MOD_106KBPS_A,
|
||||
PN533_POLL_MOD_212KBPS_FELICA,
|
||||
PN533_POLL_MOD_424KBPS_FELICA,
|
||||
PN533_POLL_MOD_106KBPS_JEWEL,
|
||||
PN533_POLL_MOD_847KBPS_B,
|
||||
PN533_LISTEN_MOD,
|
||||
|
||||
__PN533_POLL_MOD_AFTER_LAST,
|
||||
};
|
||||
#define PN533_POLL_MOD_MAX (__PN533_POLL_MOD_AFTER_LAST - 1)
|
||||
|
||||
struct pn533_std_frame {
|
||||
u8 preamble;
|
||||
__be16 start_frame;
|
||||
u8 datalen;
|
||||
u8 datalen_checksum;
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
struct pn533_ext_frame { /* Extended Information frame */
|
||||
u8 preamble;
|
||||
__be16 start_frame;
|
||||
__be16 eif_flag; /* fixed to 0xFFFF */
|
||||
__be16 datalen;
|
||||
u8 datalen_checksum;
|
||||
u8 data[];
|
||||
} __packed;
|
||||
|
||||
struct pn533 {
|
||||
struct nfc_dev *nfc_dev;
|
||||
u32 device_type;
|
||||
enum pn533_protocol_type protocol_type;
|
||||
|
||||
struct sk_buff_head resp_q;
|
||||
struct sk_buff_head fragment_skb;
|
||||
|
||||
struct workqueue_struct *wq;
|
||||
struct work_struct cmd_work;
|
||||
struct work_struct cmd_complete_work;
|
||||
struct delayed_work poll_work;
|
||||
struct work_struct mi_rx_work;
|
||||
struct work_struct mi_tx_work;
|
||||
struct work_struct mi_tm_rx_work;
|
||||
struct work_struct mi_tm_tx_work;
|
||||
struct work_struct tg_work;
|
||||
struct work_struct rf_work;
|
||||
|
||||
struct list_head cmd_queue;
|
||||
struct pn533_cmd *cmd;
|
||||
u8 cmd_pending;
|
||||
struct mutex cmd_lock; /* protects cmd queue */
|
||||
|
||||
void *cmd_complete_mi_arg;
|
||||
void *cmd_complete_dep_arg;
|
||||
|
||||
struct pn533_poll_modulations *poll_mod_active[PN533_POLL_MOD_MAX + 1];
|
||||
u8 poll_mod_count;
|
||||
u8 poll_mod_curr;
|
||||
u8 poll_dep;
|
||||
u32 poll_protocols;
|
||||
u32 listen_protocols;
|
||||
struct timer_list listen_timer;
|
||||
int cancel_listen;
|
||||
|
||||
u8 *gb;
|
||||
size_t gb_len;
|
||||
|
||||
u8 tgt_available_prots;
|
||||
u8 tgt_active_prot;
|
||||
u8 tgt_mode;
|
||||
|
||||
struct pn533_frame_ops *ops;
|
||||
|
||||
struct device *dev;
|
||||
void *phy;
|
||||
struct pn533_phy_ops *phy_ops;
|
||||
};
|
||||
|
||||
typedef int (*pn533_send_async_complete_t) (struct pn533 *dev, void *arg,
|
||||
struct sk_buff *resp);
|
||||
|
||||
struct pn533_cmd {
|
||||
struct list_head queue;
|
||||
u8 code;
|
||||
int status;
|
||||
struct sk_buff *req;
|
||||
struct sk_buff *resp;
|
||||
pn533_send_async_complete_t complete_cb;
|
||||
void *complete_cb_context;
|
||||
};
|
||||
|
||||
|
||||
struct pn533_frame_ops {
|
||||
void (*tx_frame_init)(void *frame, u8 cmd_code);
|
||||
void (*tx_frame_finish)(void *frame);
|
||||
void (*tx_update_payload_len)(void *frame, int len);
|
||||
int tx_header_len;
|
||||
int tx_tail_len;
|
||||
|
||||
bool (*rx_is_frame_valid)(void *frame, struct pn533 *dev);
|
||||
bool (*rx_frame_is_ack)(void *frame);
|
||||
int (*rx_frame_size)(void *frame);
|
||||
int rx_header_len;
|
||||
int rx_tail_len;
|
||||
|
||||
int max_payload_len;
|
||||
u8 (*get_cmd_code)(void *frame);
|
||||
};
|
||||
|
||||
|
||||
struct pn533_phy_ops {
|
||||
int (*send_frame)(struct pn533 *priv,
|
||||
struct sk_buff *out);
|
||||
int (*send_ack)(struct pn533 *dev, gfp_t flags);
|
||||
void (*abort_cmd)(struct pn533 *priv, gfp_t flags);
|
||||
};
|
||||
|
||||
|
||||
struct pn533 *pn533_register_device(u32 device_type,
|
||||
u32 protocols,
|
||||
enum pn533_protocol_type protocol_type,
|
||||
void *phy,
|
||||
struct pn533_phy_ops *phy_ops,
|
||||
struct pn533_frame_ops *fops,
|
||||
struct device *dev,
|
||||
struct device *parent);
|
||||
|
||||
void pn533_unregister_device(struct pn533 *priv);
|
||||
void pn533_recv_frame(struct pn533 *dev, struct sk_buff *skb, int status);
|
||||
|
||||
bool pn533_rx_frame_is_cmd_response(struct pn533 *dev, void *frame);
|
||||
bool pn533_rx_frame_is_ack(void *_frame);
|
597
drivers/nfc/pn533/usb.c
Normal file
597
drivers/nfc/pn533/usb.c
Normal file
|
@ -0,0 +1,597 @@
|
|||
/*
|
||||
* Driver for NXP PN533 NFC Chip - USB transport layer
|
||||
*
|
||||
* Copyright (C) 2011 Instituto Nokia de Tecnologia
|
||||
* Copyright (C) 2012-2013 Tieto Poland
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/nfc.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/nfc/nfc.h>
|
||||
#include "pn533.h"
|
||||
|
||||
#define VERSION "0.1"
|
||||
|
||||
#define PN533_VENDOR_ID 0x4CC
|
||||
#define PN533_PRODUCT_ID 0x2533
|
||||
|
||||
#define SCM_VENDOR_ID 0x4E6
|
||||
#define SCL3711_PRODUCT_ID 0x5591
|
||||
|
||||
#define SONY_VENDOR_ID 0x054c
|
||||
#define PASORI_PRODUCT_ID 0x02e1
|
||||
|
||||
#define ACS_VENDOR_ID 0x072f
|
||||
#define ACR122U_PRODUCT_ID 0x2200
|
||||
|
||||
static const struct usb_device_id pn533_usb_table[] = {
|
||||
{ USB_DEVICE(PN533_VENDOR_ID, PN533_PRODUCT_ID),
|
||||
.driver_info = PN533_DEVICE_STD },
|
||||
{ USB_DEVICE(SCM_VENDOR_ID, SCL3711_PRODUCT_ID),
|
||||
.driver_info = PN533_DEVICE_STD },
|
||||
{ USB_DEVICE(SONY_VENDOR_ID, PASORI_PRODUCT_ID),
|
||||
.driver_info = PN533_DEVICE_PASORI },
|
||||
{ USB_DEVICE(ACS_VENDOR_ID, ACR122U_PRODUCT_ID),
|
||||
.driver_info = PN533_DEVICE_ACR122U },
|
||||
{ }
|
||||
};
|
||||
MODULE_DEVICE_TABLE(usb, pn533_usb_table);
|
||||
|
||||
struct pn533_usb_phy {
|
||||
struct usb_device *udev;
|
||||
struct usb_interface *interface;
|
||||
|
||||
struct urb *out_urb;
|
||||
struct urb *in_urb;
|
||||
|
||||
struct pn533 *priv;
|
||||
};
|
||||
|
||||
static void pn533_recv_response(struct urb *urb)
|
||||
{
|
||||
struct pn533_usb_phy *phy = urb->context;
|
||||
struct sk_buff *skb = NULL;
|
||||
|
||||
if (!urb->status) {
|
||||
skb = alloc_skb(urb->actual_length, GFP_KERNEL);
|
||||
if (!skb) {
|
||||
nfc_err(&phy->udev->dev, "failed to alloc memory\n");
|
||||
} else {
|
||||
memcpy(skb_put(skb, urb->actual_length),
|
||||
urb->transfer_buffer, urb->actual_length);
|
||||
}
|
||||
}
|
||||
|
||||
pn533_recv_frame(phy->priv, skb, urb->status);
|
||||
}
|
||||
|
||||
static int pn533_submit_urb_for_response(struct pn533_usb_phy *phy, gfp_t flags)
|
||||
{
|
||||
phy->in_urb->complete = pn533_recv_response;
|
||||
|
||||
return usb_submit_urb(phy->in_urb, flags);
|
||||
}
|
||||
|
||||
static void pn533_recv_ack(struct urb *urb)
|
||||
{
|
||||
struct pn533_usb_phy *phy = urb->context;
|
||||
struct pn533 *priv = phy->priv;
|
||||
struct pn533_cmd *cmd = priv->cmd;
|
||||
struct pn533_std_frame *in_frame;
|
||||
int rc;
|
||||
|
||||
cmd->status = urb->status;
|
||||
|
||||
switch (urb->status) {
|
||||
case 0:
|
||||
break; /* success */
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
dev_dbg(&phy->udev->dev,
|
||||
"The urb has been stopped (status %d)\n",
|
||||
urb->status);
|
||||
goto sched_wq;
|
||||
case -ESHUTDOWN:
|
||||
default:
|
||||
nfc_err(&phy->udev->dev,
|
||||
"Urb failure (status %d)\n", urb->status);
|
||||
goto sched_wq;
|
||||
}
|
||||
|
||||
in_frame = phy->in_urb->transfer_buffer;
|
||||
|
||||
if (!pn533_rx_frame_is_ack(in_frame)) {
|
||||
nfc_err(&phy->udev->dev, "Received an invalid ack\n");
|
||||
cmd->status = -EIO;
|
||||
goto sched_wq;
|
||||
}
|
||||
|
||||
rc = pn533_submit_urb_for_response(phy, GFP_ATOMIC);
|
||||
if (rc) {
|
||||
nfc_err(&phy->udev->dev,
|
||||
"usb_submit_urb failed with result %d\n", rc);
|
||||
cmd->status = rc;
|
||||
goto sched_wq;
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
sched_wq:
|
||||
queue_work(priv->wq, &priv->cmd_complete_work);
|
||||
}
|
||||
|
||||
static int pn533_submit_urb_for_ack(struct pn533_usb_phy *phy, gfp_t flags)
|
||||
{
|
||||
phy->in_urb->complete = pn533_recv_ack;
|
||||
|
||||
return usb_submit_urb(phy->in_urb, flags);
|
||||
}
|
||||
|
||||
static int pn533_usb_send_ack(struct pn533 *dev, gfp_t flags)
|
||||
{
|
||||
struct pn533_usb_phy *phy = dev->phy;
|
||||
u8 ack[6] = {0x00, 0x00, 0xff, 0x00, 0xff, 0x00};
|
||||
/* spec 7.1.1.3: Preamble, SoPC (2), ACK Code (2), Postamble */
|
||||
int rc;
|
||||
|
||||
phy->out_urb->transfer_buffer = ack;
|
||||
phy->out_urb->transfer_buffer_length = sizeof(ack);
|
||||
rc = usb_submit_urb(phy->out_urb, flags);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static int pn533_usb_send_frame(struct pn533 *dev,
|
||||
struct sk_buff *out)
|
||||
{
|
||||
struct pn533_usb_phy *phy = dev->phy;
|
||||
int rc;
|
||||
|
||||
if (phy->priv == NULL)
|
||||
phy->priv = dev;
|
||||
|
||||
phy->out_urb->transfer_buffer = out->data;
|
||||
phy->out_urb->transfer_buffer_length = out->len;
|
||||
|
||||
print_hex_dump_debug("PN533 TX: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
out->data, out->len, false);
|
||||
|
||||
rc = usb_submit_urb(phy->out_urb, GFP_KERNEL);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
if (dev->protocol_type == PN533_PROTO_REQ_RESP) {
|
||||
/* request for response for sent packet directly */
|
||||
rc = pn533_submit_urb_for_response(phy, GFP_ATOMIC);
|
||||
if (rc)
|
||||
goto error;
|
||||
} else if (dev->protocol_type == PN533_PROTO_REQ_ACK_RESP) {
|
||||
/* request for ACK if that's the case */
|
||||
rc = pn533_submit_urb_for_ack(phy, GFP_KERNEL);
|
||||
if (rc)
|
||||
goto error;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
usb_unlink_urb(phy->out_urb);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void pn533_usb_abort_cmd(struct pn533 *dev, gfp_t flags)
|
||||
{
|
||||
struct pn533_usb_phy *phy = dev->phy;
|
||||
|
||||
/* ACR122U does not support any command which aborts last
|
||||
* issued command i.e. as ACK for standard PN533. Additionally,
|
||||
* it behaves stange, sending broken or incorrect responses,
|
||||
* when we cancel urb before the chip will send response.
|
||||
*/
|
||||
if (dev->device_type == PN533_DEVICE_ACR122U)
|
||||
return;
|
||||
|
||||
/* An ack will cancel the last issued command */
|
||||
pn533_usb_send_ack(dev, flags);
|
||||
|
||||
/* cancel the urb request */
|
||||
usb_kill_urb(phy->in_urb);
|
||||
}
|
||||
|
||||
/* ACR122 specific structs and fucntions */
|
||||
|
||||
/* ACS ACR122 pn533 frame definitions */
|
||||
#define PN533_ACR122_TX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_tx_frame) \
|
||||
+ 2)
|
||||
#define PN533_ACR122_TX_FRAME_TAIL_LEN 0
|
||||
#define PN533_ACR122_RX_FRAME_HEADER_LEN (sizeof(struct pn533_acr122_rx_frame) \
|
||||
+ 2)
|
||||
#define PN533_ACR122_RX_FRAME_TAIL_LEN 2
|
||||
#define PN533_ACR122_FRAME_MAX_PAYLOAD_LEN PN533_STD_FRAME_MAX_PAYLOAD_LEN
|
||||
|
||||
/* CCID messages types */
|
||||
#define PN533_ACR122_PC_TO_RDR_ICCPOWERON 0x62
|
||||
#define PN533_ACR122_PC_TO_RDR_ESCAPE 0x6B
|
||||
|
||||
#define PN533_ACR122_RDR_TO_PC_ESCAPE 0x83
|
||||
|
||||
|
||||
struct pn533_acr122_ccid_hdr {
|
||||
u8 type;
|
||||
u32 datalen;
|
||||
u8 slot;
|
||||
u8 seq;
|
||||
|
||||
/*
|
||||
* 3 msg specific bytes or status, error and 1 specific
|
||||
* byte for reposnse msg
|
||||
*/
|
||||
u8 params[3];
|
||||
u8 data[]; /* payload */
|
||||
} __packed;
|
||||
|
||||
struct pn533_acr122_apdu_hdr {
|
||||
u8 class;
|
||||
u8 ins;
|
||||
u8 p1;
|
||||
u8 p2;
|
||||
} __packed;
|
||||
|
||||
struct pn533_acr122_tx_frame {
|
||||
struct pn533_acr122_ccid_hdr ccid;
|
||||
struct pn533_acr122_apdu_hdr apdu;
|
||||
u8 datalen;
|
||||
u8 data[]; /* pn533 frame: TFI ... */
|
||||
} __packed;
|
||||
|
||||
struct pn533_acr122_rx_frame {
|
||||
struct pn533_acr122_ccid_hdr ccid;
|
||||
u8 data[]; /* pn533 frame : TFI ... */
|
||||
} __packed;
|
||||
|
||||
static void pn533_acr122_tx_frame_init(void *_frame, u8 cmd_code)
|
||||
{
|
||||
struct pn533_acr122_tx_frame *frame = _frame;
|
||||
|
||||
frame->ccid.type = PN533_ACR122_PC_TO_RDR_ESCAPE;
|
||||
/* sizeof(apdu_hdr) + sizeof(datalen) */
|
||||
frame->ccid.datalen = sizeof(frame->apdu) + 1;
|
||||
frame->ccid.slot = 0;
|
||||
frame->ccid.seq = 0;
|
||||
frame->ccid.params[0] = 0;
|
||||
frame->ccid.params[1] = 0;
|
||||
frame->ccid.params[2] = 0;
|
||||
|
||||
frame->data[0] = PN533_STD_FRAME_DIR_OUT;
|
||||
frame->data[1] = cmd_code;
|
||||
frame->datalen = 2; /* data[0] + data[1] */
|
||||
|
||||
frame->apdu.class = 0xFF;
|
||||
frame->apdu.ins = 0;
|
||||
frame->apdu.p1 = 0;
|
||||
frame->apdu.p2 = 0;
|
||||
}
|
||||
|
||||
static void pn533_acr122_tx_frame_finish(void *_frame)
|
||||
{
|
||||
struct pn533_acr122_tx_frame *frame = _frame;
|
||||
|
||||
frame->ccid.datalen += frame->datalen;
|
||||
}
|
||||
|
||||
static void pn533_acr122_tx_update_payload_len(void *_frame, int len)
|
||||
{
|
||||
struct pn533_acr122_tx_frame *frame = _frame;
|
||||
|
||||
frame->datalen += len;
|
||||
}
|
||||
|
||||
static bool pn533_acr122_is_rx_frame_valid(void *_frame, struct pn533 *dev)
|
||||
{
|
||||
struct pn533_acr122_rx_frame *frame = _frame;
|
||||
|
||||
if (frame->ccid.type != 0x83)
|
||||
return false;
|
||||
|
||||
if (!frame->ccid.datalen)
|
||||
return false;
|
||||
|
||||
if (frame->data[frame->ccid.datalen - 2] == 0x63)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int pn533_acr122_rx_frame_size(void *frame)
|
||||
{
|
||||
struct pn533_acr122_rx_frame *f = frame;
|
||||
|
||||
/* f->ccid.datalen already includes tail length */
|
||||
return sizeof(struct pn533_acr122_rx_frame) + f->ccid.datalen;
|
||||
}
|
||||
|
||||
static u8 pn533_acr122_get_cmd_code(void *frame)
|
||||
{
|
||||
struct pn533_acr122_rx_frame *f = frame;
|
||||
|
||||
return PN533_FRAME_CMD(f);
|
||||
}
|
||||
|
||||
static struct pn533_frame_ops pn533_acr122_frame_ops = {
|
||||
.tx_frame_init = pn533_acr122_tx_frame_init,
|
||||
.tx_frame_finish = pn533_acr122_tx_frame_finish,
|
||||
.tx_update_payload_len = pn533_acr122_tx_update_payload_len,
|
||||
.tx_header_len = PN533_ACR122_TX_FRAME_HEADER_LEN,
|
||||
.tx_tail_len = PN533_ACR122_TX_FRAME_TAIL_LEN,
|
||||
|
||||
.rx_is_frame_valid = pn533_acr122_is_rx_frame_valid,
|
||||
.rx_header_len = PN533_ACR122_RX_FRAME_HEADER_LEN,
|
||||
.rx_tail_len = PN533_ACR122_RX_FRAME_TAIL_LEN,
|
||||
.rx_frame_size = pn533_acr122_rx_frame_size,
|
||||
|
||||
.max_payload_len = PN533_ACR122_FRAME_MAX_PAYLOAD_LEN,
|
||||
.get_cmd_code = pn533_acr122_get_cmd_code,
|
||||
};
|
||||
|
||||
struct pn533_acr122_poweron_rdr_arg {
|
||||
int rc;
|
||||
struct completion done;
|
||||
};
|
||||
|
||||
static void pn533_acr122_poweron_rdr_resp(struct urb *urb)
|
||||
{
|
||||
struct pn533_acr122_poweron_rdr_arg *arg = urb->context;
|
||||
|
||||
dev_dbg(&urb->dev->dev, "%s\n", __func__);
|
||||
|
||||
print_hex_dump_debug("ACR122 RX: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
urb->transfer_buffer, urb->transfer_buffer_length,
|
||||
false);
|
||||
|
||||
arg->rc = urb->status;
|
||||
complete(&arg->done);
|
||||
}
|
||||
|
||||
static int pn533_acr122_poweron_rdr(struct pn533_usb_phy *phy)
|
||||
{
|
||||
/* Power on th reader (CCID cmd) */
|
||||
u8 cmd[10] = {PN533_ACR122_PC_TO_RDR_ICCPOWERON,
|
||||
0, 0, 0, 0, 0, 0, 3, 0, 0};
|
||||
int rc;
|
||||
void *cntx;
|
||||
struct pn533_acr122_poweron_rdr_arg arg;
|
||||
|
||||
dev_dbg(&phy->udev->dev, "%s\n", __func__);
|
||||
|
||||
init_completion(&arg.done);
|
||||
cntx = phy->in_urb->context; /* backup context */
|
||||
|
||||
phy->in_urb->complete = pn533_acr122_poweron_rdr_resp;
|
||||
phy->in_urb->context = &arg;
|
||||
|
||||
phy->out_urb->transfer_buffer = cmd;
|
||||
phy->out_urb->transfer_buffer_length = sizeof(cmd);
|
||||
|
||||
print_hex_dump_debug("ACR122 TX: ", DUMP_PREFIX_NONE, 16, 1,
|
||||
cmd, sizeof(cmd), false);
|
||||
|
||||
rc = usb_submit_urb(phy->out_urb, GFP_KERNEL);
|
||||
if (rc) {
|
||||
nfc_err(&phy->udev->dev,
|
||||
"Reader power on cmd error %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
rc = usb_submit_urb(phy->in_urb, GFP_KERNEL);
|
||||
if (rc) {
|
||||
nfc_err(&phy->udev->dev,
|
||||
"Can't submit reader poweron cmd response %d\n", rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
wait_for_completion(&arg.done);
|
||||
phy->in_urb->context = cntx; /* restore context */
|
||||
|
||||
return arg.rc;
|
||||
}
|
||||
|
||||
static void pn533_send_complete(struct urb *urb)
|
||||
{
|
||||
struct pn533_usb_phy *phy = urb->context;
|
||||
|
||||
switch (urb->status) {
|
||||
case 0:
|
||||
break; /* success */
|
||||
case -ECONNRESET:
|
||||
case -ENOENT:
|
||||
dev_dbg(&phy->udev->dev,
|
||||
"The urb has been stopped (status %d)\n",
|
||||
urb->status);
|
||||
break;
|
||||
case -ESHUTDOWN:
|
||||
default:
|
||||
nfc_err(&phy->udev->dev,
|
||||
"Urb failure (status %d)\n",
|
||||
urb->status);
|
||||
}
|
||||
}
|
||||
|
||||
static struct pn533_phy_ops usb_phy_ops = {
|
||||
.send_frame = pn533_usb_send_frame,
|
||||
.send_ack = pn533_usb_send_ack,
|
||||
.abort_cmd = pn533_usb_abort_cmd,
|
||||
};
|
||||
|
||||
static int pn533_usb_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
struct pn533 *priv;
|
||||
struct pn533_usb_phy *phy;
|
||||
struct usb_host_interface *iface_desc;
|
||||
struct usb_endpoint_descriptor *endpoint;
|
||||
int in_endpoint = 0;
|
||||
int out_endpoint = 0;
|
||||
int rc = -ENOMEM;
|
||||
int i;
|
||||
u32 protocols;
|
||||
enum pn533_protocol_type protocol_type = PN533_PROTO_REQ_ACK_RESP;
|
||||
struct pn533_frame_ops *fops = NULL;
|
||||
unsigned char *in_buf;
|
||||
int in_buf_len = PN533_EXT_FRAME_HEADER_LEN +
|
||||
PN533_STD_FRAME_MAX_PAYLOAD_LEN +
|
||||
PN533_STD_FRAME_TAIL_LEN;
|
||||
|
||||
phy = devm_kzalloc(&interface->dev, sizeof(*phy), GFP_KERNEL);
|
||||
if (!phy)
|
||||
return -ENOMEM;
|
||||
|
||||
in_buf = kzalloc(in_buf_len, GFP_KERNEL);
|
||||
if (!in_buf) {
|
||||
rc = -ENOMEM;
|
||||
goto out_free_phy;
|
||||
}
|
||||
|
||||
phy->udev = usb_get_dev(interface_to_usbdev(interface));
|
||||
phy->interface = interface;
|
||||
|
||||
iface_desc = interface->cur_altsetting;
|
||||
for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
|
||||
endpoint = &iface_desc->endpoint[i].desc;
|
||||
|
||||
if (!in_endpoint && usb_endpoint_is_bulk_in(endpoint))
|
||||
in_endpoint = endpoint->bEndpointAddress;
|
||||
|
||||
if (!out_endpoint && usb_endpoint_is_bulk_out(endpoint))
|
||||
out_endpoint = endpoint->bEndpointAddress;
|
||||
}
|
||||
|
||||
if (!in_endpoint || !out_endpoint) {
|
||||
nfc_err(&interface->dev,
|
||||
"Could not find bulk-in or bulk-out endpoint\n");
|
||||
rc = -ENODEV;
|
||||
goto error;
|
||||
}
|
||||
|
||||
phy->in_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
phy->out_urb = usb_alloc_urb(0, GFP_KERNEL);
|
||||
|
||||
if (!phy->in_urb || !phy->out_urb)
|
||||
goto error;
|
||||
|
||||
usb_fill_bulk_urb(phy->in_urb, phy->udev,
|
||||
usb_rcvbulkpipe(phy->udev, in_endpoint),
|
||||
in_buf, in_buf_len, NULL, phy);
|
||||
|
||||
usb_fill_bulk_urb(phy->out_urb, phy->udev,
|
||||
usb_sndbulkpipe(phy->udev, out_endpoint),
|
||||
NULL, 0, pn533_send_complete, phy);
|
||||
|
||||
|
||||
switch (id->driver_info) {
|
||||
case PN533_DEVICE_STD:
|
||||
protocols = PN533_ALL_PROTOCOLS;
|
||||
break;
|
||||
|
||||
case PN533_DEVICE_PASORI:
|
||||
protocols = PN533_NO_TYPE_B_PROTOCOLS;
|
||||
break;
|
||||
|
||||
case PN533_DEVICE_ACR122U:
|
||||
protocols = PN533_NO_TYPE_B_PROTOCOLS;
|
||||
fops = &pn533_acr122_frame_ops;
|
||||
protocol_type = PN533_PROTO_REQ_RESP,
|
||||
|
||||
rc = pn533_acr122_poweron_rdr(phy);
|
||||
if (rc < 0) {
|
||||
nfc_err(&interface->dev,
|
||||
"Couldn't poweron the reader (error %d)\n", rc);
|
||||
goto error;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
nfc_err(&interface->dev, "Unknown device type %lu\n",
|
||||
id->driver_info);
|
||||
rc = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
|
||||
priv = pn533_register_device(id->driver_info, protocols, protocol_type,
|
||||
phy, &usb_phy_ops, fops,
|
||||
&phy->udev->dev, &interface->dev);
|
||||
|
||||
if (IS_ERR(priv)) {
|
||||
rc = PTR_ERR(priv);
|
||||
goto error;
|
||||
}
|
||||
|
||||
phy->priv = priv;
|
||||
|
||||
usb_set_intfdata(interface, phy);
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
usb_free_urb(phy->in_urb);
|
||||
usb_free_urb(phy->out_urb);
|
||||
usb_put_dev(phy->udev);
|
||||
kfree(in_buf);
|
||||
out_free_phy:
|
||||
kfree(phy);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void pn533_usb_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct pn533_usb_phy *phy = usb_get_intfdata(interface);
|
||||
|
||||
if (!phy)
|
||||
return;
|
||||
|
||||
pn533_unregister_device(phy->priv);
|
||||
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
usb_kill_urb(phy->in_urb);
|
||||
usb_kill_urb(phy->out_urb);
|
||||
|
||||
kfree(phy->in_urb->transfer_buffer);
|
||||
usb_free_urb(phy->in_urb);
|
||||
usb_free_urb(phy->out_urb);
|
||||
|
||||
nfc_info(&interface->dev, "NXP PN533 NFC device disconnected\n");
|
||||
}
|
||||
|
||||
static struct usb_driver pn533_usb_driver = {
|
||||
.name = "pn533_usb",
|
||||
.probe = pn533_usb_probe,
|
||||
.disconnect = pn533_usb_disconnect,
|
||||
.id_table = pn533_usb_table,
|
||||
};
|
||||
|
||||
module_usb_driver(pn533_usb_driver);
|
||||
|
||||
MODULE_AUTHOR("Lauro Ramos Venancio <lauro.venancio@openbossa.org>");
|
||||
MODULE_AUTHOR("Aloisio Almeida Jr <aloisio.almeida@openbossa.org>");
|
||||
MODULE_AUTHOR("Waldemar Rymarkiewicz <waldemar.rymarkiewicz@tieto.com>");
|
||||
MODULE_DESCRIPTION("PN533 USB driver ver " VERSION);
|
||||
MODULE_VERSION(VERSION);
|
||||
MODULE_LICENSE("GPL");
|
|
@ -1106,7 +1106,6 @@ MODULE_DEVICE_TABLE(of, of_pn544_i2c_match);
|
|||
static struct i2c_driver pn544_hci_i2c_driver = {
|
||||
.driver = {
|
||||
.name = PN544_HCI_I2C_DRIVER_NAME,
|
||||
.owner = THIS_MODULE,
|
||||
.of_match_table = of_match_ptr(of_pn544_i2c_match),
|
||||
.acpi_match_table = ACPI_PTR(pn544_hci_i2c_acpi_match),
|
||||
},
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
#define ST_NCI_I2C_DRIVER_NAME "st_nci_i2c"
|
||||
|
||||
#define ST_NCI_GPIO_NAME_RESET "clf_reset"
|
||||
#define ST_NCI_GPIO_NAME_RESET "reset"
|
||||
|
||||
struct st_nci_i2c_phy {
|
||||
struct i2c_client *i2c_dev;
|
||||
|
@ -211,19 +211,9 @@ static struct nfc_phy_ops i2c_phy_ops = {
|
|||
static int st_nci_i2c_acpi_request_resources(struct i2c_client *client)
|
||||
{
|
||||
struct st_nci_i2c_phy *phy = i2c_get_clientdata(client);
|
||||
const struct acpi_device_id *id;
|
||||
struct gpio_desc *gpiod_reset;
|
||||
struct device *dev;
|
||||
|
||||
if (!client)
|
||||
return -EINVAL;
|
||||
|
||||
dev = &client->dev;
|
||||
|
||||
/* Match the struct device against a given list of ACPI IDs */
|
||||
id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
struct device *dev = &client->dev;
|
||||
u8 tmp;
|
||||
|
||||
/* Get RESET GPIO from ACPI */
|
||||
gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, 1,
|
||||
|
@ -237,10 +227,18 @@ static int st_nci_i2c_acpi_request_resources(struct i2c_client *client)
|
|||
|
||||
phy->irq_polarity = irq_get_trigger_type(client->irq);
|
||||
|
||||
phy->se_status.is_ese_present =
|
||||
device_property_present(dev, "ese-present");
|
||||
phy->se_status.is_uicc_present =
|
||||
device_property_present(dev, "uicc-present");
|
||||
phy->se_status.is_ese_present = false;
|
||||
phy->se_status.is_uicc_present = false;
|
||||
|
||||
if (device_property_present(dev, "ese-present")) {
|
||||
device_property_read_u8(dev, "ese-present", &tmp);
|
||||
phy->se_status.is_ese_present = tmp;
|
||||
}
|
||||
|
||||
if (device_property_present(dev, "uicc-present")) {
|
||||
device_property_read_u8(dev, "uicc-present", &tmp);
|
||||
phy->se_status.is_uicc_present = tmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -416,7 +414,6 @@ MODULE_DEVICE_TABLE(of, of_st_nci_i2c_match);
|
|||
|
||||
static struct i2c_driver st_nci_i2c_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = ST_NCI_I2C_DRIVER_NAME,
|
||||
.of_match_table = of_match_ptr(of_st_nci_i2c_match),
|
||||
.acpi_match_table = ACPI_PTR(st_nci_i2c_acpi_match),
|
||||
|
|
|
@ -113,8 +113,6 @@ static struct nci_hci_gate st_nci_gates[] = {
|
|||
|
||||
{NCI_HCI_IDENTITY_MGMT_GATE, NCI_HCI_INVALID_PIPE,
|
||||
ST_NCI_HOST_CONTROLLER_ID},
|
||||
{NCI_HCI_LOOPBACK_GATE, NCI_HCI_INVALID_PIPE,
|
||||
ST_NCI_HOST_CONTROLLER_ID},
|
||||
|
||||
/* Secure element pipes are created by secure element host */
|
||||
{ST_NCI_CONNECTIVITY_GATE, NCI_HCI_DO_NOT_OPEN_PIPE,
|
||||
|
@ -222,7 +220,7 @@ int st_nci_hci_load_session(struct nci_dev *ndev)
|
|||
*/
|
||||
dm_pipe_info = (struct st_nci_pipe_info *)skb_pipe_info->data;
|
||||
if (dm_pipe_info->dst_gate_id == ST_NCI_APDU_READER_GATE &&
|
||||
dm_pipe_info->src_host_id != ST_NCI_ESE_HOST_ID) {
|
||||
dm_pipe_info->src_host_id == ST_NCI_UICC_HOST_ID) {
|
||||
pr_err("Unexpected apdu_reader pipe on host %x\n",
|
||||
dm_pipe_info->src_host_id);
|
||||
kfree_skb(skb_pipe_info);
|
||||
|
@ -385,9 +383,6 @@ void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe,
|
|||
case ST_NCI_CONNECTIVITY_GATE:
|
||||
st_nci_hci_connectivity_event_received(ndev, host, event, skb);
|
||||
break;
|
||||
case NCI_HCI_LOOPBACK_GATE:
|
||||
st_nci_hci_loopback_event_received(ndev, event, skb);
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(st_nci_hci_event_received);
|
||||
|
@ -520,7 +515,7 @@ int st_nci_enable_se(struct nci_dev *ndev, u32 se_idx)
|
|||
* Same for eSE.
|
||||
*/
|
||||
r = st_nci_control_se(ndev, se_idx, ST_NCI_SE_MODE_ON);
|
||||
if (r == ST_NCI_HCI_HOST_ID_ESE) {
|
||||
if (r == ST_NCI_ESE_HOST_ID) {
|
||||
st_nci_se_get_atr(ndev);
|
||||
r = nci_hci_send_event(ndev, ST_NCI_APDU_READER_GATE,
|
||||
ST_NCI_EVT_SE_SOFT_RESET, NULL, 0);
|
||||
|
@ -600,10 +595,12 @@ static int st_nci_hci_network_init(struct nci_dev *ndev)
|
|||
* HCI will be used here only for proprietary commands.
|
||||
*/
|
||||
if (test_bit(ST_NCI_FACTORY_MODE, &info->flags))
|
||||
r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id,
|
||||
r = nci_nfcee_mode_set(ndev,
|
||||
ndev->hci_dev->conn_info->dest_params->id,
|
||||
NCI_NFCEE_DISABLE);
|
||||
else
|
||||
r = nci_nfcee_mode_set(ndev, ndev->hci_dev->conn_info->id,
|
||||
r = nci_nfcee_mode_set(ndev,
|
||||
ndev->hci_dev->conn_info->dest_params->id,
|
||||
NCI_NFCEE_ENABLE);
|
||||
|
||||
free_dest_params:
|
||||
|
@ -629,17 +626,10 @@ int st_nci_discover_se(struct nci_dev *ndev)
|
|||
if (test_bit(ST_NCI_FACTORY_MODE, &info->flags))
|
||||
return 0;
|
||||
|
||||
if (info->se_info.se_status->is_ese_present &&
|
||||
info->se_info.se_status->is_uicc_present) {
|
||||
if (info->se_info.se_status->is_uicc_present)
|
||||
white_list[wl_size++] = ST_NCI_UICC_HOST_ID;
|
||||
if (info->se_info.se_status->is_ese_present)
|
||||
white_list[wl_size++] = ST_NCI_ESE_HOST_ID;
|
||||
} else if (!info->se_info.se_status->is_ese_present &&
|
||||
info->se_info.se_status->is_uicc_present) {
|
||||
white_list[wl_size++] = ST_NCI_UICC_HOST_ID;
|
||||
} else if (info->se_info.se_status->is_ese_present &&
|
||||
!info->se_info.se_status->is_uicc_present) {
|
||||
white_list[wl_size++] = ST_NCI_ESE_HOST_ID;
|
||||
}
|
||||
|
||||
if (wl_size) {
|
||||
r = nci_hci_set_param(ndev, NCI_HCI_ADMIN_GATE,
|
||||
|
@ -672,7 +662,7 @@ int st_nci_se_io(struct nci_dev *ndev, u32 se_idx,
|
|||
pr_debug("\n");
|
||||
|
||||
switch (se_idx) {
|
||||
case ST_NCI_HCI_HOST_ID_ESE:
|
||||
case ST_NCI_ESE_HOST_ID:
|
||||
info->se_info.cb = cb;
|
||||
info->se_info.cb_context = cb_context;
|
||||
mod_timer(&info->se_info.bwi_timer, jiffies +
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
|
||||
#define ST_NCI_SPI_DRIVER_NAME "st_nci_spi"
|
||||
|
||||
#define ST_NCI_GPIO_NAME_RESET "clf_reset"
|
||||
#define ST_NCI_GPIO_NAME_RESET "reset"
|
||||
|
||||
struct st_nci_spi_phy {
|
||||
struct spi_device *spi_dev;
|
||||
|
@ -226,19 +226,9 @@ static struct nfc_phy_ops spi_phy_ops = {
|
|||
static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev)
|
||||
{
|
||||
struct st_nci_spi_phy *phy = spi_get_drvdata(spi_dev);
|
||||
const struct acpi_device_id *id;
|
||||
struct gpio_desc *gpiod_reset;
|
||||
struct device *dev;
|
||||
|
||||
if (!spi_dev)
|
||||
return -EINVAL;
|
||||
|
||||
dev = &spi_dev->dev;
|
||||
|
||||
/* Match the struct device against a given list of ACPI IDs */
|
||||
id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
struct device *dev = &spi_dev->dev;
|
||||
u8 tmp;
|
||||
|
||||
/* Get RESET GPIO from ACPI */
|
||||
gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, 1,
|
||||
|
@ -252,10 +242,18 @@ static int st_nci_spi_acpi_request_resources(struct spi_device *spi_dev)
|
|||
|
||||
phy->irq_polarity = irq_get_trigger_type(spi_dev->irq);
|
||||
|
||||
phy->se_status.is_ese_present =
|
||||
device_property_present(dev, "ese-present");
|
||||
phy->se_status.is_uicc_present =
|
||||
device_property_present(dev, "uicc-present");
|
||||
phy->se_status.is_ese_present = false;
|
||||
phy->se_status.is_uicc_present = false;
|
||||
|
||||
if (device_property_present(dev, "ese-present")) {
|
||||
device_property_read_u8(dev, "ese-present", &tmp);
|
||||
tmp = phy->se_status.is_ese_present;
|
||||
}
|
||||
|
||||
if (device_property_present(dev, "uicc-present")) {
|
||||
device_property_read_u8(dev, "uicc-present", &tmp);
|
||||
tmp = phy->se_status.is_uicc_present;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -32,7 +32,6 @@
|
|||
* sequence of at most 32 characters.
|
||||
*/
|
||||
#define ST_NCI_ESE_MAX_LENGTH 33
|
||||
#define ST_NCI_HCI_HOST_ID_ESE 0xc0
|
||||
|
||||
#define ST_NCI_DEVICE_MGNT_GATE 0x01
|
||||
|
||||
|
@ -93,8 +92,7 @@ struct st_nci_se_info {
|
|||
* white list).
|
||||
* @HCI_DM_FIELD_GENERATOR: Allow to generate different kind of RF
|
||||
* technology. When using this command to anti-collision is done.
|
||||
* @HCI_LOOPBACK: Allow to echo a command and test the Dh to CLF
|
||||
* connectivity.
|
||||
* @LOOPBACK: Allow to echo a command and test the Dh to CLF connectivity.
|
||||
* @HCI_DM_VDC_MEASUREMENT_VALUE: Allow to measure the field applied on the
|
||||
* CLF antenna. A value between 0 and 0x0f is returned. 0 is maximum.
|
||||
* @HCI_DM_FWUPD_START: Allow to put CLF into firmware update mode. It is a
|
||||
|
@ -116,7 +114,7 @@ enum nfc_vendor_cmds {
|
|||
HCI_DM_RESET,
|
||||
HCI_GET_PARAM,
|
||||
HCI_DM_FIELD_GENERATOR,
|
||||
HCI_LOOPBACK,
|
||||
LOOPBACK,
|
||||
HCI_DM_FWUPD_START,
|
||||
HCI_DM_FWUPD_END,
|
||||
HCI_DM_VDC_MEASUREMENT_VALUE,
|
||||
|
@ -124,17 +122,11 @@ enum nfc_vendor_cmds {
|
|||
MANUFACTURER_SPECIFIC,
|
||||
};
|
||||
|
||||
struct st_nci_vendor_info {
|
||||
struct completion req_completion;
|
||||
struct sk_buff *rx_skb;
|
||||
};
|
||||
|
||||
struct st_nci_info {
|
||||
struct llt_ndlc *ndlc;
|
||||
unsigned long flags;
|
||||
|
||||
struct st_nci_se_info se_info;
|
||||
struct st_nci_vendor_info vendor_info;
|
||||
};
|
||||
|
||||
void st_nci_remove(struct nci_dev *ndev);
|
||||
|
@ -156,8 +148,6 @@ void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe,
|
|||
void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
|
||||
struct sk_buff *skb);
|
||||
|
||||
void st_nci_hci_loopback_event_received(struct nci_dev *ndev, u8 event,
|
||||
struct sk_buff *skb);
|
||||
int st_nci_vendor_cmds_init(struct nci_dev *ndev);
|
||||
|
||||
#endif /* __LOCAL_ST_NCI_H_ */
|
||||
|
|
|
@ -333,62 +333,28 @@ static int st_nci_hci_dm_vdc_value_comparison(struct nfc_dev *dev, void *data,
|
|||
return r;
|
||||
}
|
||||
|
||||
void st_nci_hci_loopback_event_received(struct nci_dev *ndev, u8 event,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
struct st_nci_info *info = nci_get_drvdata(ndev);
|
||||
|
||||
switch (event) {
|
||||
case ST_NCI_EVT_POST_DATA:
|
||||
info->vendor_info.rx_skb = skb;
|
||||
break;
|
||||
default:
|
||||
nfc_err(&ndev->nfc_dev->dev, "Unexpected event on loopback gate\n");
|
||||
}
|
||||
complete(&info->vendor_info.req_completion);
|
||||
}
|
||||
EXPORT_SYMBOL(st_nci_hci_loopback_event_received);
|
||||
|
||||
static int st_nci_hci_loopback(struct nfc_dev *dev, void *data,
|
||||
size_t data_len)
|
||||
static int st_nci_loopback(struct nfc_dev *dev, void *data,
|
||||
size_t data_len)
|
||||
{
|
||||
int r;
|
||||
struct sk_buff *msg;
|
||||
struct sk_buff *msg, *skb;
|
||||
struct nci_dev *ndev = nfc_get_drvdata(dev);
|
||||
struct st_nci_info *info = nci_get_drvdata(ndev);
|
||||
|
||||
if (data_len <= 0)
|
||||
return -EPROTO;
|
||||
|
||||
reinit_completion(&info->vendor_info.req_completion);
|
||||
info->vendor_info.rx_skb = NULL;
|
||||
r = nci_nfcc_loopback(ndev, data, data_len, &skb);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = nci_hci_send_event(ndev, NCI_HCI_LOOPBACK_GATE,
|
||||
ST_NCI_EVT_POST_DATA, data, data_len);
|
||||
if (r != data_len) {
|
||||
r = -EPROTO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
wait_for_completion_interruptible(&info->vendor_info.req_completion);
|
||||
|
||||
if (!info->vendor_info.rx_skb ||
|
||||
info->vendor_info.rx_skb->len != data_len) {
|
||||
r = -EPROTO;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
msg = nfc_vendor_cmd_alloc_reply_skb(ndev->nfc_dev,
|
||||
ST_NCI_VENDOR_OUI,
|
||||
HCI_LOOPBACK,
|
||||
info->vendor_info.rx_skb->len);
|
||||
msg = nfc_vendor_cmd_alloc_reply_skb(dev, ST_NCI_VENDOR_OUI,
|
||||
LOOPBACK, skb->len);
|
||||
if (!msg) {
|
||||
r = -ENOMEM;
|
||||
goto free_skb;
|
||||
}
|
||||
|
||||
if (nla_put(msg, NFC_ATTR_VENDOR_DATA, info->vendor_info.rx_skb->len,
|
||||
info->vendor_info.rx_skb->data)) {
|
||||
if (nla_put(msg, NFC_ATTR_VENDOR_DATA, skb->len, skb->data)) {
|
||||
kfree_skb(msg);
|
||||
r = -ENOBUFS;
|
||||
goto free_skb;
|
||||
|
@ -396,8 +362,7 @@ static int st_nci_hci_loopback(struct nfc_dev *dev, void *data,
|
|||
|
||||
r = nfc_vendor_cmd_reply(msg);
|
||||
free_skb:
|
||||
kfree_skb(info->vendor_info.rx_skb);
|
||||
exit:
|
||||
kfree_skb(skb);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -485,8 +450,8 @@ static struct nfc_vendor_cmd st_nci_vendor_cmds[] = {
|
|||
},
|
||||
{
|
||||
.vendor_id = ST_NCI_VENDOR_OUI,
|
||||
.subcmd = HCI_LOOPBACK,
|
||||
.doit = st_nci_hci_loopback,
|
||||
.subcmd = LOOPBACK,
|
||||
.doit = st_nci_loopback,
|
||||
},
|
||||
{
|
||||
.vendor_id = ST_NCI_VENDOR_OUI,
|
||||
|
@ -507,9 +472,6 @@ static struct nfc_vendor_cmd st_nci_vendor_cmds[] = {
|
|||
|
||||
int st_nci_vendor_cmds_init(struct nci_dev *ndev)
|
||||
{
|
||||
struct st_nci_info *info = nci_get_drvdata(ndev);
|
||||
|
||||
init_completion(&info->vendor_info.req_completion);
|
||||
return nfc_set_vendor_cmds(ndev->nfc_dev, st_nci_vendor_cmds,
|
||||
sizeof(st_nci_vendor_cmds));
|
||||
}
|
||||
|
|
|
@ -176,7 +176,7 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
|
|||
*/
|
||||
info = (struct st21nfca_pipe_info *) skb_pipe_info->data;
|
||||
if (info->dst_gate_id == ST21NFCA_APDU_READER_GATE &&
|
||||
info->src_host_id != ST21NFCA_ESE_HOST_ID) {
|
||||
info->src_host_id == NFC_HCI_UICC_HOST_ID) {
|
||||
pr_err("Unexpected apdu_reader pipe on host %x\n",
|
||||
info->src_host_id);
|
||||
kfree_skb(skb_pipe_info);
|
||||
|
@ -262,17 +262,10 @@ static int st21nfca_hci_ready(struct nfc_hci_dev *hdev)
|
|||
int wl_size = 0;
|
||||
int r;
|
||||
|
||||
if (info->se_status->is_ese_present &&
|
||||
info->se_status->is_uicc_present) {
|
||||
if (info->se_status->is_uicc_present)
|
||||
white_list[wl_size++] = NFC_HCI_UICC_HOST_ID;
|
||||
if (info->se_status->is_ese_present)
|
||||
white_list[wl_size++] = ST21NFCA_ESE_HOST_ID;
|
||||
} else if (!info->se_status->is_ese_present &&
|
||||
info->se_status->is_uicc_present) {
|
||||
white_list[wl_size++] = NFC_HCI_UICC_HOST_ID;
|
||||
} else if (info->se_status->is_ese_present &&
|
||||
!info->se_status->is_uicc_present) {
|
||||
white_list[wl_size++] = ST21NFCA_ESE_HOST_ID;
|
||||
}
|
||||
|
||||
if (wl_size) {
|
||||
r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE,
|
||||
|
|
|
@ -62,7 +62,7 @@
|
|||
|
||||
#define ST21NFCA_HCI_I2C_DRIVER_NAME "st21nfca_hci_i2c"
|
||||
|
||||
#define ST21NFCA_GPIO_NAME_EN "clf_enable"
|
||||
#define ST21NFCA_GPIO_NAME_EN "enable"
|
||||
|
||||
struct st21nfca_i2c_phy {
|
||||
struct i2c_client *i2c_dev;
|
||||
|
@ -507,34 +507,34 @@ static struct nfc_phy_ops i2c_phy_ops = {
|
|||
static int st21nfca_hci_i2c_acpi_request_resources(struct i2c_client *client)
|
||||
{
|
||||
struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client);
|
||||
const struct acpi_device_id *id;
|
||||
struct gpio_desc *gpiod_ena;
|
||||
struct device *dev;
|
||||
|
||||
if (!client)
|
||||
return -EINVAL;
|
||||
|
||||
dev = &client->dev;
|
||||
|
||||
/* Match the struct device against a given list of ACPI IDs */
|
||||
id = acpi_match_device(dev->driver->acpi_match_table, dev);
|
||||
if (!id)
|
||||
return -ENODEV;
|
||||
struct device *dev = &client->dev;
|
||||
u8 tmp;
|
||||
|
||||
/* Get EN GPIO from ACPI */
|
||||
gpiod_ena = devm_gpiod_get_index(dev, ST21NFCA_GPIO_NAME_EN, 1,
|
||||
GPIOD_OUT_LOW);
|
||||
if (!IS_ERR(gpiod_ena))
|
||||
phy->gpio_ena = desc_to_gpio(gpiod_ena);
|
||||
if (!IS_ERR(gpiod_ena)) {
|
||||
nfc_err(dev, "Unable to get ENABLE GPIO\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
phy->gpio_ena = desc_to_gpio(gpiod_ena);
|
||||
|
||||
phy->irq_polarity = irq_get_trigger_type(client->irq);
|
||||
|
||||
phy->se_status.is_ese_present =
|
||||
device_property_present(dev, "ese-present");
|
||||
phy->se_status.is_uicc_present =
|
||||
device_property_present(dev, "uicc-present");
|
||||
phy->se_status.is_ese_present = false;
|
||||
phy->se_status.is_uicc_present = false;
|
||||
|
||||
if (device_property_present(dev, "ese-present")) {
|
||||
device_property_read_u8(dev, "ese-present", &tmp);
|
||||
phy->se_status.is_ese_present = tmp;
|
||||
}
|
||||
|
||||
if (device_property_present(dev, "uicc-present")) {
|
||||
device_property_read_u8(dev, "uicc-present", &tmp);
|
||||
phy->se_status.is_uicc_present = tmp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -721,7 +721,6 @@ MODULE_DEVICE_TABLE(of, of_st21nfca_i2c_match);
|
|||
|
||||
static struct i2c_driver st21nfca_hci_i2c_driver = {
|
||||
.driver = {
|
||||
.owner = THIS_MODULE,
|
||||
.name = ST21NFCA_HCI_I2C_DRIVER_NAME,
|
||||
.of_match_table = of_match_ptr(of_st21nfca_i2c_match),
|
||||
.acpi_match_table = ACPI_PTR(st21nfca_hci_i2c_acpi_match),
|
||||
|
|
|
@ -32,8 +32,6 @@
|
|||
#define ST21NFCA_EVT_CONNECTIVITY 0x10
|
||||
#define ST21NFCA_EVT_TRANSACTION 0x12
|
||||
|
||||
#define ST21NFCA_ESE_HOST_ID 0xc0
|
||||
|
||||
#define ST21NFCA_SE_TO_HOT_PLUG 1000
|
||||
/* Connectivity pipe only */
|
||||
#define ST21NFCA_SE_COUNT_PIPE_UICC 0x01
|
||||
|
|
|
@ -109,7 +109,13 @@ struct nci_ops {
|
|||
|
||||
struct nci_conn_info {
|
||||
struct list_head list;
|
||||
__u8 id; /* can be an RF Discovery ID or an NFCEE ID */
|
||||
/* NCI specification 4.4.2 Connection Creation
|
||||
* The combination of destination type and destination specific
|
||||
* parameters shall uniquely identify a single destination for the
|
||||
* Logical Connection
|
||||
*/
|
||||
struct dest_spec_params *dest_params;
|
||||
__u8 dest_type;
|
||||
__u8 conn_id;
|
||||
__u8 max_pkt_payload_len;
|
||||
|
||||
|
@ -260,7 +266,9 @@ struct nci_dev {
|
|||
__u32 manufact_specific_info;
|
||||
|
||||
/* Save RF Discovery ID or NFCEE ID under conn_create */
|
||||
__u8 cur_id;
|
||||
struct dest_spec_params cur_params;
|
||||
/* Save destination type under conn_create */
|
||||
__u8 cur_dest_type;
|
||||
|
||||
/* stored during nci_data_exchange */
|
||||
struct sk_buff *rx_data_reassembly;
|
||||
|
@ -298,6 +306,8 @@ int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type,
|
|||
size_t params_len,
|
||||
struct core_conn_create_dest_spec_params *params);
|
||||
int nci_core_conn_close(struct nci_dev *ndev, u8 conn_id);
|
||||
int nci_nfcc_loopback(struct nci_dev *ndev, void *data, size_t data_len,
|
||||
struct sk_buff **resp);
|
||||
|
||||
struct nci_hci_dev *nci_hci_allocate(struct nci_dev *ndev);
|
||||
int nci_hci_send_event(struct nci_dev *ndev, u8 gate, u8 event,
|
||||
|
@ -378,7 +388,8 @@ void nci_clear_target_list(struct nci_dev *ndev);
|
|||
void nci_req_complete(struct nci_dev *ndev, int result);
|
||||
struct nci_conn_info *nci_get_conn_info_by_conn_id(struct nci_dev *ndev,
|
||||
int conn_id);
|
||||
int nci_get_conn_info_by_id(struct nci_dev *ndev, u8 id);
|
||||
int nci_get_conn_info_by_dest_type_params(struct nci_dev *ndev, u8 dest_type,
|
||||
struct dest_spec_params *params);
|
||||
|
||||
/* ----- NCI status code ----- */
|
||||
int nci_to_errno(__u8 code);
|
||||
|
|
|
@ -64,18 +64,26 @@ struct nci_conn_info *nci_get_conn_info_by_conn_id(struct nci_dev *ndev,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
int nci_get_conn_info_by_id(struct nci_dev *ndev, u8 id)
|
||||
int nci_get_conn_info_by_dest_type_params(struct nci_dev *ndev, u8 dest_type,
|
||||
struct dest_spec_params *params)
|
||||
{
|
||||
struct nci_conn_info *conn_info;
|
||||
|
||||
list_for_each_entry(conn_info, &ndev->conn_info_list, list) {
|
||||
if (conn_info->id == id)
|
||||
return conn_info->conn_id;
|
||||
if (conn_info->dest_type == dest_type) {
|
||||
if (!params)
|
||||
return conn_info->conn_id;
|
||||
if (conn_info) {
|
||||
if (params->id == conn_info->dest_params->id &&
|
||||
params->protocol == conn_info->dest_params->protocol)
|
||||
return conn_info->conn_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(nci_get_conn_info_by_id);
|
||||
EXPORT_SYMBOL(nci_get_conn_info_by_dest_type_params);
|
||||
|
||||
/* ---- NCI requests ---- */
|
||||
|
||||
|
@ -392,6 +400,83 @@ int nci_core_init(struct nci_dev *ndev)
|
|||
}
|
||||
EXPORT_SYMBOL(nci_core_init);
|
||||
|
||||
struct nci_loopback_data {
|
||||
u8 conn_id;
|
||||
struct sk_buff *data;
|
||||
};
|
||||
|
||||
static void nci_send_data_req(struct nci_dev *ndev, unsigned long opt)
|
||||
{
|
||||
struct nci_loopback_data *data = (struct nci_loopback_data *)opt;
|
||||
|
||||
nci_send_data(ndev, data->conn_id, data->data);
|
||||
}
|
||||
|
||||
static void nci_nfcc_loopback_cb(void *context, struct sk_buff *skb, int err)
|
||||
{
|
||||
struct nci_dev *ndev = (struct nci_dev *)context;
|
||||
struct nci_conn_info *conn_info;
|
||||
|
||||
conn_info = nci_get_conn_info_by_conn_id(ndev, ndev->cur_conn_id);
|
||||
if (!conn_info) {
|
||||
nci_req_complete(ndev, NCI_STATUS_REJECTED);
|
||||
return;
|
||||
}
|
||||
|
||||
conn_info->rx_skb = skb;
|
||||
|
||||
nci_req_complete(ndev, NCI_STATUS_OK);
|
||||
}
|
||||
|
||||
int nci_nfcc_loopback(struct nci_dev *ndev, void *data, size_t data_len,
|
||||
struct sk_buff **resp)
|
||||
{
|
||||
int r;
|
||||
struct nci_loopback_data loopback_data;
|
||||
struct nci_conn_info *conn_info;
|
||||
struct sk_buff *skb;
|
||||
int conn_id = nci_get_conn_info_by_dest_type_params(ndev,
|
||||
NCI_DESTINATION_NFCC_LOOPBACK, NULL);
|
||||
|
||||
if (conn_id < 0) {
|
||||
r = nci_core_conn_create(ndev, NCI_DESTINATION_NFCC_LOOPBACK,
|
||||
0, 0, NULL);
|
||||
if (r != NCI_STATUS_OK)
|
||||
return r;
|
||||
|
||||
conn_id = nci_get_conn_info_by_dest_type_params(ndev,
|
||||
NCI_DESTINATION_NFCC_LOOPBACK,
|
||||
NULL);
|
||||
}
|
||||
|
||||
conn_info = nci_get_conn_info_by_conn_id(ndev, conn_id);
|
||||
if (!conn_info)
|
||||
return -EPROTO;
|
||||
|
||||
/* store cb and context to be used on receiving data */
|
||||
conn_info->data_exchange_cb = nci_nfcc_loopback_cb;
|
||||
conn_info->data_exchange_cb_context = ndev;
|
||||
|
||||
skb = nci_skb_alloc(ndev, NCI_DATA_HDR_SIZE + data_len, GFP_KERNEL);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
|
||||
skb_reserve(skb, NCI_DATA_HDR_SIZE);
|
||||
memcpy(skb_put(skb, data_len), data, data_len);
|
||||
|
||||
loopback_data.conn_id = conn_id;
|
||||
loopback_data.data = skb;
|
||||
|
||||
ndev->cur_conn_id = conn_id;
|
||||
r = nci_request(ndev, nci_send_data_req, (unsigned long)&loopback_data,
|
||||
msecs_to_jiffies(NCI_DATA_TIMEOUT));
|
||||
if (r == NCI_STATUS_OK && resp)
|
||||
*resp = conn_info->rx_skb;
|
||||
|
||||
return r;
|
||||
}
|
||||
EXPORT_SYMBOL(nci_nfcc_loopback);
|
||||
|
||||
static int nci_open_device(struct nci_dev *ndev)
|
||||
{
|
||||
int rc = 0;
|
||||
|
@ -610,9 +695,6 @@ int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type,
|
|||
struct nci_core_conn_create_cmd *cmd;
|
||||
struct core_conn_create_data data;
|
||||
|
||||
if (!number_destination_params)
|
||||
return -EINVAL;
|
||||
|
||||
data.length = params_len + sizeof(struct nci_core_conn_create_cmd);
|
||||
cmd = kzalloc(data.length, GFP_KERNEL);
|
||||
if (!cmd)
|
||||
|
@ -620,17 +702,23 @@ int nci_core_conn_create(struct nci_dev *ndev, u8 destination_type,
|
|||
|
||||
cmd->destination_type = destination_type;
|
||||
cmd->number_destination_params = number_destination_params;
|
||||
memcpy(cmd->params, params, params_len);
|
||||
|
||||
data.cmd = cmd;
|
||||
|
||||
if (params->length > 0)
|
||||
ndev->cur_id = params->value[DEST_SPEC_PARAMS_ID_INDEX];
|
||||
else
|
||||
ndev->cur_id = 0;
|
||||
if (params) {
|
||||
memcpy(cmd->params, params, params_len);
|
||||
if (params->length > 0)
|
||||
memcpy(&ndev->cur_params,
|
||||
¶ms->value[DEST_SPEC_PARAMS_ID_INDEX],
|
||||
sizeof(struct dest_spec_params));
|
||||
else
|
||||
ndev->cur_params.id = 0;
|
||||
} else {
|
||||
ndev->cur_params.id = 0;
|
||||
}
|
||||
ndev->cur_dest_type = destination_type;
|
||||
|
||||
r = __nci_request(ndev, nci_core_conn_create_req,
|
||||
(unsigned long)&data,
|
||||
r = __nci_request(ndev, nci_core_conn_create_req, (unsigned long)&data,
|
||||
msecs_to_jiffies(NCI_CMD_TIMEOUT));
|
||||
kfree(cmd);
|
||||
return r;
|
||||
|
@ -646,6 +734,7 @@ static void nci_core_conn_close_req(struct nci_dev *ndev, unsigned long opt)
|
|||
|
||||
int nci_core_conn_close(struct nci_dev *ndev, u8 conn_id)
|
||||
{
|
||||
ndev->cur_conn_id = conn_id;
|
||||
return __nci_request(ndev, nci_core_conn_close_req, conn_id,
|
||||
msecs_to_jiffies(NCI_CMD_TIMEOUT));
|
||||
}
|
||||
|
|
|
@ -734,7 +734,7 @@ static void nci_nfcee_discover_ntf_packet(struct nci_dev *ndev,
|
|||
* “HCI Access”, even if the HCI Network contains multiple NFCEEs.
|
||||
*/
|
||||
ndev->hci_dev->nfcee_id = nfcee_ntf->nfcee_id;
|
||||
ndev->cur_id = nfcee_ntf->nfcee_id;
|
||||
ndev->cur_params.id = nfcee_ntf->nfcee_id;
|
||||
|
||||
nci_req_complete(ndev, status);
|
||||
}
|
||||
|
|
|
@ -226,7 +226,7 @@ static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev,
|
|||
struct sk_buff *skb)
|
||||
{
|
||||
__u8 status = skb->data[0];
|
||||
struct nci_conn_info *conn_info;
|
||||
struct nci_conn_info *conn_info = NULL;
|
||||
struct nci_core_conn_create_rsp *rsp;
|
||||
|
||||
pr_debug("status 0x%x\n", status);
|
||||
|
@ -241,7 +241,17 @@ static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev,
|
|||
goto exit;
|
||||
}
|
||||
|
||||
conn_info->id = ndev->cur_id;
|
||||
conn_info->dest_params = devm_kzalloc(&ndev->nfc_dev->dev,
|
||||
sizeof(struct dest_spec_params),
|
||||
GFP_KERNEL);
|
||||
if (!conn_info->dest_params) {
|
||||
status = NCI_STATUS_REJECTED;
|
||||
goto free_conn_info;
|
||||
}
|
||||
|
||||
conn_info->dest_type = ndev->cur_dest_type;
|
||||
conn_info->dest_params->id = ndev->cur_params.id;
|
||||
conn_info->dest_params->protocol = ndev->cur_params.protocol;
|
||||
conn_info->conn_id = rsp->conn_id;
|
||||
|
||||
/* Note: data_exchange_cb and data_exchange_cb_context need to
|
||||
|
@ -251,7 +261,7 @@ static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev,
|
|||
INIT_LIST_HEAD(&conn_info->list);
|
||||
list_add(&conn_info->list, &ndev->conn_info_list);
|
||||
|
||||
if (ndev->cur_id == ndev->hci_dev->nfcee_id)
|
||||
if (ndev->cur_params.id == ndev->hci_dev->nfcee_id)
|
||||
ndev->hci_dev->conn_info = conn_info;
|
||||
|
||||
conn_info->conn_id = rsp->conn_id;
|
||||
|
@ -259,7 +269,11 @@ static void nci_core_conn_create_rsp_packet(struct nci_dev *ndev,
|
|||
atomic_set(&conn_info->credits_cnt, rsp->credits_cnt);
|
||||
}
|
||||
|
||||
free_conn_info:
|
||||
if (status == NCI_STATUS_REJECTED)
|
||||
devm_kfree(&ndev->nfc_dev->dev, conn_info);
|
||||
exit:
|
||||
|
||||
nci_req_complete(ndev, status);
|
||||
}
|
||||
|
||||
|
@ -271,7 +285,8 @@ static void nci_core_conn_close_rsp_packet(struct nci_dev *ndev,
|
|||
|
||||
pr_debug("status 0x%x\n", status);
|
||||
if (status == NCI_STATUS_OK) {
|
||||
conn_info = nci_get_conn_info_by_conn_id(ndev, ndev->cur_id);
|
||||
conn_info = nci_get_conn_info_by_conn_id(ndev,
|
||||
ndev->cur_conn_id);
|
||||
if (conn_info) {
|
||||
list_del(&conn_info->list);
|
||||
devm_kfree(&ndev->nfc_dev->dev, conn_info);
|
||||
|
|
Loading…
Reference in a new issue