Commit 99abe65f authored by John W. Linville's avatar John W. Linville

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

Samuel Ortiz <sameo@linux.intel.com> says:

"NFC: 3.16: First pull request

This is the NFC pull request for 3.16. We have:

- STMicroeectronics st21nfca support. The st21nfca is an HCI chipset and
  thus relies on the HCI stack. This submission provides support for tag
  redaer/writer mode (including Type 5) and device tree bindings.

- PM runtime support and a bunch of bug fixes for TI's trf7970a.

- Device tree support for NXP's pn544. Legacy platform data support is
  obviously kept intact.

- NFC Tag type 4B support to the NFC Digital stack.

- SOCK_RAW type support to the raw NFC socket, and allow NCI
  sniffing from that. This can be extended to report HCI frames and also
  proprietarry ones like e.g. the pn533 ones."
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parents 96810471 79747280
* NXP Semiconductors PN544 NFC Controller
Required properties:
- compatible: Should be "nxp,pn544-i2c".
- clock-frequency: IC work frequency.
- reg: address on the bus
- interrupt-parent: phandle for the interrupt gpio controller
- interrupts: GPIO interrupt to which the chip is connected
- enable-gpios: Output GPIO pin used for enabling/disabling the PN544
- firmware-gpios: Output GPIO pin used to enter firmware download mode
Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller.
Example (for ARM-based BeagleBone with PN544 on I2C2):
&i2c2 {
status = "okay";
pn544: pn544@28 {
compatible = "nxp,pn544-i2c";
reg = <0x28>;
clock-frequency = <400000>;
interrupt-parent = <&gpio1>;
interrupts = <17 GPIO_ACTIVE_HIGH>;
enable-gpios = <&gpio3 21 GPIO_ACTIVE_HIGH>;
firmware-gpios = <&gpio3 19 GPIO_ACTIVE_HIGH>;
};
};
* STMicroelectronics SAS. ST21NFCA NFC Controller
Required properties:
- 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
- interrupts: GPIO interrupt to which the chip is connected
- enable-gpios: Output GPIO pin used for enabling/disabling the ST21NFCA
Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller.
Example (for ARM-based BeagleBoard xM with ST21NFCA on I2C2):
&i2c2 {
status = "okay";
st21nfca: st21nfca@1 {
compatible = "st,st21nfca_i2c";
reg = <0x01>;
clock-frequency = <400000>;
interrupt-parent = <&gpio5>;
interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
enable-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
};
};
......@@ -12,6 +12,7 @@ Required properties:
Optional SoC Specific Properties:
- pinctrl-names: Contains only one value - "default".
- pintctrl-0: Specifies the pin control groups used for this controller.
- autosuspend-delay: Specify autosuspend delay in milliseconds.
Example (for ARM-based BeagleBone with TRF7970A on SPI1):
......@@ -29,6 +30,7 @@ Example (for ARM-based BeagleBone with TRF7970A on SPI1):
ti,enable-gpios = <&gpio2 2 GPIO_ACTIVE_LOW>,
<&gpio2 5 GPIO_ACTIVE_LOW>;
vin-supply = <&ldo3_reg>;
autosuspend-delay = <30000>;
status = "okay";
};
};
......@@ -71,5 +71,6 @@ config NFC_PORT100
source "drivers/nfc/pn544/Kconfig"
source "drivers/nfc/microread/Kconfig"
source "drivers/nfc/nfcmrvl/Kconfig"
source "drivers/nfc/st21nfca/Kconfig"
endmenu
......@@ -11,5 +11,6 @@ obj-$(CONFIG_NFC_SIM) += nfcsim.o
obj-$(CONFIG_NFC_PORT100) += port100.o
obj-$(CONFIG_NFC_MRVL) += nfcmrvl/
obj-$(CONFIG_NFC_TRF7970A) += trf7970a.o
obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
......@@ -22,6 +22,8 @@
#include <linux/module.h>
#include <linux/i2c.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/miscdevice.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
......@@ -857,6 +859,92 @@ static void pn544_hci_i2c_fw_work(struct work_struct *work)
}
}
#ifdef CONFIG_OF
static int pn544_hci_i2c_of_request_resources(struct i2c_client *client)
{
struct pn544_i2c_phy *phy = i2c_get_clientdata(client);
struct device_node *pp;
int ret;
pp = client->dev.of_node;
if (!pp) {
ret = -ENODEV;
goto err_dt;
}
/* Obtention of EN GPIO from device tree */
ret = of_get_named_gpio(pp, "enable-gpios", 0);
if (ret < 0) {
if (ret != -EPROBE_DEFER)
nfc_err(&client->dev,
"Failed to get EN gpio, error: %d\n", ret);
goto err_dt;
}
phy->gpio_en = ret;
/* Configuration of EN GPIO */
ret = gpio_request(phy->gpio_en, "pn544_en");
if (ret) {
nfc_err(&client->dev, "Fail EN pin\n");
goto err_dt;
}
ret = gpio_direction_output(phy->gpio_en, 0);
if (ret) {
nfc_err(&client->dev, "Fail EN pin direction\n");
goto err_gpio_en;
}
/* Obtention of FW GPIO from device tree */
ret = of_get_named_gpio(pp, "firmware-gpios", 0);
if (ret < 0) {
if (ret != -EPROBE_DEFER)
nfc_err(&client->dev,
"Failed to get FW gpio, error: %d\n", ret);
goto err_gpio_en;
}
phy->gpio_fw = ret;
/* Configuration of FW GPIO */
ret = gpio_request(phy->gpio_fw, "pn544_fw");
if (ret) {
nfc_err(&client->dev, "Fail FW pin\n");
goto err_gpio_en;
}
ret = gpio_direction_output(phy->gpio_fw, 0);
if (ret) {
nfc_err(&client->dev, "Fail FW pin direction\n");
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:
gpio_free(phy->gpio_fw);
err_gpio_en:
gpio_free(phy->gpio_en);
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)
{
......@@ -887,25 +975,36 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
i2c_set_clientdata(client, phy);
pdata = client->dev.platform_data;
if (pdata == NULL) {
nfc_err(&client->dev, "No platform data\n");
return -EINVAL;
}
if (pdata->request_resources == NULL) {
nfc_err(&client->dev, "request_resources() missing\n");
return -EINVAL;
}
/* No platform data, using device tree. */
if (!pdata && client->dev.of_node) {
r = pn544_hci_i2c_of_request_resources(client);
if (r) {
nfc_err(&client->dev, "No DT data\n");
return r;
}
/* Using platform data. */
} else if (pdata) {
r = pdata->request_resources(client);
if (r) {
nfc_err(&client->dev, "Cannot get platform resources\n");
return r;
}
if (pdata->request_resources == NULL) {
nfc_err(&client->dev, "request_resources() missing\n");
return -EINVAL;
}
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);
r = pdata->request_resources(client);
if (r) {
nfc_err(&client->dev,
"Cannot get platform resources\n");
return r;
}
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);
} else {
nfc_err(&client->dev, "No platform data\n");
return -EINVAL;
}
pn544_hci_i2c_platform_init(phy);
......@@ -930,8 +1029,12 @@ static int pn544_hci_i2c_probe(struct i2c_client *client,
free_irq(client->irq, phy);
err_rti:
if (pdata->free_resources != NULL)
if (!pdata) {
gpio_free(phy->gpio_en);
gpio_free(phy->gpio_fw);
} else if (pdata->free_resources) {
pdata->free_resources();
}
return r;
}
......@@ -953,15 +1056,30 @@ static int pn544_hci_i2c_remove(struct i2c_client *client)
pn544_hci_i2c_disable(phy);
free_irq(client->irq, phy);
if (pdata->free_resources)
/* No platform data, GPIOs have been requested by this driver */
if (!pdata) {
gpio_free(phy->gpio_en);
gpio_free(phy->gpio_fw);
/* Using platform data */
} else if (pdata->free_resources) {
pdata->free_resources();
}
return 0;
}
static const struct of_device_id of_pn544_i2c_match[] = {
{ .compatible = "nxp,pn544-i2c", },
{},
};
MODULE_DEVICE_TABLE(of, of_pn544_i2c_match);
static struct i2c_driver pn544_hci_i2c_driver = {
.driver = {
.name = PN544_HCI_I2C_DRIVER_NAME,
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(of_pn544_i2c_match),
},
.probe = pn544_hci_i2c_probe,
.id_table = pn544_hci_i2c_id_table,
......
config NFC_ST21NFCA
tristate "STMicroelectronics ST21NFCA NFC driver"
depends on NFC_HCI
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
---help---
This module adds support for the STMicroelectronics st21nfca i2c interface.
Select this if your platform is using the i2c bus.
If you choose to build a module, it'll be called st21nfca_i2c.
Say N if unsure.
#
# Makefile for ST21NFCA HCI based NFC driver
#
st21nfca_i2c-objs = i2c.o
obj-$(CONFIG_NFC_ST21NFCA) += st21nfca.o
obj-$(CONFIG_NFC_ST21NFCA_I2C) += st21nfca_i2c.o
This diff is collapsed.
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 __LOCAL_ST21NFCA_H_
#define __LOCAL_ST21NFCA_H_
#include <net/nfc/hci.h>
#define HCI_MODE 0
/* framing in HCI mode */
#define ST21NFCA_SOF_EOF_LEN 2
/* Almost every time value is 0 */
#define ST21NFCA_HCI_LLC_LEN 1
/* Size in worst case :
* In normal case CRC len = 2 but byte stuffing
* may appear in case one CRC byte = ST21NFCA_SOF_EOF
*/
#define ST21NFCA_HCI_LLC_CRC 4
#define ST21NFCA_HCI_LLC_LEN_CRC (ST21NFCA_SOF_EOF_LEN + \
ST21NFCA_HCI_LLC_LEN + \
ST21NFCA_HCI_LLC_CRC)
#define ST21NFCA_HCI_LLC_MIN_SIZE (1 + ST21NFCA_HCI_LLC_LEN_CRC)
/* Worst case when adding byte stuffing between each byte */
#define ST21NFCA_HCI_LLC_MAX_PAYLOAD 29
#define ST21NFCA_HCI_LLC_MAX_SIZE (ST21NFCA_HCI_LLC_LEN_CRC + 1 + \
ST21NFCA_HCI_LLC_MAX_PAYLOAD)
#define DRIVER_DESC "HCI NFC driver for ST21NFCA"
#define ST21NFCA_HCI_MODE 0
#define ST21NFCA_NUM_DEVICES 256
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);
void st21nfca_hci_remove(struct nfc_hci_dev *hdev);
enum st21nfca_state {
ST21NFCA_ST_COLD,
ST21NFCA_ST_READY,
};
struct st21nfca_hci_info {
struct nfc_phy_ops *phy_ops;
void *phy_id;
struct nfc_hci_dev *hdev;
enum st21nfca_state state;
struct mutex info_lock;
int async_cb_type;
data_exchange_cb_t async_cb;
void *async_cb_context;
} __packed;
/* Reader RF commands */
#define ST21NFCA_WR_XCHG_DATA 0x10
#define ST21NFCA_RF_READER_F_GATE 0x14
#define ST21NFCA_RF_READER_F_DATARATE 0x01
#define ST21NFCA_RF_READER_F_DATARATE_106 0x01
#define ST21NFCA_RF_READER_F_DATARATE_212 0x02
#define ST21NFCA_RF_READER_F_DATARATE_424 0x04
#endif /* __LOCAL_ST21NFCA_H_ */
This diff is collapsed.
/*
* Driver include for the ST21NFCA NFC chip.
*
* 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_HCI_H_
#define _ST21NFCA_HCI_H_
#include <linux/i2c.h>
#define ST21NFCA_HCI_DRIVER_NAME "st21nfca_hci"
struct st21nfca_nfc_platform_data {
unsigned int gpio_irq;
unsigned int gpio_ena;
unsigned int irq_polarity;
};
#endif /* _ST21NFCA_HCI_H_ */
......@@ -36,6 +36,7 @@ enum {
NFC_DIGITAL_RF_TECH_212F,
NFC_DIGITAL_RF_TECH_424F,
NFC_DIGITAL_RF_TECH_ISO15693,
NFC_DIGITAL_RF_TECH_106B,
NFC_DIGITAL_RF_TECH_LAST,
};
......@@ -62,6 +63,9 @@ enum {
NFC_DIGITAL_FRAMING_ISO15693_INVENTORY,
NFC_DIGITAL_FRAMING_ISO15693_T5T,
NFC_DIGITAL_FRAMING_NFCB,
NFC_DIGITAL_FRAMING_NFCB_T4T,
NFC_DIGITAL_FRAMING_LAST,
};
......
......@@ -27,6 +27,7 @@ struct nfc_hci_dev;
struct nfc_hci_ops {
int (*open) (struct nfc_hci_dev *hdev);
void (*close) (struct nfc_hci_dev *hdev);
int (*load_session) (struct nfc_hci_dev *hdev);
int (*hci_ready) (struct nfc_hci_dev *hdev);
/*
* xmit must always send the complete buffer before
......
......@@ -264,4 +264,7 @@ 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);
void nfc_send_to_raw_sock(struct nfc_dev *dev, struct sk_buff *skb,
u8 payload_type, u8 direction);
#endif /* __NET_NFC_H */
......@@ -273,11 +273,19 @@ struct sockaddr_nfc_llcp {
* First byte is the adapter index
* Second byte contains flags
* - 0x01 - Direction (0=RX, 1=TX)
* - 0x02-0x80 - Reserved
* - 0x02-0x04 - Payload type (000=LLCP, 001=NCI, 010=HCI, 011=Digital,
* 100=Proprietary)
* - 0x05-0x80 - Reserved
**/
#define NFC_LLCP_RAW_HEADER_SIZE 2
#define NFC_LLCP_DIRECTION_RX 0x00
#define NFC_LLCP_DIRECTION_TX 0x01
#define NFC_RAW_HEADER_SIZE 2
#define NFC_DIRECTION_RX 0x00
#define NFC_DIRECTION_TX 0x01
#define RAW_PAYLOAD_LLCP 0
#define RAW_PAYLOAD_NCI 1
#define RAW_PAYLOAD_HCI 2
#define RAW_PAYLOAD_DIGITAL 3
#define RAW_PAYLOAD_PROPRIETARY 4
/* socket option names */
#define NFC_LLCP_RW 0
......
......@@ -71,6 +71,7 @@ static inline int digital_in_send_cmd(struct nfc_digital_dev *ddev,
void digital_poll_next_tech(struct nfc_digital_dev *ddev);
int digital_in_send_sens_req(struct nfc_digital_dev *ddev, u8 rf_tech);
int digital_in_send_sensb_req(struct nfc_digital_dev *ddev, u8 rf_tech);
int digital_in_send_sensf_req(struct nfc_digital_dev *ddev, u8 rf_tech);
int digital_in_send_iso15693_inv_req(struct nfc_digital_dev *ddev, u8 rf_tech);
......
......@@ -22,6 +22,8 @@
#define DIGITAL_PROTO_NFCA_RF_TECH \
(NFC_PROTO_JEWEL_MASK | NFC_PROTO_MIFARE_MASK | NFC_PROTO_NFC_DEP_MASK)
#define DIGITAL_PROTO_NFCB_RF_TECH NFC_PROTO_ISO14443_B_MASK
#define DIGITAL_PROTO_NFCF_RF_TECH \
(NFC_PROTO_FELICA_MASK | NFC_PROTO_NFC_DEP_MASK)
......@@ -345,6 +347,12 @@ int digital_target_found(struct nfc_digital_dev *ddev,
add_crc = digital_skb_add_crc_a;
break;
case NFC_PROTO_ISO14443_B:
framing = NFC_DIGITAL_FRAMING_NFCB_T4T;
check_crc = digital_skb_check_crc_b;
add_crc = digital_skb_add_crc_b;
break;
default:
pr_err("Invalid protocol %d\n", protocol);
return -EINVAL;
......@@ -475,6 +483,10 @@ static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols,
digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A,
digital_in_send_sens_req);
if (matching_im_protocols & DIGITAL_PROTO_NFCB_RF_TECH)
digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106B,
digital_in_send_sensb_req);
if (matching_im_protocols & DIGITAL_PROTO_NFCF_RF_TECH) {
digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_212F,
digital_in_send_sensf_req);
......@@ -635,7 +647,8 @@ static void digital_in_send_complete(struct nfc_digital_dev *ddev, void *arg,
goto done;
}
if (ddev->curr_protocol == NFC_PROTO_ISO14443) {
if ((ddev->curr_protocol == NFC_PROTO_ISO14443) ||
(ddev->curr_protocol == NFC_PROTO_ISO14443_B)) {
rc = digital_in_iso_dep_pull_sod(ddev, resp);
if (rc)
goto done;
......@@ -676,7 +689,8 @@ static int digital_in_send(struct nfc_dev *nfc_dev, struct nfc_target *target,
goto exit;
}
if (ddev->curr_protocol == NFC_PROTO_ISO14443) {
if ((ddev->curr_protocol == NFC_PROTO_ISO14443) ||
(ddev->curr_protocol == NFC_PROTO_ISO14443_B)) {
rc = digital_in_iso_dep_push_sod(ddev, skb);
if (rc)
goto exit;
......@@ -747,6 +761,8 @@ struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops,
ddev->protocols |= NFC_PROTO_ISO15693_MASK;
if (supported_protocols & NFC_PROTO_ISO14443_MASK)
ddev->protocols |= NFC_PROTO_ISO14443_MASK;
if (supported_protocols & NFC_PROTO_ISO14443_B_MASK)
ddev->protocols |= NFC_PROTO_ISO14443_B_MASK;
ddev->tx_headroom = tx_headroom + DIGITAL_MAX_HEADER_LEN;
ddev->tx_tailroom = tx_tailroom + DIGITAL_CRC_LEN;
......
......@@ -41,6 +41,24 @@
#define DIGITAL_MIFARE_READ_RES_LEN 16
#define DIGITAL_MIFARE_ACK_RES 0x0A
#define DIGITAL_CMD_SENSB_REQ 0x05
#define DIGITAL_SENSB_ADVANCED BIT(5)
#define DIGITAL_SENSB_EXTENDED BIT(4)
#define DIGITAL_SENSB_ALLB_REQ BIT(3)
#define DIGITAL_SENSB_N(n) ((n) & 0x7)
#define DIGITAL_CMD_SENSB_RES 0x50
#define DIGITAL_CMD_ATTRIB_REQ 0x1D
#define DIGITAL_ATTRIB_P1_TR0_DEFAULT (0x0 << 6)
#define DIGITAL_ATTRIB_P1_TR1_DEFAULT (0x0 << 4)
#define DIGITAL_ATTRIB_P1_SUPRESS_EOS BIT(3)
#define DIGITAL_ATTRIB_P1_SUPRESS_SOS BIT(2)
#define DIGITAL_ATTRIB_P2_LISTEN_POLL_1 (0x0 << 6)
#define DIGITAL_ATTRIB_P2_POLL_LISTEN_1 (0x0 << 4)
#define DIGITAL_ATTRIB_P2_MAX_FRAME_256 0x8
#define DIGITAL_ATTRIB_P4_DID(n) ((n) & 0xf)
#define DIGITAL_CMD_SENSF_REQ 0x00
#define DIGITAL_CMD_SENSF_RES 0x01
......@@ -75,6 +93,7 @@ static const u8 digital_ats_fsc[] = {
};
#define DIGITAL_ATS_FSCI(t0) ((t0) & 0x0F)
#define DIGITAL_SENSB_FSCI(pi2) (((pi2) & 0xF0) >> 4)
#define DIGITAL_ATS_MAX_FSC 256
#define DIGITAL_RATS_BYTE1 0xE0
......@@ -92,6 +111,32 @@ struct digital_sel_req {
u8 bcc;
} __packed;
struct digital_sensb_req {
u8 cmd;
u8 afi;
u8 param;
} __packed;
struct digital_sensb_res {
u8 cmd;
u8 nfcid0[4];
u8 app_data[4];
u8 proto_info[3];
} __packed;
struct digital_attrib_req {
u8 cmd;
u8 nfcid0[4];
u8 param1;
u8 param2;
u8 param3;
u8 param4;
} __packed;
struct digital_attrib_res {
u8 mbli_did;
} __packed;
struct digital_sensf_req {
u8 cmd;
u8 sc1;
......@@ -531,6 +576,175 @@ int digital_in_recv_mifare_res(struct sk_buff *resp)
return -EIO;
}
static void digital_in_recv_attrib_res(struct nfc_digital_dev *ddev, void *arg,
struct sk_buff *resp)
{
struct nfc_target *target = arg;
struct digital_attrib_res *attrib_res;
int rc;
if (IS_ERR(resp)) {
rc = PTR_ERR(resp);
resp = NULL;
goto exit;
}
if (resp->len < sizeof(*attrib_res)) {
PROTOCOL_ERR("12.6.2");
rc = -EIO;
goto exit;
}
attrib_res = (struct digital_attrib_res *)resp->data;
if (attrib_res->mbli_did & 0x0f) {
PROTOCOL_ERR("12.6.2.1");
rc = -EIO;
goto exit;
}
rc = digital_target_found(ddev, target, NFC_PROTO_ISO14443_B);
exit:
dev_kfree_skb(resp);
kfree(target);
if (rc)
digital_poll_next_tech(ddev);
}
int digital_in_send_attrib_req(struct nfc_digital_dev *ddev,
struct nfc_target *target,
struct digital_sensb_res *sensb_res)
{
struct digital_attrib_req *attrib_req;
struct sk_buff *skb;
int rc;
skb = digital_skb_alloc(ddev, sizeof(*attrib_req));
if (!skb)
return -ENOMEM;
attrib_req = (struct digital_attrib_req *)skb_put(skb,
sizeof(*attrib_req));
attrib_req->cmd = DIGITAL_CMD_ATTRIB_REQ;
memcpy(attrib_req->nfcid0, sensb_res->nfcid0,
sizeof(attrib_req->nfcid0));
attrib_req->param1 = DIGITAL_ATTRIB_P1_TR0_DEFAULT |
DIGITAL_ATTRIB_P1_TR1_DEFAULT;
attrib_req->param2 = DIGITAL_ATTRIB_P2_LISTEN_POLL_1 |
DIGITAL_ATTRIB_P2_POLL_LISTEN_1 |
DIGITAL_ATTRIB_P2_MAX_FRAME_256;
attrib_req->param3 = sensb_res->proto_info[1] & 0x07;
attrib_req->param4 = DIGITAL_ATTRIB_P4_DID(0);
rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_attrib_res,
target);
if (rc)
kfree_skb(skb);
return rc;
}
static void digital_in_recv_sensb_res(struct nfc_digital_dev *ddev, void *arg,
struct sk_buff *resp)
{
struct nfc_target *target = NULL;
struct digital_sensb_res *sensb_res;
u8 fsci;
int rc;
if (IS_ERR(resp)) {
rc = PTR_ERR(resp);
resp = NULL;
goto exit;
}
if (resp->len != sizeof(*sensb_res)) {
PROTOCOL_ERR("5.6.2.1");
rc = -EIO;
goto exit;
}
sensb_res = (struct digital_sensb_res *)resp->data;
if (sensb_res->cmd != DIGITAL_CMD_SENSB_RES) {
PROTOCOL_ERR("5.6.2");
rc = -EIO;
goto exit;
}
if (!(sensb_res->proto_info[1] & BIT(0))) {
PROTOCOL_ERR("5.6.2.12");
rc = -EIO;
goto exit;
}
if (sensb_res->proto_info[1] & BIT(3)) {
PROTOCOL_ERR("5.6.2.16");
rc = -EIO;
goto exit;
}
fsci = DIGITAL_SENSB_FSCI(sensb_res->proto_info[1]);
if (fsci >= 8)
ddev->target_fsc = DIGITAL_ATS_MAX_FSC;
else
ddev->target_fsc = digital_ats_fsc[fsci];
target = kzalloc(sizeof(struct nfc_target), GFP_KERNEL);
if (!target) {
rc = -ENOMEM;
goto exit;
}
rc = digital_in_send_attrib_req(ddev, target, sensb_res);
exit:
dev_kfree_skb(resp);
if (rc) {
kfree(target);
digital_poll_next_tech(ddev);
}
}
int digital_in_send_sensb_req(struct nfc_digital_dev *ddev, u8 rf_tech)
{
struct digital_sensb_req *sensb_req;
struct sk_buff *skb;
int rc;
rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH,
NFC_DIGITAL_RF_TECH_106B);
if (rc)
return rc;
rc = digital_in_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
NFC_DIGITAL_FRAMING_NFCB);
if (rc)
return rc;
skb = digital_skb_alloc(ddev, sizeof(*sensb_req));
if (!skb)
return -ENOMEM;
sensb_req = (struct digital_sensb_req *)skb_put(skb,
sizeof(*sensb_req));
sensb_req->cmd = DIGITAL_CMD_SENSB_REQ;
sensb_req->afi = 0x00; /* All families and sub-families */
sensb_req->param = DIGITAL_SENSB_N(0);
rc = digital_in_send_cmd(ddev, skb, 30, digital_in_recv_sensb_res,
NULL);
if (rc)
kfree_skb(skb);
return rc;
}
static void digital_in_recv_sensf_res(struct nfc_digital_dev *ddev, void *arg,
struct sk_buff *resp)
{
......@@ -877,6 +1091,18 @@ void digital_tg_recv_sens_req(struct nfc_digital_dev *ddev, void *arg,
dev_kfree_skb(resp);
}
static void digital_tg_recv_atr_or_sensf_req(struct nfc_digital_dev *ddev,
void *arg, struct sk_buff *resp)
{
if (!IS_ERR(resp) && (resp->len >= 2) &&
(resp->data[1] == DIGITAL_CMD_SENSF_REQ))
digital_tg_recv_sensf_req(ddev, arg, resp);
else
digital_tg_recv_atr_req(ddev, arg, resp);
return;
}
static int digital_tg_send_sensf_res(struct nfc_digital_dev *ddev,
struct digital_sensf_req *sensf_req)
{
......@@ -887,7 +1113,7 @@ static int digital_tg_send_sensf_res(struct nfc_digital_dev *ddev,
size = sizeof(struct digital_sensf_res);
if (sensf_req->rc != DIGITAL_SENSF_REQ_RC_NONE)
if (sensf_req->rc == DIGITAL_SENSF_REQ_RC_NONE)
size -= sizeof(sensf_res->rd);
skb = digital_skb_alloc(ddev, size);
......@@ -922,7 +1148,7 @@ static int digital_tg_send_sensf_res(struct nfc_digital_dev *ddev,
digital_skb_add_crc_f(skb);
rc = digital_tg_send_cmd(ddev, skb, 300,
digital_tg_recv_atr_req, NULL);
digital_tg_recv_atr_or_sensf_req, NULL);
if (rc)
kfree_skb(skb);
......
......@@ -26,6 +26,8 @@
#include "hci.h"
#define MAX_FWI 4949
static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
const u8 *param, size_t param_len,
data_exchange_cb_t cb, void *cb_context)
......@@ -37,7 +39,7 @@ static int nfc_hci_execute_cmd_async(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
* for all commands?
*/
return nfc_hci_hcp_message_tx(hdev, pipe, NFC_HCI_HCP_COMMAND, cmd,
param, param_len, cb, cb_context, 3000);
param, param_len, cb, cb_context, MAX_FWI);
}
/*
......@@ -82,7 +84,7 @@ static int nfc_hci_execute_cmd(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
NFC_HCI_HCP_COMMAND, cmd,
param, param_len,
nfc_hci_execute_cb, &hcp_ew,
3000);
MAX_FWI);
if (hcp_ew.exec_result < 0)
return hcp_ew.exec_result;
......
......@@ -225,7 +225,7 @@ int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
goto exit;
}
targets->sens_res = be16_to_cpu(*(u16 *)atqa_skb->data);
targets->sens_res = be16_to_cpu(*(__be16 *)atqa_skb->data);
targets->sel_res = sak_skb->data[0];
r = nfc_hci_get_param(hdev, NFC_HCI_RF_READER_A_GATE,
......@@ -380,34 +380,31 @@ static int hci_dev_session_init(struct nfc_hci_dev *hdev)
if (r < 0)
goto disconnect_all;
if (skb->len && skb->len == strlen(hdev->init_data.session_id))
if (memcmp(hdev->init_data.session_id, skb->data,
skb->len) == 0) {
/* TODO ELa: restore gate<->pipe table from
* some TBD location.
* note: it doesn't seem possible to get the chip
* currently open gate/pipe table.
* It is only possible to obtain the supported
* gate list.
*/
if (skb->len && skb->len == strlen(hdev->init_data.session_id) &&
(memcmp(hdev->init_data.session_id, skb->data,
skb->len) == 0) && hdev->ops->load_session) {
/* Restore gate<->pipe table from some proprietary location. */
/* goto exit
* For now, always do a full initialization */
}
r = hdev->ops->load_session(hdev);
r = nfc_hci_disconnect_all_gates(hdev);
if (r < 0)
goto exit;
if (r < 0)
goto disconnect_all;
} else {
r = hci_dev_connect_gates(hdev, hdev->init_data.gate_count,
hdev->init_data.gates);
if (r < 0)
goto disconnect_all;
r = nfc_hci_disconnect_all_gates(hdev);
if (r < 0)
goto exit;
r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE,
NFC_HCI_ADMIN_SESSION_IDENTITY,
hdev->init_data.session_id,
strlen(hdev->init_data.session_id));
r = hci_dev_connect_gates(hdev, hdev->init_data.gate_count,
hdev->init_data.gates);
if (r < 0)
goto disconnect_all;
r = nfc_hci_set_param(hdev, NFC_HCI_ADMIN_GATE,
NFC_HCI_ADMIN_SESSION_IDENTITY,
hdev->init_data.session_id,
strlen(hdev->init_data.session_id));
}
if (r == 0)
goto exit;
......
......@@ -387,7 +387,7 @@ int nfc_llcp_send_symm(struct nfc_dev *dev)
__net_timestamp(skb);
nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_TX);
nfc_llcp_send_to_raw_sock(local, skb, NFC_DIRECTION_TX);
return nfc_data_exchange(dev, local->target_idx, skb,
nfc_llcp_recv, local);
......
......@@ -680,16 +680,17 @@ void nfc_llcp_send_to_raw_sock(struct nfc_llcp_local *local,
continue;
if (skb_copy == NULL) {
skb_copy = __pskb_copy(skb, NFC_LLCP_RAW_HEADER_SIZE,
skb_copy = __pskb_copy(skb, NFC_RAW_HEADER_SIZE,
GFP_ATOMIC);
if (skb_copy == NULL)
continue;
data = skb_push(skb_copy, NFC_LLCP_RAW_HEADER_SIZE);
data = skb_push(skb_copy, NFC_RAW_HEADER_SIZE);
data[0] = local->dev ? local->dev->idx : 0xFF;
data[1] = direction;
data[1] = direction & 0x01;
data[1] |= (RAW_PAYLOAD_LLCP << 1);
}
nskb = skb_clone(skb_copy, GFP_ATOMIC);
......@@ -747,7 +748,7 @@ static void nfc_llcp_tx_work(struct work_struct *work)
__net_timestamp(skb);
nfc_llcp_send_to_raw_sock(local, skb,
NFC_LLCP_DIRECTION_TX);
NFC_DIRECTION_TX);
ret = nfc_data_exchange(local->dev, local->target_idx,
skb, nfc_llcp_recv, local);
......@@ -1476,7 +1477,7 @@ static void nfc_llcp_rx_work(struct work_struct *work)
__net_timestamp(skb);
nfc_llcp_send_to_raw_sock(local, skb, NFC_LLCP_DIRECTION_RX);
nfc_llcp_send_to_raw_sock(local, skb, NFC_DIRECTION_RX);
nfc_llcp_rx_skb(local, skb);
......
......@@ -861,6 +861,10 @@ static int nci_send_frame(struct nci_dev *ndev, struct sk_buff *skb)
/* Get rid of skb owner, prior to sending to the driver. */
skb_orphan(skb);
/* Send copy to sniffer */
nfc_send_to_raw_sock(ndev->nfc_dev, skb,
RAW_PAYLOAD_NCI, NFC_DIRECTION_TX);
return ndev->ops->send(ndev, skb);
}
......@@ -935,6 +939,11 @@ static void nci_rx_work(struct work_struct *work)
struct sk_buff *skb;
while ((skb = skb_dequeue(&ndev->rx_q))) {
/* Send copy to sniffer */
nfc_send_to_raw_sock(ndev->nfc_dev, skb,
RAW_PAYLOAD_NCI, NFC_DIRECTION_RX);
/* Process frame */
switch (nci_mt(skb->data)) {
case NCI_MT_RSP_PKT:
......
......@@ -366,7 +366,6 @@ static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev,
struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
{
struct activation_params_poll_nfc_dep *poll;
int i;
switch (ntf->activation_rf_tech_and_mode) {
case NCI_NFC_A_PASSIVE_POLL_MODE:
......@@ -374,10 +373,8 @@ static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev,
poll = &ntf->activation_params.poll_nfc_dep;
poll->atr_res_len = min_t(__u8, *data++, 63);
pr_debug("atr_res_len %d\n", poll->atr_res_len);
if (poll->atr_res_len > 0) {
for (i = 0; i < poll->atr_res_len; i++)
poll->atr_res[poll->atr_res_len-1-i] = data[i];
}
if (poll->atr_res_len > 0)
memcpy(poll->atr_res, data, poll->atr_res_len);
break;
default:
......
......@@ -40,6 +40,12 @@ struct nfc_rawsock {
struct work_struct tx_work;
bool tx_work_scheduled;
};
struct nfc_sock_list {
struct hlist_head head;
rwlock_t lock;
};
#define nfc_rawsock(sk) ((struct nfc_rawsock *) sk)
#define to_rawsock_sk(_tx_work) \
((struct sock *) container_of(_tx_work, struct nfc_rawsock, tx_work))
......
......@@ -27,6 +27,24 @@
#include "nfc.h"
static struct nfc_sock_list raw_sk_list = {
.lock = __RW_LOCK_UNLOCKED(raw_sk_list.lock)
};
void nfc_sock_link(struct nfc_sock_list *l, struct sock *sk)
{
write_lock(&l->lock);
sk_add_node(sk, &l->head);
write_unlock(&l->lock);
}
void nfc_sock_unlink(struct nfc_sock_list *l, struct sock *sk)
{
write_lock(&l->lock);
sk_del_node_init(sk);
write_unlock(&l->lock);
}
static void rawsock_write_queue_purge(struct sock *sk)
{
pr_debug("sk=%p\n", sk);
......@@ -57,6 +75,9 @@ static int rawsock_release(struct socket *sock)
if (!sk)
return 0;
if (sock->type == SOCK_RAW)
nfc_sock_unlink(&raw_sk_list, sk);
sock_orphan(sk);
sock_put(sk);
......@@ -275,6 +296,26 @@ static const struct proto_ops rawsock_ops = {
.mmap = sock_no_mmap,
};
static const struct proto_ops rawsock_raw_ops = {
.family = PF_NFC,
.owner = THIS_MODULE,
.release = rawsock_release,
.bind = sock_no_bind,
.connect = sock_no_connect,
.socketpair = sock_no_socketpair,
.accept = sock_no_accept,
.getname = sock_no_getname,
.poll = datagram_poll,
.ioctl = sock_no_ioctl,
.listen = sock_no_listen,
.shutdown = sock_no_shutdown,
.setsockopt = sock_no_setsockopt,
.getsockopt = sock_no_getsockopt,
.sendmsg = sock_no_sendmsg,
.recvmsg = rawsock_recvmsg,
.mmap = sock_no_mmap,
};
static void rawsock_destruct(struct sock *sk)
{
pr_debug("sk=%p\n", sk);
......@@ -300,10 +341,13 @@ static int rawsock_create(struct net *net, struct socket *sock,
pr_debug("sock=%p\n", sock);
if (sock->type != SOCK_SEQPACKET)
if ((sock->type != SOCK_SEQPACKET) && (sock->type != SOCK_RAW))
return -ESOCKTNOSUPPORT;
sock->ops = &rawsock_ops;
if (sock->type == SOCK_RAW)
sock->ops = &rawsock_raw_ops;
else
sock->ops = &rawsock_ops;
sk = sk_alloc(net, PF_NFC, GFP_ATOMIC, nfc_proto->proto);
if (!sk)
......@@ -313,13 +357,53 @@ static int rawsock_create(struct net *net, struct socket *sock,
sk->sk_protocol = nfc_proto->id;
sk->sk_destruct = rawsock_destruct;
sock->state = SS_UNCONNECTED;
INIT_WORK(&nfc_rawsock(sk)->tx_work, rawsock_tx_work);
nfc_rawsock(sk)->tx_work_scheduled = false;
if (sock->type == SOCK_RAW)
nfc_sock_link(&raw_sk_list, sk);
else {
INIT_WORK(&nfc_rawsock(sk)->tx_work, rawsock_tx_work);
nfc_rawsock(sk)->tx_work_scheduled = false;
}
return 0;
}
void nfc_send_to_raw_sock(struct nfc_dev *dev, struct sk_buff *skb,
u8 payload_type, u8 direction)
{
struct sk_buff *skb_copy = NULL, *nskb;
struct sock *sk;
u8 *data;
read_lock(&raw_sk_list.lock);
sk_for_each(sk, &raw_sk_list.head) {
if (!skb_copy) {
skb_copy = __pskb_copy(skb, NFC_RAW_HEADER_SIZE,
GFP_ATOMIC);
if (!skb_copy)
continue;
data = skb_push(skb_copy, NFC_RAW_HEADER_SIZE);
data[0] = dev ? dev->idx : 0xFF;
data[1] = direction & 0x01;
data[1] |= (payload_type << 1);
}
nskb = skb_clone(skb_copy, GFP_ATOMIC);
if (!nskb)
continue;
if (sock_queue_rcv_skb(sk, nskb))
kfree_skb(nskb);
}
read_unlock(&raw_sk_list.lock);
kfree_skb(skb_copy);
}
EXPORT_SYMBOL(nfc_send_to_raw_sock);
static struct proto rawsock_proto = {
.name = "NFC_RAW",
.owner = THIS_MODULE,
......
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