]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/commitdiff
Merge tag 'for-linville-20140725' of git://github.com/kvalo/ath
authorJohn W. Linville <linville@tuxdriver.com>
Tue, 29 Jul 2014 14:32:12 +0000 (10:32 -0400)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 29 Jul 2014 14:32:12 +0000 (10:32 -0400)
29 files changed:
Documentation/devicetree/bindings/net/nfc/st21nfcb.txt [new file with mode: 0644]
drivers/net/wireless/ath/ath9k/xmit.c
drivers/nfc/Kconfig
drivers/nfc/Makefile
drivers/nfc/st21nfca/Makefile
drivers/nfc/st21nfca/i2c.c
drivers/nfc/st21nfca/st21nfca.c
drivers/nfc/st21nfca/st21nfca.h
drivers/nfc/st21nfca/st21nfca_dep.c [new file with mode: 0644]
drivers/nfc/st21nfca/st21nfca_dep.h [new file with mode: 0644]
drivers/nfc/st21nfcb/Kconfig [new file with mode: 0644]
drivers/nfc/st21nfcb/Makefile [new file with mode: 0644]
drivers/nfc/st21nfcb/i2c.c [new file with mode: 0644]
drivers/nfc/st21nfcb/ndlc.c [new file with mode: 0644]
drivers/nfc/st21nfcb/ndlc.h [new file with mode: 0644]
drivers/nfc/st21nfcb/st21nfcb.c [new file with mode: 0644]
drivers/nfc/st21nfcb/st21nfcb.h [new file with mode: 0644]
include/linux/platform_data/st21nfcb.h [new file with mode: 0644]
include/net/nfc/digital.h
include/net/nfc/hci.h
net/mac80211/sta_info.c
net/mac80211/tx.c
net/nfc/digital.h
net/nfc/digital_core.c
net/nfc/digital_dep.c
net/nfc/digital_technology.c
net/nfc/hci/core.c
net/nfc/nci/ntf.c
net/wireless/trace.h

diff --git a/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt b/Documentation/devicetree/bindings/net/nfc/st21nfcb.txt
new file mode 100644 (file)
index 0000000..3b58ae4
--- /dev/null
@@ -0,0 +1,33 @@
+* 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>;
+       };
+};
index 36115298f64e95678a767a1098bea1bb0d042b57..704fcbcbe20b5a59723063c77ac0d98ee482a99f 100644 (file)
@@ -897,6 +897,15 @@ ath_tx_get_tid_subframe(struct ath_softc *sc, struct ath_txq *txq,
 
                tx_info = IEEE80211_SKB_CB(skb);
                tx_info->flags &= ~IEEE80211_TX_CTL_CLEAR_PS_FILT;
+
+               /*
+                * No aggregation session is running, but there may be frames
+                * from a previous session or a failed attempt in the queue.
+                * Send them out as normal data frames
+                */
+               if (!tid->active)
+                       tx_info->flags &= ~IEEE80211_TX_CTL_AMPDU;
+
                if (!(tx_info->flags & IEEE80211_TX_CTL_AMPDU)) {
                        bf->bf_state.bf_type = 0;
                        return bf;
index 26c66a1265518c32f5262d3aa98afb668e2715ff..7929fac13e1c55ac072d46f6c2d3a6ea10528fa7 100644 (file)
@@ -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
index 23225b0287fdf2e7b6f809466e58b5cc5fc53d2c..6b23a2c6e34adf7c1ed35e0aa7e40aa2e9a7cc66 100644 (file)
@@ -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
index 038ed093a119f24f69d0e41a4f67a7c68c0817e7..db7a38ae05f7a5cee13241b43ae1a675dc79ab1f 100644 (file)
@@ -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
index 3f954ed86d98e4346172e95098c985f35e8b7648..ff31939978ae595713fea28e9bbd8f153fc4640c 100644 (file)
@@ -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);
index 51e0f00b3a4fd81fb5ff5d8bf5ed239ca90ac2da..a902b0551c86a10b0d158c76c568613144f4d254 100644 (file)
@@ -22,6 +22,7 @@
 #include <net/nfc/llc.h>
 
 #include "st21nfca.h"
+#include "st21nfca_dep.h"
 
 #define DRIVER_DESC "HCI NFC driver for ST21NFCA"
 
@@ -53,6 +54,7 @@
 #define ST21NFCA_DM_PIPE_CREATED        0x02
 #define ST21NFCA_DM_PIPE_OPEN           0x04
 #define ST21NFCA_DM_RF_ACTIVE           0x80
+#define ST21NFCA_DM_DISCONNECT         0x30
 
 #define ST21NFCA_DM_IS_PIPE_OPEN(p) \
        ((p & 0x0f) == (ST21NFCA_DM_PIPE_CREATED | ST21NFCA_DM_PIPE_OPEN))
@@ -72,6 +74,7 @@ static struct nfc_hci_gate st21nfca_gates[] = {
        {ST21NFCA_RF_READER_F_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_CARD_F_GATE, NFC_HCI_INVALID_PIPE},
 };
 
 struct st21nfca_pipe_info {
@@ -299,6 +302,9 @@ static int st21nfca_hci_start_poll(struct nfc_hci_dev *hdev,
                                   u32 im_protocols, u32 tm_protocols)
 {
        int r;
+       u32 pol_req;
+       u8 param[19];
+       struct sk_buff *datarate_skb;
 
        pr_info(DRIVER_DESC ": %s protocols 0x%x 0x%x\n",
                __func__, im_protocols, tm_protocols);
@@ -331,6 +337,31 @@ static int st21nfca_hci_start_poll(struct nfc_hci_dev *hdev,
                                        ST21NFCA_RF_READER_F_GATE);
                        if (r < 0)
                                return r;
+               } else {
+                       hdev->gb = nfc_get_local_general_bytes(hdev->ndev,
+                                                              &hdev->gb_len);
+
+                       if (hdev->gb == NULL || hdev->gb_len == 0) {
+                               im_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
+                               tm_protocols &= ~NFC_PROTO_NFC_DEP_MASK;
+                       }
+
+                       param[0] = ST21NFCA_RF_READER_F_DATARATE_106 |
+                           ST21NFCA_RF_READER_F_DATARATE_212 |
+                           ST21NFCA_RF_READER_F_DATARATE_424;
+                       r = nfc_hci_set_param(hdev, ST21NFCA_RF_READER_F_GATE,
+                                             ST21NFCA_RF_READER_F_DATARATE,
+                                             param, 1);
+                       if (r < 0)
+                               return r;
+
+                       pol_req =
+                           be32_to_cpu(ST21NFCA_RF_READER_F_POL_REQ_DEFAULT);
+                       r = nfc_hci_set_param(hdev, ST21NFCA_RF_READER_F_GATE,
+                                             ST21NFCA_RF_READER_F_POL_REQ,
+                                             (u8 *) &pol_req, 4);
+                       if (r < 0)
+                               return r;
                }
 
                if ((ST21NFCA_RF_READER_14443_3_A_GATE & im_protocols) == 0) {
@@ -353,9 +384,104 @@ static int st21nfca_hci_start_poll(struct nfc_hci_dev *hdev,
                        nfc_hci_send_event(hdev, NFC_HCI_RF_READER_A_GATE,
                                           NFC_HCI_EVT_END_OPERATION, NULL, 0);
        }
+
+       if (tm_protocols & NFC_PROTO_NFC_DEP_MASK) {
+               r = nfc_hci_get_param(hdev, ST21NFCA_RF_CARD_F_GATE,
+                                     ST21NFCA_RF_CARD_F_DATARATE,
+                                     &datarate_skb);
+               if (r < 0)
+                       return r;
+
+               /* Configure the maximum supported datarate to 424Kbps */
+               if (datarate_skb->len > 0 &&
+                   datarate_skb->data[0] !=
+                   ST21NFCA_RF_CARD_F_DATARATE_212_424) {
+                       param[0] = ST21NFCA_RF_CARD_F_DATARATE_212_424;
+                       r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
+                                             ST21NFCA_RF_CARD_F_DATARATE,
+                                             param, 1);
+                       if (r < 0)
+                               return r;
+               }
+
+               /*
+                * Configure sens_res
+                *
+                * NFC Forum Digital Spec Table 7:
+                * NFCID1 size: triple (10 bytes)
+                */
+               param[0] = 0x00;
+               param[1] = 0x08;
+               r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
+                                     ST21NFCA_RF_CARD_F_SENS_RES, param, 2);
+               if (r < 0)
+                       return r;
+
+               /*
+                * Configure sel_res
+                *
+                * NFC Forum Digistal Spec Table 17:
+                * b3 set to 0b (value b7-b6):
+                * - 10b: Configured for NFC-DEP Protocol
+                */
+               param[0] = 0x40;
+               r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
+                                     ST21NFCA_RF_CARD_F_SEL_RES, param, 1);
+               if (r < 0)
+                       return r;
+
+               /* Configure NFCID1 Random uid */
+               r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
+                                     ST21NFCA_RF_CARD_F_NFCID1, NULL, 0);
+               if (r < 0)
+                       return r;
+
+               /* Configure NFCID2_LIST */
+               /* System Code */
+               param[0] = 0x00;
+               param[1] = 0x00;
+               /* NFCID2 */
+               param[2] = 0x01;
+               param[3] = 0xfe;
+               param[4] = 'S';
+               param[5] = 'T';
+               param[6] = 'M';
+               param[7] = 'i';
+               param[8] = 'c';
+               param[9] = 'r';
+               /* 8 byte Pad bytes used for polling respone frame */
+
+               /*
+                * Configuration byte:
+                * - bit 0: define the default NFCID2 entry used when the
+                * system code is equal to 'FFFF'
+                * - bit 1: use a random value for lowest 6 bytes of
+                * NFCID2 value
+                * - bit 2: ignore polling request frame if request code
+                * is equal to '01'
+                * - Other bits are RFU
+                */
+               param[18] = 0x01;
+               r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
+                                     ST21NFCA_RF_CARD_F_NFCID2_LIST, param,
+                                     19);
+               if (r < 0)
+                       return r;
+
+               param[0] = 0x02;
+               r = nfc_hci_set_param(hdev, ST21NFCA_RF_CARD_F_GATE,
+                                     ST21NFCA_RF_CARD_F_MODE, param, 1);
+       }
+
        return r;
 }
 
+static void st21nfca_hci_stop_poll(struct nfc_hci_dev *hdev)
+{
+       nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
+                       ST21NFCA_DM_DISCONNECT, NULL, 0, NULL);
+}
+
 static int st21nfca_get_iso14443_3_atqa(struct nfc_hci_dev *hdev, u16 *atqa)
 {
        int r;
@@ -451,6 +577,26 @@ exit:
        return r;
 }
 
+static int st21nfca_hci_dep_link_up(struct nfc_hci_dev *hdev,
+                                   struct nfc_target *target, u8 comm_mode,
+                                   u8 *gb, size_t gb_len)
+{
+       struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+       info->dep_info.idx = target->idx;
+       return st21nfca_im_send_atr_req(hdev, gb, gb_len);
+}
+
+static int st21nfca_hci_dep_link_down(struct nfc_hci_dev *hdev)
+{
+       struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+       info->state = ST21NFCA_ST_READY;
+
+       return nfc_hci_send_cmd(hdev, ST21NFCA_DEVICE_MGNT_GATE,
+                               ST21NFCA_DM_DISCONNECT, NULL, 0, NULL);
+}
+
 static int st21nfca_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
                                         struct nfc_target *target)
 {
@@ -505,6 +651,69 @@ static int st21nfca_hci_target_from_gate(struct nfc_hci_dev *hdev, u8 gate,
        return 0;
 }
 
+static int st21nfca_hci_complete_target_discovered(struct nfc_hci_dev *hdev,
+                                               u8 gate,
+                                               struct nfc_target *target)
+{
+       int r;
+       struct sk_buff *nfcid2_skb = NULL, *nfcid1_skb;
+
+       if (gate == ST21NFCA_RF_READER_F_GATE) {
+               r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE,
+                               ST21NFCA_RF_READER_F_NFCID2, &nfcid2_skb);
+               if (r < 0)
+                       goto exit;
+
+               if (nfcid2_skb->len > NFC_SENSF_RES_MAXSIZE) {
+                       r = -EPROTO;
+                       goto exit;
+               }
+
+               /*
+                * - After the recepton of polling response for type F frame
+                * at 212 or 424 Kbit/s, NFCID2 registry parameters will be
+                * updated.
+                * - After the reception of SEL_RES with NFCIP-1 compliant bit
+                * set for type A frame NFCID1 will be updated
+                */
+               if (nfcid2_skb->len > 0) {
+                       /* P2P in type F */
+                       memcpy(target->sensf_res, nfcid2_skb->data,
+                               nfcid2_skb->len);
+                       target->sensf_res_len = nfcid2_skb->len;
+                       /* NFC Forum Digital Protocol Table 44 */
+                       if (target->sensf_res[0] == 0x01 &&
+                           target->sensf_res[1] == 0xfe)
+                               target->supported_protocols =
+                                                       NFC_PROTO_NFC_DEP_MASK;
+                       else
+                               target->supported_protocols =
+                                                       NFC_PROTO_FELICA_MASK;
+               } else {
+                       /* P2P in type A */
+                       r = nfc_hci_get_param(hdev, ST21NFCA_RF_READER_F_GATE,
+                                       ST21NFCA_RF_READER_F_NFCID1,
+                                       &nfcid1_skb);
+                       if (r < 0)
+                               goto exit;
+
+                       if (nfcid1_skb->len > NFC_NFCID1_MAXSIZE) {
+                               r = -EPROTO;
+                               goto exit;
+                       }
+                       memcpy(target->sensf_res, nfcid1_skb->data,
+                               nfcid1_skb->len);
+                       target->sensf_res_len = nfcid1_skb->len;
+                       target->supported_protocols = NFC_PROTO_NFC_DEP_MASK;
+               }
+               target->hci_reader_gate = ST21NFCA_RF_READER_F_GATE;
+       }
+       r = 1;
+exit:
+       kfree_skb(nfcid2_skb);
+       return r;
+}
+
 #define ST21NFCA_CB_TYPE_READER_ISO15693 1
 static void st21nfca_hci_data_exchange_cb(void *context, struct sk_buff *skb,
                                          int err)
@@ -541,6 +750,9 @@ static int st21nfca_hci_im_transceive(struct nfc_hci_dev *hdev,
 
        switch (target->hci_reader_gate) {
        case ST21NFCA_RF_READER_F_GATE:
+               if (target->supported_protocols == NFC_PROTO_NFC_DEP_MASK)
+                       return st21nfca_im_send_dep_req(hdev, skb);
+
                *skb_push(skb, 1) = 0x1a;
                return nfc_hci_send_cmd_async(hdev, target->hci_reader_gate,
                                              ST21NFCA_WR_XCHG_DATA, skb->data,
@@ -569,6 +781,11 @@ static int st21nfca_hci_im_transceive(struct nfc_hci_dev *hdev,
        }
 }
 
+static int st21nfca_hci_tm_send(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+{
+       return st21nfca_tm_send_dep_res(hdev, skb);
+}
+
 static int st21nfca_hci_check_presence(struct nfc_hci_dev *hdev,
                                       struct nfc_target *target)
 {
@@ -594,6 +811,50 @@ static int st21nfca_hci_check_presence(struct nfc_hci_dev *hdev,
        }
 }
 
+/*
+ * Returns:
+ * <= 0: driver handled the event, skb consumed
+ *    1: driver does not handle the event, please do standard processing
+ */
+static int st21nfca_hci_event_received(struct nfc_hci_dev *hdev, u8 gate,
+                                      u8 event, struct sk_buff *skb)
+{
+       int r;
+       struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+       pr_debug("hci event: %d\n", event);
+
+       switch (event) {
+       case ST21NFCA_EVT_CARD_ACTIVATED:
+               if (gate == ST21NFCA_RF_CARD_F_GATE)
+                       info->dep_info.curr_nfc_dep_pni = 0;
+               break;
+       case ST21NFCA_EVT_CARD_DEACTIVATED:
+               break;
+       case ST21NFCA_EVT_FIELD_ON:
+               break;
+       case ST21NFCA_EVT_FIELD_OFF:
+               break;
+       case ST21NFCA_EVT_SEND_DATA:
+               if (gate == ST21NFCA_RF_CARD_F_GATE) {
+                       r = st21nfca_tm_event_send_data(hdev, skb, gate);
+                       if (r < 0)
+                               goto exit;
+                       return 0;
+               } else {
+                       info->dep_info.curr_nfc_dep_pni = 0;
+                       return 1;
+               }
+               break;
+       default:
+               return 1;
+       }
+       kfree_skb(skb);
+       return 0;
+exit:
+       return r;
+}
+
 static struct nfc_hci_ops st21nfca_hci_ops = {
        .open = st21nfca_hci_open,
        .close = st21nfca_hci_close,
@@ -601,9 +862,15 @@ static struct nfc_hci_ops st21nfca_hci_ops = {
        .hci_ready = st21nfca_hci_ready,
        .xmit = st21nfca_hci_xmit,
        .start_poll = st21nfca_hci_start_poll,
+       .stop_poll = st21nfca_hci_stop_poll,
+       .dep_link_up = st21nfca_hci_dep_link_up,
+       .dep_link_down = st21nfca_hci_dep_link_down,
        .target_from_gate = st21nfca_hci_target_from_gate,
+       .complete_target_discovered = st21nfca_hci_complete_target_discovered,
        .im_transceive = st21nfca_hci_im_transceive,
+       .tm_send = st21nfca_hci_tm_send,
        .check_presence = st21nfca_hci_check_presence,
+       .event_received = st21nfca_hci_event_received,
 };
 
 int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
@@ -648,7 +915,8 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
            NFC_PROTO_FELICA_MASK |
            NFC_PROTO_ISO14443_MASK |
            NFC_PROTO_ISO14443_B_MASK |
-           NFC_PROTO_ISO15693_MASK;
+           NFC_PROTO_ISO15693_MASK |
+           NFC_PROTO_NFC_DEP_MASK;
 
        set_bit(NFC_HCI_QUIRK_SHORT_CLEAR, &quirks);
 
@@ -671,6 +939,7 @@ int st21nfca_hci_probe(void *phy_id, struct nfc_phy_ops *phy_ops,
                goto err_regdev;
 
        *hdev = info->hdev;
+       st21nfca_dep_init(info->hdev);
 
        return 0;
 
@@ -688,6 +957,7 @@ void st21nfca_hci_remove(struct nfc_hci_dev *hdev)
 {
        struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
 
+       st21nfca_dep_deinit(hdev);
        nfc_hci_unregister_device(hdev);
        nfc_hci_free_device(hdev);
        kfree(info);
index 334cd90bcc8c3ec5e29c624f8d7b0b1ac61de728..96fe5a62dc0dced5dd7ed41ee2f33496e1a1d61e 100644 (file)
@@ -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_ */
diff --git a/drivers/nfc/st21nfca/st21nfca_dep.c b/drivers/nfc/st21nfca/st21nfca_dep.c
new file mode 100644 (file)
index 0000000..b2d9957
--- /dev/null
@@ -0,0 +1,661 @@
+/*
+ * 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_dep.h"
+
+#define ST21NFCA_NFCIP1_INITIATOR 0x00
+#define ST21NFCA_NFCIP1_REQ 0xd4
+#define ST21NFCA_NFCIP1_RES 0xd5
+#define ST21NFCA_NFCIP1_ATR_REQ 0x00
+#define ST21NFCA_NFCIP1_ATR_RES 0x01
+#define ST21NFCA_NFCIP1_PSL_REQ 0x04
+#define ST21NFCA_NFCIP1_PSL_RES 0x05
+#define ST21NFCA_NFCIP1_DEP_REQ 0x06
+#define ST21NFCA_NFCIP1_DEP_RES 0x07
+
+#define ST21NFCA_NFC_DEP_PFB_PNI(pfb)     ((pfb) & 0x03)
+#define ST21NFCA_NFC_DEP_PFB_TYPE(pfb) ((pfb) & 0xE0)
+#define ST21NFCA_NFC_DEP_PFB_IS_TIMEOUT(pfb) \
+                               ((pfb) & ST21NFCA_NFC_DEP_PFB_TIMEOUT_BIT)
+#define ST21NFCA_NFC_DEP_DID_BIT_SET(pfb) ((pfb) & 0x04)
+#define ST21NFCA_NFC_DEP_NAD_BIT_SET(pfb) ((pfb) & 0x08)
+#define ST21NFCA_NFC_DEP_PFB_TIMEOUT_BIT 0x10
+
+#define ST21NFCA_NFC_DEP_PFB_IS_TIMEOUT(pfb) \
+                               ((pfb) & ST21NFCA_NFC_DEP_PFB_TIMEOUT_BIT)
+
+#define ST21NFCA_NFC_DEP_PFB_I_PDU          0x00
+#define ST21NFCA_NFC_DEP_PFB_ACK_NACK_PDU   0x40
+#define ST21NFCA_NFC_DEP_PFB_SUPERVISOR_PDU 0x80
+
+#define ST21NFCA_ATR_REQ_MIN_SIZE 17
+#define ST21NFCA_ATR_REQ_MAX_SIZE 65
+#define ST21NFCA_LR_BITS_PAYLOAD_SIZE_254B 0x30
+#define ST21NFCA_GB_BIT  0x02
+
+#define ST21NFCA_EVT_CARD_F_BITRATE 0x16
+#define ST21NFCA_EVT_READER_F_BITRATE 0x13
+#define        ST21NFCA_PSL_REQ_SEND_SPEED(brs) (brs & 0x38)
+#define ST21NFCA_PSL_REQ_RECV_SPEED(brs) (brs & 0x07)
+#define ST21NFCA_PP2LRI(pp) ((pp & 0x30) >> 4)
+#define ST21NFCA_CARD_BITRATE_212 0x01
+#define ST21NFCA_CARD_BITRATE_424 0x02
+
+#define ST21NFCA_DEFAULT_TIMEOUT 0x0a
+
+
+#define PROTOCOL_ERR(req) pr_err("%d: ST21NFCA Protocol error: %s\n", \
+                                __LINE__, req)
+
+struct st21nfca_atr_req {
+       u8 length;
+       u8 cmd0;
+       u8 cmd1;
+       u8 nfcid3[NFC_NFCID3_MAXSIZE];
+       u8 did;
+       u8 bsi;
+       u8 bri;
+       u8 ppi;
+       u8 gbi[0];
+} __packed;
+
+struct st21nfca_atr_res {
+       u8 length;
+       u8 cmd0;
+       u8 cmd1;
+       u8 nfcid3[NFC_NFCID3_MAXSIZE];
+       u8 did;
+       u8 bsi;
+       u8 bri;
+       u8 to;
+       u8 ppi;
+       u8 gbi[0];
+} __packed;
+
+struct st21nfca_psl_req {
+       u8 length;
+       u8 cmd0;
+       u8 cmd1;
+       u8 did;
+       u8 brs;
+       u8 fsl;
+} __packed;
+
+struct st21nfca_psl_res {
+       u8 length;
+       u8 cmd0;
+       u8 cmd1;
+       u8 did;
+} __packed;
+
+struct st21nfca_dep_req_res {
+       u8 length;
+       u8 cmd0;
+       u8 cmd1;
+       u8 pfb;
+       u8 did;
+       u8 nad;
+} __packed;
+
+static void st21nfca_tx_work(struct work_struct *work)
+{
+       struct st21nfca_hci_info *info = container_of(work,
+                                               struct st21nfca_hci_info,
+                                               dep_info.tx_work);
+
+       struct nfc_dev *dev;
+       struct sk_buff *skb;
+       if (info) {
+               dev = info->hdev->ndev;
+               skb = info->dep_info.tx_pending;
+
+               device_lock(&dev->dev);
+
+               nfc_hci_send_cmd_async(info->hdev, ST21NFCA_RF_READER_F_GATE,
+                                                       ST21NFCA_WR_XCHG_DATA,
+                                                       skb->data, skb->len,
+                                                       info->async_cb, info);
+               device_unlock(&dev->dev);
+               kfree_skb(skb);
+       }
+}
+
+static void st21nfca_im_send_pdu(struct st21nfca_hci_info *info,
+                                               struct sk_buff *skb)
+{
+       info->dep_info.tx_pending = skb;
+       schedule_work(&info->dep_info.tx_work);
+}
+
+static int st21nfca_tm_send_atr_res(struct nfc_hci_dev *hdev,
+                                   struct st21nfca_atr_req *atr_req)
+{
+       struct st21nfca_atr_res *atr_res;
+       struct sk_buff *skb;
+       size_t gb_len;
+       int r;
+       struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+       gb_len = atr_req->length - sizeof(struct st21nfca_atr_req);
+       skb = alloc_skb(atr_req->length + 1, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       skb_put(skb, sizeof(struct st21nfca_atr_res));
+
+       atr_res = (struct st21nfca_atr_res *)skb->data;
+       memset(atr_res, 0, sizeof(struct st21nfca_atr_res));
+
+       atr_res->length = atr_req->length + 1;
+       atr_res->cmd0 = ST21NFCA_NFCIP1_RES;
+       atr_res->cmd1 = ST21NFCA_NFCIP1_ATR_RES;
+
+       memcpy(atr_res->nfcid3, atr_req->nfcid3, 6);
+       atr_res->bsi = 0x00;
+       atr_res->bri = 0x00;
+       atr_res->to = ST21NFCA_DEFAULT_TIMEOUT;
+       atr_res->ppi = ST21NFCA_LR_BITS_PAYLOAD_SIZE_254B;
+
+       if (gb_len) {
+               skb_put(skb, gb_len);
+
+               atr_res->ppi |= ST21NFCA_GB_BIT;
+               memcpy(atr_res->gbi, atr_req->gbi, gb_len);
+               r = nfc_set_remote_general_bytes(hdev->ndev, atr_res->gbi,
+                                                 gb_len);
+               if (r < 0)
+                       return r;
+       }
+
+       info->dep_info.curr_nfc_dep_pni = 0;
+
+       return nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE,
+                               ST21NFCA_EVT_SEND_DATA, skb->data, skb->len);
+}
+
+static int st21nfca_tm_recv_atr_req(struct nfc_hci_dev *hdev,
+                                   struct sk_buff *skb)
+{
+       struct st21nfca_atr_req *atr_req;
+       size_t gb_len;
+       int r;
+
+       skb_trim(skb, skb->len - 1);
+       if (IS_ERR(skb)) {
+               r = PTR_ERR(skb);
+               goto exit;
+       }
+
+       if (!skb->len) {
+               r = -EIO;
+               goto exit;
+       }
+
+       if (skb->len < ST21NFCA_ATR_REQ_MIN_SIZE) {
+               r = -EPROTO;
+               goto exit;
+       }
+
+       atr_req = (struct st21nfca_atr_req *)skb->data;
+
+       r = st21nfca_tm_send_atr_res(hdev, atr_req);
+       if (r)
+               goto exit;
+
+       gb_len = skb->len - sizeof(struct st21nfca_atr_req);
+
+       r = nfc_tm_activated(hdev->ndev, NFC_PROTO_NFC_DEP_MASK,
+                             NFC_COMM_PASSIVE, atr_req->gbi, gb_len);
+       if (r)
+               goto exit;
+
+       r = 0;
+
+exit:
+       return r;
+}
+
+static int st21nfca_tm_send_psl_res(struct nfc_hci_dev *hdev,
+                                   struct st21nfca_psl_req *psl_req)
+{
+       struct st21nfca_psl_res *psl_res;
+       struct sk_buff *skb;
+       u8 bitrate[2] = {0, 0};
+
+       int r;
+
+       skb = alloc_skb(sizeof(struct st21nfca_psl_res), GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+       skb_put(skb, sizeof(struct st21nfca_psl_res));
+
+       psl_res = (struct st21nfca_psl_res *)skb->data;
+
+       psl_res->length = sizeof(struct st21nfca_psl_res);
+       psl_res->cmd0 = ST21NFCA_NFCIP1_RES;
+       psl_res->cmd1 = ST21NFCA_NFCIP1_PSL_RES;
+       psl_res->did = psl_req->did;
+
+       r = nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE,
+                               ST21NFCA_EVT_SEND_DATA, skb->data, skb->len);
+
+       /*
+        * ST21NFCA only support P2P passive.
+        * PSL_REQ BRS value != 0 has only a meaning to
+        * change technology to type F.
+        * We change to BITRATE 424Kbits.
+        * In other case switch to BITRATE 106Kbits.
+        */
+       if (ST21NFCA_PSL_REQ_SEND_SPEED(psl_req->brs) &&
+           ST21NFCA_PSL_REQ_RECV_SPEED(psl_req->brs)) {
+               bitrate[0] = ST21NFCA_CARD_BITRATE_424;
+               bitrate[1] = ST21NFCA_CARD_BITRATE_424;
+       }
+
+       /* Send an event to change bitrate change event to card f */
+       return nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE,
+                       ST21NFCA_EVT_CARD_F_BITRATE, bitrate, 2);
+}
+
+static int st21nfca_tm_recv_psl_req(struct nfc_hci_dev *hdev,
+                                   struct sk_buff *skb)
+{
+       struct st21nfca_psl_req *psl_req;
+       int r;
+
+       skb_trim(skb, skb->len - 1);
+       if (IS_ERR(skb)) {
+               r = PTR_ERR(skb);
+               skb = NULL;
+               goto exit;
+       }
+
+       if (!skb->len) {
+               r = -EIO;
+               goto exit;
+       }
+
+       psl_req = (struct st21nfca_psl_req *)skb->data;
+
+       if (skb->len < sizeof(struct st21nfca_psl_req)) {
+               r = -EIO;
+               goto exit;
+       }
+
+       r = st21nfca_tm_send_psl_res(hdev, psl_req);
+exit:
+       return r;
+}
+
+int st21nfca_tm_send_dep_res(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+{
+       int r;
+       struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+       *skb_push(skb, 1) = info->dep_info.curr_nfc_dep_pni;
+       *skb_push(skb, 1) = ST21NFCA_NFCIP1_DEP_RES;
+       *skb_push(skb, 1) = ST21NFCA_NFCIP1_RES;
+       *skb_push(skb, 1) = skb->len;
+
+       r = nfc_hci_send_event(hdev, ST21NFCA_RF_CARD_F_GATE,
+                               ST21NFCA_EVT_SEND_DATA, skb->data, skb->len);
+       kfree_skb(skb);
+
+       return r;
+}
+EXPORT_SYMBOL(st21nfca_tm_send_dep_res);
+
+static int st21nfca_tm_recv_dep_req(struct nfc_hci_dev *hdev,
+                                   struct sk_buff *skb)
+{
+       struct st21nfca_dep_req_res *dep_req;
+       u8 size;
+       int r;
+       struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+       skb_trim(skb, skb->len - 1);
+       if (IS_ERR(skb)) {
+               r = PTR_ERR(skb);
+               skb = NULL;
+               goto exit;
+       }
+
+       size = 4;
+
+       dep_req = (struct st21nfca_dep_req_res *)skb->data;
+       if (skb->len < size) {
+               r = -EIO;
+               goto exit;
+       }
+
+       if (ST21NFCA_NFC_DEP_DID_BIT_SET(dep_req->pfb))
+               size++;
+       if (ST21NFCA_NFC_DEP_NAD_BIT_SET(dep_req->pfb))
+               size++;
+
+       if (skb->len < size) {
+               r = -EIO;
+               goto exit;
+       }
+
+       /* Receiving DEP_REQ - Decoding */
+       switch (ST21NFCA_NFC_DEP_PFB_TYPE(dep_req->pfb)) {
+       case ST21NFCA_NFC_DEP_PFB_I_PDU:
+               info->dep_info.curr_nfc_dep_pni =
+                               ST21NFCA_NFC_DEP_PFB_PNI(dep_req->pfb);
+               break;
+       case ST21NFCA_NFC_DEP_PFB_ACK_NACK_PDU:
+               pr_err("Received a ACK/NACK PDU\n");
+               break;
+       case ST21NFCA_NFC_DEP_PFB_SUPERVISOR_PDU:
+               pr_err("Received a SUPERVISOR PDU\n");
+               break;
+       }
+
+       if (IS_ERR(skb)) {
+               r = PTR_ERR(skb);
+               skb = NULL;
+               goto exit;
+       }
+
+       skb_pull(skb, size);
+
+       return nfc_tm_data_received(hdev->ndev, skb);
+exit:
+       return r;
+}
+
+int st21nfca_tm_event_send_data(struct nfc_hci_dev *hdev, struct sk_buff *skb,
+                               u8 gate)
+{
+       u8 cmd0, cmd1;
+       int r;
+
+       cmd0 = skb->data[1];
+       switch (cmd0) {
+       case ST21NFCA_NFCIP1_REQ:
+               cmd1 = skb->data[2];
+               switch (cmd1) {
+               case ST21NFCA_NFCIP1_ATR_REQ:
+                       r = st21nfca_tm_recv_atr_req(hdev, skb);
+                       break;
+               case ST21NFCA_NFCIP1_PSL_REQ:
+                       r = st21nfca_tm_recv_psl_req(hdev, skb);
+                       break;
+               case ST21NFCA_NFCIP1_DEP_REQ:
+                       r = st21nfca_tm_recv_dep_req(hdev, skb);
+                       break;
+               default:
+                       return 1;
+               }
+       default:
+               return 1;
+       }
+       return r;
+}
+EXPORT_SYMBOL(st21nfca_tm_event_send_data);
+
+static void st21nfca_im_send_psl_req(struct nfc_hci_dev *hdev, u8 did, u8 bsi,
+                                    u8 bri, u8 lri)
+{
+       struct sk_buff *skb;
+       struct st21nfca_psl_req *psl_req;
+       struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+       skb =
+           alloc_skb(sizeof(struct st21nfca_psl_req) + 1, GFP_KERNEL);
+       if (!skb)
+               return;
+       skb_reserve(skb, 1);
+
+       skb_put(skb, sizeof(struct st21nfca_psl_req));
+       psl_req = (struct st21nfca_psl_req *) skb->data;
+
+       psl_req->length = sizeof(struct st21nfca_psl_req);
+       psl_req->cmd0 = ST21NFCA_NFCIP1_REQ;
+       psl_req->cmd1 = ST21NFCA_NFCIP1_PSL_REQ;
+       psl_req->did = did;
+       psl_req->brs = (0x30 & bsi << 4) | (bri & 0x03);
+       psl_req->fsl = lri;
+
+       *skb_push(skb, 1) = info->dep_info.to | 0x10;
+
+       st21nfca_im_send_pdu(info, skb);
+
+       kfree_skb(skb);
+}
+
+#define ST21NFCA_CB_TYPE_READER_F 1
+static void st21nfca_im_recv_atr_res_cb(void *context, struct sk_buff *skb,
+                                       int err)
+{
+       struct st21nfca_hci_info *info = context;
+       struct st21nfca_atr_res *atr_res;
+       int r;
+
+       if (err != 0)
+               return;
+
+       if (IS_ERR(skb))
+               return;
+
+       switch (info->async_cb_type) {
+       case ST21NFCA_CB_TYPE_READER_F:
+               skb_trim(skb, skb->len - 1);
+               atr_res = (struct st21nfca_atr_res *)skb->data;
+               r = nfc_set_remote_general_bytes(info->hdev->ndev,
+                               atr_res->gbi,
+                               skb->len - sizeof(struct st21nfca_atr_res));
+               if (r < 0)
+                       return;
+
+               if (atr_res->to >= 0x0e)
+                       info->dep_info.to = 0x0e;
+               else
+                       info->dep_info.to = atr_res->to + 1;
+
+               info->dep_info.to |= 0x10;
+
+               r = nfc_dep_link_is_up(info->hdev->ndev, info->dep_info.idx,
+                                       NFC_COMM_PASSIVE, NFC_RF_INITIATOR);
+               if (r < 0)
+                       return;
+
+               info->dep_info.curr_nfc_dep_pni = 0;
+               if (ST21NFCA_PP2LRI(atr_res->ppi) != info->dep_info.lri)
+                       st21nfca_im_send_psl_req(info->hdev, atr_res->did,
+                                               atr_res->bsi, atr_res->bri,
+                                               ST21NFCA_PP2LRI(atr_res->ppi));
+               break;
+       default:
+               if (err == 0)
+                       kfree_skb(skb);
+               break;
+       }
+}
+
+int st21nfca_im_send_atr_req(struct nfc_hci_dev *hdev, u8 *gb, size_t gb_len)
+{
+       struct sk_buff *skb;
+       struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+       struct st21nfca_atr_req *atr_req;
+       struct nfc_target *target;
+       uint size;
+
+       info->dep_info.to = ST21NFCA_DEFAULT_TIMEOUT;
+       size = ST21NFCA_ATR_REQ_MIN_SIZE + gb_len;
+       if (size > ST21NFCA_ATR_REQ_MAX_SIZE) {
+               PROTOCOL_ERR("14.6.1.1");
+               return -EINVAL;
+       }
+
+       skb =
+           alloc_skb(sizeof(struct st21nfca_atr_req) + gb_len + 1, GFP_KERNEL);
+       if (!skb)
+               return -ENOMEM;
+
+       skb_reserve(skb, 1);
+
+       skb_put(skb, sizeof(struct st21nfca_atr_req));
+
+       atr_req = (struct st21nfca_atr_req *)skb->data;
+       memset(atr_req, 0, sizeof(struct st21nfca_atr_req));
+
+       atr_req->cmd0 = ST21NFCA_NFCIP1_REQ;
+       atr_req->cmd1 = ST21NFCA_NFCIP1_ATR_REQ;
+       memset(atr_req->nfcid3, 0, NFC_NFCID3_MAXSIZE);
+       target = hdev->ndev->targets;
+
+       if (target->sensf_res)
+               memcpy(atr_req->nfcid3, target->sensf_res,
+                               target->sensf_res_len);
+       else
+               get_random_bytes(atr_req->nfcid3, NFC_NFCID3_MAXSIZE);
+
+       atr_req->did = 0x0;
+
+       atr_req->bsi = 0x00;
+       atr_req->bri = 0x00;
+       atr_req->ppi = ST21NFCA_LR_BITS_PAYLOAD_SIZE_254B;
+       if (gb_len) {
+               atr_req->ppi |= ST21NFCA_GB_BIT;
+               memcpy(skb_put(skb, gb_len), gb, gb_len);
+       }
+       atr_req->length = sizeof(struct st21nfca_atr_req) + hdev->gb_len;
+
+       *skb_push(skb, 1) = info->dep_info.to | 0x10; /* timeout */
+
+       info->async_cb_type = ST21NFCA_CB_TYPE_READER_F;
+       info->async_cb_context = info;
+       info->async_cb = st21nfca_im_recv_atr_res_cb;
+       info->dep_info.bri = atr_req->bri;
+       info->dep_info.bsi = atr_req->bsi;
+       info->dep_info.lri = ST21NFCA_PP2LRI(atr_req->ppi);
+
+       return nfc_hci_send_cmd_async(hdev, ST21NFCA_RF_READER_F_GATE,
+                               ST21NFCA_WR_XCHG_DATA, skb->data,
+                               skb->len, info->async_cb, info);
+}
+EXPORT_SYMBOL(st21nfca_im_send_atr_req);
+
+static void st21nfca_im_recv_dep_res_cb(void *context, struct sk_buff *skb,
+                                       int err)
+{
+       struct st21nfca_hci_info *info = context;
+       struct st21nfca_dep_req_res *dep_res;
+
+       int size;
+
+       if (err != 0)
+               return;
+
+       if (IS_ERR(skb))
+               return;
+
+       switch (info->async_cb_type) {
+       case ST21NFCA_CB_TYPE_READER_F:
+               dep_res = (struct st21nfca_dep_req_res *)skb->data;
+
+               size = 3;
+               if (skb->len < size)
+                       goto exit;
+
+               if (ST21NFCA_NFC_DEP_DID_BIT_SET(dep_res->pfb))
+                       size++;
+               if (ST21NFCA_NFC_DEP_NAD_BIT_SET(dep_res->pfb))
+                       size++;
+
+               if (skb->len < size)
+                       goto exit;
+
+               skb_trim(skb, skb->len - 1);
+
+               /* Receiving DEP_REQ - Decoding */
+               switch (ST21NFCA_NFC_DEP_PFB_TYPE(dep_res->pfb)) {
+               case ST21NFCA_NFC_DEP_PFB_ACK_NACK_PDU:
+                       pr_err("Received a ACK/NACK PDU\n");
+               case ST21NFCA_NFC_DEP_PFB_I_PDU:
+                       info->dep_info.curr_nfc_dep_pni =
+                           ST21NFCA_NFC_DEP_PFB_PNI(dep_res->pfb + 1);
+                       size++;
+                       skb_pull(skb, size);
+                       nfc_tm_data_received(info->hdev->ndev, skb);
+                       break;
+               case ST21NFCA_NFC_DEP_PFB_SUPERVISOR_PDU:
+                       pr_err("Received a SUPERVISOR PDU\n");
+                       skb_pull(skb, size);
+                       *skb_push(skb, 1) = ST21NFCA_NFCIP1_DEP_REQ;
+                       *skb_push(skb, 1) = ST21NFCA_NFCIP1_REQ;
+                       *skb_push(skb, 1) = skb->len;
+                       *skb_push(skb, 1) = info->dep_info.to | 0x10;
+
+                       st21nfca_im_send_pdu(info, skb);
+                       break;
+               }
+
+               return;
+       default:
+               break;
+       }
+
+exit:
+       if (err == 0)
+               kfree_skb(skb);
+}
+
+int st21nfca_im_send_dep_req(struct nfc_hci_dev *hdev, struct sk_buff *skb)
+{
+       struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+       info->async_cb_type = ST21NFCA_CB_TYPE_READER_F;
+       info->async_cb_context = info;
+       info->async_cb = st21nfca_im_recv_dep_res_cb;
+
+       *skb_push(skb, 1) = info->dep_info.curr_nfc_dep_pni;
+       *skb_push(skb, 1) = ST21NFCA_NFCIP1_DEP_REQ;
+       *skb_push(skb, 1) = ST21NFCA_NFCIP1_REQ;
+       *skb_push(skb, 1) = skb->len;
+
+       *skb_push(skb, 1) = info->dep_info.to | 0x10;
+
+       return nfc_hci_send_cmd_async(hdev, ST21NFCA_RF_READER_F_GATE,
+                                     ST21NFCA_WR_XCHG_DATA,
+                                     skb->data, skb->len,
+                                     info->async_cb, info);
+}
+EXPORT_SYMBOL(st21nfca_im_send_dep_req);
+
+void st21nfca_dep_init(struct nfc_hci_dev *hdev)
+{
+       struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+       INIT_WORK(&info->dep_info.tx_work, st21nfca_tx_work);
+       info->dep_info.curr_nfc_dep_pni = 0;
+       info->dep_info.idx = 0;
+       info->dep_info.to = ST21NFCA_DEFAULT_TIMEOUT;
+}
+EXPORT_SYMBOL(st21nfca_dep_init);
+
+void st21nfca_dep_deinit(struct nfc_hci_dev *hdev)
+{
+       struct st21nfca_hci_info *info = nfc_hci_get_clientdata(hdev);
+
+       cancel_work_sync(&info->dep_info.tx_work);
+}
+EXPORT_SYMBOL(st21nfca_dep_deinit);
diff --git a/drivers/nfc/st21nfca/st21nfca_dep.h b/drivers/nfc/st21nfca/st21nfca_dep.h
new file mode 100644 (file)
index 0000000..ca213de
--- /dev/null
@@ -0,0 +1,43 @@
+/*
+ * 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 */
diff --git a/drivers/nfc/st21nfcb/Kconfig b/drivers/nfc/st21nfcb/Kconfig
new file mode 100644 (file)
index 0000000..e0322dd
--- /dev/null
@@ -0,0 +1,22 @@
+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.
diff --git a/drivers/nfc/st21nfcb/Makefile b/drivers/nfc/st21nfcb/Makefile
new file mode 100644 (file)
index 0000000..13d9f03
--- /dev/null
@@ -0,0 +1,8 @@
+#
+# 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
diff --git a/drivers/nfc/st21nfcb/i2c.c b/drivers/nfc/st21nfcb/i2c.c
new file mode 100644 (file)
index 0000000..8af880e
--- /dev/null
@@ -0,0 +1,462 @@
+/*
+ * I2C Link Layer for ST21NFCB NCI based Driver
+ * 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/>.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/crc-ccitt.h>
+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/gpio.h>
+#include <linux/of_irq.h>
+#include <linux/of_gpio.h>
+#include <linux/miscdevice.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/nfc.h>
+#include <linux/firmware.h>
+#include <linux/unaligned/access_ok.h>
+#include <linux/platform_data/st21nfcb.h>
+
+#include <net/nfc/nci.h>
+#include <net/nfc/llc.h>
+#include <net/nfc/nfc.h>
+
+#include "ndlc.h"
+
+#define DRIVER_DESC "NCI NFC driver for ST21NFCB"
+
+/* ndlc header */
+#define ST21NFCB_FRAME_HEADROOM        1
+#define ST21NFCB_FRAME_TAILROOM 0
+
+#define ST21NFCB_NCI_I2C_MIN_SIZE 4   /* PCB(1) + NCI Packet header(3) */
+#define ST21NFCB_NCI_I2C_MAX_SIZE 250 /* req 4.2.1 */
+
+#define ST21NFCB_NCI_I2C_DRIVER_NAME "st21nfcb_nci_i2c"
+
+static struct i2c_device_id st21nfcb_nci_i2c_id_table[] = {
+       {ST21NFCB_NCI_DRIVER_NAME, 0},
+       {}
+};
+MODULE_DEVICE_TABLE(i2c, st21nfcb_nci_i2c_id_table);
+
+struct st21nfcb_i2c_phy {
+       struct i2c_client *i2c_dev;
+       struct llt_ndlc *ndlc;
+
+       unsigned int gpio_irq;
+       unsigned int gpio_reset;
+       unsigned int irq_polarity;
+
+       int powered;
+
+       /*
+        * < 0 if hardware error occured (e.g. i2c err)
+        * and prevents normal operation.
+        */
+       int hard_fault;
+};
+
+#define I2C_DUMP_SKB(info, skb)                                        \
+do {                                                           \
+       pr_debug("%s:\n", info);                                \
+       print_hex_dump(KERN_DEBUG, "i2c: ", DUMP_PREFIX_OFFSET, \
+                      16, 1, (skb)->data, (skb)->len, 0);      \
+} while (0)
+
+static int st21nfcb_nci_i2c_enable(void *phy_id)
+{
+       struct st21nfcb_i2c_phy *phy = phy_id;
+
+       gpio_set_value(phy->gpio_reset, 0);
+       usleep_range(10000, 15000);
+       gpio_set_value(phy->gpio_reset, 1);
+       phy->powered = 1;
+       usleep_range(80000, 85000);
+
+       return 0;
+}
+
+static void st21nfcb_nci_i2c_disable(void *phy_id)
+{
+       struct st21nfcb_i2c_phy *phy = phy_id;
+
+       pr_info("\n");
+
+       phy->powered = 0;
+       /* reset chip in order to flush clf */
+       gpio_set_value(phy->gpio_reset, 0);
+       usleep_range(10000, 15000);
+       gpio_set_value(phy->gpio_reset, 1);
+}
+
+static void st21nfcb_nci_remove_header(struct sk_buff *skb)
+{
+       skb_pull(skb, ST21NFCB_FRAME_HEADROOM);
+}
+
+/*
+ * Writing a frame must not return the number of written bytes.
+ * It must return either zero for success, or <0 for error.
+ * In addition, it must not alter the skb
+ */
+static int st21nfcb_nci_i2c_write(void *phy_id, struct sk_buff *skb)
+{
+       int r = -1;
+       struct st21nfcb_i2c_phy *phy = phy_id;
+       struct i2c_client *client = phy->i2c_dev;
+
+       I2C_DUMP_SKB("st21nfcb_nci_i2c_write", skb);
+
+       if (phy->hard_fault != 0)
+               return phy->hard_fault;
+
+       r = i2c_master_send(client, skb->data, skb->len);
+       if (r == -EREMOTEIO) {  /* Retry, chip was in standby */
+               usleep_range(1000, 4000);
+               r = i2c_master_send(client, skb->data, skb->len);
+       }
+
+       if (r >= 0) {
+               if (r != skb->len)
+                       r = -EREMOTEIO;
+               else
+                       r = 0;
+       }
+
+       st21nfcb_nci_remove_header(skb);
+
+       return r;
+}
+
+/*
+ * Reads an ndlc frame and returns it in a newly allocated sk_buff.
+ * returns:
+ * frame size : if received frame is complete (find ST21NFCB_SOF_EOF at
+ * end of read)
+ * -EAGAIN : if received frame is incomplete (not find ST21NFCB_SOF_EOF
+ * at end of read)
+ * -EREMOTEIO : i2c read error (fatal)
+ * -EBADMSG : frame was incorrect and discarded
+ * (value returned from st21nfcb_nci_i2c_repack)
+ * -EIO : if no ST21NFCB_SOF_EOF is found after reaching
+ * the read length end sequence
+ */
+static int st21nfcb_nci_i2c_read(struct st21nfcb_i2c_phy *phy,
+                                struct sk_buff **skb)
+{
+       int r;
+       u8 len;
+       u8 buf[ST21NFCB_NCI_I2C_MAX_SIZE];
+       struct i2c_client *client = phy->i2c_dev;
+
+       r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE);
+       if (r == -EREMOTEIO) {  /* Retry, chip was in standby */
+               usleep_range(1000, 4000);
+               r = i2c_master_recv(client, buf, ST21NFCB_NCI_I2C_MIN_SIZE);
+       } else if (r != ST21NFCB_NCI_I2C_MIN_SIZE) {
+               nfc_err(&client->dev, "cannot read ndlc & nci header\n");
+               return -EREMOTEIO;
+       }
+
+       len = be16_to_cpu(*(__be16 *) (buf + 2));
+       if (len > ST21NFCB_NCI_I2C_MAX_SIZE) {
+               nfc_err(&client->dev, "invalid frame len\n");
+               return -EBADMSG;
+       }
+
+       *skb = alloc_skb(ST21NFCB_NCI_I2C_MIN_SIZE + len, GFP_KERNEL);
+       if (*skb == NULL)
+               return -ENOMEM;
+
+       skb_reserve(*skb, ST21NFCB_NCI_I2C_MIN_SIZE);
+       skb_put(*skb, ST21NFCB_NCI_I2C_MIN_SIZE);
+       memcpy((*skb)->data, buf, ST21NFCB_NCI_I2C_MIN_SIZE);
+
+       if (!len)
+               return 0;
+
+       r = i2c_master_recv(client, buf, len);
+       if (r != len) {
+               kfree_skb(*skb);
+               return -EREMOTEIO;
+       }
+
+       skb_put(*skb, len);
+       memcpy((*skb)->data + ST21NFCB_NCI_I2C_MIN_SIZE, buf, len);
+
+       I2C_DUMP_SKB("i2c frame read", *skb);
+
+       return 0;
+}
+
+/*
+ * Reads an ndlc frame from the chip.
+ *
+ * On ST21NFCB, IRQ goes in idle state when read starts.
+ */
+static irqreturn_t st21nfcb_nci_irq_thread_fn(int irq, void *phy_id)
+{
+       struct st21nfcb_i2c_phy *phy = phy_id;
+       struct i2c_client *client;
+       struct sk_buff *skb = NULL;
+       int r;
+
+       if (!phy || irq != phy->i2c_dev->irq) {
+               WARN_ON_ONCE(1);
+               return IRQ_NONE;
+       }
+
+       client = phy->i2c_dev;
+       dev_dbg(&client->dev, "IRQ\n");
+
+       if (phy->hard_fault)
+               return IRQ_HANDLED;
+
+       if (!phy->powered) {
+               st21nfcb_nci_i2c_disable(phy);
+               return IRQ_HANDLED;
+       }
+
+       r = st21nfcb_nci_i2c_read(phy, &skb);
+       if (r == -EREMOTEIO) {
+               phy->hard_fault = r;
+                ndlc_recv(phy->ndlc, NULL);
+               return IRQ_HANDLED;
+       } else if (r == -ENOMEM || r == -EBADMSG) {
+               return IRQ_HANDLED;
+       }
+
+       ndlc_recv(phy->ndlc, skb);
+
+       return IRQ_HANDLED;
+}
+
+static struct nfc_phy_ops i2c_phy_ops = {
+       .write = st21nfcb_nci_i2c_write,
+       .enable = st21nfcb_nci_i2c_enable,
+       .disable = st21nfcb_nci_i2c_disable,
+};
+
+#ifdef CONFIG_OF
+static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client)
+{
+       struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client);
+       struct device_node *pp;
+       int gpio;
+       int r;
+
+       pp = client->dev.of_node;
+       if (!pp)
+               return -ENODEV;
+
+       /* Get GPIO from device tree */
+       gpio = of_get_named_gpio(pp, "reset-gpios", 0);
+       if (gpio < 0) {
+               nfc_err(&client->dev,
+                       "Failed to retrieve reset-gpios from device tree\n");
+               return gpio;
+       }
+
+       /* GPIO request and configuration */
+       r = devm_gpio_request(&client->dev, gpio, "clf_reset");
+       if (r) {
+               nfc_err(&client->dev, "Failed to request reset pin\n");
+               return -ENODEV;
+       }
+
+       r = gpio_direction_output(gpio, 1);
+       if (r) {
+               nfc_err(&client->dev,
+                       "Failed to set reset pin direction as output\n");
+               return -ENODEV;
+       }
+       phy->gpio_reset = gpio;
+
+       /* IRQ */
+       r = irq_of_parse_and_map(pp, 0);
+       if (r < 0) {
+               nfc_err(&client->dev,
+                               "Unable to get irq, error: %d\n", r);
+               return r;
+       }
+
+       phy->irq_polarity = irq_get_trigger_type(r);
+       client->irq = r;
+
+       return 0;
+}
+#else
+static int st21nfcb_nci_i2c_of_request_resources(struct i2c_client *client)
+{
+       return -ENODEV;
+}
+#endif
+
+static int st21nfcb_nci_i2c_request_resources(struct i2c_client *client)
+{
+       struct st21nfcb_nfc_platform_data *pdata;
+       struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client);
+       int r;
+       int irq;
+
+       pdata = client->dev.platform_data;
+       if (pdata == NULL) {
+               nfc_err(&client->dev, "No platform data\n");
+               return -EINVAL;
+       }
+
+       /* store for later use */
+       phy->gpio_irq = pdata->gpio_irq;
+       phy->gpio_reset = pdata->gpio_reset;
+       phy->irq_polarity = pdata->irq_polarity;
+
+       r = devm_gpio_request(&client->dev, phy->gpio_irq, "wake_up");
+       if (r) {
+               pr_err("%s : gpio_request failed\n", __FILE__);
+               return -ENODEV;
+       }
+
+       r = gpio_direction_input(phy->gpio_irq);
+       if (r) {
+               pr_err("%s : gpio_direction_input failed\n", __FILE__);
+               return -ENODEV;
+       }
+
+       r = devm_gpio_request(&client->dev,
+                             phy->gpio_reset, "clf_reset");
+       if (r) {
+               pr_err("%s : reset gpio_request failed\n", __FILE__);
+               return -ENODEV;
+       }
+
+       r = gpio_direction_output(phy->gpio_reset, 1);
+       if (r) {
+               pr_err("%s : reset gpio_direction_output failed\n",
+                       __FILE__);
+               return -ENODEV;
+       }
+
+       /* IRQ */
+       irq = gpio_to_irq(phy->gpio_irq);
+       if (irq < 0) {
+               nfc_err(&client->dev,
+                       "Unable to get irq number for GPIO %d error %d\n",
+                       phy->gpio_irq, r);
+               return -ENODEV;
+       }
+       client->irq = irq;
+
+       return 0;
+}
+
+static int st21nfcb_nci_i2c_probe(struct i2c_client *client,
+                                 const struct i2c_device_id *id)
+{
+       struct st21nfcb_i2c_phy *phy;
+       struct st21nfcb_nfc_platform_data *pdata;
+       int r;
+
+       dev_dbg(&client->dev, "%s\n", __func__);
+       dev_dbg(&client->dev, "IRQ: %d\n", client->irq);
+
+       if (!i2c_check_functionality(client->adapter, I2C_FUNC_I2C)) {
+               nfc_err(&client->dev, "Need I2C_FUNC_I2C\n");
+               return -ENODEV;
+       }
+
+       phy = devm_kzalloc(&client->dev, sizeof(struct st21nfcb_i2c_phy),
+                          GFP_KERNEL);
+       if (!phy) {
+               nfc_err(&client->dev,
+                       "Cannot allocate memory for st21nfcb i2c phy.\n");
+               return -ENOMEM;
+       }
+
+       phy->i2c_dev = client;
+
+       i2c_set_clientdata(client, phy);
+
+       pdata = client->dev.platform_data;
+       if (!pdata && client->dev.of_node) {
+               r = st21nfcb_nci_i2c_of_request_resources(client);
+               if (r) {
+                       nfc_err(&client->dev, "No platform data\n");
+                       return r;
+               }
+       } else if (pdata) {
+               r = st21nfcb_nci_i2c_request_resources(client);
+               if (r) {
+                       nfc_err(&client->dev,
+                               "Cannot get platform resources\n");
+                       return r;
+               }
+       } else {
+               nfc_err(&client->dev,
+                       "st21nfcb platform resources not available\n");
+               return -ENODEV;
+       }
+
+       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) {
+               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);
+}
+
+static int st21nfcb_nci_i2c_remove(struct i2c_client *client)
+{
+       struct st21nfcb_i2c_phy *phy = i2c_get_clientdata(client);
+
+       dev_dbg(&client->dev, "%s\n", __func__);
+
+       ndlc_remove(phy->ndlc);
+
+       if (phy->powered)
+               st21nfcb_nci_i2c_disable(phy);
+
+       return 0;
+}
+
+static const struct of_device_id of_st21nfcb_i2c_match[] = {
+       { .compatible = "st,st21nfcb_i2c", },
+       {}
+};
+
+static struct i2c_driver st21nfcb_nci_i2c_driver = {
+       .driver = {
+               .owner = THIS_MODULE,
+               .name = ST21NFCB_NCI_I2C_DRIVER_NAME,
+               .owner = THIS_MODULE,
+               .of_match_table = of_match_ptr(of_st21nfcb_i2c_match),
+       },
+       .probe = st21nfcb_nci_i2c_probe,
+       .id_table = st21nfcb_nci_i2c_id_table,
+       .remove = st21nfcb_nci_i2c_remove,
+};
+
+module_i2c_driver(st21nfcb_nci_i2c_driver);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION(DRIVER_DESC);
diff --git a/drivers/nfc/st21nfcb/ndlc.c b/drivers/nfc/st21nfcb/ndlc.c
new file mode 100644 (file)
index 0000000..83c97c3
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * 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);
diff --git a/drivers/nfc/st21nfcb/ndlc.h b/drivers/nfc/st21nfcb/ndlc.h
new file mode 100644 (file)
index 0000000..c30a2f0
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * 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__ */
diff --git a/drivers/nfc/st21nfcb/st21nfcb.c b/drivers/nfc/st21nfcb/st21nfcb.c
new file mode 100644 (file)
index 0000000..4d95863
--- /dev/null
@@ -0,0 +1,129 @@
+/*
+ * 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);
diff --git a/drivers/nfc/st21nfcb/st21nfcb.h b/drivers/nfc/st21nfcb/st21nfcb.h
new file mode 100644 (file)
index 0000000..4bbbebb
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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_ */
diff --git a/include/linux/platform_data/st21nfcb.h b/include/linux/platform_data/st21nfcb.h
new file mode 100644 (file)
index 0000000..2d11f1f
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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_ */
index bdf55c3b7a19ee1756c528ba067d79cef7e89d57..d9a5cf7ac1c4750c8418ce867366089e1f133bdc 100644 (file)
@@ -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);
index 61286db54388b9d03b6a49b494d1492e7cfd8e5c..7ee8f4cc610bebecb119ce28566604e1cd6c3f3c 100644 (file)
@@ -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);
index f41177f58b30c483f95596bc3e9d5acf90b00512..c6ee2139fbc579bab35e8cc5bfb6f3b4994930d2 100644 (file)
@@ -1724,12 +1724,15 @@ void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
 {
        struct ieee80211_sub_if_data *sdata = sta->sdata;
        struct ieee80211_local *local = sdata->local;
-       struct rate_control_ref *ref = local->rate_ctrl;
+       struct rate_control_ref *ref = NULL;
        struct timespec uptime;
        u64 packets = 0;
        u32 thr = 0;
        int i, ac;
 
+       if (test_sta_flag(sta, WLAN_STA_RATE_CONTROL))
+               ref = local->rate_ctrl;
+
        sinfo->generation = sdata->local->sta_generation;
 
        sinfo->filled = STATION_INFO_INACTIVE_TIME |
index 865bdaf06ff16d8a94f57c79f6d11d7f84a29620..464106c023d8c7d9cb1bd65b39ad642bd1090bc1 100644 (file)
@@ -415,6 +415,9 @@ ieee80211_tx_h_multicast_ps_buf(struct ieee80211_tx_data *tx)
        if (ieee80211_has_order(hdr->frame_control))
                return TX_CONTINUE;
 
+       if (ieee80211_is_probe_req(hdr->frame_control))
+               return TX_CONTINUE;
+
        if (tx->local->hw.flags & IEEE80211_HW_QUEUE_CONTROL)
                info->hw_queue = tx->sdata->vif.cab_queue;
 
@@ -464,6 +467,7 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 {
        struct sta_info *sta = tx->sta;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
        struct ieee80211_local *local = tx->local;
 
        if (unlikely(!sta))
@@ -475,6 +479,12 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
                     !(info->flags & IEEE80211_TX_CTL_NO_PS_BUFFER))) {
                int ac = skb_get_queue_mapping(tx->skb);
 
+               if (ieee80211_is_mgmt(hdr->frame_control) &&
+                   !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) {
+                       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
+                       return TX_CONTINUE;
+               }
+
                ps_dbg(sta->sdata, "STA %pM aid %d: PS buffer for AC %d\n",
                       sta->sta.addr, sta->sta.aid, ac);
                if (tx->local->total_ps_buffered >= TOTAL_MAX_TX_BUFFER)
@@ -534,19 +544,9 @@ ieee80211_tx_h_unicast_ps_buf(struct ieee80211_tx_data *tx)
 static ieee80211_tx_result debug_noinline
 ieee80211_tx_h_ps_buf(struct ieee80211_tx_data *tx)
 {
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(tx->skb);
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)tx->skb->data;
-
        if (unlikely(tx->flags & IEEE80211_TX_PS_BUFFERED))
                return TX_CONTINUE;
 
-       if (ieee80211_is_mgmt(hdr->frame_control) &&
-           !ieee80211_is_bufferable_mmpdu(hdr->frame_control)) {
-               if (tx->flags & IEEE80211_TX_UNICAST)
-                       info->flags |= IEEE80211_TX_CTL_NO_PS_BUFFER;
-               return TX_CONTINUE;
-       }
-
        if (tx->flags & IEEE80211_TX_UNICAST)
                return ieee80211_tx_h_unicast_ps_buf(tx);
        else
index 71ad7eefddd4dfa69319ca06b3595e1bebca459f..3c39c72eb038bbe07225b744dba91f0c24b13371 100644 (file)
@@ -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);
 
index a6ce3c627e4e40ff4a6fcdb0bb0a2704dd0872b0..009bcf317101003e4095fda37ed1b6b7e31565e1 100644 (file)
@@ -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);
index 171cb9949ab58560bc3d1c997d963e2928cf5aa5..7cc1830633ccbb8e3fda9f38490f90225513f572 100644 (file)
@@ -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:
index c2c1c0189b7cbe931c279bc039df4d26801902d4..fb58ed2dd41d1afcfd2368de28e754a17535b705 100644 (file)
@@ -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 @@ exit:
        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);
+}
index 47403705197e85930d9f3e480d2e2d5dbd2012fa..117708263ced38dfa690e1d49a6c19d661751289 100644 (file)
@@ -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,
index f8f6af231381b336b111a9c01ce0ccb2dfc72856..df91bb95b12aacd265f89ba82db7e3ae4cf0553e 100644 (file)
@@ -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)
index 85474ee501ebbe95599f8ca3f14ba037be690c74..0c524cd76c837ccf23a070a802e1ab405fd235f4 100644 (file)
@@ -2049,7 +2049,8 @@ TRACE_EVENT(cfg80211_michael_mic_failure,
                MAC_ASSIGN(addr, addr);
                __entry->key_type = key_type;
                __entry->key_id = key_id;
-               memcpy(__entry->tsc, tsc, 6);
+               if (tsc)
+                       memcpy(__entry->tsc, tsc, 6);
        ),
        TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT ", key type: %d, key id: %d, tsc: %pm",
                  NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->key_type,