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
Required properties:
- compatible: Should be "st,st21nfca_i2c".
- compatible: Should be "st,st21nfca-i2c".
- clock-frequency: I²C work frequency.
- reg: address on the bus
- interrupt-parent: phandle for the interrupt gpio controller
......@@ -11,6 +11,10 @@ Required properties:
Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default".
- 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):
......@@ -20,7 +24,7 @@ Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2):
st21nfca: st21nfca@1 {
compatible = "st,st21nfca_i2c";
compatible = "st,st21nfca-i2c";
reg = <0x01>;
clock-frequency = <400000>;
......@@ -29,5 +33,8 @@ Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2):
interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
enable-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
ese-present;
uicc-present;
};
};
* STMicroelectronics SAS. ST21NFCB NFC Controller
Required properties:
- compatible: Should be "st,st21nfcb_i2c".
- compatible: Should be "st,st21nfcb-i2c".
- clock-frequency: I²C work frequency.
- reg: address on the bus
- interrupt-parent: phandle for the interrupt gpio controller
......@@ -20,7 +20,7 @@ Example (for ARM-based BeagleBoard xM with ST21NFCB on I2C2):
st21nfcb: st21nfcb@8 {
compatible = "st,st21nfcb_i2c";
compatible = "st,st21nfcb-i2c";
reg = <0x08>;
clock-frequency = <400000>;
......
......@@ -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);
}
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)
{
int r;
u8 gate = hdev->pipes[pipe].gate;
u8 mode;
pr_info("Microread received event 0x%x to gate 0x%x\n", event, gate);
......
......@@ -24,11 +24,13 @@
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/acpi.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/nfc.h>
#include <linux/firmware.h>
#include <linux/gpio/consumer.h>
#include <linux/platform_data/pn544.h>
#include <asm/unaligned.h>
......@@ -41,6 +43,11 @@
#define PN544_I2C_FRAME_HEADROOM 1
#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 */
#define PN544_HCI_I2C_LLC_LEN 1
#define PN544_HCI_I2C_LLC_CRC 2
......@@ -58,6 +65,13 @@ static struct i2c_device_id 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"
/*
......@@ -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");
/* Disable fw download */
gpio_set_value(phy->gpio_fw, 0);
gpio_set_value_cansleep(phy->gpio_fw, 0);
for (polarity = 0; polarity < 2; polarity++) {
phy->en_polarity = polarity;
retry = 3;
while (retry--) {
/* 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);
/* 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);
/* send reset */
......@@ -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");
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)
{
gpio_set_value(phy->gpio_fw, run_mode == PN544_FW_MODE ? 1 : 0);
gpio_set_value(phy->gpio_en, phy->en_polarity);
gpio_set_value_cansleep(phy->gpio_fw,
run_mode == PN544_FW_MODE ? 1 : 0);
gpio_set_value_cansleep(phy->gpio_en, phy->en_polarity);
usleep_range(10000, 15000);
phy->run_mode = run_mode;
......@@ -254,14 +270,14 @@ static void pn544_hci_i2c_disable(void *phy_id)
{
struct pn544_i2c_phy *phy = phy_id;
gpio_set_value(phy->gpio_fw, 0);
gpio_set_value(phy->gpio_en, !phy->en_polarity);
gpio_set_value_cansleep(phy->gpio_fw, 0);
gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity);
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);
gpio_set_value(phy->gpio_en, !phy->en_polarity);
gpio_set_value_cansleep(phy->gpio_en, !phy->en_polarity);
usleep_range(10000, 15000);
phy->powered = 0;
......@@ -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
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;
/* Configuration of EN GPIO */
ret = gpio_request(phy->gpio_en, "pn544_en");
ret = gpio_request(phy->gpio_en, PN544_GPIO_NAME_EN);
if (ret) {
nfc_err(&client->dev, "Fail EN pin\n");
goto err_dt;
......@@ -906,7 +1006,7 @@ static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
phy->gpio_fw = ret;
/* Configuration of FW GPIO */
ret = gpio_request(phy->gpio_fw, "pn544_fw");
ret = gpio_request(phy->gpio_fw, PN544_GPIO_NAME_FW);
if (ret) {
nfc_err(&client->dev, "Fail FW pin\n");
goto err_gpio_en;
......@@ -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_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);
if (r) {
nfc_err(&client->dev,
"Cannot get ACPI data\n");
return r;
}
} else {
nfc_err(&client->dev, "No platform data\n");
return -EINVAL;
......@@ -1080,6 +1188,7 @@ static struct i2c_driver pn544_hci_i2c_driver = {
.name = PN544_HCI_I2C_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_pn544_i2c_match),
.acpi_match_table = ACPI_PTR(pn544_hci_i2c_acpi_match),
},
.probe = pn544_hci_i2c_probe,
.id_table = pn544_hci_i2c_id_table,
......
......@@ -724,10 +724,11 @@ static int pn544_hci_check_presence(struct nfc_hci_dev *hdev,
* <= 0: driver handled the event, skb consumed
* 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 *rgb_skb = NULL;
u8 gate = hdev->pipes[pipe].gate;
int r;
pr_debug("hci event %d\n", event);
......
......@@ -2,7 +2,7 @@
# 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
st21nfca_i2c-objs = i2c.o
......
......@@ -74,6 +74,8 @@ struct st21nfca_i2c_phy {
unsigned int gpio_ena;
unsigned int irq_polarity;
struct st21nfca_se_status se_status;
struct sk_buff *pending_skb;
int current_read_len;
/*
......@@ -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->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;
}
#else
......@@ -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;
}
......@@ -591,11 +601,8 @@ static int st21nfca_hci_i2c_probe(struct i2c_client *client,
phy = devm_kzalloc(&client->dev, sizeof(struct st21nfca_i2c_phy),
GFP_KERNEL);
if (!phy) {
nfc_err(&client->dev,
"Cannot allocate memory for st21nfca i2c phy.\n");
if (!phy)
return -ENOMEM;
}
phy->i2c_dev = client;
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,
}
return st21nfca_hci_probe(phy, &i2c_phy_ops, LLC_SHDLC_NAME,
ST21NFCA_FRAME_HEADROOM, ST21NFCA_FRAME_TAILROOM,
ST21NFCA_HCI_LLC_MAX_PAYLOAD, &phy->hdev);
ST21NFCA_FRAME_HEADROOM,
ST21NFCA_FRAME_TAILROOM,
ST21NFCA_HCI_LLC_MAX_PAYLOAD,
&phy->hdev,
&phy->se_status);
}
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
static const struct of_device_id of_st21nfca_i2c_match[] = {
{ .compatible = "st,st21nfca-i2c", },
{ .compatible = "st,st21nfca_i2c", },
{}
};
......
This diff is collapsed.
......@@ -20,6 +20,7 @@
#include <net/nfc/hci.h>
#include "st21nfca_dep.h"
#include "st21nfca_se.h"
#define HCI_MODE 0
......@@ -51,9 +52,15 @@
#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,
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);
enum st21nfca_state {
......@@ -66,6 +73,7 @@ struct st21nfca_hci_info {
void *phy_id;
struct nfc_hci_dev *hdev;
struct st21nfca_se_status *se_status;
enum st21nfca_state state;
......@@ -76,13 +84,16 @@ struct st21nfca_hci_info {
void *async_cb_context;
struct st21nfca_dep_info dep_info;
struct st21nfca_se_info se_info;
};
/* Reader RF commands */
#define ST21NFCA_WR_XCHG_DATA 0x10
#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_ */
This diff is collapsed.
/*
* 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)
struct sk_buff *skb = NULL;
int r;
if (!phy || irq != phy->i2c_dev->irq) {
if (!phy || !phy->ndlc || irq != phy->i2c_dev->irq) {
WARN_ON_ONCE(1);
return IRQ_NONE;
}
......@@ -343,18 +343,22 @@ static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
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,
st21nfcb_nci_irq_thread_fn,
phy->irq_polarity | IRQF_ONESHOT,
ST21NFCB_NCI_DRIVER_NAME, phy);
if (r < 0) {
if (r < 0)
nfc_err(&client->dev, "Unable to register IRQ handler\n");
return r;
}
return ndlc_probe(phy, &i2c_phy_ops, &client->dev,
ST21NFCB_FRAME_HEADROOM, ST21NFCB_FRAME_TAILROOM,
&phy->ndlc);
return r;
}
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
static const struct of_device_id of_st21nfcb_i2c_match[] = {
{ .compatible = "st,st21nfcb-i2c", },
{ .compatible = "st,st21nfcb_i2c", },
{}
};
......
......@@ -138,7 +138,7 @@ static void llt_ndlc_requeue_data_pending(struct llt_ndlc *ndlc)
default:
pr_err("UNKNOWN Packet Control Byte=%d\n", pcb);
kfree_skb(skb);
break;
continue;
}
skb_queue_head(&ndlc->send_q, skb);
}
......@@ -297,6 +297,5 @@ void ndlc_remove(struct llt_ndlc *ndlc)
skb_queue_purge(&ndlc->send_q);
st21nfcb_nci_remove(ndlc->ndev);
kfree(ndlc);
}
EXPORT_SYMBOL(ndlc_remove);
......@@ -26,6 +26,8 @@
struct st21nfca_nfc_platform_data {
unsigned int gpio_ena;
unsigned int irq_polarity;
bool is_ese_present;
bool is_uicc_present;
};
#endif /* _ST21NFCA_HCI_H_ */
......@@ -19,8 +19,6 @@
#ifndef _ST21NFCB_NCI_H_
#define _ST21NFCB_NCI_H_
#include <linux/i2c.h>
#define ST21NFCB_NCI_DRIVER_NAME "st21nfcb_nci"
struct st21nfcb_nfc_platform_data {
......@@ -28,4 +26,4 @@ struct st21nfcb_nfc_platform_data {
unsigned int irq_polarity;
};
#endif /* _ST21NFCA_HCI_H_ */
#endif /* _ST21NFCB_NCI_H_ */
......@@ -51,7 +51,9 @@ struct nfc_hci_ops {
int (*tm_send)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*check_presence)(struct nfc_hci_dev *hdev,
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);
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 (*discover_se)(struct nfc_hci_dev *dev);
......@@ -63,8 +65,10 @@ struct nfc_hci_ops {
};
/* Pipes */
#define NFC_HCI_INVALID_PIPE 0x80
#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_ADMIN_PIPE 0x01
......@@ -73,7 +77,13 @@ struct nfc_hci_gate {
u8 pipe;
};
struct nfc_hci_pipe {
u8 gate;
u8 dest_host;
};
#define NFC_HCI_MAX_CUSTOM_GATES 50
#define NFC_HCI_MAX_PIPES 127
struct nfc_hci_init_data {
u8 gate_count;
struct nfc_hci_gate gates[NFC_HCI_MAX_CUSTOM_GATES];
......@@ -125,6 +135,7 @@ struct nfc_hci_dev {
void *clientdata;
u8 gate2pipe[NFC_HCI_MAX_GATES];
struct nfc_hci_pipe pipes[NFC_HCI_MAX_PIPES];
u8 sw_romlib;
u8 sw_patch;
......@@ -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);
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 */
#define NFC_HCI_HOST_CONTROLLER_ID 0x00
......@@ -219,6 +232,12 @@ int nfc_hci_result_to_errno(u8 result);
#define NFC_HCI_EVT_POST_DATA 0x02
#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 */
#define NFC_HCI_EVT_READER_REQUESTED 0x10
#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,
int nfc_hci_send_cmd_async(struct nfc_hci_dev *hdev, u8 gate, u8 cmd,
const u8 *param, size_t param_len,
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,
const u8 *param, size_t param_len);
int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate);
......
......@@ -555,7 +555,6 @@ EXPORT_SYMBOL(nfc_find_se);
int nfc_enable_se(struct nfc_dev *dev, u32 se_idx)
{
struct nfc_se *se;
int rc;
......@@ -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)
{
struct nfc_se *se;
int rc;
......
......@@ -116,23 +116,6 @@ int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 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.
* 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)
if (r < 0)
return r;
memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe));
nfc_hci_reset_pipes(hdev);
return 0;
}
......@@ -345,7 +328,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate,
pr_debug("\n");
if (hdev->gate2pipe[dest_gate] == NFC_HCI_DO_NOT_CREATE_PIPE)
if (pipe == NFC_HCI_DO_NOT_CREATE_PIPE)
return 0;
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,
return r;
}
hdev->pipes[pipe].gate = dest_gate;
hdev->pipes[pipe].dest_host = dest_host;
hdev->gate2pipe[dest_gate] = pipe;
return 0;
......
......@@ -46,6 +46,32 @@ int nfc_hci_result_to_errno(u8 result)
}
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)
{
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,
void nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
struct sk_buff *skb)
{
int r = 0;
u8 gate = nfc_hci_pipe2gate(hdev, pipe);
u8 local_gate, new_pipe;
u8 gate_opened = 0x00;
u8 gate = hdev->pipes[pipe].gate;
u8 status = NFC_HCI_ANY_OK;
struct hci_create_pipe_resp *create_info;
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);
switch (cmd) {
case NFC_HCI_ADM_NOTIFY_PIPE_CREATED:
if (skb->len != 5) {
r = -EPROTO;
break;
status = NFC_HCI_ANY_E_NOK;
goto exit;
}
create_info = (struct hci_create_pipe_resp *)skb->data;
local_gate = skb->data[3];
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,
/* Save the new created pipe and bind with local gate,
* the description for skb->data[3] is destination gate id
* but since we received this cmd from host controller, we
* 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;
case NFC_HCI_ANY_OPEN_PIPE:
/* if the pipe is already created, we allow remote host to
* open it
*/
if (gate != 0xff)
nfc_hci_send_response(hdev, gate, NFC_HCI_ANY_OK,
&gate_opened, 1);
if (gate == NFC_HCI_INVALID_GATE) {
status = NFC_HCI_ANY_E_NOK;
goto exit;
}
break;
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;
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;
default:
pr_info("Discarded unknown cmd %x to gate %x\n", cmd, gate);
r = -EINVAL;
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);
}
......@@ -330,15 +377,15 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
struct sk_buff *skb)
{
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);
goto exit;
}
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)
goto exit_noskb;
}
......@@ -573,7 +620,7 @@ static int hci_dev_down(struct nfc_dev *nfc_dev)
if (hdev->ops->close)
hdev->ops->close(hdev);
memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe));
nfc_hci_reset_pipes(hdev);
return 0;
}
......@@ -932,7 +979,7 @@ struct nfc_hci_dev *nfc_hci_allocate_device(struct nfc_hci_ops *ops,
nfc_set_drvdata(hdev->ndev, hdev);
memset(hdev->gate2pipe, NFC_HCI_INVALID_PIPE, sizeof(hdev->gate2pipe));
nfc_hci_reset_pipes(hdev);
hdev->quirks = quirks;
......
......@@ -65,6 +65,14 @@ struct hci_create_pipe_resp {
u8 pipe;
} __packed;
struct hci_delete_pipe_noti {
u8 pipe;
} __packed;
struct hci_all_pipe_cleared_noti {
u8 host;
} __packed;
#define NFC_HCI_FRAGMENT 0x7f
#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,
data_exchange_cb_t cb, void *cb_context,
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,
u8 instruction, struct sk_buff *skb);
......
......@@ -124,17 +124,6 @@ int nfc_hci_hcp_message_tx(struct nfc_hci_dev *hdev, u8 pipe,
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.
* 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