NFC: NCI: Handle Target mode activation
authorJulien Lefrique <lefrique@marvell.com>
Tue, 21 Oct 2014 14:52:46 +0000 (16:52 +0200)
committerSamuel Ortiz <sameo@linux.intel.com>
Fri, 28 Nov 2014 13:07:51 +0000 (14:07 +0100)
Changes:

 * Extract the Listen mode activation parameters from RF_INTF_ACTIVATED_NTF.

 * Store the General Bytes of ATR_REQ.

 * Signal that Target mode is activated in case of an activation in NFC-DEP.

 * Update the NCI state accordingly.

 * Use the various constants defined in nfc.h.

 * Fix the ATR_REQ and ATR_RES maximum size. As per NCI 1.0 and NCI 1.1, the
   Activation Parameters for both Poll and Listen mode contain all the bytes of
   ATR_REQ/ATR_RES starting and including Byte 3 as defined in [DIGITAL].
   In [DIGITAL], the maximum size of ATR_REQ/ATR_RES is 64 bytes and they are
   numbered starting from Byte 1.

Signed-off-by: Julien Lefrique <lefrique@marvell.com>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>
include/net/nfc/nci.h
include/net/nfc/nci_core.h
include/net/nfc/nfc.h
include/uapi/linux/nfc.h
net/nfc/nci/ntf.c

index 36cf65386b8620550eb773f30bbbd8e0131bdebb..fffadc706e067589fd50ccd4f091e54800636096 100644 (file)
@@ -28,6 +28,8 @@
 #ifndef __NCI_H
 #define __NCI_H
 
+#include <net/nfc/nfc.h>
+
 /* NCI constants */
 #define NCI_MAX_NUM_MAPPING_CONFIGS                            10
 #define NCI_MAX_NUM_RF_CONFIGS                                 10
@@ -73,6 +75,8 @@
 #define NCI_NFC_A_ACTIVE_LISTEN_MODE                           0x83
 #define NCI_NFC_F_ACTIVE_LISTEN_MODE                           0x85
 
+#define NCI_RF_TECH_MODE_LISTEN_MASK                           0x80
+
 /* NCI RF Technologies */
 #define NCI_NFC_RF_TECHNOLOGY_A                                        0x00
 #define NCI_NFC_RF_TECHNOLOGY_B                                        0x01
@@ -324,26 +328,31 @@ struct nci_core_intf_error_ntf {
 struct rf_tech_specific_params_nfca_poll {
        __u16   sens_res;
        __u8    nfcid1_len;     /* 0, 4, 7, or 10 Bytes */
-       __u8    nfcid1[10];
+       __u8    nfcid1[NFC_NFCID1_MAXSIZE];
        __u8    sel_res_len;    /* 0 or 1 Bytes */
        __u8    sel_res;
 } __packed;
 
 struct rf_tech_specific_params_nfcb_poll {
        __u8    sensb_res_len;
-       __u8    sensb_res[12];  /* 11 or 12 Bytes */
+       __u8    sensb_res[NFC_SENSB_RES_MAXSIZE];       /* 11 or 12 Bytes */
 } __packed;
 
 struct rf_tech_specific_params_nfcf_poll {
        __u8    bit_rate;
        __u8    sensf_res_len;
-       __u8    sensf_res[18];  /* 16 or 18 Bytes */
+       __u8    sensf_res[NFC_SENSF_RES_MAXSIZE];       /* 16 or 18 Bytes */
 } __packed;
 
 struct rf_tech_specific_params_nfcv_poll {
        __u8    res_flags;
        __u8    dsfid;
-       __u8    uid[8]; /* 8 Bytes */
+       __u8    uid[NFC_ISO15693_UID_MAXSIZE];  /* 8 Bytes */
+} __packed;
+
+struct rf_tech_specific_params_nfcf_listen {
+       __u8    local_nfcid2_len;
+       __u8    local_nfcid2[NFC_NFCID2_MAXSIZE];       /* 0 or 8 Bytes */
 } __packed;
 
 struct nci_rf_discover_ntf {
@@ -375,7 +384,12 @@ struct activation_params_nfcb_poll_iso_dep {
 
 struct activation_params_poll_nfc_dep {
        __u8    atr_res_len;
-       __u8    atr_res[63];
+       __u8    atr_res[NFC_ATR_RES_MAXSIZE - 2]; /* ATR_RES from byte 3 */
+};
+
+struct activation_params_listen_nfc_dep {
+       __u8    atr_req_len;
+       __u8    atr_req[NFC_ATR_REQ_MAXSIZE - 2]; /* ATR_REQ from byte 3 */
 };
 
 struct nci_rf_intf_activated_ntf {
@@ -392,6 +406,7 @@ struct nci_rf_intf_activated_ntf {
                struct rf_tech_specific_params_nfcb_poll nfcb_poll;
                struct rf_tech_specific_params_nfcf_poll nfcf_poll;
                struct rf_tech_specific_params_nfcv_poll nfcv_poll;
+               struct rf_tech_specific_params_nfcf_listen nfcf_listen;
        } rf_tech_specific_params;
 
        __u8    data_exch_rf_tech_and_mode;
@@ -403,6 +418,7 @@ struct nci_rf_intf_activated_ntf {
                struct activation_params_nfca_poll_iso_dep nfca_poll_iso_dep;
                struct activation_params_nfcb_poll_iso_dep nfcb_poll_iso_dep;
                struct activation_params_poll_nfc_dep poll_nfc_dep;
+               struct activation_params_listen_nfc_dep listen_nfc_dep;
        } activation_params;
 
 } __packed;
index 75d10e625c4969b0ddc806e5588815347ad9e73d..cfea60748a3900ec8576f67246473cd3f440817e 100644 (file)
@@ -4,6 +4,7 @@
  *
  *  Copyright (C) 2011 Texas Instruments, Inc.
  *  Copyright (C) 2013 Intel Corporation. All rights reserved.
+ *  Copyright (C) 2014 Marvell International Ltd.
  *
  *  Written by Ilan Elias <ilane@ti.com>
  *
@@ -49,6 +50,8 @@ enum nci_state {
        NCI_W4_ALL_DISCOVERIES,
        NCI_W4_HOST_SELECT,
        NCI_POLL_ACTIVE,
+       NCI_LISTEN_ACTIVE,
+       NCI_LISTEN_SLEEP,
 };
 
 /* NCI timeouts */
index 6c583e244de2198d41effbf8a21086296a2c7e40..12adb817c27a3f157f351915e38ecc131fd52e82 100644 (file)
@@ -1,5 +1,6 @@
 /*
  * Copyright (C) 2011 Instituto Nokia de Tecnologia
+ * Copyright (C) 2014 Marvell International Ltd.
  *
  * Authors:
  *    Lauro Ramos Venancio <lauro.venancio@openbossa.org>
@@ -87,6 +88,7 @@ struct nfc_ops {
 #define NFC_TARGET_IDX_ANY -1
 #define NFC_MAX_GT_LEN 48
 #define NFC_ATR_RES_GT_OFFSET 15
+#define NFC_ATR_REQ_GT_OFFSET 14
 
 /**
  * struct nfc_target - NFC target descriptiom
index 9b19b44619286616b04f1aa9f04d026878730744..19a75daac14c498edaf171cc6c91eec436329fe2 100644 (file)
@@ -196,15 +196,17 @@ enum nfc_sdp_attr {
 };
 #define NFC_SDP_ATTR_MAX (__NFC_SDP_ATTR_AFTER_LAST - 1)
 
-#define NFC_DEVICE_NAME_MAXSIZE 8
-#define NFC_NFCID1_MAXSIZE 10
-#define NFC_NFCID2_MAXSIZE 8
-#define NFC_NFCID3_MAXSIZE 10
-#define NFC_SENSB_RES_MAXSIZE 12
-#define NFC_SENSF_RES_MAXSIZE 18
-#define NFC_GB_MAXSIZE        48
-#define NFC_FIRMWARE_NAME_MAXSIZE 32
-#define NFC_ISO15693_UID_MAXSIZE 8
+#define NFC_DEVICE_NAME_MAXSIZE                8
+#define NFC_NFCID1_MAXSIZE             10
+#define NFC_NFCID2_MAXSIZE             8
+#define NFC_NFCID3_MAXSIZE             10
+#define NFC_SENSB_RES_MAXSIZE          12
+#define NFC_SENSF_RES_MAXSIZE          18
+#define NFC_ATR_REQ_MAXSIZE            64
+#define NFC_ATR_RES_MAXSIZE            64
+#define NFC_GB_MAXSIZE                 48
+#define NFC_FIRMWARE_NAME_MAXSIZE      32
+#define NFC_ISO15693_UID_MAXSIZE       8
 
 /* NFC protocols */
 #define NFC_PROTO_JEWEL                1
index 205b35f666dba827d4daafd6d29c33483e73a609..46b2a90ac55a02bb4a0ca879f47221bf8bb36b48 100644 (file)
@@ -167,6 +167,18 @@ static __u8 *nci_extract_rf_params_nfcv_passive_poll(struct nci_dev *ndev,
        return data;
 }
 
+static __u8 *nci_extract_rf_params_nfcf_passive_listen(struct nci_dev *ndev,
+                       struct rf_tech_specific_params_nfcf_listen *nfcf_listen,
+                                                    __u8 *data)
+{
+       nfcf_listen->local_nfcid2_len = min_t(__u8, *data++,
+                                             NFC_NFCID2_MAXSIZE);
+       memcpy(nfcf_listen->local_nfcid2, data, nfcf_listen->local_nfcid2_len);
+       data += nfcf_listen->local_nfcid2_len;
+
+       return data;
+}
+
 __u32 nci_get_prop_rf_protocol(struct nci_dev *ndev, __u8 rf_protocol)
 {
        if (ndev->ops->get_rfprotocol)
@@ -401,17 +413,29 @@ static int nci_extract_activation_params_nfc_dep(struct nci_dev *ndev,
                        struct nci_rf_intf_activated_ntf *ntf, __u8 *data)
 {
        struct activation_params_poll_nfc_dep *poll;
+       struct activation_params_listen_nfc_dep *listen;
 
        switch (ntf->activation_rf_tech_and_mode) {
        case NCI_NFC_A_PASSIVE_POLL_MODE:
        case NCI_NFC_F_PASSIVE_POLL_MODE:
                poll = &ntf->activation_params.poll_nfc_dep;
-               poll->atr_res_len = min_t(__u8, *data++, 63);
+               poll->atr_res_len = min_t(__u8, *data++,
+                                         NFC_ATR_RES_MAXSIZE - 2);
                pr_debug("atr_res_len %d\n", poll->atr_res_len);
                if (poll->atr_res_len > 0)
                        memcpy(poll->atr_res, data, poll->atr_res_len);
                break;
 
+       case NCI_NFC_A_PASSIVE_LISTEN_MODE:
+       case NCI_NFC_F_PASSIVE_LISTEN_MODE:
+               listen = &ntf->activation_params.listen_nfc_dep;
+               listen->atr_req_len = min_t(__u8, *data++,
+                                           NFC_ATR_REQ_MAXSIZE - 2);
+               pr_debug("atr_req_len %d\n", listen->atr_req_len);
+               if (listen->atr_req_len > 0)
+                       memcpy(listen->atr_req, data, listen->atr_req_len);
+               break;
+
        default:
                pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
                       ntf->activation_rf_tech_and_mode);
@@ -444,6 +468,50 @@ static void nci_target_auto_activated(struct nci_dev *ndev,
        nfc_targets_found(ndev->nfc_dev, ndev->targets, ndev->n_targets);
 }
 
+static int nci_store_general_bytes_nfc_dep(struct nci_dev *ndev,
+               struct nci_rf_intf_activated_ntf *ntf)
+{
+       ndev->remote_gb_len = 0;
+
+       if (ntf->activation_params_len <= 0)
+               return NCI_STATUS_OK;
+
+       switch (ntf->activation_rf_tech_and_mode) {
+       case NCI_NFC_A_PASSIVE_POLL_MODE:
+       case NCI_NFC_F_PASSIVE_POLL_MODE:
+               /* ATR_RES general bytes at offset 15 */
+               ndev->remote_gb_len = min_t(__u8,
+                       (ntf->activation_params.poll_nfc_dep.atr_res_len
+                                               - NFC_ATR_RES_GT_OFFSET),
+                       NFC_MAX_GT_LEN);
+               memcpy(ndev->remote_gb,
+                      (ntf->activation_params.poll_nfc_dep .atr_res
+                                               + NFC_ATR_RES_GT_OFFSET),
+                      ndev->remote_gb_len);
+               break;
+
+       case NCI_NFC_A_PASSIVE_LISTEN_MODE:
+       case NCI_NFC_F_PASSIVE_LISTEN_MODE:
+               /* ATR_REQ general bytes at offset 14 */
+               ndev->remote_gb_len = min_t(__u8,
+                       (ntf->activation_params.listen_nfc_dep.atr_req_len
+                                               - NFC_ATR_REQ_GT_OFFSET),
+                       NFC_MAX_GT_LEN);
+               memcpy(ndev->remote_gb,
+                      (ntf->activation_params.listen_nfc_dep.atr_req
+                                               + NFC_ATR_REQ_GT_OFFSET),
+                      ndev->remote_gb_len);
+               break;
+
+       default:
+               pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
+                      ntf->activation_rf_tech_and_mode);
+               return NCI_STATUS_RF_PROTOCOL_ERROR;
+       }
+
+       return NCI_STATUS_OK;
+}
+
 static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
                                             struct sk_buff *skb)
 {
@@ -493,6 +561,16 @@ static void nci_rf_intf_activated_ntf_packet(struct nci_dev *ndev,
                                &(ntf.rf_tech_specific_params.nfcv_poll), data);
                        break;
 
+               case NCI_NFC_A_PASSIVE_LISTEN_MODE:
+                       /* no RF technology specific parameters */
+                       break;
+
+               case NCI_NFC_F_PASSIVE_LISTEN_MODE:
+                       data = nci_extract_rf_params_nfcf_passive_listen(ndev,
+                               &(ntf.rf_tech_specific_params.nfcf_listen),
+                               data);
+                       break;
+
                default:
                        pr_err("unsupported activation_rf_tech_and_mode 0x%x\n",
                               ntf.activation_rf_tech_and_mode);
@@ -546,32 +624,39 @@ exit:
 
                /* store general bytes to be reported later in dep_link_up */
                if (ntf.rf_interface == NCI_RF_INTERFACE_NFC_DEP) {
-                       ndev->remote_gb_len = 0;
-
-                       if (ntf.activation_params_len > 0) {
-                               /* ATR_RES general bytes at offset 15 */
-                               ndev->remote_gb_len = min_t(__u8,
-                                       (ntf.activation_params
-                                       .poll_nfc_dep.atr_res_len
-                                       - NFC_ATR_RES_GT_OFFSET),
-                                       NFC_MAX_GT_LEN);
-                               memcpy(ndev->remote_gb,
-                                      (ntf.activation_params.poll_nfc_dep
-                                      .atr_res + NFC_ATR_RES_GT_OFFSET),
-                                      ndev->remote_gb_len);
-                       }
+                       err = nci_store_general_bytes_nfc_dep(ndev, &ntf);
+                       if (err != NCI_STATUS_OK)
+                               pr_err("unable to store general bytes\n");
                }
        }
 
-       if (atomic_read(&ndev->state) == NCI_DISCOVERY) {
-               /* A single target was found and activated automatically */
-               atomic_set(&ndev->state, NCI_POLL_ACTIVE);
-               if (err == NCI_STATUS_OK)
-                       nci_target_auto_activated(ndev, &ntf);
-       } else {        /* ndev->state == NCI_W4_HOST_SELECT */
-               /* A selected target was activated, so complete the request */
-               atomic_set(&ndev->state, NCI_POLL_ACTIVE);
-               nci_req_complete(ndev, err);
+       if (!(ntf.activation_rf_tech_and_mode & NCI_RF_TECH_MODE_LISTEN_MASK)) {
+               /* Poll mode */
+               if (atomic_read(&ndev->state) == NCI_DISCOVERY) {
+                       /* A single target was found and activated
+                        * automatically */
+                       atomic_set(&ndev->state, NCI_POLL_ACTIVE);
+                       if (err == NCI_STATUS_OK)
+                               nci_target_auto_activated(ndev, &ntf);
+               } else {        /* ndev->state == NCI_W4_HOST_SELECT */
+                       /* A selected target was activated, so complete the
+                        * request */
+                       atomic_set(&ndev->state, NCI_POLL_ACTIVE);
+                       nci_req_complete(ndev, err);
+               }
+       } else {
+               /* Listen mode */
+               atomic_set(&ndev->state, NCI_LISTEN_ACTIVE);
+               if (err == NCI_STATUS_OK &&
+                   ntf.rf_protocol == NCI_RF_PROTOCOL_NFC_DEP) {
+                       err = nfc_tm_activated(ndev->nfc_dev,
+                                              NFC_PROTO_NFC_DEP_MASK,
+                                              NFC_COMM_PASSIVE,
+                                              ndev->remote_gb,
+                                              ndev->remote_gb_len);
+                       if (err != NCI_STATUS_OK)
+                               pr_err("error when signaling tm activation\n");
+               }
        }
 }