Commit b8f8be3f authored by David S. Miller's avatar David S. Miller

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

NFC: 3.20 first pull request

This is the first NFC pull request for 3.20.

With this one we have:

- Secure element support for the ST Micro st21nfca driver. This depends
  on a few HCI internal changes in order for example to support more
  than one secure element per controller.

- ACPI support for NXP's pn544 HCI driver. This controller is found on
  many x86 SoCs and is typically enumerated on the ACPI bus there.

- A few st21nfca and st21nfcb fixes.
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents ff660f75 0a5942c8
* STMicroelectronics SAS. ST21NFCA NFC Controller * STMicroelectronics SAS. ST21NFCA NFC Controller
Required properties: Required properties:
- compatible: Should be "st,st21nfca_i2c". - compatible: Should be "st,st21nfca-i2c".
- clock-frequency: I²C work frequency. - clock-frequency: I²C work frequency.
- reg: address on the bus - reg: address on the bus
- interrupt-parent: phandle for the interrupt gpio controller - interrupt-parent: phandle for the interrupt gpio controller
...@@ -11,6 +11,10 @@ Required properties: ...@@ -11,6 +11,10 @@ Required properties:
Optional SoC Specific Properties: Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default". - pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller. - pintctrl-0: Specifies the pin control groups used for this controller.
- ese-present: Specifies that an ese is physically connected to the nfc
controller.
- uicc-present: Specifies that the uicc swp signal can be physically
connected to the nfc controller.
Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2): Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2):
...@@ -20,7 +24,7 @@ Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2): ...@@ -20,7 +24,7 @@ Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2):
st21nfca: st21nfca@1 { st21nfca: st21nfca@1 {
compatible = "st,st21nfca_i2c"; compatible = "st,st21nfca-i2c";
reg = <0x01>; reg = <0x01>;
clock-frequency = <400000>; clock-frequency = <400000>;
...@@ -29,5 +33,8 @@ Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2): ...@@ -29,5 +33,8 @@ Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2):
interrupts = <2 IRQ_TYPE_LEVEL_LOW>; interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
enable-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>; enable-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
ese-present;
uicc-present;
}; };
}; };
* STMicroelectronics SAS. ST21NFCB NFC Controller * STMicroelectronics SAS. ST21NFCB NFC Controller
Required properties: Required properties:
- compatible: Should be "st,st21nfcb_i2c". - compatible: Should be "st,st21nfcb-i2c".
- clock-frequency: I²C work frequency. - clock-frequency: I²C work frequency.
- reg: address on the bus - reg: address on the bus
- interrupt-parent: phandle for the interrupt gpio controller - interrupt-parent: phandle for the interrupt gpio controller
...@@ -20,7 +20,7 @@ Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2): ...@@ -20,7 +20,7 @@ Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2):
st21nfcb: st21nfcb@8 { st21nfcb: st21nfcb@8 {
compatible = "st,st21nfcb_i2c"; compatible = "st,st21nfcb-i2c";
reg = <0x08>; reg = <0x08>;
clock-frequency = <400000>; clock-frequency = <400000>;
......
...@@ -557,10 +557,11 @@ static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate, ...@@ -557,10 +557,11 @@ static void microread_target_discovered(struct nfc_hci_dev *hdev, u8 gate,
pr_err("Failed to handle discovered target err=%d\n", r); pr_err("Failed to handle discovered target err=%d\n", r);
} }
static int microread_event_received(struct nfc_hci_dev *hdev, u8 gate, static int microread_event_received(struct nfc_hci_dev *hdev, u8 pipe,
u8 event, struct sk_buff *skb) u8 event, struct sk_buff *skb)
{ {
int r; int r;
u8 gate = hdev->pipes[pipe].gate;
u8 mode; u8 mode;
pr_info("Microread received event 0x%x to gate 0x%x\n", event, gate); pr_info("Microread received event 0x%x to gate 0x%x\n", event, gate);
......
...@@ -24,11 +24,13 @@ ...@@ -24,11 +24,13 @@
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
#include <linux/of_irq.h> #include <linux/of_irq.h>
#include <linux/acpi.h>
#include <linux/miscdevice.h> #include <linux/miscdevice.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/delay.h> #include <linux/delay.h>
#include <linux/nfc.h> #include <linux/nfc.h>
#include <linux/firmware.h> #include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_data/pn544.h> #include <linux/platform_data/pn544.h>
#include <asm/unaligned.h> #include <asm/unaligned.h>
...@@ -41,6 +43,11 @@ ...@@ -41,6 +43,11 @@
#define PN544_I2C_FRAME_HEADROOM 1 #define PN544_I2C_FRAME_HEADROOM 1
#define PN544_I2C_FRAME_TAILROOM 2 #define PN544_I2C_FRAME_TAILROOM 2
/* GPIO names */
#define PN544_GPIO_NAME_IRQ "pn544_irq"
#define PN544_GPIO_NAME_FW "pn544_fw"
#define PN544_GPIO_NAME_EN "pn544_en"
/* framing in HCI mode */ /* framing in HCI mode */
#define PN544_HCI_I2C_LLC_LEN 1 #define PN544_HCI_I2C_LLC_LEN 1
#define PN544_HCI_I2C_LLC_CRC 2 #define PN544_HCI_I2C_LLC_CRC 2
...@@ -58,6 +65,13 @@ static struct i2c_device_id pn544_hci_i2c_id_table[] = { ...@@ -58,6 +65,13 @@ static struct i2c_device_id pn544_hci_i2c_id_table[] = {
MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table); MODULE_DEVICE_TABLE(i2c, pn544_hci_i2c_id_table);
static const struct acpi_device_id pn544_hci_i2c_acpi_match[] = {
{"NXP5440", 0},
{}
};
MODULE_DEVICE_TABLE(acpi, pn544_hci_i2c_acpi_match);
#define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c" #define PN544_HCI_I2C_DRIVER_NAME "pn544_hci_i2c"
/* /*
...@@ -195,18 +209,19 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy) ...@@ -195,18 +209,19 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
nfc_info(&phy->i2c_dev->dev, "Detecting nfc_en polarity\n"); nfc_info(&phy->i2c_dev->dev, "Detecting nfc_en polarity\n");
/* Disable fw download */ /* Disable fw download */
gpio_set_value(phy->gpio_fw, 0); gpio_set_value_cansleep(phy->gpio_fw, 0);
for (polarity = 0; polarity < 2; polarity++) { for (polarity = 0; polarity < 2; polarity++) {
phy->en_polarity = polarity; phy->en_polarity = polarity;
retry = 3; retry = 3;
while (retry--) { while (retry--) {
/* power off */ /* power off */
gpio_set_value(phy->gpio_en, !phy->en_polarity); gpio_set_value_cansleep(phy->gpio_en,
!phy->en_polarity);
usleep_range(10000, 15000); usleep_range(10000, 15000);
/* power on */ /* power on */
gpio_set_value(phy->gpio_en, phy->en_polarity); gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity);
usleep_range(10000, 15000); usleep_range(10000, 15000);
/* send reset */ /* send reset */
...@@ -225,13 +240,14 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy) ...@@ -225,13 +240,14 @@ static void pn544_hci_i2c_platform_init(struct pn544_i2c_phy *phy)
"Could not detect nfc_en polarity, fallback to active high\n"); "Could not detect nfc_en polarity, fallback to active high\n");
out: out:
gpio_set_value(phy->gpio_en, !phy->en_polarity); gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity);
} }
static void pn544_hci_i2c_enable_mode(struct pn544_i2c_phy *phy, int run_mode) static void pn544_hci_i2c_enable_mode(struct pn544_i2c_phy *phy, int run_mode)
{ {
gpio_set_value(phy->gpio_fw, run_mode == PN544_FW_MODE ? 1 : 0); gpio_set_value_cansleep(phy->gpio_fw,
gpio_set_value(phy->gpio_en, phy->en_polarity); run_mode == PN544_FW_MODE ? 1 : 0);
gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity);
usleep_range(10000, 15000); usleep_range(10000, 15000);
phy->run_mode = run_mode; phy->run_mode = run_mode;
...@@ -254,14 +270,14 @@ static void pn544_hci_i2c_disable(void *phy_id) ...@@ -254,14 +270,14 @@ static void pn544_hci_i2c_disable(void *phy_id)
{ {
struct pn544_i2c_phy *phy = phy_id; struct pn544_i2c_phy *phy = phy_id;
gpio_set_value(phy->gpio_fw, 0); gpio_set_value_cansleep(phy->gpio_fw, 0);
gpio_set_value(phy->gpio_en, !phy->en_polarity); gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity);
usleep_range(10000, 15000); usleep_range(10000, 15000);
gpio_set_value(phy->gpio_en, phy->en_polarity); gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity);
usleep_range(10000, 15000); usleep_range(10000, 15000);
gpio_set_value(phy->gpio_en, !phy->en_polarity); gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity);
usleep_range(10000, 15000); usleep_range(10000, 15000);
phy->powered = 0; phy->powered = 0;
...@@ -859,6 +875,90 @@ static void pn544_hci_i2c_fw_work(struct work_struct *work) ...@@ -859,6 +875,90 @@ static void pn544_hci_i2c_fw_work(struct work_struct *work)
} }
} }
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 device *dev;
int ret;
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_en = devm_gpiod_get_index(dev, PN544_GPIO_NAME_EN, 1);
if (IS_ERR(gpiod_en)) {
nfc_err(dev,
"Unable to get EN GPIO\n");
return -ENODEV;
}
phy->gpio_en = desc_to_gpio(gpiod_en);
/* Configuration EN GPIO */
ret = gpiod_direction_output(gpiod_en, 0);
if (ret) {
nfc_err(dev, "Fail EN pin direction\n");
return ret;
}
/* Get FW GPIO from ACPI */
gpiod_fw = devm_gpiod_get_index(dev, PN544_GPIO_NAME_FW, 2);
if (IS_ERR(gpiod_fw)) {
nfc_err(dev,
"Unable to get FW GPIO\n");
return -ENODEV;
}
phy->gpio_fw = desc_to_gpio(gpiod_fw);
/* Configuration FW GPIO */
ret = gpiod_direction_output(gpiod_fw, 0);
if (ret) {
nfc_err(dev, "Fail FW pin direction\n");
return ret;
}
/* Get IRQ GPIO */
gpiod_irq = devm_gpiod_get_index(dev, PN544_GPIO_NAME_IRQ, 0);
if (IS_ERR(gpiod_irq)) {
nfc_err(dev,
"Unable to get IRQ GPIO\n");
return -ENODEV;
}
phy->gpio_irq = desc_to_gpio(gpiod_irq);
/* Configure IRQ GPIO */
ret = gpiod_direction_input(gpiod_irq);
if (ret) {
nfc_err(dev, "Fail IRQ pin direction\n");
return ret;
}
/* 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 #ifdef CONFIG_OF
static int pn544_hci_i2c_of_request_resources(struct i2c_client *client) static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
...@@ -884,7 +984,7 @@ static int pn544_hci_i2c_of_request_resources(struct i2c_client *client) ...@@ -884,7 +984,7 @@ static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
phy->gpio_en = ret; phy->gpio_en = ret;
/* Configuration of EN GPIO */ /* Configuration of EN GPIO */
ret = gpio_request(phy->gpio_en, "pn544_en"); ret = gpio_request(phy->gpio_en, PN544_GPIO_NAME_EN);
if (ret) { if (ret) {
nfc_err(&client->dev, "Fail EN pin\n"); nfc_err(&client->dev, "Fail EN pin\n");
goto err_dt; goto err_dt;
...@@ -906,7 +1006,7 @@ static int pn544_hci_i2c_of_request_resources(struct i2c_client *client) ...@@ -906,7 +1006,7 @@ static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
phy->gpio_fw = ret; phy->gpio_fw = ret;
/* Configuration of FW GPIO */ /* Configuration of FW GPIO */
ret = gpio_request(phy->gpio_fw, "pn544_fw"); ret = gpio_request(phy->gpio_fw, PN544_GPIO_NAME_FW);
if (ret) { if (ret) {
nfc_err(&client->dev, "Fail FW pin\n"); nfc_err(&client->dev, "Fail FW pin\n");
goto err_gpio_en; goto err_gpio_en;
...@@ -1001,6 +1101,14 @@ static int pn544_hci_i2c_probe(struct i2c_client *client, ...@@ -1001,6 +1101,14 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE); phy->gpio_en = pdata->get_gpio(NFC_GPIO_ENABLE);
phy->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET); phy->gpio_fw = pdata->get_gpio(NFC_GPIO_FW_RESET);
phy->gpio_irq = pdata->get_gpio(NFC_GPIO_IRQ); 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);
if (r) {
nfc_err(&client->dev,
"Cannot get ACPI data\n");
return r;
}
} else { } else {
nfc_err(&client->dev, "No platform data\n"); nfc_err(&client->dev, "No platform data\n");
return -EINVAL; return -EINVAL;
...@@ -1080,6 +1188,7 @@ static struct i2c_driver pn544_hci_i2c_driver = { ...@@ -1080,6 +1188,7 @@ static struct i2c_driver pn544_hci_i2c_driver = {
.name = PN544_HCI_I2C_DRIVER_NAME, .name = PN544_HCI_I2C_DRIVER_NAME,
.owner = THIS_MODULE, .owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_pn544_i2c_match), .of_match_table = of_match_ptr(of_pn544_i2c_match),
.acpi_match_table = ACPI_PTR(pn544_hci_i2c_acpi_match),
}, },
.probe = pn544_hci_i2c_probe, .probe = pn544_hci_i2c_probe,
.id_table = pn544_hci_i2c_id_table, .id_table = pn544_hci_i2c_id_table,
......
...@@ -724,10 +724,11 @@ static int pn544_hci_check_presence(struct nfc_hci_dev *hdev, ...@@ -724,10 +724,11 @@ static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
* <= 0: driver handled the event, skb consumed * <= 0: driver handled the event, skb consumed
* 1: driver does not handle the event, please do standard processing * 1: driver does not handle the event, please do standard processing
*/ */
static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, u8 event, static int pn544_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
struct sk_buff *skb) struct sk_buff *skb)
{ {
struct sk_buff *rgb_skb = NULL; struct sk_buff *rgb_skb = NULL;
u8 gate = hdev->pipes[pipe].gate;
int r; int r;
pr_debug("hci event %d\n", event); pr_debug("hci event %d\n", event);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
# Makefile for ST21NFCA HCI based NFC driver # Makefile for ST21NFCA HCI based NFC driver
# #
st21nfca_hci-objs = st21nfca.o st21nfca_dep.o st21nfca_hci-objs = st21nfca.o st21nfca_dep.o st21nfca_se.o
obj-$(CONFIG_NFC_ST21NFCA) += st21nfca_hci.o obj-$(CONFIG_NFC_ST21NFCA) += st21nfca_hci.o
st21nfca_i2c-objs = i2c.o st21nfca_i2c-objs = i2c.o
......
...@@ -74,6 +74,8 @@ struct st21nfca_i2c_phy { ...@@ -74,6 +74,8 @@ struct st21nfca_i2c_phy {
unsigned int gpio_ena; unsigned int gpio_ena;
unsigned int irq_polarity; unsigned int irq_polarity;
struct st21nfca_se_status se_status;
struct sk_buff *pending_skb; struct sk_buff *pending_skb;
int current_read_len; int current_read_len;
/* /*
...@@ -537,6 +539,11 @@ static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client) ...@@ -537,6 +539,11 @@ static int st21nfca_hci_i2c_of_request_resources(struct i2c_client *client)
phy->irq_polarity = irq_get_trigger_type(client->irq); phy->irq_polarity = irq_get_trigger_type(client->irq);
phy->se_status.is_ese_present =
of_property_read_bool(pp, "ese-present");
phy->se_status.is_uicc_present =
of_property_read_bool(pp, "uicc-present");
return 0; return 0;
} }
#else #else
...@@ -571,6 +578,9 @@ static int st21nfca_hci_i2c_request_resources(struct i2c_client *client) ...@@ -571,6 +578,9 @@ static int st21nfca_hci_i2c_request_resources(struct i2c_client *client)
} }
} }
phy->se_status.is_ese_present = pdata->is_ese_present;
phy->se_status.is_uicc_present = pdata->is_uicc_present;
return 0; return 0;
} }
...@@ -591,11 +601,8 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client, ...@@ -591,11 +601,8 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
phy = devm_kzalloc(&client->dev, sizeof(struct st21nfca_i2c_phy), phy = devm_kzalloc(&client->dev, sizeof(struct st21nfca_i2c_phy),
GFP_KERNEL); GFP_KERNEL);
if (!phy) { if (!phy)
nfc_err(&client->dev,
"Cannot allocate memory for st21nfca i2c phy.\n");
return -ENOMEM; return -ENOMEM;
}
phy->i2c_dev = client; phy->i2c_dev = client;
phy->pending_skb = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE * 2, GFP_KERNEL); phy->pending_skb = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE * 2, GFP_KERNEL);
...@@ -641,8 +648,11 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client, ...@@ -641,8 +648,11 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
} }
return st21nfca_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME, return st21nfca_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
ST21NFCA_FRAME_HEADROOM, ST21NFCA_FRAME_TAILROOM, ST21NFCA_FRAME_HEADROOM,
ST21NFCA_HCI_LLC_MAX_PAYLOAD, &phy->hdev); ST21NFCA_FRAME_TAILROOM,
ST21NFCA_HCI_LLC_MAX_PAYLOAD,
&phy->hdev,
&phy->se_status);
} }
static int st21nfca_hci_i2c_remove(struct i2c_client *client) static int st21nfca_hci_i2c_remove(struct i2c_client *client)
...@@ -661,6 +671,7 @@ static int st21nfca_hci_i2c_remove(struct i2c_client *client) ...@@ -661,6 +671,7 @@ static int st21nfca_hci_i2c_remove(struct i2c_client *client)
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id of_st21nfca_i2c_match[] = { static const struct of_device_id of_st21nfca_i2c_match[] = {
{ .compatible = "st,st21nfca-i2c", },
{ .compatible = "st,st21nfca_i2c", }, { .compatible = "st,st21nfca_i2c", },
{} {}
}; };
......
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
#include "st21nfca.h" #include "st21nfca.h"
#include "st21nfca_dep.h" #include "st21nfca_dep.h"
#include "st21nfca_se.h"
#define DRIVER_DESC "HCI NFC driver for ST21NFCA" #define DRIVER_DESC "HCI NFC driver for ST21NFCA"
...@@ -62,7 +63,6 @@ ...@@ -62,7 +63,6 @@
#define ST21NFCA_RF_CARD_F_DATARATE 0x08 #define ST21NFCA_RF_CARD_F_DATARATE 0x08
#define ST21NFCA_RF_CARD_F_DATARATE_212_424 0x01 #define ST21NFCA_RF_CARD_F_DATARATE_212_424 0x01
#define ST21NFCA_DEVICE_MGNT_GATE 0x01
#define ST21NFCA_DEVICE_MGNT_PIPE 0x02 #define ST21NFCA_DEVICE_MGNT_PIPE 0x02
#define ST21NFCA_DM_GETINFO 0x13 #define ST21NFCA_DM_GETINFO 0x13
...@@ -78,6 +78,11 @@ ...@@ -78,6 +78,11 @@
#define ST21NFCA_NFC_MODE 0x03 /* NFC_MODE parameter*/ #define ST21NFCA_NFC_MODE 0x03 /* NFC_MODE parameter*/
#define ST21NFCA_EVT_HOT_PLUG 0x03
#define ST21NFCA_EVT_HOT_PLUG_IS_INHIBITED(x) (x->data[0] & 0x80)
#define ST21NFCA_SE_TO_PIPES 2000
static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES); static DECLARE_BITMAP(dev_mask, ST21NFCA_NUM_DEVICES);
static struct nfc_hci_gate st21nfca_gates[] = { static struct nfc_hci_gate st21nfca_gates[] = {
...@@ -92,6 +97,10 @@ static struct nfc_hci_gate st21nfca_gates[] = { ...@@ -92,6 +97,10 @@ static struct nfc_hci_gate st21nfca_gates[] = {
{ST21NFCA_RF_READER_14443_3_A_GATE, NFC_HCI_INVALID_PIPE}, {ST21NFCA_RF_READER_14443_3_A_GATE, NFC_HCI_INVALID_PIPE},
{ST21NFCA_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE}, {ST21NFCA_RF_READER_ISO15693_GATE, NFC_HCI_INVALID_PIPE},
{ST21NFCA_RF_CARD_F_GATE, NFC_HCI_INVALID_PIPE}, {ST21NFCA_RF_CARD_F_GATE, NFC_HCI_INVALID_PIPE},
/* Secure element pipes are created by secure element host */
{ST21NFCA_CONNECTIVITY_GATE, NFC_HCI_DO_NOT_CREATE_PIPE},
{ST21NFCA_APDU_READER_GATE, NFC_HCI_DO_NOT_CREATE_PIPE},
}; };
struct st21nfca_pipe_info { struct st21nfca_pipe_info {
...@@ -118,18 +127,6 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) ...@@ -118,18 +127,6 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
NFC_HCI_TERMINAL_HOST_ID, 0 NFC_HCI_TERMINAL_HOST_ID, 0
}; };
skb_pipe_list = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE, GFP_KERNEL);
if (!skb_pipe_list) {
r = -ENOMEM;
goto free_list;
}
skb_pipe_info = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE, GFP_KERNEL);
if (!skb_pipe_info) {
r = -ENOMEM;
goto free_info;
}
/* On ST21NFCA device pipes number are dynamics /* On ST21NFCA device pipes number are dynamics
* A maximum of 16 pipes can be created at the same time * A maximum of 16 pipes can be created at the same time
* If pipes are already created, hci_dev_up will fail. * If pipes are already created, hci_dev_up will fail.
...@@ -148,7 +145,8 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) ...@@ -148,7 +145,8 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
* Pipe can be closed and need to be open. * Pipe can be closed and need to be open.
*/ */
r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID, r = nfc_hci_connect_gate(hdev, NFC_HCI_HOST_CONTROLLER_ID,
ST21NFCA_DEVICE_MGNT_GATE, ST21NFCA_DEVICE_MGNT_PIPE); ST21NFCA_DEVICE_MGNT_GATE,
ST21NFCA_DEVICE_MGNT_PIPE);
if (r < 0) if (r < 0)
goto free_info; goto free_info;
...@@ -179,17 +177,28 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) ...@@ -179,17 +177,28 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
* - destination gid (1byte) * - destination gid (1byte)
*/ */
info = (struct st21nfca_pipe_info *) skb_pipe_info->data; 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) {
pr_err("Unexpected apdu_reader pipe on host %x\n",
info->src_host_id);
continue;
}
for (j = 0; (j < ARRAY_SIZE(st21nfca_gates)) && for (j = 0; (j < ARRAY_SIZE(st21nfca_gates)) &&
(st21nfca_gates[j].gate != info->dst_gate_id); (st21nfca_gates[j].gate != info->dst_gate_id) ; j++)
j++)
; ;
if (j < ARRAY_SIZE(st21nfca_gates) && if (j < ARRAY_SIZE(st21nfca_gates) &&
st21nfca_gates[j].gate == info->dst_gate_id && st21nfca_gates[j].gate == info->dst_gate_id &&
ST21NFCA_DM_IS_PIPE_OPEN(info->pipe_state)) { ST21NFCA_DM_IS_PIPE_OPEN(info->pipe_state)) {
st21nfca_gates[j].pipe = pipe_info[2]; st21nfca_gates[j].pipe = pipe_info[2];
hdev->gate2pipe[st21nfca_gates[j].gate] = hdev->gate2pipe[st21nfca_gates[j].gate] =
st21nfca_gates[j].pipe; st21nfca_gates[j].pipe;
hdev->pipes[st21nfca_gates[j].pipe].gate =
st21nfca_gates[j].gate;
hdev->pipes[st21nfca_gates[j].pipe].dest_host =
info->src_host_id;
} }
} }
...@@ -199,7 +208,7 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) ...@@ -199,7 +208,7 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
*/ */
if (skb_pipe_list->len + 3 < ARRAY_SIZE(st21nfca_gates)) { if (skb_pipe_list->len + 3 < ARRAY_SIZE(st21nfca_gates)) {
for (i = skb_pipe_list->len + 3; for (i = skb_pipe_list->len + 3;
i < ARRAY_SIZE(st21nfca_gates); i++) { i < ARRAY_SIZE(st21nfca_gates) - 2; i++) {
r = nfc_hci_connect_gate(hdev, r = nfc_hci_connect_gate(hdev,
NFC_HCI_HOST_CONTROLLER_ID, NFC_HCI_HOST_CONTROLLER_ID,
st21nfca_gates[i].gate, st21nfca_gates[i].gate,
...@@ -212,7 +221,6 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev) ...@@ -212,7 +221,6 @@ static int st21nfca_hci_load_session(struct nfc_hci_dev *hdev)
memcpy(hdev->init_data.gates, st21nfca_gates, sizeof(st21nfca_gates)); memcpy(hdev->init_data.gates, st21nfca_gates, sizeof(st21nfca_gates));
free_info: free_info:
kfree_skb(skb_pipe_info); kfree_skb(skb_pipe_info);
free_list:
kfree_skb(skb_pipe_list); kfree_skb(skb_pipe_list);
return r; return r;
} }
...@@ -257,16 +265,33 @@ static void st21nfca_hci_close(struct nfc_hci_dev *hdev) ...@@ -257,16 +265,33 @@ static void st21nfca_hci_close(struct nfc_hci_dev *hdev)
static int st21nfca_hci_ready(struct nfc_hci_dev *hdev) static int st21nfca_hci_ready(struct nfc_hci_dev *hdev)
{ {
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
struct sk_buff *skb; struct sk_buff *skb;
u8 param; u8 param;
u8 white_list[2];
int wl_size = 0;
int r; int r;
param = NFC_HCI_UICC_HOST_ID; if (info->se_status->is_ese_present &&
r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE, info->se_status->is_uicc_present) {
NFC_HCI_ADMIN_WHITELIST, &param, 1); white_list[wl_size++] = NFC_HCI_UICC_HOST_ID;
if (r < 0) white_list[wl_size++] = ST21NFCA_ESE_HOST_ID;
return r; } 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,
NFC_HCI_ADMIN_WHITELIST,
(u8 *) &white_list, wl_size);
if (r < 0)
return r;
}
/* Set NFC_MODE in device management gate to enable */ /* Set NFC_MODE in device management gate to enable */
r = nfc_hci_get_param(hdev, ST21NFCA_DEVICE_MGNT_GATE, r = nfc_hci_get_param(hdev, ST21NFCA_DEVICE_MGNT_GATE,
...@@ -274,8 +299,9 @@ static int st21nfca_hci_ready(struct nfc_hci_dev *hdev) ...@@ -274,8 +299,9 @@ static int st21nfca_hci_ready(struct nfc_hci_dev *hdev)
if (r < 0) if (r < 0)
return r; return r;
if (skb->data[0] == 0) { param = skb->data[0];
kfree_skb(skb); kfree_skb(skb);
if (param == 0) {
param = 1; param = 1;
r = nfc_hci_set_param(hdev, ST21NFCA_DEVICE_MGNT_GATE, r = nfc_hci_set_param(hdev, ST21NFCA_DEVICE_MGNT_GATE,
...@@ -417,9 +443,12 @@ static int st21nfca_hci_start_poll(struct nfc_hci_dev *hdev, ...@@ -417,9 +443,12 @@ static int st21nfca_hci_start_poll(struct nfc_hci_dev *hdev,
r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE, r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
ST21NFCA_RF_CARD_F_DATARATE, ST21NFCA_RF_CARD_F_DATARATE,
param, 1); param, 1);
if (r < 0) if (r < 0) {
kfree_skb(datarate_skb);
return r; return r;
}
} }
kfree_skb(datarate_skb);
/* /*
* Configure sens_res * Configure sens_res
...@@ -673,15 +702,15 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev, ...@@ -673,15 +702,15 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
struct nfc_target *target) struct nfc_target *target)
{ {
int r; int r;
struct sk_buff *nfcid2_skb = NULL, *nfcid1_skb; struct sk_buff *nfcid_skb = NULL;
if (gate == ST21NFCA_RF_READER_F_GATE) { if (gate == ST21NFCA_RF_READER_F_GATE) {
r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE, r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE,
ST21NFCA_RF_READER_F_NFCID2, &nfcid2_skb); ST21NFCA_RF_READER_F_NFCID2, &nfcid_skb);
if (r < 0) if (r < 0)
goto exit; goto exit;
if (nfcid2_skb->len > NFC_SENSF_RES_MAXSIZE) { if (nfcid_skb->len > NFC_SENSF_RES_MAXSIZE) {
r = -EPROTO; r = -EPROTO;
goto exit; goto exit;
} }
...@@ -693,11 +722,11 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev, ...@@ -693,11 +722,11 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
* - After the reception of SEL_RES with NFCIP-1 compliant bit * - After the reception of SEL_RES with NFCIP-1 compliant bit
* set for type A frame NFCID1 will be updated * set for type A frame NFCID1 will be updated
*/ */
if (nfcid2_skb->len > 0) { if (nfcid_skb->len > 0) {
/* P2P in type F */ /* P2P in type F */
memcpy(target->sensf_res, nfcid2_skb->data, memcpy(target->sensf_res, nfcid_skb->data,
nfcid2_skb->len); nfcid_skb->len);
target->sensf_res_len = nfcid2_skb->len; target->sensf_res_len = nfcid_skb->len;
/* NFC Forum Digital Protocol Table 44 */ /* NFC Forum Digital Protocol Table 44 */
if (target->sensf_res[0] == 0x01 && if (target->sensf_res[0] == 0x01 &&
target->sensf_res[1] == 0xfe) target->sensf_res[1] == 0xfe)
...@@ -707,27 +736,28 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev, ...@@ -707,27 +736,28 @@ static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
target->supported_protocols = target->supported_protocols =
NFC_PROTO_FELICA_MASK; NFC_PROTO_FELICA_MASK;
} else { } else {
kfree_skb(nfcid_skb);
/* P2P in type A */ /* P2P in type A */
r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE, r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE,
ST21NFCA_RF_READER_F_NFCID1, ST21NFCA_RF_READER_F_NFCID1,
&nfcid1_skb); &nfcid_skb);
if (r < 0) if (r < 0)
goto exit; goto exit;
if (nfcid1_skb->len > NFC_NFCID1_MAXSIZE) { if (nfcid_skb->len > NFC_NFCID1_MAXSIZE) {
r = -EPROTO; r = -EPROTO;
goto exit; goto exit;
} }
memcpy(target->sensf_res, nfcid1_skb->data, memcpy(target->sensf_res, nfcid_skb->data,
nfcid1_skb->len); nfcid_skb->len);
target->sensf_res_len = nfcid1_skb->len; target->sensf_res_len = nfcid_skb->len;
target->supported_protocols = NFC_PROTO_NFC_DEP_MASK; target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
} }
target->hci_reader_gate = ST21NFCA_RF_READER_F_GATE; target->hci_reader_gate = ST21NFCA_RF_READER_F_GATE;
} }
r = 1; r = 1;
exit: exit:
kfree_skb(nfcid2_skb); kfree_skb(nfcid_skb);
return r; return r;
} }
...@@ -829,24 +859,82 @@ static int st21nfca_hci_check_presence(struct nfc_hci_dev *hdev, ...@@ -829,24 +859,82 @@ static int st21nfca_hci_check_presence(struct nfc_hci_dev *hdev,
} }
} }
static void st21nfca_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
struct sk_buff *skb)
{
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
u8 gate = hdev->pipes[pipe].gate;
pr_debug("cmd: %x\n", cmd);
switch (cmd) {
case NFC_HCI_ANY_OPEN_PIPE:
if (gate != ST21NFCA_APDU_READER_GATE &&
hdev->pipes[pipe].dest_host != NFC_HCI_UICC_HOST_ID)
info->se_info.count_pipes++;
if (info->se_info.count_pipes == info->se_info.expected_pipes) {
del_timer_sync(&info->se_info.se_active_timer);
info->se_info.se_active = false;
info->se_info.count_pipes = 0;
complete(&info->se_info.req_completion);
}
break;
}
}
static int st21nfca_admin_event_received(struct nfc_hci_dev *hdev, u8 event,
struct sk_buff *skb)
{
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
pr_debug("admin event: %x\n", event);
switch (event) {
case ST21NFCA_EVT_HOT_PLUG:
if (info->se_info.se_active) {
if (!ST21NFCA_EVT_HOT_PLUG_IS_INHIBITED(skb)) {
del_timer_sync(&info->se_info.se_active_timer);
info->se_info.se_active = false;
complete(&info->se_info.req_completion);
} else {
mod_timer(&info->se_info.se_active_timer,
jiffies +
msecs_to_jiffies(ST21NFCA_SE_TO_PIPES));
}
}
break;
}
kfree_skb(skb);
return 0;
}
/* /*
* Returns: * Returns:
* <= 0: driver handled the event, skb consumed * <= 0: driver handled the event, skb consumed
* 1: driver does not handle the event, please do standard processing * 1: driver does not handle the event, please do standard processing
*/ */
static int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 gate, static int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe,
u8 event, struct sk_buff *skb) u8 event, struct sk_buff *skb)
{ {
u8 gate = hdev->pipes[pipe].gate;
u8 host = hdev->pipes[pipe].dest_host;
pr_debug("hci event: %d gate: %x\n", event, gate); pr_debug("hci event: %d gate: %x\n", event, gate);
switch (gate) { switch (gate) {
case NFC_HCI_ADMIN_GATE:
return st21nfca_admin_event_received(hdev, event, skb);
case ST21NFCA_RF_CARD_F_GATE: case ST21NFCA_RF_CARD_F_GATE:
return st21nfca_dep_event_received(hdev, event, skb); return st21nfca_dep_event_received(hdev, event, skb);
case ST21NFCA_CONNECTIVITY_GATE:
return st21nfca_connectivity_event_received(hdev, host,
event, skb);
case ST21NFCA_APDU_READER_GATE:
return st21nfca_apdu_reader_event_received(hdev, event, skb);
default: default:
return 1; return 1;
} }
kfree_skb(skb);
return 0;
} }
static struct nfc_hci_ops st21nfca_hci_ops = { static struct nfc_hci_ops st21nfca_hci_ops = {
...@@ -865,11 +953,17 @@ static struct nfc_hci_ops st21nfca_hci_ops = { ...@@ -865,11 +953,17 @@ static struct nfc_hci_ops st21nfca_hci_ops = {
.tm_send = st21nfca_hci_tm_send, .tm_send = st21nfca_hci_tm_send,
.check_presence = st21nfca_hci_check_presence, .check_presence = st21nfca_hci_check_presence,
.event_received = st21nfca_hci_event_received, .event_received = st21nfca_hci_event_received,
.cmd_received = st21nfca_hci_cmd_received,
.discover_se = st21nfca_hci_discover_se,
.enable_se = st21nfca_hci_enable_se,
.disable_se = st21nfca_hci_disable_se,
.se_io = st21nfca_hci_se_io,
}; };
int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
char *llc_name, int phy_headroom, int phy_tailroom, char *llc_name, int phy_headroom, int phy_tailroom,
int phy_payload, struct nfc_hci_dev **hdev) int phy_payload, struct nfc_hci_dev **hdev,
struct st21nfca_se_status *se_status)
{ {
struct st21nfca_hci_info *info; struct st21nfca_hci_info *info;
int r = 0; int r = 0;
...@@ -929,6 +1023,8 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, ...@@ -929,6 +1023,8 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
goto err_alloc_hdev; goto err_alloc_hdev;
} }
info->se_status = se_status;
nfc_hci_set_clientdata(info->hdev, info); nfc_hci_set_clientdata(info->hdev, info);
r = nfc_hci_register_device(info->hdev); r = nfc_hci_register_device(info->hdev);
...@@ -937,6 +1033,7 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, ...@@ -937,6 +1033,7 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
*hdev = info->hdev; *hdev = info->hdev;
st21nfca_dep_init(info->hdev); st21nfca_dep_init(info->hdev);
st21nfca_se_init(info->hdev);
return 0; return 0;
...@@ -955,6 +1052,7 @@ void st21nfca_hci_remove(struct nfc_hci_dev *hdev) ...@@ -955,6 +1052,7 @@ void st21nfca_hci_remove(struct nfc_hci_dev *hdev)
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev); struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
st21nfca_dep_deinit(hdev); st21nfca_dep_deinit(hdev);
st21nfca_se_deinit(hdev);
nfc_hci_unregister_device(hdev); nfc_hci_unregister_device(hdev);
nfc_hci_free_device(hdev); nfc_hci_free_device(hdev);
kfree(info); kfree(info);
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <net/nfc/hci.h> #include <net/nfc/hci.h>
#include "st21nfca_dep.h" #include "st21nfca_dep.h"
#include "st21nfca_se.h"
#define HCI_MODE 0 #define HCI_MODE 0
...@@ -51,9 +52,15 @@ ...@@ -51,9 +52,15 @@
#define ST21NFCA_NUM_DEVICES 256 #define ST21NFCA_NUM_DEVICES 256
struct st21nfca_se_status {
bool is_ese_present;
bool is_uicc_present;
};
int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops, int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
char *llc_name, int phy_headroom, int phy_tailroom, char *llc_name, int phy_headroom, int phy_tailroom,
int phy_payload, struct nfc_hci_dev **hdev); int phy_payload, struct nfc_hci_dev **hdev,
struct st21nfca_se_status *se_status);
void st21nfca_hci_remove(struct nfc_hci_dev *hdev); void st21nfca_hci_remove(struct nfc_hci_dev *hdev);
enum st21nfca_state { enum st21nfca_state {
...@@ -66,6 +73,7 @@ struct st21nfca_hci_info { ...@@ -66,6 +73,7 @@ struct st21nfca_hci_info {
void *phy_id; void *phy_id;
struct nfc_hci_dev *hdev; struct nfc_hci_dev *hdev;
struct st21nfca_se_status *se_status;
enum st21nfca_state state; enum st21nfca_state state;
...@@ -76,13 +84,16 @@ struct st21nfca_hci_info { ...@@ -76,13 +84,16 @@ struct st21nfca_hci_info {
void *async_cb_context; void *async_cb_context;
struct st21nfca_dep_info dep_info; struct st21nfca_dep_info dep_info;
struct st21nfca_se_info se_info;
}; };
/* Reader RF commands */ /* Reader RF commands */
#define ST21NFCA_WR_XCHG_DATA 0x10 #define ST21NFCA_WR_XCHG_DATA 0x10
#define ST21NFCA_RF_READER_F_GATE 0x14
#define ST21NFCA_RF_CARD_F_GATE 0x24 #define ST21NFCA_DEVICE_MGNT_GATE 0x01
#define ST21NFCA_RF_READER_F_GATE 0x14
#define ST21NFCA_RF_CARD_F_GATE 0x24
#define ST21NFCA_APDU_READER_GATE 0xf0
#define ST21NFCA_CONNECTIVITY_GATE 0x41
#endif /* __LOCAL_ST21NFCA_H_ */ #endif /* __LOCAL_ST21NFCA_H_ */
/*
* Copyright (C) 2014 STMicroelectronics SAS. 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 <net/nfc/hci.h>
#include "st21nfca.h"
#include "st21nfca_se.h"
#define ST21NFCA_EVT_UICC_ACTIVATE 0x10
#define ST21NFCA_EVT_UICC_DEACTIVATE 0x13
#define ST21NFCA_EVT_SE_HARD_RESET 0x20
#define ST21NFCA_EVT_SE_SOFT_RESET 0x11
#define ST21NFCA_EVT_SE_END_OF_APDU_TRANSFER 0x21
#define ST21NFCA_EVT_SE_ACTIVATE 0x22
#define ST21NFCA_EVT_SE_DEACTIVATE 0x23
#define ST21NFCA_EVT_TRANSMIT_DATA 0x10
#define ST21NFCA_EVT_WTX_REQUEST 0x11
#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
/* Connectivity + APDU Reader pipe */
#define ST21NFCA_SE_COUNT_PIPE_EMBEDDED 0x02
#define ST21NFCA_SE_MODE_OFF 0x00
#define ST21NFCA_SE_MODE_ON 0x01
#define ST21NFCA_PARAM_ATR 0x01
#define ST21NFCA_ATR_DEFAULT_BWI 0x04
/*
* WT = 2^BWI/10[s], convert into msecs and add a secure
* room by increasing by 2 this timeout
*/
#define ST21NFCA_BWI_TO_TIMEOUT(x) ((1 << x) * 200)
#define ST21NFCA_ATR_GET_Y_FROM_TD(x) (x >> 4)
/* If TA is present bit 0 is set */
#define ST21NFCA_ATR_TA_PRESENT(x) (x & 0x01)
/* If TB is present bit 1 is set */
#define ST21NFCA_ATR_TB_PRESENT(x) (x & 0x02)
static u8 st21nfca_se_get_bwi(struct nfc_hci_dev *hdev)
{
int i;
u8 td;
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
/* Bits 8 to 5 of the first TB for T=1 encode BWI from zero to nine */
for (i = 1; i < ST21NFCA_ESE_MAX_LENGTH; i++) {
td = ST21NFCA_ATR_GET_Y_FROM_TD(info->se_info.atr[i]);
if (ST21NFCA_ATR_TA_PRESENT(td))
i++;
if (ST21NFCA_ATR_TB_PRESENT(td)) {
i++;
return info->se_info.atr[i] >> 4;
}
}
return ST21NFCA_ATR_DEFAULT_BWI;
}
static void st21nfca_se_get_atr(struct nfc_hci_dev *hdev)
{
int r;
struct sk_buff *skb;
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
r = nfc_hci_get_param(hdev, ST21NFCA_APDU_READER_GATE,
ST21NFCA_PARAM_ATR, &skb);
if (r < 0)
return;
if (skb->len <= ST21NFCA_ESE_MAX_LENGTH) {
memcpy(info->se_info.atr, skb->data, skb->len);
info->se_info.wt_timeout =
ST21NFCA_BWI_TO_TIMEOUT(st21nfca_se_get_bwi(hdev));
}
kfree_skb(skb);
}
static int st21nfca_hci_control_se(struct nfc_hci_dev *hdev, u32 se_idx,
u8 state)
{
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
int r;
struct sk_buff *sk_host_list;
u8 se_event, host_id;
switch (se_idx) {
case NFC_HCI_UICC_HOST_ID:
se_event = (state == ST21NFCA_SE_MODE_ON ?
ST21NFCA_EVT_UICC_ACTIVATE :
ST21NFCA_EVT_UICC_DEACTIVATE);
info->se_info.count_pipes = 0;
info->se_info.expected_pipes = ST21NFCA_SE_COUNT_PIPE_UICC;
break;
case ST21NFCA_ESE_HOST_ID:
se_event = (state == ST21NFCA_SE_MODE_ON ?
ST21NFCA_EVT_SE_ACTIVATE :
ST21NFCA_EVT_SE_DEACTIVATE);
info->se_info.count_pipes = 0;
info->se_info.expected_pipes = ST21NFCA_SE_COUNT_PIPE_EMBEDDED;
break;
default:
return -EINVAL;
}
/*
* Wait for an EVT_HOT_PLUG in order to
* retrieve a relevant host list.
*/
reinit_completion(&info->se_info.req_completion);
r = nfc_hci_send_event(hdev, ST21NFCA_DEVICE_MGNT_GATE, se_event,
NULL, 0);
if (r < 0)
return r;
mod_timer(&info->se_info.se_active_timer, jiffies +
msecs_to_jiffies(ST21NFCA_SE_TO_HOT_PLUG));
info->se_info.se_active = true;
/* Ignore return value and check in any case the host_list */
wait_for_completion_interruptible(&info->se_info.req_completion);
r = nfc_hci_get_param(hdev, NFC_HCI_ADMIN_GATE,
NFC_HCI_ADMIN_HOST_LIST,
&sk_host_list);
if (r < 0)
return r;
host_id = sk_host_list->data[sk_host_list->len - 1];
kfree_skb(sk_host_list);
if (state == ST21NFCA_SE_MODE_ON && host_id == se_idx)
return se_idx;
else if (state == ST21NFCA_SE_MODE_OFF && host_id != se_idx)
return se_idx;
return -1;
}
int st21nfca_hci_discover_se(struct nfc_hci_dev *hdev)
{
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
int se_count = 0;
if (info->se_status->is_uicc_present) {
nfc_add_se(hdev->ndev, NFC_HCI_UICC_HOST_ID, NFC_SE_UICC);
se_count++;
}
if (info->se_status->is_ese_present) {
nfc_add_se(hdev->ndev, ST21NFCA_ESE_HOST_ID, NFC_SE_EMBEDDED);
se_count++;
}
return !se_count;
}
EXPORT_SYMBOL(st21nfca_hci_discover_se);
int st21nfca_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx)
{
int r;
/*
* According to upper layer, se_idx == NFC_SE_UICC when
* info->se_status->is_uicc_enable is true should never happen.
* Same for eSE.
*/
r = st21nfca_hci_control_se(hdev, se_idx, ST21NFCA_SE_MODE_ON);
if (r == ST21NFCA_ESE_HOST_ID) {
st21nfca_se_get_atr(hdev);
r = nfc_hci_send_event(hdev, ST21NFCA_APDU_READER_GATE,
ST21NFCA_EVT_SE_SOFT_RESET, NULL, 0);
if (r < 0)
return r;
} else if (r < 0) {
/*
* The activation tentative failed, the secure element
* is not connected. Remove from the list.
*/
nfc_remove_se(hdev->ndev, se_idx);
return r;
}
return 0;
}
EXPORT_SYMBOL(st21nfca_hci_enable_se);
int st21nfca_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx)
{
int r;
/*
* According to upper layer, se_idx == NFC_SE_UICC when
* info->se_status->is_uicc_enable is true should never happen
* Same for eSE.
*/
r = st21nfca_hci_control_se(hdev, se_idx, ST21NFCA_SE_MODE_OFF);
if (r < 0)
return r;
return 0;
}
EXPORT_SYMBOL(st21nfca_hci_disable_se);
int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx,
u8 *apdu, size_t apdu_length,
se_io_cb_t cb, void *cb_context)
{
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
pr_debug("se_io %x\n", se_idx);
switch (se_idx) {
case ST21NFCA_ESE_HOST_ID:
info->se_info.cb = cb;
info->se_info.cb_context = cb_context;
mod_timer(&info->se_info.bwi_timer, jiffies +
msecs_to_jiffies(info->se_info.wt_timeout));
info->se_info.bwi_active = true;
return nfc_hci_send_event(hdev, ST21NFCA_APDU_READER_GATE,
ST21NFCA_EVT_TRANSMIT_DATA,
apdu, apdu_length);
default:
return -ENODEV;
}
}
EXPORT_SYMBOL(st21nfca_hci_se_io);
static void st21nfca_se_wt_timeout(unsigned long data)
{
/*
* No answer from the secure element
* within the defined timeout.
* Let's send a reset request as recovery procedure.
* According to the situation, we first try to send a software reset
* to the secure element. If the next command is still not
* answering in time, we send to the CLF a secure element hardware
* reset request.
*/
/* hardware reset managed through VCC_UICC_OUT power supply */
u8 param = 0x01;
struct st21nfca_hci_info *info = (struct st21nfca_hci_info *) data;
pr_debug("\n");
info->se_info.bwi_active = false;
if (!info->se_info.xch_error) {
info->se_info.xch_error = true;
nfc_hci_send_event(info->hdev, ST21NFCA_APDU_READER_GATE,
ST21NFCA_EVT_SE_SOFT_RESET, NULL, 0);
} else {
info->se_info.xch_error = false;
nfc_hci_send_event(info->hdev, ST21NFCA_DEVICE_MGNT_GATE,
ST21NFCA_EVT_SE_HARD_RESET, &param, 1);
}
info->se_info.cb(info->se_info.cb_context, NULL, 0, -ETIME);
}
static void st21nfca_se_activation_timeout(unsigned long data)
{
struct st21nfca_hci_info *info = (struct st21nfca_hci_info *) data;
pr_debug("\n");
info->se_info.se_active = false;
complete(&info->se_info.req_completion);
}
/*
* Returns:
* <= 0: driver handled the event, skb consumed
* 1: driver does not handle the event, please do standard processing
*/
int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
u8 event, struct sk_buff *skb)
{
int r = 0;
pr_debug("connectivity gate event: %x\n", event);
switch (event) {
case ST21NFCA_EVT_CONNECTIVITY:
break;
case ST21NFCA_EVT_TRANSACTION:
break;
default:
return 1;
}
kfree_skb(skb);
return r;
}
EXPORT_SYMBOL(st21nfca_connectivity_event_received);
int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev,
u8 event, struct sk_buff *skb)
{
int r = 0;
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
pr_debug("apdu reader gate event: %x\n", event);
switch (event) {
case ST21NFCA_EVT_TRANSMIT_DATA:
del_timer_sync(&info->se_info.bwi_timer);
info->se_info.bwi_active = false;
r = nfc_hci_send_event(hdev, ST21NFCA_DEVICE_MGNT_GATE,
ST21NFCA_EVT_SE_END_OF_APDU_TRANSFER, NULL, 0);
if (r < 0)
goto exit;
info->se_info.cb(info->se_info.cb_context,
skb->data, skb->len, 0);
break;
case ST21NFCA_EVT_WTX_REQUEST:
mod_timer(&info->se_info.bwi_timer, jiffies +
msecs_to_jiffies(info->se_info.wt_timeout));
break;
}
exit:
kfree_skb(skb);
return r;
}
EXPORT_SYMBOL(st21nfca_apdu_reader_event_received);
void st21nfca_se_init(struct nfc_hci_dev *hdev)
{
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
init_completion(&info->se_info.req_completion);
/* initialize timers */
init_timer(&info->se_info.bwi_timer);
info->se_info.bwi_timer.data = (unsigned long)info;
info->se_info.bwi_timer.function = st21nfca_se_wt_timeout;
info->se_info.bwi_active = false;
init_timer(&info->se_info.se_active_timer);
info->se_info.se_active_timer.data = (unsigned long)info;
info->se_info.se_active_timer.function = st21nfca_se_activation_timeout;
info->se_info.se_active = false;
info->se_info.count_pipes = 0;
info->se_info.expected_pipes = 0;
info->se_info.xch_error = false;
info->se_info.wt_timeout =
ST21NFCA_BWI_TO_TIMEOUT(ST21NFCA_ATR_DEFAULT_BWI);
}
EXPORT_SYMBOL(st21nfca_se_init);
void st21nfca_se_deinit(struct nfc_hci_dev *hdev)
{
struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
if (info->se_info.bwi_active)
del_timer_sync(&info->se_info.bwi_timer);
if (info->se_info.se_active)
del_timer_sync(&info->se_info.se_active_timer);
info->se_info.bwi_active = false;
info->se_info.se_active = false;
}
EXPORT_SYMBOL(st21nfca_se_deinit);
/*
* Copyright (C) 2014 STMicroelectronics SAS. 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 __ST21NFCA_SE_H
#define __ST21NFCA_SE_H
#include <linux/skbuff.h>
#include <linux/workqueue.h>
/*
* ref ISO7816-3 chap 8.1. the initial character TS is followed by a
* sequence of at most 32 characters.
*/
#define ST21NFCA_ESE_MAX_LENGTH 33
#define ST21NFCA_ESE_HOST_ID 0xc0
struct st21nfca_se_info {
u8 atr[ST21NFCA_ESE_MAX_LENGTH];
struct completion req_completion;
struct timer_list bwi_timer;
int wt_timeout; /* in msecs */
bool bwi_active;
struct timer_list se_active_timer;
bool se_active;
int expected_pipes;
int count_pipes;
bool xch_error;
se_io_cb_t cb;
void *cb_context;
};
int st21nfca_connectivity_event_received(struct nfc_hci_dev *hdev, u8 host,
u8 event, struct sk_buff *skb);
int st21nfca_apdu_reader_event_received(struct nfc_hci_dev *hdev,
u8 event, struct sk_buff *skb);
int st21nfca_hci_discover_se(struct nfc_hci_dev *hdev);
int st21nfca_hci_enable_se(struct nfc_hci_dev *hdev, u32 se_idx);
int st21nfca_hci_disable_se(struct nfc_hci_dev *hdev, u32 se_idx);
int st21nfca_hci_se_io(struct nfc_hci_dev *hdev, u32 se_idx,
u8 *apdu, size_t apdu_length,
se_io_cb_t cb, void *cb_context);
void st21nfca_se_init(struct nfc_hci_dev *hdev);
void st21nfca_se_deinit(struct nfc_hci_dev *hdev);
#endif /* __ST21NFCA_SE_H */
...@@ -199,7 +199,7 @@ static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id) ...@@ -199,7 +199,7 @@ static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id)
struct sk_buff *skb = NULL; struct sk_buff *skb = NULL;
int r; int r;
if (!phy || irq != phy->i2c_dev->irq) { if (!phy || !phy->ndlc || irq != phy->i2c_dev->irq) {
WARN_ON_ONCE(1); WARN_ON_ONCE(1);
return IRQ_NONE; return IRQ_NONE;
} }
...@@ -343,18 +343,22 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client, ...@@ -343,18 +343,22 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
return -ENODEV; return -ENODEV;
} }
r = ndlc_probe(phy, &i2c_phy_ops, &client->dev,
ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM,
&phy->ndlc);
if (r < 0) {
nfc_err(&client->dev, "Unable to register ndlc layer\n");
return r;
}
r = devm_request_threaded_irq(&client->dev, client->irq, NULL, r = devm_request_threaded_irq(&client->dev, client->irq, NULL,
st21nfcb_nci_irq_thread_fn, st21nfcb_nci_irq_thread_fn,
phy->irq_polarity | IRQF_ONESHOT, phy->irq_polarity | IRQF_ONESHOT,
ST21NFCB_NCI_DRIVER_NAME, phy); ST21NFCB_NCI_DRIVER_NAME, phy);
if (r < 0) { if (r < 0)
nfc_err(&client->dev, "Unable to register IRQ handler\n"); nfc_err(&client->dev, "Unable to register IRQ handler\n");
return r;
}
return ndlc_probe(phy, &i2c_phy_ops, &client->dev, return r;
ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM,
&phy->ndlc);
} }
static int st21nfcb_nci_i2c_remove(struct i2c_client *client) static int st21nfcb_nci_i2c_remove(struct i2c_client *client)
...@@ -373,6 +377,7 @@ static int st21nfcb_nci_i2c_remove(struct i2c_client *client) ...@@ -373,6 +377,7 @@ static int st21nfcb_nci_i2c_remove(struct i2c_client *client)
#ifdef CONFIG_OF #ifdef CONFIG_OF
static const struct of_device_id of_st21nfcb_i2c_match[] = { static const struct of_device_id of_st21nfcb_i2c_match[] = {
{ .compatible = "st,st21nfcb-i2c", },
{ .compatible = "st,st21nfcb_i2c", }, { .compatible = "st,st21nfcb_i2c", },
{} {}
}; };
......
...@@ -138,7 +138,7 @@ static void llt_ndlc_requeue_data_pending(struct llt_ndlc *ndlc) ...@@ -138,7 +138,7 @@ static void llt_ndlc_requeue_data_pending(struct llt_ndlc *ndlc)
default: default:
pr_err("UNKNOWN Packet Control Byte=%d\n", pcb); pr_err("UNKNOWN Packet Control Byte=%d\n", pcb);
kfree_skb(skb); kfree_skb(skb);
break; continue;
} }
skb_queue_head(&ndlc->send_q, skb); skb_queue_head(&ndlc->send_q, skb);
} }
...@@ -297,6 +297,5 @@ void ndlc_remove(struct llt_ndlc *ndlc) ...@@ -297,6 +297,5 @@ void ndlc_remove(struct llt_ndlc *ndlc)
skb_queue_purge(&ndlc->send_q); skb_queue_purge(&ndlc->send_q);
st21nfcb_nci_remove(ndlc->ndev); st21nfcb_nci_remove(ndlc->ndev);
kfree(ndlc);
} }
EXPORT_SYMBOL(ndlc_remove); EXPORT_SYMBOL(ndlc_remove);
...@@ -26,6 +26,8 @@ ...@@ -26,6 +26,8 @@
struct st21nfca_nfc_platform_data { struct st21nfca_nfc_platform_data {
unsigned int gpio_ena; unsigned int gpio_ena;
unsigned int irq_polarity; unsigned int irq_polarity;
bool is_ese_present;
bool is_uicc_present;
}; };
#endif /* _ST21NFCA_HCI_H_ */ #endif /* _ST21NFCA_HCI_H_ */
...@@ -19,8 +19,6 @@ ...@@ -19,8 +19,6 @@
#ifndef _ST21NFCB_NCI_H_ #ifndef _ST21NFCB_NCI_H_
#define _ST21NFCB_NCI_H_ #define _ST21NFCB_NCI_H_
#include <linux/i2c.h>
#define ST21NFCB_NCI_DRIVER_NAME "st21nfcb_nci" #define ST21NFCB_NCI_DRIVER_NAME "st21nfcb_nci"
struct st21nfcb_nfc_platform_data { struct st21nfcb_nfc_platform_data {
...@@ -28,4 +26,4 @@ struct st21nfcb_nfc_platform_data { ...@@ -28,4 +26,4 @@ struct st21nfcb_nfc_platform_data {
unsigned int irq_polarity; unsigned int irq_polarity;
}; };
#endif /* _ST21NFCA_HCI_H_ */ #endif /* _ST21NFCB_NCI_H_ */
...@@ -51,8 +51,10 @@ struct nfc_hci_ops { ...@@ -51,8 +51,10 @@ struct nfc_hci_ops {
int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb); int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*check_presence)(struct nfc_hci_dev *hdev, int (*check_presence)(struct nfc_hci_dev *hdev,
struct nfc_target *target); struct nfc_target *target);
int (*event_received)(struct nfc_hci_dev *hdev, u8 gate, u8 event, int (*event_received)(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
struct sk_buff *skb); struct sk_buff *skb);
void (*cmd_received)(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
struct sk_buff *skb);
int (*fw_download)(struct nfc_hci_dev *hdev, const char *firmware_name); int (*fw_download)(struct nfc_hci_dev *hdev, const char *firmware_name);
int (*discover_se)(struct nfc_hci_dev *dev); int (*discover_se)(struct nfc_hci_dev *dev);
int (*enable_se)(struct nfc_hci_dev *dev, u32 se_idx); int (*enable_se)(struct nfc_hci_dev *dev, u32 se_idx);
...@@ -63,8 +65,10 @@ struct nfc_hci_ops { ...@@ -63,8 +65,10 @@ struct nfc_hci_ops {
}; };
/* Pipes */ /* Pipes */
#define NFC_HCI_INVALID_PIPE 0x80
#define NFC_HCI_DO_NOT_CREATE_PIPE 0x81 #define NFC_HCI_DO_NOT_CREATE_PIPE 0x81
#define NFC_HCI_INVALID_PIPE 0x80
#define NFC_HCI_INVALID_GATE 0xFF
#define NFC_HCI_INVALID_HOST 0x80
#define NFC_HCI_LINK_MGMT_PIPE 0x00 #define NFC_HCI_LINK_MGMT_PIPE 0x00
#define NFC_HCI_ADMIN_PIPE 0x01 #define NFC_HCI_ADMIN_PIPE 0x01
...@@ -73,7 +77,13 @@ struct nfc_hci_gate { ...@@ -73,7 +77,13 @@ struct nfc_hci_gate {
u8 pipe; u8 pipe;
}; };
struct nfc_hci_pipe {
u8 gate;
u8 dest_host;
};
#define NFC_HCI_MAX_CUSTOM_GATES 50 #define NFC_HCI_MAX_CUSTOM_GATES 50
#define NFC_HCI_MAX_PIPES 127
struct nfc_hci_init_data { struct nfc_hci_init_data {
u8 gate_count; u8 gate_count;
struct nfc_hci_gate gates[NFC_HCI_MAX_CUSTOM_GATES]; struct nfc_hci_gate gates[NFC_HCI_MAX_CUSTOM_GATES];
...@@ -125,6 +135,7 @@ struct nfc_hci_dev { ...@@ -125,6 +135,7 @@ struct nfc_hci_dev {
void *clientdata; void *clientdata;
u8 gate2pipe[NFC_HCI_MAX_GATES]; u8 gate2pipe[NFC_HCI_MAX_GATES];
struct nfc_hci_pipe pipes[NFC_HCI_MAX_PIPES];
u8 sw_romlib; u8 sw_romlib;
u8 sw_patch; u8 sw_patch;
...@@ -167,6 +178,8 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev); ...@@ -167,6 +178,8 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev);
void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err); void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err);
int nfc_hci_result_to_errno(u8 result); int nfc_hci_result_to_errno(u8 result);
void nfc_hci_reset_pipes(struct nfc_hci_dev *dev);
void nfc_hci_reset_pipes_per_host(struct nfc_hci_dev *hdev, u8 host);
/* Host IDs */ /* Host IDs */
#define NFC_HCI_HOST_CONTROLLER_ID 0x00 #define NFC_HCI_HOST_CONTROLLER_ID 0x00
...@@ -219,6 +232,12 @@ int nfc_hci_result_to_errno(u8 result); ...@@ -219,6 +232,12 @@ int nfc_hci_result_to_errno(u8 result);
#define NFC_HCI_EVT_POST_DATA 0x02 #define NFC_HCI_EVT_POST_DATA 0x02
#define NFC_HCI_EVT_HOT_PLUG 0x03 #define NFC_HCI_EVT_HOT_PLUG 0x03
/* Generic commands */
#define NFC_HCI_ANY_SET_PARAMETER 0x01
#define NFC_HCI_ANY_GET_PARAMETER 0x02
#define NFC_HCI_ANY_OPEN_PIPE 0x03
#define NFC_HCI_ANY_CLOSE_PIPE 0x04
/* Reader RF gates events */ /* Reader RF gates events */
#define NFC_HCI_EVT_READER_REQUESTED 0x10 #define NFC_HCI_EVT_READER_REQUESTED 0x10
#define NFC_HCI_EVT_END_OPERATION 0x11 #define NFC_HCI_EVT_END_OPERATION 0x11
...@@ -249,8 +268,6 @@ int nfc_hci_send_cmd(struct nfc_hci_dev *hdev, u8 gate, u8 cmd, ...@@ -249,8 +268,6 @@ int nfc_hci_send_cmd(struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
int nfc_hci_send_cmd_async(struct nfc_hci_dev *hdev, u8 gate, u8 cmd, int nfc_hci_send_cmd_async(struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
const u8 *param, size_t param_len, const u8 *param, size_t param_len,
data_exchange_cb_t cb, void *cb_context); data_exchange_cb_t cb, void *cb_context);
int nfc_hci_send_response(struct nfc_hci_dev *hdev, u8 gate, u8 response,
const u8 *param, size_t param_len);
int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event, int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event,
const u8 *param, size_t param_len); const u8 *param, size_t param_len);
int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate); int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate);
......
...@@ -555,7 +555,6 @@ EXPORT_SYMBOL(nfc_find_se); ...@@ -555,7 +555,6 @@ EXPORT_SYMBOL(nfc_find_se);
int nfc_enable_se(struct nfc_dev *dev, u32 se_idx) int nfc_enable_se(struct nfc_dev *dev, u32 se_idx)
{ {
struct nfc_se *se; struct nfc_se *se;
int rc; int rc;
...@@ -605,7 +604,6 @@ int nfc_enable_se(struct nfc_dev *dev, u32 se_idx) ...@@ -605,7 +604,6 @@ int nfc_enable_se(struct nfc_dev *dev, u32 se_idx)
int nfc_disable_se(struct nfc_dev *dev, u32 se_idx) int nfc_disable_se(struct nfc_dev *dev, u32 se_idx)
{ {
struct nfc_se *se; struct nfc_se *se;
int rc; int rc;
......
...@@ -116,23 +116,6 @@ int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event, ...@@ -116,23 +116,6 @@ int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event,
} }
EXPORT_SYMBOL(nfc_hci_send_event); EXPORT_SYMBOL(nfc_hci_send_event);
int nfc_hci_send_response(struct nfc_hci_dev *hdev, u8 gate, u8 response,
const u8 *param, size_t param_len)
{
u8 pipe;
pr_debug("\n");
pipe = hdev->gate2pipe[gate];
if (pipe == NFC_HCI_INVALID_PIPE)
return -EADDRNOTAVAIL;
return nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_RESPONSE,
response, param, param_len, NULL, NULL,
0);
}
EXPORT_SYMBOL(nfc_hci_send_response);
/* /*
* Execute an hci command sent to gate. * Execute an hci command sent to gate.
* skb will contain response data if success. skb can be NULL if you are not * skb will contain response data if success. skb can be NULL if you are not
...@@ -331,7 +314,7 @@ int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev) ...@@ -331,7 +314,7 @@ int nfc_hci_disconnect_all_gates(struct nfc_hci_dev *hdev)
if (r < 0) if (r < 0)
return r; return r;
memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe)); nfc_hci_reset_pipes(hdev);
return 0; return 0;
} }
...@@ -345,7 +328,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, ...@@ -345,7 +328,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate,
pr_debug("\n"); pr_debug("\n");
if (hdev->gate2pipe[dest_gate] == NFC_HCI_DO_NOT_CREATE_PIPE) if (pipe == NFC_HCI_DO_NOT_CREATE_PIPE)
return 0; return 0;
if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE) if (hdev->gate2pipe[dest_gate] != NFC_HCI_INVALID_PIPE)
...@@ -380,6 +363,8 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate, ...@@ -380,6 +363,8 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate,
return r; return r;
} }
hdev->pipes[pipe].gate = dest_gate;
hdev->pipes[pipe].dest_host = dest_host;
hdev->gate2pipe[dest_gate] = pipe; hdev->gate2pipe[dest_gate] = pipe;
return 0; return 0;
......
...@@ -46,6 +46,32 @@ int nfc_hci_result_to_errno(u8 result) ...@@ -46,6 +46,32 @@ int nfc_hci_result_to_errno(u8 result)
} }
EXPORT_SYMBOL(nfc_hci_result_to_errno); EXPORT_SYMBOL(nfc_hci_result_to_errno);
void nfc_hci_reset_pipes(struct nfc_hci_dev *hdev)
{
int i = 0;
for (i = 0; i < NFC_HCI_MAX_PIPES; i++) {
hdev->pipes[i].gate = NFC_HCI_INVALID_GATE;
hdev->pipes[i].dest_host = NFC_HCI_INVALID_HOST;
}
memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe));
}
EXPORT_SYMBOL(nfc_hci_reset_pipes);
void nfc_hci_reset_pipes_per_host(struct nfc_hci_dev *hdev, u8 host)
{
int i = 0;
for (i = 0; i < NFC_HCI_MAX_PIPES; i++) {
if (hdev->pipes[i].dest_host != host)
continue;
hdev->pipes[i].gate = NFC_HCI_INVALID_GATE;
hdev->pipes[i].dest_host = NFC_HCI_INVALID_HOST;
}
}
EXPORT_SYMBOL(nfc_hci_reset_pipes_per_host);
static void nfc_hci_msg_tx_work(struct work_struct *work) static void nfc_hci_msg_tx_work(struct work_struct *work)
{ {
struct nfc_hci_dev *hdev = container_of(work, struct nfc_hci_dev, struct nfc_hci_dev *hdev = container_of(work, struct nfc_hci_dev,
...@@ -167,48 +193,69 @@ void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result, ...@@ -167,48 +193,69 @@ void nfc_hci_resp_received(struct nfc_hci_dev *hdev, u8 result,
void nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd, void nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
struct sk_buff *skb) struct sk_buff *skb)
{ {
int r = 0; u8 gate = hdev->pipes[pipe].gate;
u8 gate = nfc_hci_pipe2gate(hdev, pipe); u8 status = NFC_HCI_ANY_OK;
u8 local_gate, new_pipe; struct hci_create_pipe_resp *create_info;
u8 gate_opened = 0x00; struct hci_delete_pipe_noti *delete_info;
struct hci_all_pipe_cleared_noti *cleared_info;
pr_debug("from gate %x pipe %x cmd %x\n", gate, pipe, cmd); pr_debug("from gate %x pipe %x cmd %x\n", gate, pipe, cmd);
switch (cmd) { switch (cmd) {
case NFC_HCI_ADM_NOTIFY_PIPE_CREATED: case NFC_HCI_ADM_NOTIFY_PIPE_CREATED:
if (skb->len != 5) { if (skb->len != 5) {
r = -EPROTO; status = NFC_HCI_ANY_E_NOK;
break; goto exit;
} }
create_info = (struct hci_create_pipe_resp *)skb->data;
local_gate = skb->data[3]; /* Save the new created pipe and bind with local gate,
new_pipe = skb->data[4];
nfc_hci_send_response(hdev, gate, NFC_HCI_ANY_OK, NULL, 0);
/* save the new created pipe and bind with local gate,
* the description for skb->data[3] is destination gate id * the description for skb->data[3] is destination gate id
* but since we received this cmd from host controller, we * but since we received this cmd from host controller, we
* are the destination and it is our local gate * are the destination and it is our local gate
*/ */
hdev->gate2pipe[local_gate] = new_pipe; hdev->gate2pipe[create_info->dest_gate] = create_info->pipe;
hdev->pipes[create_info->pipe].gate = create_info->dest_gate;
hdev->pipes[create_info->pipe].dest_host =
create_info->src_host;
break; break;
case NFC_HCI_ANY_OPEN_PIPE: case NFC_HCI_ANY_OPEN_PIPE:
/* if the pipe is already created, we allow remote host to if (gate == NFC_HCI_INVALID_GATE) {
* open it status = NFC_HCI_ANY_E_NOK;
*/ goto exit;
if (gate != 0xff) }
nfc_hci_send_response(hdev, gate, NFC_HCI_ANY_OK, break;
&gate_opened, 1); case NFC_HCI_ADM_NOTIFY_PIPE_DELETED:
if (skb->len != 1) {
status = NFC_HCI_ANY_E_NOK;
goto exit;
}
delete_info = (struct hci_delete_pipe_noti *)skb->data;
hdev->pipes[delete_info->pipe].gate = NFC_HCI_INVALID_GATE;
hdev->pipes[delete_info->pipe].dest_host = NFC_HCI_INVALID_HOST;
break; break;
case NFC_HCI_ADM_NOTIFY_ALL_PIPE_CLEARED: case NFC_HCI_ADM_NOTIFY_ALL_PIPE_CLEARED:
nfc_hci_send_response(hdev, gate, NFC_HCI_ANY_OK, NULL, 0); if (skb->len != 1) {
status = NFC_HCI_ANY_E_NOK;
goto exit;
}
cleared_info = (struct hci_all_pipe_cleared_noti *)skb->data;
nfc_hci_reset_pipes_per_host(hdev, cleared_info->host);
break; break;
default: default:
pr_info("Discarded unknown cmd %x to gate %x\n", cmd, gate); pr_info("Discarded unknown cmd %x to gate %x\n", cmd, gate);
r = -EINVAL;
break; break;
} }
if (hdev->ops->cmd_received)
hdev->ops->cmd_received(hdev, pipe, cmd, skb);
exit:
nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_RESPONSE,
status, NULL, 0, NULL, NULL, 0);
kfree_skb(skb); kfree_skb(skb);
} }
...@@ -330,15 +377,15 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event, ...@@ -330,15 +377,15 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
struct sk_buff *skb) struct sk_buff *skb)
{ {
int r = 0; int r = 0;
u8 gate = nfc_hci_pipe2gate(hdev, pipe); u8 gate = hdev->pipes[pipe].gate;
if (gate == 0xff) { if (gate == NFC_HCI_INVALID_GATE) {
pr_err("Discarded event %x to unopened pipe %x\n", event, pipe); pr_err("Discarded event %x to unopened pipe %x\n", event, pipe);
goto exit; goto exit;
} }
if (hdev->ops->event_received) { if (hdev->ops->event_received) {
r = hdev->ops->event_received(hdev, gate, event, skb); r = hdev->ops->event_received(hdev, pipe, event, skb);
if (r <= 0) if (r <= 0)
goto exit_noskb; goto exit_noskb;
} }
...@@ -573,7 +620,7 @@ static int hci_dev_down(struct nfc_dev *nfc_dev) ...@@ -573,7 +620,7 @@ static int hci_dev_down(struct nfc_dev *nfc_dev)
if (hdev->ops->close) if (hdev->ops->close)
hdev->ops->close(hdev); hdev->ops->close(hdev);
memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe)); nfc_hci_reset_pipes(hdev);
return 0; return 0;
} }
...@@ -932,7 +979,7 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops, ...@@ -932,7 +979,7 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
nfc_set_drvdata(hdev->ndev, hdev); nfc_set_drvdata(hdev->ndev, hdev);
memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe)); nfc_hci_reset_pipes(hdev);
hdev->quirks = quirks; hdev->quirks = quirks;
......
...@@ -65,6 +65,14 @@ struct hci_create_pipe_resp { ...@@ -65,6 +65,14 @@ struct hci_create_pipe_resp {
u8 pipe; u8 pipe;
} __packed; } __packed;
struct hci_delete_pipe_noti {
u8 pipe;
} __packed;
struct hci_all_pipe_cleared_noti {
u8 host;
} __packed;
#define NFC_HCI_FRAGMENT 0x7f #define NFC_HCI_FRAGMENT 0x7f
#define HCP_HEADER(type, instr) ((((type) & 0x03) << 6) | ((instr) & 0x3f)) #define HCP_HEADER(type, instr) ((((type) & 0x03) << 6) | ((instr) & 0x3f))
...@@ -77,8 +85,6 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, ...@@ -77,8 +85,6 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
data_exchange_cb_t cb, void *cb_context, data_exchange_cb_t cb, void *cb_context,
unsigned long completion_delay); unsigned long completion_delay);
u8 nfc_hci_pipe2gate(struct nfc_hci_dev *hdev, u8 pipe);
void nfc_hci_hcp_message_rx(struct nfc_hci_dev *hdev, u8 pipe, u8 type, void nfc_hci_hcp_message_rx(struct nfc_hci_dev *hdev, u8 pipe, u8 type,
u8 instruction, struct sk_buff *skb); u8 instruction, struct sk_buff *skb);
......
...@@ -124,17 +124,6 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe, ...@@ -124,17 +124,6 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
return err; return err;
} }
u8 nfc_hci_pipe2gate(struct nfc_hci_dev *hdev, u8 pipe)
{
int gate;
for (gate = 0; gate < NFC_HCI_MAX_GATES; gate++)
if (hdev->gate2pipe[gate] == pipe)
return gate;
return 0xff;
}
/* /*
* Receive hcp message for pipe, with type and cmd. * Receive hcp message for pipe, with type and cmd.
* skb contains optional message data only. * skb contains optional message data only.
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment