1
0
Fork 0

NFC 4.5 pull request

This is the first NFC pull request for 4.5 and it brings:
 
 - A new driver for the STMicroelectronics ST95HF NFC chipset.
   The ST95HF is an NFC digital transceiver with an embedded analog
   front-end and as such relies on the Linux NFC digital
   implementation. This is the 3rd user of the NFC digital stack.
 
 - ACPI support for the ST st-nci and st21nfca drivers.
 
 - A small improvement for the nfcsim driver, as we can now tune
   the Rx delay through sysfs.
 
 - A bunch of minor cleanups and small fixes from Christophe Ricard,
   for a few drivers and the NFC core code.
 -----BEGIN PGP SIGNATURE-----
 Version: GnuPG v1
 
 iQIcBAABAgAGBQJWgsv0AAoJEIqAPN1PVmxKvukP/3eJwA+chAUF89/fqwqFTaJN
 fffLoOxx2OBIbTXD2VV36yw4bAo9tbKDAYBZiot3Ig7Kg0SeCJ5oPA9xCVnWPrEY
 hxFAldvl+lWQs8nrUOgUZItiFBeUPdfW9YX/yKhUZVc+602nUG/e/+6x8B5MhIce
 SAfgCyd0c16DApltP7sw1muyZMvsO6Ow6dyNzDUVYZuabvEhe3SLSj9KFJi7Thsp
 h41Iv+bwPLhwF4RXGA6rei/gdEDSMRohprdj3uTDiTarGW+OpcAO0zWACS5m4eR0
 zF19+HjGPUk/LpFRaU31xX0ZQQjOTmmfsOt4FBb3P7oJx47egycsadLYPexeG7nj
 ruyS6ezlRX1I/tZsnyLNJK92mK5TXYLz2uJ8r2ii/BgPNE+AErB3zKCC+EjXzWhh
 AvClGu5b88WJLxoq3I3l5evPwGhebGZ8N/1uiFsHOxvzKVLgxwOmNLRGN4XXxB2i
 UbIHgBb6smsu/l+3q9R83kfoMaoWnr+OUIi2QPQVDt/K7t1LfsCuIhzcGSgo1VuW
 fGlA1iu+CNDknofeCl4JDo2UXAETO4gdKWw87GXeUcbbraLUczZeO7FFLZqxbMYc
 OCaPYshmVFeZRypYdRWDHw67ivj0/h+9iq4PP1XOROkRFH746dD/p4yamJwVi20B
 samZ8VPwzgH3/ohQJyX3
 =VFUH
 -----END PGP SIGNATURE-----

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

Samuel Ortiz says:

====================
NFC 4.5 pull request

This is the first NFC pull request for 4.5 and it brings:

- A new driver for the STMicroelectronics ST95HF NFC chipset.
  The ST95HF is an NFC digital transceiver with an embedded analog
  front-end and as such relies on the Linux NFC digital
  implementation. This is the 3rd user of the NFC digital stack.

- ACPI support for the ST st-nci and st21nfca drivers.

- A small improvement for the nfcsim driver, as we can now tune
  the Rx delay through sysfs.

- A bunch of minor cleanups and small fixes from Christophe Ricard,
  for a few drivers and the NFC core code.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
hifive-unleashed-5.1
David S. Miller 2016-01-04 21:48:15 -05:00
commit 15ab90f400
34 changed files with 1862 additions and 181 deletions

View File

@ -0,0 +1,50 @@
* STMicroelectronics : NFC Transceiver ST95HF
ST NFC Transceiver is required to attach with SPI bus.
ST95HF node should be defined in DT as SPI slave device of SPI
master with which ST95HF transceiver is physically connected.
The properties defined below are required to be the part of DT
to include ST95HF transceiver into the platform.
Required properties:
===================
- reg: Address of SPI slave "ST95HF transceiver" on SPI master bus.
- compatible: should be "st,st95hf" for ST95HF NFC transceiver
- spi-max-frequency: Max. operating SPI frequency for ST95HF
transceiver.
- enable-gpio: GPIO line to enable ST95HF transceiver.
- interrupt-parent : Standard way to specify the controller to which
ST95HF transceiver's interrupt is routed.
- interrupts : Standard way to define ST95HF transceiver's out
interrupt.
Optional property:
=================
- st95hfvin-supply : This is an optional property. It contains a
phandle to ST95HF transceiver's regulator supply node in DT.
Example:
=======
spi@9840000 {
reg = <0x9840000 0x110>;
#address-cells = <1>;
#size-cells = <0>;
cs-gpios = <&pio0 4>;
status = "okay";
st95hf@0{
reg = <0>;
compatible = "st,st95hf";
status = "okay";
spi-max-frequency = <1000000>;
enable-gpio = <&pio4 0>;
interrupt-parent = <&pio0>;
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
};
};

View File

@ -7523,7 +7523,12 @@ F: net/nfc/
F: include/net/nfc/
F: include/uapi/linux/nfc.h
F: drivers/nfc/
F: include/linux/platform_data/microread.h
F: include/linux/platform_data/nfcmrvl.h
F: include/linux/platform_data/nxp-nci.h
F: include/linux/platform_data/pn544.h
F: include/linux/platform_data/st21nfca.h
F: include/linux/platform_data/st-nci.h
F: Documentation/devicetree/bindings/net/nfc/
NFS, SUNRPC, AND LOCKD CLIENTS

View File

@ -76,4 +76,5 @@ source "drivers/nfc/st21nfca/Kconfig"
source "drivers/nfc/st-nci/Kconfig"
source "drivers/nfc/nxp-nci/Kconfig"
source "drivers/nfc/s3fwrn5/Kconfig"
source "drivers/nfc/st95hf/Kconfig"
endmenu

View File

@ -16,3 +16,4 @@ obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/
obj-$(CONFIG_NFC_ST_NCI) += st-nci/
obj-$(CONFIG_NFC_NXP_NCI) += nxp-nci/
obj-$(CONFIG_NFC_S3FWRN5) += s3fwrn5/
obj-$(CONFIG_NFC_ST95HF) += st95hf/

View File

@ -298,6 +298,12 @@ static int fdp_nci_i2c_probe(struct i2c_client *client,
return -ENODEV;
}
/* Checking if we have an irq */
if (client->irq <= 0) {
nfc_err(dev, "IRQ not present\n");
return -ENODEV;
}
phy = devm_kzalloc(dev, sizeof(struct fdp_i2c_phy),
GFP_KERNEL);
if (!phy)
@ -307,12 +313,6 @@ static int fdp_nci_i2c_probe(struct i2c_client *client,
phy->next_read_size = FDP_NCI_I2C_MIN_PAYLOAD;
i2c_set_clientdata(client, phy);
/* Checking if we have an irq */
if (client->irq <= 0) {
dev_err(dev, "IRQ not present\n");
return -ENODEV;
}
r = request_threaded_irq(client->irq, NULL, fdp_nci_i2c_irq_thread_fn,
IRQF_TRIGGER_RISING | IRQF_ONESHOT,
FDP_I2C_DRIVER_NAME, phy);

View File

@ -50,8 +50,6 @@ struct microread_i2c_phy {
struct i2c_client *i2c_dev;
struct nfc_hci_dev *hdev;
int irq;
int hard_fault; /*
* < 0 if hardware error occured (e.g. i2c err)
* and prevents normal operation.

View File

@ -32,6 +32,8 @@
#define NFCSIM_POLL_TARGET 2
#define NFCSIM_POLL_DUAL (NFCSIM_POLL_INITIATOR | NFCSIM_POLL_TARGET)
#define RX_DEFAULT_DELAY 5
struct nfcsim {
struct nfc_dev *nfc_dev;
@ -51,6 +53,8 @@ struct nfcsim {
u8 initiator;
u32 rx_delay;
data_exchange_cb_t cb;
void *cb_context;
@ -320,10 +324,9 @@ static int nfcsim_tx(struct nfc_dev *nfc_dev, struct nfc_target *target,
* If packet transmission occurs immediately between them, we have a
* non-stop flow of several tens of thousands SYMM packets per second
* and a burning cpu.
*
* TODO: Add support for a sysfs entry to control this delay.
*/
queue_delayed_work(wq, &peer->recv_work, msecs_to_jiffies(5));
queue_delayed_work(wq, &peer->recv_work,
msecs_to_jiffies(dev->rx_delay));
mutex_unlock(&peer->lock);
@ -461,6 +464,7 @@ static struct nfcsim *nfcsim_init_dev(void)
if (rc)
goto free_nfc_dev;
dev->rx_delay = RX_DEFAULT_DELAY;
return dev;
free_nfc_dev:

View File

@ -52,7 +52,6 @@ struct nxp_nci_i2c_phy {
unsigned int gpio_en;
unsigned int gpio_fw;
unsigned int gpio_irq;
int hard_fault; /*
* < 0 if hardware error occurred (e.g. i2c err)
@ -85,7 +84,7 @@ static int nxp_nci_i2c_write(void *phy_id, struct sk_buff *skb)
return phy->hard_fault;
r = i2c_master_send(client, skb->data, skb->len);
if (r == -EREMOTEIO) {
if (r < 0) {
/* Retry, chip was in standby */
usleep_range(110000, 120000);
r = i2c_master_send(client, skb->data, skb->len);
@ -264,8 +263,6 @@ exit_irq_none:
return IRQ_NONE;
}
#ifdef CONFIG_OF
static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
{
struct nxp_nci_i2c_phy *phy = i2c_get_clientdata(client);
@ -294,48 +291,24 @@ static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
}
phy->gpio_fw = r;
r = irq_of_parse_and_map(pp, 0);
if (r < 0) {
nfc_err(&client->dev, "Unable to get irq, error: %d\n", r);
return r;
}
client->irq = r;
return 0;
}
#else
static int nxp_nci_i2c_parse_devtree(struct i2c_client *client)
{
return -ENODEV;
}
#endif
static int nxp_nci_i2c_acpi_config(struct nxp_nci_i2c_phy *phy)
{
struct i2c_client *client = phy->i2c_dev;
struct gpio_desc *gpiod_en, *gpiod_fw, *gpiod_irq;
struct gpio_desc *gpiod_en, *gpiod_fw;
gpiod_en = devm_gpiod_get_index(&client->dev, NULL, 2, GPIOD_OUT_LOW);
gpiod_fw = devm_gpiod_get_index(&client->dev, NULL, 1, GPIOD_OUT_LOW);
gpiod_irq = devm_gpiod_get_index(&client->dev, NULL, 0, GPIOD_IN);
if (IS_ERR(gpiod_en) || IS_ERR(gpiod_fw) || IS_ERR(gpiod_irq)) {
if (IS_ERR(gpiod_en) || IS_ERR(gpiod_fw)) {
nfc_err(&client->dev, "No GPIOs\n");
return -EINVAL;
}
client->irq = gpiod_to_irq(gpiod_irq);
if (client->irq < 0) {
nfc_err(&client->dev, "No IRQ\n");
return -EINVAL;
}
phy->gpio_en = desc_to_gpio(gpiod_en);
phy->gpio_fw = desc_to_gpio(gpiod_fw);
phy->gpio_irq = desc_to_gpio(gpiod_irq);
return 0;
}
@ -374,7 +347,6 @@ static int nxp_nci_i2c_probe(struct i2c_client *client,
} else if (pdata) {
phy->gpio_en = pdata->gpio_en;
phy->gpio_fw = pdata->gpio_fw;
client->irq = pdata->irq;
} else if (ACPI_HANDLE(&client->dev)) {
r = nxp_nci_i2c_acpi_config(phy);
if (r < 0)

View File

@ -166,7 +166,6 @@ struct pn544_i2c_phy {
struct nfc_hci_dev *hdev;
unsigned int gpio_en;
unsigned int gpio_irq;
unsigned int gpio_fw;
unsigned int en_polarity;
@ -879,9 +878,8 @@ static int pn544_hci_i2c_acpi_request_resources(struct i2c_client *client)
{
struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
const struct acpi_device_id *id;
struct gpio_desc *gpiod_en, *gpiod_irq, *gpiod_fw;
struct gpio_desc *gpiod_en, *gpiod_fw;
struct device *dev;
int ret;
if (!client)
return -EINVAL;
@ -914,32 +912,9 @@ static int pn544_hci_i2c_acpi_request_resources(struct i2c_client *client)
phy->gpio_fw = desc_to_gpio(gpiod_fw);
/* Get IRQ GPIO */
gpiod_irq = devm_gpiod_get_index(dev, PN544_GPIO_NAME_IRQ, 0,
GPIOD_IN);
if (IS_ERR(gpiod_irq)) {
nfc_err(dev, "Unable to get IRQ GPIO\n");
return -ENODEV;
}
phy->gpio_irq = desc_to_gpio(gpiod_irq);
/* Map the pin to an IRQ */
ret = gpiod_to_irq(gpiod_irq);
if (ret < 0) {
nfc_err(dev, "Fail pin IRQ mapping\n");
return ret;
}
nfc_info(dev, "GPIO resource, no:%d irq:%d\n",
desc_to_gpio(gpiod_irq), ret);
client->irq = ret;
return 0;
}
#ifdef CONFIG_OF
static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
{
struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
@ -996,15 +971,6 @@ static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
goto err_gpio_fw;
}
/* IRQ */
ret = irq_of_parse_and_map(pp, 0);
if (ret < 0) {
nfc_err(&client->dev,
"Unable to get irq, error: %d\n", ret);
goto err_gpio_fw;
}
client->irq = ret;
return 0;
err_gpio_fw:
@ -1015,15 +981,6 @@ err_dt:
return ret;
}
#else
static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
{
return -ENODEV;
}
#endif
static int pn544_hci_i2c_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@ -1076,7 +1033,6 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE);
phy->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET);
phy->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ);
/* Using ACPI */
} else if (ACPI_HANDLE(&client->dev)) {
r = pn544_hci_i2c_acpi_request_resources(client);

View File

@ -147,7 +147,7 @@ static struct nci_ops s3fwrn5_nci_ops = {
};
int s3fwrn5_probe(struct nci_dev **ndev, void *phy_id, struct device *pdev,
struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload)
const struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload)
{
struct s3fwrn5_info *info;
int ret;

View File

@ -125,7 +125,7 @@ static int s3fwrn5_i2c_write(void *phy_id, struct sk_buff *skb)
return 0;
}
static struct s3fwrn5_phy_ops i2c_phy_ops = {
static const struct s3fwrn5_phy_ops i2c_phy_ops = {
.set_wake = s3fwrn5_i2c_set_wake,
.set_mode = s3fwrn5_i2c_set_mode,
.get_mode = s3fwrn5_i2c_get_mode,

View File

@ -44,7 +44,7 @@ struct s3fwrn5_info {
void *phy_id;
struct device *pdev;
struct s3fwrn5_phy_ops *phy_ops;
const struct s3fwrn5_phy_ops *phy_ops;
unsigned int max_payload;
struct s3fwrn5_fw_info fw_info;
@ -90,7 +90,7 @@ static inline int s3fwrn5_write(struct s3fwrn5_info *info, struct sk_buff *skb)
}
int s3fwrn5_probe(struct nci_dev **ndev, void *phy_id, struct device *pdev,
struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload);
const struct s3fwrn5_phy_ops *phy_ops, unsigned int max_payload);
void s3fwrn5_remove(struct nci_dev *ndev);
int s3fwrn5_recv_frame(struct nci_dev *ndev, struct sk_buff *skb,

View File

@ -1,19 +1,14 @@
config NFC_ST_NCI
tristate "STMicroelectronics ST NCI NFC driver"
depends on NFC_NCI
default n
tristate
---help---
STMicroelectronics NFC NCI chips core driver. It implements the chipset
NCI logic and hooks into the NFC kernel APIs. Physical layers will
register against it.
To compile this driver as a module, choose m here. The module will
be called st-nci.
Say N if unsure.
config NFC_ST_NCI_I2C
tristate "NFC ST NCI i2c support"
depends on NFC_ST_NCI && I2C
tristate "STMicroelectronics ST NCI NFC driver (I2C)"
depends on NFC_NCI && I2C
select NFC_ST_NCI
---help---
This module adds support for an I2C interface to the
STMicroelectronics NFC NCI chips familly.
@ -23,8 +18,9 @@ config NFC_ST_NCI_I2C
Say N if unsure.
config NFC_ST_NCI_SPI
tristate "NFC ST NCI spi support"
depends on NFC_ST_NCI && SPI
tristate "STMicroelectronics ST NCI NFC driver (SPI)"
depends on NFC_NCI && SPI
select NFC_ST_NCI
---help---
This module adds support for an SPI interface to the
STMicroelectronics NFC NCI chips familly.

View File

@ -20,8 +20,10 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/nfc.h>
@ -40,11 +42,7 @@
#define ST_NCI_I2C_DRIVER_NAME "st_nci_i2c"
static struct i2c_device_id st_nci_i2c_id_table[] = {
{ST_NCI_DRIVER_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, st_nci_i2c_id_table);
#define ST_NCI_GPIO_NAME_RESET "clf_reset"
struct st_nci_i2c_phy {
struct i2c_client *i2c_dev;
@ -210,7 +208,43 @@ static struct nfc_phy_ops i2c_phy_ops = {
.disable = st_nci_i2c_disable,
};
#ifdef CONFIG_OF
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;
/* Get RESET GPIO from ACPI */
gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, 1,
GPIOD_OUT_HIGH);
if (IS_ERR(gpiod_reset)) {
nfc_err(dev, "Unable to get RESET GPIO\n");
return -ENODEV;
}
phy->gpio_reset = desc_to_gpio(gpiod_reset);
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");
return 0;
}
static int st_nci_i2c_of_request_resources(struct i2c_client *client)
{
struct st_nci_i2c_phy *phy = i2c_get_clientdata(client);
@ -232,7 +266,7 @@ static int st_nci_i2c_of_request_resources(struct i2c_client *client)
/* GPIO request and configuration */
r = devm_gpio_request_one(&client->dev, gpio,
GPIOF_OUT_INIT_HIGH, "clf_reset");
GPIOF_OUT_INIT_HIGH, ST_NCI_GPIO_NAME_RESET);
if (r) {
nfc_err(&client->dev, "Failed to request reset pin\n");
return r;
@ -248,12 +282,6 @@ static int st_nci_i2c_of_request_resources(struct i2c_client *client)
return 0;
}
#else
static int st_nci_i2c_of_request_resources(struct i2c_client *client)
{
return -ENODEV;
}
#endif
static int st_nci_i2c_request_resources(struct i2c_client *client)
{
@ -272,7 +300,8 @@ static int st_nci_i2c_request_resources(struct i2c_client *client)
phy->irq_polarity = pdata->irq_polarity;
r = devm_gpio_request_one(&client->dev,
phy->gpio_reset, GPIOF_OUT_INIT_HIGH, "clf_reset");
phy->gpio_reset, GPIOF_OUT_INIT_HIGH,
ST_NCI_GPIO_NAME_RESET);
if (r) {
pr_err("%s : reset gpio_request failed\n", __FILE__);
return r;
@ -322,6 +351,12 @@ static int st_nci_i2c_probe(struct i2c_client *client,
"Cannot get platform resources\n");
return r;
}
} else if (ACPI_HANDLE(&client->dev)) {
r = st_nci_i2c_acpi_request_resources(client);
if (r) {
nfc_err(&client->dev, "Cannot get ACPI data\n");
return r;
}
} else {
nfc_err(&client->dev,
"st_nci platform resources not available\n");
@ -358,7 +393,19 @@ static int st_nci_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_OF
static struct i2c_device_id st_nci_i2c_id_table[] = {
{ST_NCI_DRIVER_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, st_nci_i2c_id_table);
static const struct acpi_device_id st_nci_i2c_acpi_match[] = {
{"SMO2101"},
{"SMO2102"},
{}
};
MODULE_DEVICE_TABLE(acpi, st_nci_i2c_acpi_match);
static const struct of_device_id of_st_nci_i2c_match[] = {
{ .compatible = "st,st21nfcb-i2c", },
{ .compatible = "st,st21nfcb_i2c", },
@ -366,19 +413,18 @@ static const struct of_device_id of_st_nci_i2c_match[] = {
{}
};
MODULE_DEVICE_TABLE(of, of_st_nci_i2c_match);
#endif
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),
},
.probe = st_nci_i2c_probe,
.id_table = st_nci_i2c_id_table,
.remove = st_nci_i2c_remove,
};
module_i2c_driver(st_nci_i2c_driver);
MODULE_LICENSE("GPL");

View File

@ -20,7 +20,6 @@
#include <net/nfc/nci_core.h>
#include "st-nci.h"
#include "ndlc.h"
#define NDLC_TIMER_T1 100
#define NDLC_TIMER_T1_WAIT 400

View File

@ -331,7 +331,7 @@ static int st_nci_hci_connectivity_event_received(struct nci_dev *ndev,
switch (event) {
case ST_NCI_EVT_CONNECTIVITY:
r = nfc_se_connectivity(ndev->nfc_dev, host);
break;
case ST_NCI_EVT_TRANSACTION:
/* According to specification etsi 102 622
@ -392,7 +392,6 @@ void st_nci_hci_event_received(struct nci_dev *ndev, u8 pipe,
}
EXPORT_SYMBOL_GPL(st_nci_hci_event_received);
void st_nci_hci_cmd_received(struct nci_dev *ndev, u8 pipe, u8 cmd,
struct sk_buff *skb)
{

View File

@ -20,8 +20,10 @@
#include <linux/module.h>
#include <linux/spi/spi.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/nfc.h>
@ -34,18 +36,14 @@
/* ndlc header */
#define ST_NCI_FRAME_HEADROOM 1
#define ST_NCI_FRAME_TAILROOM 0
#define ST_NCI_FRAME_TAILROOM 0
#define ST_NCI_SPI_MIN_SIZE 4 /* PCB(1) + NCI Packet header(3) */
#define ST_NCI_SPI_MAX_SIZE 250 /* req 4.2.1 */
#define ST_NCI_SPI_DRIVER_NAME "st_nci_spi"
static struct spi_device_id st_nci_spi_id_table[] = {
{ST_NCI_SPI_DRIVER_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(spi, st_nci_spi_id_table);
#define ST_NCI_GPIO_NAME_RESET "clf_reset"
struct st_nci_spi_phy {
struct spi_device *spi_dev;
@ -225,7 +223,43 @@ static struct nfc_phy_ops spi_phy_ops = {
.disable = st_nci_spi_disable,
};
#ifdef CONFIG_OF
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;
/* Get RESET GPIO from ACPI */
gpiod_reset = devm_gpiod_get_index(dev, ST_NCI_GPIO_NAME_RESET, 1,
GPIOD_OUT_HIGH);
if (IS_ERR(gpiod_reset)) {
nfc_err(dev, "Unable to get RESET GPIO\n");
return -ENODEV;
}
phy->gpio_reset = desc_to_gpio(gpiod_reset);
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");
return 0;
}
static int st_nci_spi_of_request_resources(struct spi_device *dev)
{
struct st_nci_spi_phy *phy = spi_get_drvdata(dev);
@ -247,7 +281,7 @@ static int st_nci_spi_of_request_resources(struct spi_device *dev)
/* GPIO request and configuration */
r = devm_gpio_request_one(&dev->dev, gpio,
GPIOF_OUT_INIT_HIGH, "clf_reset");
GPIOF_OUT_INIT_HIGH, ST_NCI_GPIO_NAME_RESET);
if (r) {
nfc_err(&dev->dev, "Failed to request reset pin\n");
return r;
@ -263,12 +297,6 @@ static int st_nci_spi_of_request_resources(struct spi_device *dev)
return 0;
}
#else
static int st_nci_spi_of_request_resources(struct spi_device *dev)
{
return -ENODEV;
}
#endif
static int st_nci_spi_request_resources(struct spi_device *dev)
{
@ -287,7 +315,8 @@ static int st_nci_spi_request_resources(struct spi_device *dev)
phy->irq_polarity = pdata->irq_polarity;
r = devm_gpio_request_one(&dev->dev,
phy->gpio_reset, GPIOF_OUT_INIT_HIGH, "clf_reset");
phy->gpio_reset, GPIOF_OUT_INIT_HIGH,
ST_NCI_GPIO_NAME_RESET);
if (r) {
pr_err("%s : reset gpio_request failed\n", __FILE__);
return r;
@ -338,6 +367,12 @@ static int st_nci_spi_probe(struct spi_device *dev)
"Cannot get platform resources\n");
return r;
}
} else if (ACPI_HANDLE(&dev->dev)) {
r = st_nci_spi_acpi_request_resources(dev);
if (r) {
nfc_err(&dev->dev, "Cannot get ACPI data\n");
return r;
}
} else {
nfc_err(&dev->dev,
"st_nci platform resources not available\n");
@ -374,24 +409,34 @@ static int st_nci_spi_remove(struct spi_device *dev)
return 0;
}
#ifdef CONFIG_OF
static struct spi_device_id st_nci_spi_id_table[] = {
{ST_NCI_SPI_DRIVER_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(spi, st_nci_spi_id_table);
static const struct acpi_device_id st_nci_spi_acpi_match[] = {
{"SMO2101", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, st_nci_spi_acpi_match);
static const struct of_device_id of_st_nci_spi_match[] = {
{ .compatible = "st,st21nfcb-spi", },
{}
};
MODULE_DEVICE_TABLE(of, of_st_nci_spi_match);
#endif
static struct spi_driver st_nci_spi_driver = {
.driver = {
.name = ST_NCI_SPI_DRIVER_NAME,
.of_match_table = of_match_ptr(of_st_nci_spi_match),
.acpi_match_table = ACPI_PTR(st_nci_spi_acpi_match),
},
.probe = st_nci_spi_probe,
.id_table = st_nci_spi_id_table,
.remove = st_nci_spi_remove,
};
module_spi_driver(st_nci_spi_driver);
MODULE_LICENSE("GPL");

View File

@ -1,20 +1,15 @@
config NFC_ST21NFCA
tristate "STMicroelectronics ST21NFCA NFC driver"
depends on NFC_HCI
tristate
select CRC_CCITT
default n
---help---
STMicroelectronics ST21NFCA core driver. It implements the chipset
HCI logic and hooks into the NFC kernel APIs. Physical layers will
register against it.
To compile this driver as a module, choose m here. The module will
be called st21nfca.
Say N if unsure.
config NFC_ST21NFCA_I2C
tristate "NFC ST21NFCA i2c support"
depends on NFC_ST21NFCA && I2C && NFC_SHDLC
tristate "STMicroelectronics ST21NFCA NFC driver (I2C)"
depends on NFC_HCI && I2C && NFC_SHDLC
select NFC_ST21NFCA
---help---
This module adds support for the STMicroelectronics st21nfca i2c interface.
Select this if your platform is using the i2c bus.

View File

@ -21,8 +21,10 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of_irq.h>
#include <linux/of_gpio.h>
#include <linux/acpi.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
@ -60,12 +62,7 @@
#define ST21NFCA_HCI_I2C_DRIVER_NAME "st21nfca_hci_i2c"
static struct i2c_device_id st21nfca_hci_i2c_id_table[] = {
{ST21NFCA_HCI_DRIVER_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, st21nfca_hci_i2c_id_table);
#define ST21NFCA_GPIO_NAME_EN "clf_enable"
struct st21nfca_i2c_phy {
struct i2c_client *i2c_dev;
@ -167,7 +164,6 @@ static void st21nfca_hci_i2c_disable(void *phy_id)
{
struct st21nfca_i2c_phy *phy = phy_id;
pr_info("\n");
gpio_set_value(phy->gpio_ena, 0);
phy->powered = 0;
@ -210,7 +206,6 @@ static int st21nfca_hci_i2c_write(void *phy_id, struct sk_buff *skb)
I2C_DUMP_SKB("st21nfca_hci_i2c_write", skb);
if (phy->hard_fault != 0)
return phy->hard_fault;
@ -509,7 +504,41 @@ static struct nfc_phy_ops i2c_phy_ops = {
.disable = st21nfca_hci_i2c_disable,
};
#ifdef CONFIG_OF
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;
/* 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);
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");
return 0;
}
static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client)
{
struct st21nfca_i2c_phy *phy = i2c_get_clientdata(client);
@ -530,7 +559,7 @@ static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client)
/* GPIO request and configuration */
r = devm_gpio_request_one(&client->dev, gpio, GPIOF_OUT_INIT_HIGH,
"clf_enable");
ST21NFCA_GPIO_NAME_EN);
if (r) {
nfc_err(&client->dev, "Failed to request enable pin\n");
return r;
@ -547,12 +576,6 @@ static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client)
return 0;
}
#else
static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client)
{
return -ENODEV;
}
#endif
static int st21nfca_hci_i2c_request_resources(struct i2c_client *client)
{
@ -572,7 +595,8 @@ static int st21nfca_hci_i2c_request_resources(struct i2c_client *client)
if (phy->gpio_ena > 0) {
r = devm_gpio_request_one(&client->dev, phy->gpio_ena,
GPIOF_OUT_INIT_HIGH, "clf_enable");
GPIOF_OUT_INIT_HIGH,
ST21NFCA_GPIO_NAME_EN);
if (r) {
pr_err("%s : ena gpio_request failed\n", __FILE__);
return r;
@ -628,6 +652,12 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
nfc_err(&client->dev, "Cannot get platform resources\n");
return r;
}
} else if (ACPI_HANDLE(&client->dev)) {
r = st21nfca_hci_i2c_acpi_request_resources(client);
if (r) {
nfc_err(&client->dev, "Cannot get ACPI data\n");
return r;
}
} else {
nfc_err(&client->dev, "st21nfca platform resources not available\n");
return -ENODEV;
@ -670,26 +700,36 @@ static int st21nfca_hci_i2c_remove(struct i2c_client *client)
return 0;
}
#ifdef CONFIG_OF
static struct i2c_device_id st21nfca_hci_i2c_id_table[] = {
{ST21NFCA_HCI_DRIVER_NAME, 0},
{}
};
MODULE_DEVICE_TABLE(i2c, st21nfca_hci_i2c_id_table);
static const struct acpi_device_id st21nfca_hci_i2c_acpi_match[] = {
{"SMO2100", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, st21nfca_hci_i2c_acpi_match);
static const struct of_device_id of_st21nfca_i2c_match[] = {
{ .compatible = "st,st21nfca-i2c", },
{ .compatible = "st,st21nfca_i2c", },
{}
};
MODULE_DEVICE_TABLE(of, of_st21nfca_i2c_match);
#endif
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),
},
.probe = st21nfca_hci_i2c_probe,
.id_table = st21nfca_hci_i2c_id_table,
.remove = st21nfca_hci_i2c_remove,
};
module_i2c_driver(st21nfca_hci_i2c_driver);
MODULE_LICENSE("GPL");

View File

@ -312,7 +312,8 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
switch (event) {
case ST21NFCA_EVT_CONNECTIVITY:
break;
r = nfc_se_connectivity(hdev->ndev, host);
break;
case ST21NFCA_EVT_TRANSACTION:
/*
* According to specification etsi 102 622
@ -342,7 +343,7 @@ int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
transaction->aid_len + 4, transaction->params_len);
r = nfc_se_transaction(hdev->ndev, host, transaction);
break;
break;
default:
nfc_err(&hdev->ndev->dev, "Unexpected event on connectivity gate\n");
return 1;

View File

@ -0,0 +1,10 @@
config NFC_ST95HF
tristate "ST95HF NFC Transceiver driver"
depends on SPI && NFC_DIGITAL
help
This enables the ST NFC driver for ST95HF NFC transceiver.
This makes use of SPI framework to communicate with transceiver
and registered with NFC digital core to support Linux NFC framework.
Say Y here to compile support for ST NFC transceiver ST95HF
linux driver into the kernel or say M to compile it as module.

View File

@ -0,0 +1,6 @@
#
# Makefile for STMicroelectronics NFC transceiver ST95HF
#
obj-$(CONFIG_NFC_ST95HF) += st95hf.o
st95hf-objs := spi.o core.o

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,167 @@
/*
* ----------------------------------------------------------------------------
* drivers/nfc/st95hf/spi.c function definitions for SPI communication
* ----------------------------------------------------------------------------
* Copyright (C) 2015 STMicroelectronics Pvt. Ltd. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#include "spi.h"
/* Function to send user provided buffer to ST95HF through SPI */
int st95hf_spi_send(struct st95hf_spi_context *spicontext,
unsigned char *buffertx,
int datalen,
enum req_type reqtype)
{
struct spi_message m;
int result = 0;
struct spi_device *spidev = spicontext->spidev;
struct spi_transfer tx_transfer = {
.tx_buf = buffertx,
.len = datalen,
};
mutex_lock(&spicontext->spi_lock);
if (reqtype == SYNC) {
spicontext->req_issync = true;
reinit_completion(&spicontext->done);
} else {
spicontext->req_issync = false;
}
spi_message_init(&m);
spi_message_add_tail(&tx_transfer, &m);
result = spi_sync(spidev, &m);
if (result) {
dev_err(&spidev->dev, "error: sending cmd to st95hf using SPI = %d\n",
result);
mutex_unlock(&spicontext->spi_lock);
return result;
}
/* return for asynchronous or no-wait case */
if (reqtype == ASYNC) {
mutex_unlock(&spicontext->spi_lock);
return 0;
}
result = wait_for_completion_timeout(&spicontext->done,
msecs_to_jiffies(1000));
/* check for timeout or success */
if (!result) {
dev_err(&spidev->dev, "error: response not ready timeout\n");
result = -ETIMEDOUT;
} else {
result = 0;
}
mutex_unlock(&spicontext->spi_lock);
return result;
}
EXPORT_SYMBOL_GPL(st95hf_spi_send);
/* Function to Receive command Response */
int st95hf_spi_recv_response(struct st95hf_spi_context *spicontext,
unsigned char *receivebuff)
{
int len = 0;
struct spi_transfer tx_takedata;
struct spi_message m;
struct spi_device *spidev = spicontext->spidev;
unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE;
struct spi_transfer t[2] = {
{.tx_buf = &readdata_cmd, .len = 1,},
{.rx_buf = receivebuff, .len = 2, .cs_change = 1,},
};
int ret = 0;
memset(&tx_takedata, 0x0, sizeof(struct spi_transfer));
mutex_lock(&spicontext->spi_lock);
/* First spi transfer to know the length of valid data */
spi_message_init(&m);
spi_message_add_tail(&t[0], &m);
spi_message_add_tail(&t[1], &m);
ret = spi_sync(spidev, &m);
if (ret) {
dev_err(&spidev->dev, "spi_recv_resp, data length error = %d\n",
ret);
mutex_unlock(&spicontext->spi_lock);
return ret;
}
/* As 2 bytes are already read */
len = 2;
/* Support of long frame */
if (receivebuff[0] & 0x60)
len += (((receivebuff[0] & 0x60) >> 5) << 8) | receivebuff[1];
else
len += receivebuff[1];
/* Now make a transfer to read only relevant bytes */
tx_takedata.rx_buf = &receivebuff[2];
tx_takedata.len = len - 2;
spi_message_init(&m);
spi_message_add_tail(&tx_takedata, &m);
ret = spi_sync(spidev, &m);
mutex_unlock(&spicontext->spi_lock);
if (ret) {
dev_err(&spidev->dev, "spi_recv_resp, data read error = %d\n",
ret);
return ret;
}
return len;
}
EXPORT_SYMBOL_GPL(st95hf_spi_recv_response);
int st95hf_spi_recv_echo_res(struct st95hf_spi_context *spicontext,
unsigned char *receivebuff)
{
unsigned char readdata_cmd = ST95HF_COMMAND_RECEIVE;
struct spi_transfer t[2] = {
{.tx_buf = &readdata_cmd, .len = 1,},
{.rx_buf = receivebuff, .len = 1,},
};
struct spi_message m;
struct spi_device *spidev = spicontext->spidev;
int ret = 0;
mutex_lock(&spicontext->spi_lock);
spi_message_init(&m);
spi_message_add_tail(&t[0], &m);
spi_message_add_tail(&t[1], &m);
ret = spi_sync(spidev, &m);
mutex_unlock(&spicontext->spi_lock);
if (ret)
dev_err(&spidev->dev, "recv_echo_res, data read error = %d\n",
ret);
return ret;
}
EXPORT_SYMBOL_GPL(st95hf_spi_recv_echo_res);

View File

@ -0,0 +1,64 @@
/*
* ---------------------------------------------------------------------------
* drivers/nfc/st95hf/spi.h functions declarations for SPI communication
* ---------------------------------------------------------------------------
* Copyright (C) 2015 STMicroelectronics All Rights Reserved
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __LINUX_ST95HF_SPI_H
#define __LINUX_ST95HF_SPI_H
#include <linux/spi/spi.h>
/* Basic ST95HF SPI CMDs */
#define ST95HF_COMMAND_SEND 0x0
#define ST95HF_COMMAND_RESET 0x1
#define ST95HF_COMMAND_RECEIVE 0x2
#define ST95HF_RESET_CMD_LEN 0x1
/*
* structure to contain st95hf spi communication specific information.
* @req_issync: true for synchronous calls.
* @spidev: st95hf spi device object.
* @done: completion structure to wait for st95hf response
* for synchronous calls.
* @spi_lock: mutex to allow only one spi transfer at a time.
*/
struct st95hf_spi_context {
bool req_issync;
struct spi_device *spidev;
struct completion done;
struct mutex spi_lock;
};
/* flag to differentiate synchronous & asynchronous spi request */
enum req_type {
SYNC,
ASYNC,
};
int st95hf_spi_send(struct st95hf_spi_context *spicontext,
unsigned char *buffertx,
int datalen,
enum req_type reqtype);
int st95hf_spi_recv_response(struct st95hf_spi_context *spicontext,
unsigned char *receivebuff);
int st95hf_spi_recv_echo_res(struct st95hf_spi_context *spicontext,
unsigned char *receivebuff);
#endif

View File

@ -2139,7 +2139,7 @@ static int trf7970a_remove(struct spi_device *spi)
#ifdef CONFIG_PM_SLEEP
static int trf7970a_suspend(struct device *dev)
{
struct spi_device *spi = container_of(dev, struct spi_device, dev);
struct spi_device *spi = to_spi_device(dev);
struct trf7970a *trf = spi_get_drvdata(spi);
dev_dbg(dev, "Suspend\n");
@ -2155,7 +2155,7 @@ static int trf7970a_suspend(struct device *dev)
static int trf7970a_resume(struct device *dev)
{
struct spi_device *spi = container_of(dev, struct spi_device, dev);
struct spi_device *spi = to_spi_device(dev);
struct trf7970a *trf = spi_get_drvdata(spi);
int ret;
@ -2174,7 +2174,7 @@ static int trf7970a_resume(struct device *dev)
#ifdef CONFIG_PM
static int trf7970a_pm_runtime_suspend(struct device *dev)
{
struct spi_device *spi = container_of(dev, struct spi_device, dev);
struct spi_device *spi = to_spi_device(dev);
struct trf7970a *trf = spi_get_drvdata(spi);
int ret;
@ -2191,7 +2191,7 @@ static int trf7970a_pm_runtime_suspend(struct device *dev)
static int trf7970a_pm_runtime_resume(struct device *dev)
{
struct spi_device *spi = container_of(dev, struct spi_device, dev);
struct spi_device *spi = to_spi_device(dev);
struct trf7970a *trf = spi_get_drvdata(spi);
int ret;

View File

@ -1,5 +1,5 @@
/*
* Driver include for the PN544 NFC chip.
* Driver include for the Inside Secure microread NFC Chip.
*
* Copyright (C) 2011 Tieto Poland
* Copyright (C) 2012 Intel Corporation. All rights reserved.

View File

@ -299,6 +299,7 @@ void nfc_driver_failure(struct nfc_dev *dev, int err);
int nfc_se_transaction(struct nfc_dev *dev, u8 se_idx,
struct nfc_evt_transaction *evt_transaction);
int nfc_se_connectivity(struct nfc_dev *dev, u8 se_idx);
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);

View File

@ -953,6 +953,19 @@ out:
}
EXPORT_SYMBOL(nfc_se_transaction);
int nfc_se_connectivity(struct nfc_dev *dev, u8 se_idx)
{
int rc;
pr_debug("connectivity: %x\n", se_idx);
device_lock(&dev->dev);
rc = nfc_genl_se_connectivity(dev, se_idx);
device_unlock(&dev->dev);
return rc;
}
EXPORT_SYMBOL(nfc_se_connectivity);
static void nfc_release(struct device *d)
{
struct nfc_dev *dev = to_nfc_dev(d);

View File

@ -20,7 +20,8 @@
#include "digital.h"
#define DIGITAL_PROTO_NFCA_RF_TECH \
(NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK | NFC_PROTO_NFC_DEP_MASK)
(NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK | \
NFC_PROTO_NFC_DEP_MASK | NFC_PROTO_ISO14443_MASK)
#define DIGITAL_PROTO_NFCB_RF_TECH NFC_PROTO_ISO14443_B_MASK

View File

@ -610,14 +610,14 @@ 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)
return -ENOMEM;
if (!number_destination_params)
return -EINVAL;
cmd->destination_type = destination_type;
cmd->number_destination_params = number_destination_params;
memcpy(cmd->params, params, params_len);

View File

@ -676,7 +676,7 @@ int nci_hci_connect_gate(struct nci_dev *ndev,
break;
default:
pipe = nci_hci_create_pipe(ndev, dest_host, dest_gate, &r);
if (pipe < 0)
if (pipe == NCI_HCI_INVALID_PIPE)
return r;
pipe_created = true;
break;

View File

@ -552,6 +552,43 @@ free_msg:
return -EMSGSIZE;
}
int nfc_genl_se_connectivity(struct nfc_dev *dev, u8 se_idx)
{
struct nfc_se *se;
struct sk_buff *msg;
void *hdr;
msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
if (!msg)
return -ENOMEM;
hdr = genlmsg_put(msg, 0, 0, &nfc_genl_family, 0,
NFC_EVENT_SE_CONNECTIVITY);
if (!hdr)
goto free_msg;
se = nfc_find_se(dev, se_idx);
if (!se)
goto free_msg;
if (nla_put_u32(msg, NFC_ATTR_DEVICE_INDEX, dev->idx) ||
nla_put_u32(msg, NFC_ATTR_SE_INDEX, se_idx) ||
nla_put_u8(msg, NFC_ATTR_SE_TYPE, se->type))
goto nla_put_failure;
genlmsg_end(msg, hdr);
genlmsg_multicast(&nfc_genl_family, msg, 0, 0, GFP_KERNEL);
return 0;
nla_put_failure:
genlmsg_cancel(msg, hdr);
free_msg:
nlmsg_free(msg);
return -EMSGSIZE;
}
static int nfc_genl_send_device(struct sk_buff *msg, struct nfc_dev *dev,
u32 portid, u32 seq,
struct netlink_callback *cb,

View File

@ -105,6 +105,7 @@ int nfc_genl_se_added(struct nfc_dev *dev, u32 se_idx, u16 type);
int nfc_genl_se_removed(struct nfc_dev *dev, u32 se_idx);
int nfc_genl_se_transaction(struct nfc_dev *dev, u8 se_idx,
struct nfc_evt_transaction *evt_transaction);
int nfc_genl_se_connectivity(struct nfc_dev *dev, u8 se_idx);
struct nfc_dev *nfc_get_device(unsigned int idx);