Commit ec876526 authored by John W. Linville's avatar John W. Linville

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

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

"NFC: 3.17 pull request

This is the NFC pull request for 3.17.
This is a rather quiet one, we have:

- A new driver from ST Microelectronics for their NCI ST21NFCB,
  including device tree  support.

- p2p support for the ST21NFCA driver

- A few fixes an enhancements for the NFC digital layer"
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parents 9a244409 bf30a67c
* STMicroelectronics SAS. ST21NFCB NFC Controller
Required properties:
- 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
- interrupts: GPIO interrupt to which the chip is connected
- reset-gpios: Output GPIO pin used to reset the ST21NFCB
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 ST21NFCB on I2C2):
&i2c2 {
status = "okay";
st21nfcb: st21nfcb@8 {
compatible = "st,st21nfcb_i2c";
reg = <0x08>;
clock-frequency = <400000>;
interrupt-parent = <&gpio5>;
interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
reset-gpios = <&gpio5 29 GPIO_ACTIVE_HIGH>;
};
};
......@@ -72,5 +72,5 @@ source "drivers/nfc/pn544/Kconfig"
source "drivers/nfc/microread/Kconfig"
source "drivers/nfc/nfcmrvl/Kconfig"
source "drivers/nfc/st21nfca/Kconfig"
source "drivers/nfc/st21nfcb/Kconfig"
endmenu
......@@ -11,6 +11,7 @@ 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/
obj-$(CONFIG_NFC_ST21NFCA) += st21nfca/
obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb/
ccflags-$(CONFIG_NFC_DEBUG) := -DDEBUG
......@@ -4,5 +4,5 @@
st21nfca_i2c-objs = i2c.o
obj-$(CONFIG_NFC_ST21NFCA) += st21nfca.o
obj-$(CONFIG_NFC_ST21NFCA) += st21nfca.o st21nfca_dep.o
obj-$(CONFIG_NFC_ST21NFCA_I2C) += st21nfca_i2c.o
......@@ -93,7 +93,7 @@ struct st21nfca_i2c_phy {
int hard_fault;
struct mutex phy_lock;
};
static u8 len_seq[] = { 13, 24, 15, 29 };
static u8 len_seq[] = { 16, 24, 12, 29 };
static u16 wait_tab[] = { 2, 3, 5, 15, 20, 40};
#define I2C_DUMP_SKB(info, skb) \
......@@ -397,12 +397,11 @@ static int st21nfca_hci_i2c_read(struct st21nfca_i2c_phy *phy,
* The first read sequence does not start with SOF.
* Data is corrupeted so we drop it.
*/
if (!phy->current_read_len && buf[0] != ST21NFCA_SOF_EOF) {
if (!phy->current_read_len && !IS_START_OF_FRAME(buf)) {
skb_trim(skb, 0);
phy->current_read_len = 0;
return -EIO;
} else if (phy->current_read_len &&
IS_START_OF_FRAME(buf)) {
} else if (phy->current_read_len && IS_START_OF_FRAME(buf)) {
/*
* Previous frame transmission was interrupted and
* the frame got repeated.
......@@ -487,6 +486,8 @@ static irqreturn_t st21nfca_hci_irq_thread_fn(int irq, void *phy_id)
*/
nfc_hci_recv_frame(phy->hdev, phy->pending_skb);
phy->crc_trials = 0;
} else {
kfree_skb(phy->pending_skb);
}
phy->pending_skb = alloc_skb(ST21NFCA_HCI_LLC_MAX_SIZE * 2, GFP_KERNEL);
......
This diff is collapsed.
......@@ -19,6 +19,8 @@
#include <net/nfc/hci.h>
#include "st21nfca_dep.h"
#define HCI_MODE 0
/* framing in HCI mode */
......@@ -73,7 +75,8 @@ struct st21nfca_hci_info {
data_exchange_cb_t async_cb;
void *async_cb_context;
} __packed;
struct st21nfca_dep_info dep_info;
};
/* Reader RF commands */
#define ST21NFCA_WR_XCHG_DATA 0x10
......@@ -83,5 +86,26 @@ struct st21nfca_hci_info {
#define ST21NFCA_RF_READER_F_DATARATE_106 0x01
#define ST21NFCA_RF_READER_F_DATARATE_212 0x02
#define ST21NFCA_RF_READER_F_DATARATE_424 0x04
#define ST21NFCA_RF_READER_F_POL_REQ 0x02
#define ST21NFCA_RF_READER_F_POL_REQ_DEFAULT 0xffff0000
#define ST21NFCA_RF_READER_F_NFCID2 0x03
#define ST21NFCA_RF_READER_F_NFCID1 0x04
#define ST21NFCA_RF_READER_F_SENS_RES 0x05
#define ST21NFCA_RF_CARD_F_GATE 0x24
#define ST21NFCA_RF_CARD_F_MODE 0x01
#define ST21NFCA_RF_CARD_F_NFCID2_LIST 0x04
#define ST21NFCA_RF_CARD_F_NFCID1 0x05
#define ST21NFCA_RF_CARD_F_SENS_RES 0x06
#define ST21NFCA_RF_CARD_F_SEL_RES 0x07
#define ST21NFCA_RF_CARD_F_DATARATE 0x08
#define ST21NFCA_RF_CARD_F_DATARATE_106 0x00
#define ST21NFCA_RF_CARD_F_DATARATE_212_424 0x01
#define ST21NFCA_EVT_SEND_DATA 0x10
#define ST21NFCA_EVT_FIELD_ON 0x11
#define ST21NFCA_EVT_CARD_DEACTIVATED 0x12
#define ST21NFCA_EVT_CARD_ACTIVATED 0x13
#define ST21NFCA_EVT_FIELD_OFF 0x14
#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_DEP_H
#define __ST21NFCA_DEP_H
#include <linux/skbuff.h>
#include <linux/workqueue.h>
struct st21nfca_dep_info {
struct sk_buff *tx_pending;
struct work_struct tx_work;
u8 curr_nfc_dep_pni;
u32 idx;
u8 to;
u8 did;
u8 bsi;
u8 bri;
u8 lri;
} __packed;
int st21nfca_tm_event_send_data(struct nfc_hci_dev *hdev, struct sk_buff *skb,
u8 gate);
int st21nfca_tm_send_dep_res(struct nfc_hci_dev *hdev, struct sk_buff *skb);
int st21nfca_im_send_atr_req(struct nfc_hci_dev *hdev, u8 *gb, size_t gb_len);
int st21nfca_im_send_dep_req(struct nfc_hci_dev *hdev, struct sk_buff *skb);
void st21nfca_dep_init(struct nfc_hci_dev *hdev);
void st21nfca_dep_deinit(struct nfc_hci_dev *hdev);
#endif /* __ST21NFCA_DEP_H */
config NFC_ST21NFCB
tristate "STMicroelectronics ST21NFCB NFC driver"
depends on NFC_NCI
default n
---help---
STMicroelectronics ST21NFCB core driver. It implements the chipset
NCI logic and hooks into the NFC kernel APIs. Physical layers will
register against it.
To compile this driver as a module, choose m here. The module will
be called st21nfcb.
Say N if unsure.
config NFC_ST21NFCB_I2C
tristate "NFC ST21NFCB i2c support"
depends on NFC_ST21NFCB && I2C
---help---
This module adds support for the STMicroelectronics st21nfcb i2c interface.
Select this if your platform is using the i2c bus.
If you choose to build a module, it'll be called st21nfcb_i2c.
Say N if unsure.
#
# Makefile for ST21NFCB NCI based NFC driver
#
st21nfcb_i2c-objs = i2c.o
obj-$(CONFIG_NFC_ST21NFCB) += st21nfcb.o ndlc.o
obj-$(CONFIG_NFC_ST21NFCB_I2C) += st21nfcb_i2c.o
This diff is collapsed.
/*
* Low Level Transport (NDLC) Driver for STMicroelectronics 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/>.
*/
#include <linux/sched.h>
#include <net/nfc/nci_core.h>
#include "ndlc.h"
#include "st21nfcb.h"
#define NDLC_TIMER_T1 100
#define NDLC_TIMER_T1_WAIT 400
#define NDLC_TIMER_T2 1200
#define PCB_TYPE_DATAFRAME 0x80
#define PCB_TYPE_SUPERVISOR 0xc0
#define PCB_TYPE_MASK PCB_TYPE_SUPERVISOR
#define PCB_SYNC_ACK 0x20
#define PCB_SYNC_NACK 0x10
#define PCB_SYNC_WAIT 0x30
#define PCB_SYNC_NOINFO 0x00
#define PCB_SYNC_MASK PCB_SYNC_WAIT
#define PCB_DATAFRAME_RETRANSMIT_YES 0x00
#define PCB_DATAFRAME_RETRANSMIT_NO 0x04
#define PCB_DATAFRAME_RETRANSMIT_MASK PCB_DATAFRAME_RETRANSMIT_NO
#define PCB_SUPERVISOR_RETRANSMIT_YES 0x00
#define PCB_SUPERVISOR_RETRANSMIT_NO 0x02
#define PCB_SUPERVISOR_RETRANSMIT_MASK PCB_SUPERVISOR_RETRANSMIT_NO
#define PCB_FRAME_CRC_INFO_PRESENT 0x08
#define PCB_FRAME_CRC_INFO_NOTPRESENT 0x00
#define PCB_FRAME_CRC_INFO_MASK PCB_FRAME_CRC_INFO_PRESENT
#define NDLC_DUMP_SKB(info, skb) \
do { \
pr_debug("%s:\n", info); \
print_hex_dump(KERN_DEBUG, "ndlc: ", DUMP_PREFIX_OFFSET, \
16, 1, skb->data, skb->len, 0); \
} while (0)
int ndlc_open(struct llt_ndlc *ndlc)
{
/* toggle reset pin */
ndlc->ops->enable(ndlc->phy_id);
return 0;
}
EXPORT_SYMBOL(ndlc_open);
void ndlc_close(struct llt_ndlc *ndlc)
{
/* toggle reset pin */
ndlc->ops->disable(ndlc->phy_id);
}
EXPORT_SYMBOL(ndlc_close);
int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb)
{
/* add ndlc header */
u8 pcb = PCB_TYPE_DATAFRAME | PCB_DATAFRAME_RETRANSMIT_NO |
PCB_FRAME_CRC_INFO_NOTPRESENT;
*skb_push(skb, 1) = pcb;
skb_queue_tail(&ndlc->send_q, skb);
schedule_work(&ndlc->sm_work);
return 0;
}
EXPORT_SYMBOL(ndlc_send);
static void llt_ndlc_send_queue(struct llt_ndlc *ndlc)
{
struct sk_buff *skb;
int r;
unsigned long time_sent;
if (ndlc->send_q.qlen)
pr_debug("sendQlen=%d unackQlen=%d\n",
ndlc->send_q.qlen, ndlc->ack_pending_q.qlen);
while (ndlc->send_q.qlen) {
skb = skb_dequeue(&ndlc->send_q);
NDLC_DUMP_SKB("ndlc frame written", skb);
r = ndlc->ops->write(ndlc->phy_id, skb);
if (r < 0) {
ndlc->hard_fault = r;
break;
}
time_sent = jiffies;
*(unsigned long *)skb->cb = time_sent;
skb_queue_tail(&ndlc->ack_pending_q, skb);
/* start timer t1 for ndlc aknowledge */
ndlc->t1_active = true;
mod_timer(&ndlc->t1_timer, time_sent +
msecs_to_jiffies(NDLC_TIMER_T1));
}
}
static void llt_ndlc_requeue_data_pending(struct llt_ndlc *ndlc)
{
struct sk_buff *skb;
u8 pcb;
while ((skb = skb_dequeue_tail(&ndlc->ack_pending_q))) {
pcb = skb->data[0];
switch (pcb & PCB_TYPE_MASK) {
case PCB_TYPE_SUPERVISOR:
skb->data[0] = (pcb & ~PCB_SUPERVISOR_RETRANSMIT_MASK) |
PCB_SUPERVISOR_RETRANSMIT_YES;
break;
case PCB_TYPE_DATAFRAME:
skb->data[0] = (pcb & ~PCB_DATAFRAME_RETRANSMIT_MASK) |
PCB_DATAFRAME_RETRANSMIT_YES;
break;
default:
pr_err("UNKNOWN Packet Control Byte=%d\n", pcb);
kfree_skb(skb);
break;
}
skb_queue_head(&ndlc->send_q, skb);
}
}
static void llt_ndlc_rcv_queue(struct llt_ndlc *ndlc)
{
struct sk_buff *skb;
u8 pcb;
unsigned long time_sent;
if (ndlc->rcv_q.qlen)
pr_debug("rcvQlen=%d\n", ndlc->rcv_q.qlen);
while ((skb = skb_dequeue(&ndlc->rcv_q)) != NULL) {
pcb = skb->data[0];
skb_pull(skb, 1);
if ((pcb & PCB_TYPE_MASK) == PCB_TYPE_SUPERVISOR) {
switch (pcb & PCB_SYNC_MASK) {
case PCB_SYNC_ACK:
del_timer_sync(&ndlc->t1_timer);
del_timer_sync(&ndlc->t2_timer);
ndlc->t2_active = false;
ndlc->t1_active = false;
break;
case PCB_SYNC_NACK:
llt_ndlc_requeue_data_pending(ndlc);
llt_ndlc_send_queue(ndlc);
/* start timer t1 for ndlc aknowledge */
time_sent = jiffies;
ndlc->t1_active = true;
mod_timer(&ndlc->t1_timer, time_sent +
msecs_to_jiffies(NDLC_TIMER_T1));
break;
case PCB_SYNC_WAIT:
time_sent = jiffies;
ndlc->t1_active = true;
mod_timer(&ndlc->t1_timer, time_sent +
msecs_to_jiffies(NDLC_TIMER_T1_WAIT));
break;
default:
pr_err("UNKNOWN Packet Control Byte=%d\n", pcb);
kfree_skb(skb);
break;
}
} else {
nci_recv_frame(ndlc->ndev, skb);
}
}
}
static void llt_ndlc_sm_work(struct work_struct *work)
{
struct llt_ndlc *ndlc = container_of(work, struct llt_ndlc, sm_work);
llt_ndlc_send_queue(ndlc);
llt_ndlc_rcv_queue(ndlc);
if (ndlc->t1_active && timer_pending(&ndlc->t1_timer) == 0) {
pr_debug
("Handle T1(recv SUPERVISOR) elapsed (T1 now inactive)\n");
ndlc->t1_active = false;
llt_ndlc_requeue_data_pending(ndlc);
llt_ndlc_send_queue(ndlc);
}
if (ndlc->t2_active && timer_pending(&ndlc->t2_timer) == 0) {
pr_debug("Handle T2(recv DATA) elapsed (T2 now inactive)\n");
ndlc->t2_active = false;
ndlc->t1_active = false;
del_timer_sync(&ndlc->t1_timer);
ndlc_close(ndlc);
ndlc->hard_fault = -EREMOTEIO;
}
}
void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb)
{
if (skb == NULL) {
pr_err("NULL Frame -> link is dead\n");
ndlc->hard_fault = -EREMOTEIO;
ndlc_close(ndlc);
} else {
NDLC_DUMP_SKB("incoming frame", skb);
skb_queue_tail(&ndlc->rcv_q, skb);
}
schedule_work(&ndlc->sm_work);
}
EXPORT_SYMBOL(ndlc_recv);
static void ndlc_t1_timeout(unsigned long data)
{
struct llt_ndlc *ndlc = (struct llt_ndlc *)data;
pr_debug("\n");
schedule_work(&ndlc->sm_work);
}
static void ndlc_t2_timeout(unsigned long data)
{
struct llt_ndlc *ndlc = (struct llt_ndlc *)data;
pr_debug("\n");
schedule_work(&ndlc->sm_work);
}
int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id)
{
struct llt_ndlc *ndlc;
ndlc = devm_kzalloc(dev, sizeof(struct llt_ndlc), GFP_KERNEL);
if (!ndlc) {
nfc_err(dev, "Cannot allocate memory for ndlc.\n");
return -ENOMEM;
}
ndlc->ops = phy_ops;
ndlc->phy_id = phy_id;
ndlc->dev = dev;
*ndlc_id = ndlc;
/* start timers */
init_timer(&ndlc->t1_timer);
ndlc->t1_timer.data = (unsigned long)ndlc;
ndlc->t1_timer.function = ndlc_t1_timeout;
init_timer(&ndlc->t2_timer);
ndlc->t2_timer.data = (unsigned long)ndlc;
ndlc->t2_timer.function = ndlc_t2_timeout;
skb_queue_head_init(&ndlc->rcv_q);
skb_queue_head_init(&ndlc->send_q);
skb_queue_head_init(&ndlc->ack_pending_q);
INIT_WORK(&ndlc->sm_work, llt_ndlc_sm_work);
return st21nfcb_nci_probe(ndlc, phy_headroom, phy_tailroom);
}
EXPORT_SYMBOL(ndlc_probe);
void ndlc_remove(struct llt_ndlc *ndlc)
{
/* cancel timers */
del_timer_sync(&ndlc->t1_timer);
del_timer_sync(&ndlc->t2_timer);
ndlc->t2_active = false;
ndlc->t1_active = false;
skb_queue_purge(&ndlc->rcv_q);
skb_queue_purge(&ndlc->send_q);
st21nfcb_nci_remove(ndlc->ndev);
kfree(ndlc);
}
EXPORT_SYMBOL(ndlc_remove);
/*
* NCI based Driver for STMicroelectronics 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 __LOCAL_NDLC_H_
#define __LOCAL_NDLC_H_
#include <linux/skbuff.h>
#include <net/nfc/nfc.h>
/* Low Level Transport description */
struct llt_ndlc {
struct nci_dev *ndev;
struct nfc_phy_ops *ops;
void *phy_id;
struct timer_list t1_timer;
bool t1_active;
struct timer_list t2_timer;
bool t2_active;
struct sk_buff_head rcv_q;
struct sk_buff_head send_q;
struct sk_buff_head ack_pending_q;
struct work_struct sm_work;
struct device *dev;
int hard_fault;
};
int ndlc_open(struct llt_ndlc *ndlc);
void ndlc_close(struct llt_ndlc *ndlc);
int ndlc_send(struct llt_ndlc *ndlc, struct sk_buff *skb);
void ndlc_recv(struct llt_ndlc *ndlc, struct sk_buff *skb);
int ndlc_probe(void *phy_id, struct nfc_phy_ops *phy_ops, struct device *dev,
int phy_headroom, int phy_tailroom, struct llt_ndlc **ndlc_id);
void ndlc_remove(struct llt_ndlc *ndlc);
#endif /* __LOCAL_NDLC_H__ */
/*
* NCI based Driver for STMicroelectronics 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/>.
*/
#include <linux/module.h>
#include <linux/nfc.h>
#include <net/nfc/nci.h>
#include <net/nfc/nci_core.h>
#include "st21nfcb.h"
#include "ndlc.h"
#define DRIVER_DESC "NCI NFC driver for ST21NFCB"
static int st21nfcb_nci_open(struct nci_dev *ndev)
{
struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
int r;
if (test_and_set_bit(ST21NFCB_NCI_RUNNING, &info->flags))
return 0;
r = ndlc_open(info->ndlc);
if (r)
clear_bit(ST21NFCB_NCI_RUNNING, &info->flags);
return r;
}
static int st21nfcb_nci_close(struct nci_dev *ndev)
{
struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
if (!test_and_clear_bit(ST21NFCB_NCI_RUNNING, &info->flags))
return 0;
ndlc_close(info->ndlc);
return 0;
}
static int st21nfcb_nci_send(struct nci_dev *ndev, struct sk_buff *skb)
{
struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
skb->dev = (void *)ndev;
if (!test_bit(ST21NFCB_NCI_RUNNING, &info->flags))
return -EBUSY;
return ndlc_send(info->ndlc, skb);
}
static struct nci_ops st21nfcb_nci_ops = {
.open = st21nfcb_nci_open,
.close = st21nfcb_nci_close,
.send = st21nfcb_nci_send,
};
int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
int phy_tailroom)
{
struct st21nfcb_nci_info *info;
int r;
u32 protocols;
info = devm_kzalloc(ndlc->dev,
sizeof(struct st21nfcb_nci_info), GFP_KERNEL);
if (!info)
return -ENOMEM;
protocols = NFC_PROTO_JEWEL_MASK
| NFC_PROTO_MIFARE_MASK
| NFC_PROTO_FELICA_MASK
| NFC_PROTO_ISO14443_MASK
| NFC_PROTO_ISO14443_B_MASK
| NFC_PROTO_NFC_DEP_MASK;
ndlc->ndev = nci_allocate_device(&st21nfcb_nci_ops, protocols,
phy_headroom, phy_tailroom);
if (!ndlc->ndev) {
pr_err("Cannot allocate nfc ndev\n");
r = -ENOMEM;
goto err_alloc_ndev;
}
info->ndlc = ndlc;
nci_set_drvdata(ndlc->ndev, info);
r = nci_register_device(ndlc->ndev);
if (r)
goto err_regdev;
return r;
err_regdev:
nci_free_device(ndlc->ndev);
err_alloc_ndev:
kfree(info);
return r;
}
EXPORT_SYMBOL_GPL(st21nfcb_nci_probe);
void st21nfcb_nci_remove(struct nci_dev *ndev)
{
struct st21nfcb_nci_info *info = nci_get_drvdata(ndev);
nci_unregister_device(ndev);
nci_free_device(ndev);
kfree(info);
}
EXPORT_SYMBOL_GPL(st21nfcb_nci_remove);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRIVER_DESC);
/*
* NCI based Driver for STMicroelectronics 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 __LOCAL_ST21NFCB_H_
#define __LOCAL_ST21NFCB_H_
#include <net/nfc/nci_core.h>
#include "ndlc.h"
/* Define private flags: */
#define ST21NFCB_NCI_RUNNING 1
struct st21nfcb_nci_info {
struct llt_ndlc *ndlc;
unsigned long flags;
};
void st21nfcb_nci_remove(struct nci_dev *ndev);
int st21nfcb_nci_probe(struct llt_ndlc *ndlc, int phy_headroom,
int phy_tailroom);
#endif /* __LOCAL_ST21NFCB_H_ */
/*
* Driver include for the ST21NFCB 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 _ST21NFCB_NCI_H_
#define _ST21NFCB_NCI_H_
#include <linux/i2c.h>
#define ST21NFCB_NCI_DRIVER_NAME "st21nfcb_nci"
struct st21nfcb_nfc_platform_data {
unsigned int gpio_irq;
unsigned int gpio_reset;
unsigned int irq_polarity;
};
#endif /* _ST21NFCA_HCI_H_ */
......@@ -49,6 +49,7 @@ enum {
NFC_DIGITAL_FRAMING_NFCA_SHORT = 0,
NFC_DIGITAL_FRAMING_NFCA_STANDARD,
NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A,
NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE,
NFC_DIGITAL_FRAMING_NFCA_T1T,
NFC_DIGITAL_FRAMING_NFCA_T2T,
......@@ -126,6 +127,15 @@ typedef void (*nfc_digital_cmd_complete_t)(struct nfc_digital_dev *ddev,
* the NFC-DEP ATR_REQ command through cb. The digital stack deducts the RF
* tech by analyzing the SoD of the frame containing the ATR_REQ command.
* This is an asynchronous function.
* @tg_listen_md: If supported, put the device in automatic listen mode with
* mode detection but without automatic anti-collision. In this mode, the
* device automatically detects the RF technology. What the actual
* RF technology is can be retrieved by calling @tg_get_rf_tech.
* The digital stack will then perform the appropriate anti-collision
* sequence. This is an asynchronous function.
* @tg_get_rf_tech: Required when @tg_listen_md is supported, unused otherwise.
* Return the RF Technology that was detected by the @tg_listen_md call.
* This is a synchronous function.
*
* @switch_rf: Turns device radio on or off. The stack does not call explicitly
* switch_rf to turn the radio on. A call to in|tg_configure_hw must turn
......@@ -160,6 +170,9 @@ struct nfc_digital_ops {
struct digital_tg_mdaa_params *mdaa_params,
u16 timeout, nfc_digital_cmd_complete_t cb,
void *arg);
int (*tg_listen_md)(struct nfc_digital_dev *ddev, u16 timeout,
nfc_digital_cmd_complete_t cb, void *arg);
int (*tg_get_rf_tech)(struct nfc_digital_dev *ddev, u8 *rf_tech);
int (*switch_rf)(struct nfc_digital_dev *ddev, bool on);
void (*abort_cmd)(struct nfc_digital_dev *ddev);
......
......@@ -37,6 +37,7 @@ struct nfc_hci_ops {
int (*xmit) (struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*start_poll) (struct nfc_hci_dev *hdev,
u32 im_protocols, u32 tm_protocols);
void (*stop_poll) (struct nfc_hci_dev *hdev);
int (*dep_link_up)(struct nfc_hci_dev *hdev, struct nfc_target *target,
u8 comm_mode, u8 *gb, size_t gb_len);
int (*dep_link_down)(struct nfc_hci_dev *hdev);
......
......@@ -29,6 +29,7 @@
#define DIGITAL_CMD_TG_SEND 1
#define DIGITAL_CMD_TG_LISTEN 2
#define DIGITAL_CMD_TG_LISTEN_MDAA 3
#define DIGITAL_CMD_TG_LISTEN_MD 4
#define DIGITAL_MAX_HEADER_LEN 7
#define DIGITAL_CRC_LEN 2
......@@ -121,6 +122,8 @@ int digital_tg_send_dep_res(struct nfc_digital_dev *ddev, struct sk_buff *skb);
int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech);
int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech);
void digital_tg_recv_md_req(struct nfc_digital_dev *ddev, void *arg,
struct sk_buff *resp);
typedef u16 (*crc_func_t)(u16, const u8 *, size_t);
......
......@@ -201,6 +201,11 @@ static void digital_wq_cmd(struct work_struct *work)
digital_send_cmd_complete, cmd);
break;
case DIGITAL_CMD_TG_LISTEN_MD:
rc = ddev->ops->tg_listen_md(ddev, cmd->timeout,
digital_send_cmd_complete, cmd);
break;
default:
pr_err("Unknown cmd type %d\n", cmd->type);
return;
......@@ -293,12 +298,19 @@ static int digital_tg_listen_mdaa(struct nfc_digital_dev *ddev, u8 rf_tech)
500, digital_tg_recv_atr_req, NULL);
}
static int digital_tg_listen_md(struct nfc_digital_dev *ddev, u8 rf_tech)
{
return digital_send_cmd(ddev, DIGITAL_CMD_TG_LISTEN_MD, NULL, NULL, 500,
digital_tg_recv_md_req, NULL);
}
int digital_target_found(struct nfc_digital_dev *ddev,
struct nfc_target *target, u8 protocol)
{
int rc;
u8 framing;
u8 rf_tech;
u8 poll_tech_count;
int (*check_crc)(struct sk_buff *skb);
void (*add_crc)(struct sk_buff *skb);
......@@ -375,12 +387,16 @@ int digital_target_found(struct nfc_digital_dev *ddev,
return rc;
target->supported_protocols = (1 << protocol);
rc = nfc_targets_found(ddev->nfc_dev, target, 1);
if (rc)
return rc;
poll_tech_count = ddev->poll_tech_count;
ddev->poll_tech_count = 0;
rc = nfc_targets_found(ddev->nfc_dev, target, 1);
if (rc) {
ddev->poll_tech_count = poll_tech_count;
return rc;
}
return 0;
}
......@@ -505,6 +521,9 @@ static int digital_start_poll(struct nfc_dev *nfc_dev, __u32 im_protocols,
if (ddev->ops->tg_listen_mdaa) {
digital_add_poll_tech(ddev, 0,
digital_tg_listen_mdaa);
} else if (ddev->ops->tg_listen_md) {
digital_add_poll_tech(ddev, 0,
digital_tg_listen_md);
} else {
digital_add_poll_tech(ddev, NFC_DIGITAL_RF_TECH_106A,
digital_tg_listen_nfca);
......@@ -732,7 +751,7 @@ struct nfc_digital_dev *nfc_digital_allocate_device(struct nfc_digital_ops *ops,
if (!ops->in_configure_hw || !ops->in_send_cmd || !ops->tg_listen ||
!ops->tg_configure_hw || !ops->tg_send_cmd || !ops->abort_cmd ||
!ops->switch_rf)
!ops->switch_rf || (ops->tg_listen_md && !ops->tg_get_rf_tech))
return NULL;
ddev = kzalloc(sizeof(struct nfc_digital_dev), GFP_KERNEL);
......
......@@ -673,6 +673,7 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg,
int rc;
struct digital_atr_req *atr_req;
size_t gb_len, min_size;
u8 poll_tech_count;
if (IS_ERR(resp)) {
rc = PTR_ERR(resp);
......@@ -730,12 +731,16 @@ void digital_tg_recv_atr_req(struct nfc_digital_dev *ddev, void *arg,
goto exit;
gb_len = resp->len - sizeof(struct digital_atr_req);
poll_tech_count = ddev->poll_tech_count;
ddev->poll_tech_count = 0;
rc = nfc_tm_activated(ddev->nfc_dev, NFC_PROTO_NFC_DEP_MASK,
NFC_COMM_PASSIVE, atr_req->gb, gb_len);
if (rc)
if (rc) {
ddev->poll_tech_count = poll_tech_count;
goto exit;
ddev->poll_tech_count = 0;
}
rc = 0;
exit:
......
......@@ -318,6 +318,8 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg,
if (DIGITAL_SEL_RES_IS_T2T(sel_res)) {
nfc_proto = NFC_PROTO_MIFARE;
} else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) {
nfc_proto = NFC_PROTO_NFC_DEP;
} else if (DIGITAL_SEL_RES_IS_T4T(sel_res)) {
rc = digital_in_send_rats(ddev, target);
if (rc)
......@@ -327,8 +329,6 @@ static void digital_in_recv_sel_res(struct nfc_digital_dev *ddev, void *arg,
* done when receiving the ATS
*/
goto exit_free_skb;
} else if (DIGITAL_SEL_RES_IS_NFC_DEP(sel_res)) {
nfc_proto = NFC_PROTO_NFC_DEP;
} else {
rc = -EOPNOTSUPP;
goto exit;
......@@ -944,6 +944,13 @@ static int digital_tg_send_sel_res(struct nfc_digital_dev *ddev)
if (!DIGITAL_DRV_CAPS_TG_CRC(ddev))
digital_skb_add_crc_a(skb);
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
NFC_DIGITAL_FRAMING_NFCA_ANTICOL_COMPLETE);
if (rc) {
kfree_skb(skb);
return rc;
}
rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_atr_req,
NULL);
if (rc)
......@@ -1002,6 +1009,13 @@ static int digital_tg_send_sdd_res(struct nfc_digital_dev *ddev)
for (i = 0; i < 4; i++)
sdd_res->bcc ^= sdd_res->nfcid1[i];
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
NFC_DIGITAL_FRAMING_NFCA_STANDARD_WITH_CRC_A);
if (rc) {
kfree_skb(skb);
return rc;
}
rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sel_req,
NULL);
if (rc)
......@@ -1054,6 +1068,13 @@ static int digital_tg_send_sens_res(struct nfc_digital_dev *ddev)
sens_res[0] = (DIGITAL_SENS_RES_NFC_DEP >> 8) & 0xFF;
sens_res[1] = DIGITAL_SENS_RES_NFC_DEP & 0xFF;
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
NFC_DIGITAL_FRAMING_NFCA_STANDARD);
if (rc) {
kfree_skb(skb);
return rc;
}
rc = digital_tg_send_cmd(ddev, skb, 300, digital_tg_recv_sdd_req,
NULL);
if (rc)
......@@ -1197,33 +1218,48 @@ void digital_tg_recv_sensf_req(struct nfc_digital_dev *ddev, void *arg,
dev_kfree_skb(resp);
}
int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech)
static int digital_tg_config_nfca(struct nfc_digital_dev *ddev)
{
int rc;
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech);
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH,
NFC_DIGITAL_RF_TECH_106A);
if (rc)
return rc;
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
NFC_DIGITAL_FRAMING_NFCA_NFC_DEP);
return digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
NFC_DIGITAL_FRAMING_NFCA_NFC_DEP);
}
int digital_tg_listen_nfca(struct nfc_digital_dev *ddev, u8 rf_tech)
{
int rc;
rc = digital_tg_config_nfca(ddev);
if (rc)
return rc;
return digital_tg_listen(ddev, 300, digital_tg_recv_sens_req, NULL);
}
int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech)
static int digital_tg_config_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech)
{
int rc;
u8 *nfcid2;
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_RF_TECH, rf_tech);
if (rc)
return rc;
rc = digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
NFC_DIGITAL_FRAMING_NFCF_NFC_DEP);
return digital_tg_configure_hw(ddev, NFC_DIGITAL_CONFIG_FRAMING,
NFC_DIGITAL_FRAMING_NFCF_NFC_DEP);
}
int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech)
{
int rc;
u8 *nfcid2;
rc = digital_tg_config_nfcf(ddev, rf_tech);
if (rc)
return rc;
......@@ -1237,3 +1273,43 @@ int digital_tg_listen_nfcf(struct nfc_digital_dev *ddev, u8 rf_tech)
return digital_tg_listen(ddev, 300, digital_tg_recv_sensf_req, nfcid2);
}
void digital_tg_recv_md_req(struct nfc_digital_dev *ddev, void *arg,
struct sk_buff *resp)
{
u8 rf_tech;
int rc;
if (IS_ERR(resp)) {
resp = NULL;
goto exit_free_skb;
}
rc = ddev->ops->tg_get_rf_tech(ddev, &rf_tech);
if (rc)
goto exit_free_skb;
switch (rf_tech) {
case NFC_DIGITAL_RF_TECH_106A:
rc = digital_tg_config_nfca(ddev);
if (rc)
goto exit_free_skb;
digital_tg_recv_sens_req(ddev, arg, resp);
break;
case NFC_DIGITAL_RF_TECH_212F:
case NFC_DIGITAL_RF_TECH_424F:
rc = digital_tg_config_nfcf(ddev, rf_tech);
if (rc)
goto exit_free_skb;
digital_tg_recv_sensf_req(ddev, arg, resp);
break;
default:
goto exit_free_skb;
}
return;
exit_free_skb:
digital_poll_next_tech(ddev);
dev_kfree_skb(resp);
}
......@@ -553,8 +553,11 @@ static void hci_stop_poll(struct nfc_dev *nfc_dev)
{
struct nfc_hci_dev *hdev = nfc_get_drvdata(nfc_dev);
nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
NFC_HCI_EVT_END_OPERATION, NULL, 0);
if (hdev->ops->stop_poll)
hdev->ops->stop_poll(hdev);
else
nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
NFC_HCI_EVT_END_OPERATION, NULL, 0);
}
static int hci_dep_link_up(struct nfc_dev *nfc_dev, struct nfc_target *target,
......
......@@ -166,7 +166,9 @@ static int nci_add_new_protocol(struct nci_dev *ndev,
struct rf_tech_specific_params_nfcf_poll *nfcf_poll;
__u32 protocol;
if (rf_protocol == NCI_RF_PROTOCOL_T2T)
if (rf_protocol == NCI_RF_PROTOCOL_T1T)
protocol = NFC_PROTO_JEWEL_MASK;
else if (rf_protocol == NCI_RF_PROTOCOL_T2T)
protocol = NFC_PROTO_MIFARE_MASK;
else if (rf_protocol == NCI_RF_PROTOCOL_ISO_DEP)
if (rf_tech_and_mode == NCI_NFC_A_PASSIVE_POLL_MODE)
......
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