普通文本  |  3114行  |  112.52 KB

/******************************************************************************
 *
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at:
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/

/******************************************************************************
 *
 *  This file contains the action functions for device manager discovery
 *  function.
 *
 ******************************************************************************/
#include <string>

#include <android-base/stringprintf.h>
#include <base/logging.h>

#include "nci_hmsgs.h"
#include "nfa_api.h"
#include "nfa_dm_int.h"
#include "nfa_p2p_int.h"

#if (NFC_NFCEE_INCLUDED == TRUE)
#include "nfa_ee_api.h"
#include "nfa_ee_int.h"
#endif
#include "nfa_rw_int.h"

#include "nfc_int.h"

using android::base::StringPrintf;

extern bool nfc_debug_enabled;

/*
**  static functions
*/
static uint8_t nfa_dm_get_rf_discover_config(
    tNFA_DM_DISC_TECH_PROTO_MASK dm_disc_mask,
    tNFC_DISCOVER_PARAMS disc_params[], uint8_t max_params);
static tNFA_STATUS nfa_dm_set_rf_listen_mode_config(
    tNFA_DM_DISC_TECH_PROTO_MASK tech_proto_mask);
static void nfa_dm_set_rf_listen_mode_raw_config(
    tNFA_DM_DISC_TECH_PROTO_MASK* p_disc_mask);
static tNFA_DM_DISC_TECH_PROTO_MASK nfa_dm_disc_get_disc_mask(
    tNFC_RF_TECH_N_MODE tech_n_mode, tNFC_PROTOCOL protocol);
static void nfa_dm_notify_discovery(tNFA_DM_RF_DISC_DATA* p_data);
static tNFA_STATUS nfa_dm_disc_notify_activation(tNFC_DISCOVER* p_data);
static void nfa_dm_disc_notify_deactivation(tNFA_DM_RF_DISC_SM_EVENT sm_event,
                                            tNFC_DISCOVER* p_data);
static void nfa_dm_disc_data_cback(uint8_t conn_id, tNFC_CONN_EVT event,
                                   tNFC_CONN* p_data);
static void nfa_dm_disc_kovio_timeout_cback(TIMER_LIST_ENT* p_tle);
static void nfa_dm_disc_report_kovio_presence_check(tNFC_STATUS status);

static std::string nfa_dm_disc_state_2_str(uint8_t state);
static std::string nfa_dm_disc_event_2_str(uint8_t event);

typedef struct nfa_dm_p2p_prio_logic {
  bool isodep_detected;      /* flag to check if ISO-DEP is detected */
  bool timer_expired;        /* flag to check whether timer is expired */
  TIMER_LIST_ENT timer_list; /*timer structure pointer */
  uint8_t first_tech_mode;
} nfa_dm_p2p_prio_logic_t;

static nfa_dm_p2p_prio_logic_t p2p_prio_logic_data;

static void nfa_dm_send_tag_deselect_cmd(tNFA_NFC_PROTOCOL protocol);

/*******************************************************************************
**
** Function         nfa_dm_get_rf_discover_config
**
** Description      Build RF discovery configurations from
**                  tNFA_DM_DISC_TECH_PROTO_MASK
**
** Returns          number of RF discovery configurations
**
*******************************************************************************/
static uint8_t nfa_dm_get_rf_discover_config(
    tNFA_DM_DISC_TECH_PROTO_MASK dm_disc_mask,
    tNFC_DISCOVER_PARAMS disc_params[], uint8_t max_params) {
  uint8_t num_params = 0;

  if (nfa_dm_cb.flags & NFA_DM_FLAGS_LISTEN_DISABLED) {
    DLOG_IF(INFO, nfc_debug_enabled)
        << StringPrintf("listen disabled, rm listen from 0x%x", dm_disc_mask);
    dm_disc_mask &= NFA_DM_DISC_MASK_POLL;
  }
  if (nfa_dm_is_p2p_paused()) {
    dm_disc_mask &= ~NFA_DM_DISC_MASK_NFC_DEP;
  }

  /* Check polling A */
  if (dm_disc_mask &
      (NFA_DM_DISC_MASK_PA_T1T | NFA_DM_DISC_MASK_PA_T2T |
       NFA_DM_DISC_MASK_PA_ISO_DEP | NFA_DM_DISC_MASK_PA_NFC_DEP |
       NFA_DM_DISC_MASK_P_LEGACY)) {
    disc_params[num_params].type = NFC_DISCOVERY_TYPE_POLL_A;
    disc_params[num_params].frequency = p_nfa_dm_rf_disc_freq_cfg->pa;
    num_params++;

    if (num_params >= max_params) return num_params;
  }

  /* Check polling B */
  if (dm_disc_mask & NFA_DM_DISC_MASK_PB_ISO_DEP) {
    disc_params[num_params].type = NFC_DISCOVERY_TYPE_POLL_B;
    disc_params[num_params].frequency = p_nfa_dm_rf_disc_freq_cfg->pb;
    num_params++;

    if (num_params >= max_params) return num_params;
  }

  /* Check polling F */
  if (dm_disc_mask & (NFA_DM_DISC_MASK_PF_T3T | NFA_DM_DISC_MASK_PF_NFC_DEP)) {
    disc_params[num_params].type = NFC_DISCOVERY_TYPE_POLL_F;
    disc_params[num_params].frequency = p_nfa_dm_rf_disc_freq_cfg->pf;
    num_params++;

    if (num_params >= max_params) return num_params;
  }
  if (NFC_GetNCIVersion() == NCI_VERSION_2_0) {
    /* Check polling Active mode  */
    if (dm_disc_mask & NFA_DM_DISC_MASK_PACM_NFC_DEP) {
      disc_params[num_params].type = NFC_DISCOVERY_TYPE_POLL_ACTIVE;
      disc_params[num_params].frequency = p_nfa_dm_rf_disc_freq_cfg->pacm;
      num_params++;

      if (num_params >= max_params) return num_params;
    }
  } else {
    /* Check polling A Active mode  */
    if (dm_disc_mask & NFA_DM_DISC_MASK_PAA_NFC_DEP) {
      disc_params[num_params].type = NFC_DISCOVERY_TYPE_POLL_A_ACTIVE;
      disc_params[num_params].frequency = p_nfa_dm_rf_disc_freq_cfg->paa;
      num_params++;

      if (num_params >= max_params) return num_params;
    }

    /* Check polling F Active mode  */
    if (dm_disc_mask & NFA_DM_DISC_MASK_PFA_NFC_DEP) {
      disc_params[num_params].type = NFC_DISCOVERY_TYPE_POLL_F_ACTIVE;
      disc_params[num_params].frequency = p_nfa_dm_rf_disc_freq_cfg->pfa;
      num_params++;

      if (num_params >= max_params) return num_params;
    }
  }
  /* Check listening A */
  if (dm_disc_mask &
      (NFA_DM_DISC_MASK_LA_T1T | NFA_DM_DISC_MASK_LA_T2T |
       NFA_DM_DISC_MASK_LA_ISO_DEP | NFA_DM_DISC_MASK_LA_NFC_DEP)) {
    disc_params[num_params].type = NFC_DISCOVERY_TYPE_LISTEN_A;
    disc_params[num_params].frequency = 1;
    num_params++;

    if (num_params >= max_params) return num_params;
  }

  /* Check listening B */
  if (dm_disc_mask & NFA_DM_DISC_MASK_LB_ISO_DEP) {
    disc_params[num_params].type = NFC_DISCOVERY_TYPE_LISTEN_B;
    disc_params[num_params].frequency = 1;
    num_params++;

    if (num_params >= max_params) return num_params;
  }

  /* Check listening F */
  if (dm_disc_mask & (NFA_DM_DISC_MASK_LF_T3T | NFA_DM_DISC_MASK_LF_NFC_DEP)) {
    disc_params[num_params].type = NFC_DISCOVERY_TYPE_LISTEN_F;
    disc_params[num_params].frequency = 1;
    num_params++;

    if (num_params >= max_params) return num_params;
  }
  if (NFC_GetNCIVersion() == NCI_VERSION_2_0) {
    /* Check polling Active mode  */
    if (dm_disc_mask & NFA_DM_DISC_MASK_LACM_NFC_DEP) {
      disc_params[num_params].type = NFC_DISCOVERY_TYPE_LISTEN_ACTIVE;
      disc_params[num_params].frequency = p_nfa_dm_rf_disc_freq_cfg->pacm;
      num_params++;
      if (num_params >= max_params) return num_params;
    }
  } else {
    /* Check listening A Active mode */
    if (dm_disc_mask & NFA_DM_DISC_MASK_LAA_NFC_DEP) {
      disc_params[num_params].type = NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE;
      disc_params[num_params].frequency = 1;
      num_params++;

      if (num_params >= max_params) return num_params;
    }

    /* Check listening F Active mode */
    if (dm_disc_mask & NFA_DM_DISC_MASK_LFA_NFC_DEP) {
      disc_params[num_params].type = NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE;
      disc_params[num_params].frequency = 1;
      num_params++;

      if (num_params >= max_params) return num_params;
    }
  }

  /* Check polling ISO 15693 */
  if (dm_disc_mask & NFA_DM_DISC_MASK_P_T5T) {
    disc_params[num_params].type = NFC_DISCOVERY_TYPE_POLL_V;
    disc_params[num_params].frequency = p_nfa_dm_rf_disc_freq_cfg->pi93;
    num_params++;

    if (num_params >= max_params) return num_params;
  }

  /* Check polling B' */
  if (dm_disc_mask & NFA_DM_DISC_MASK_P_B_PRIME) {
    disc_params[num_params].type = NFC_DISCOVERY_TYPE_POLL_B_PRIME;
    disc_params[num_params].frequency = p_nfa_dm_rf_disc_freq_cfg->pbp;
    num_params++;

    if (num_params >= max_params) return num_params;
  }

  /* Check polling KOVIO */
  if (dm_disc_mask & NFA_DM_DISC_MASK_P_KOVIO) {
    disc_params[num_params].type = NFC_DISCOVERY_TYPE_POLL_KOVIO;
    disc_params[num_params].frequency = p_nfa_dm_rf_disc_freq_cfg->pk;
    num_params++;

    if (num_params >= max_params) return num_params;
  }

  /* Check listening ISO 15693 */
  if (dm_disc_mask & NFA_DM_DISC_MASK_L_ISO15693) {
    disc_params[num_params].type = NFC_DISCOVERY_TYPE_LISTEN_ISO15693;
    disc_params[num_params].frequency = 1;
    num_params++;

    if (num_params >= max_params) return num_params;
  }

  /* Check listening B' */
  if (dm_disc_mask & NFA_DM_DISC_MASK_L_B_PRIME) {
    disc_params[num_params].type = NFC_DISCOVERY_TYPE_LISTEN_B_PRIME;
    disc_params[num_params].frequency = 1;
    num_params++;

    if (num_params >= max_params) return num_params;
  }

  return num_params;
}

/*******************************************************************************
**
** Function         nfa_dm_set_rf_listen_mode_config
**
** Description      Update listening protocol to NFCC
**
** Returns          NFA_STATUS_OK if success
**
*******************************************************************************/
static tNFA_STATUS nfa_dm_set_rf_listen_mode_config(
    tNFA_DM_DISC_TECH_PROTO_MASK tech_proto_mask) {
  uint8_t params[40], *p;
  uint8_t platform = 0;
  uint8_t sens_info = 0;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("tech_proto_mask = 0x%08X", tech_proto_mask);

  /*
  ** T1T listen     LA_PROT 0x80, LA_SENS_RES byte1:0x00 byte2:0x0C
  ** T2T listen     LA_PROT 0x00
  ** T3T listen     No bit for T3T in LF_PROT (CE T3T set listen parameters,
  **                system code, NFCID2, etc.)
  ** ISO-DEP listen LA_PROT 0x01, LB_PROT 0x01
  ** NFC-DEP listen LA_PROT 0x02, LF_PROT 0x02
  */

  if (tech_proto_mask & NFA_DM_DISC_MASK_LA_T1T) {
    platform = NCI_PARAM_PLATFORM_T1T;
  } else if (tech_proto_mask & NFA_DM_DISC_MASK_LA_T2T) {
    /* platform = 0 and sens_info = 0 */
  } else {
    if (tech_proto_mask & NFA_DM_DISC_MASK_LA_ISO_DEP) {
      sens_info |= NCI_PARAM_SEL_INFO_ISODEP;
    }

    if (tech_proto_mask & NFA_DM_DISC_MASK_LA_NFC_DEP) {
      sens_info |= NCI_PARAM_SEL_INFO_NFCDEP;
    }
  }

  p = params;

  /*
  ** for Listen A
  **
  ** Set ATQA 0x0C00 for T1T listen
  ** If the ATQA values are 0x0000, then the FW will use 0x0400
  ** which works for ISODEP, T2T and NFCDEP.
  */
  if (nfa_dm_cb.disc_cb.listen_RT[NFA_DM_DISC_LRT_NFC_A] ==
      NFA_DM_DISC_HOST_ID_DH) {
    UINT8_TO_STREAM(p, NFC_PMID_LA_BIT_FRAME_SDD);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LA_BIT_FRAME_SDD);
    UINT8_TO_STREAM(p, 0x04);
    UINT8_TO_STREAM(p, NFC_PMID_LA_PLATFORM_CONFIG);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LA_PLATFORM_CONFIG);
    UINT8_TO_STREAM(p, platform);
    UINT8_TO_STREAM(p, NFC_PMID_LA_SEL_INFO);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LA_SEL_INFO);
    UINT8_TO_STREAM(p, sens_info);
  } else /* Let NFCC use UICC configuration by configuring with length = 0 */
  {
    UINT8_TO_STREAM(p, NFC_PMID_LA_BIT_FRAME_SDD);
    UINT8_TO_STREAM(p, 0);
    UINT8_TO_STREAM(p, NFC_PMID_LA_PLATFORM_CONFIG);
    UINT8_TO_STREAM(p, 0);
    UINT8_TO_STREAM(p, NFC_PMID_LA_SEL_INFO);
    UINT8_TO_STREAM(p, 0);
    UINT8_TO_STREAM(p, NFC_PMID_LA_NFCID1);
    UINT8_TO_STREAM(p, 0);
    UINT8_TO_STREAM(p, NFC_PMID_LA_HIST_BY);
    UINT8_TO_STREAM(p, 0);
  }

  /* for Listen B */
  if (nfa_dm_cb.disc_cb.listen_RT[NFA_DM_DISC_LRT_NFC_B] ==
      NFA_DM_DISC_HOST_ID_DH) {
    UINT8_TO_STREAM(p, NFC_PMID_LB_SENSB_INFO);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LB_SENSB_INFO);
    if (tech_proto_mask & NFA_DM_DISC_MASK_LB_ISO_DEP) {
      UINT8_TO_STREAM(p, NCI_LISTEN_PROTOCOL_ISO_DEP);
    } else {
      UINT8_TO_STREAM(p, 0x00);
    }
  } else /* Let NFCC use UICC configuration by configuring with length = 0 */
  {
    UINT8_TO_STREAM(p, NFC_PMID_LB_SENSB_INFO);
    UINT8_TO_STREAM(p, 0);
    UINT8_TO_STREAM(p, NFC_PMID_LB_NFCID0);
    UINT8_TO_STREAM(p, 0);
    UINT8_TO_STREAM(p, NFC_PMID_LB_APPDATA);
    UINT8_TO_STREAM(p, 0);
    UINT8_TO_STREAM(p, NFC_PMID_LB_ADC_FO);
    UINT8_TO_STREAM(p, 0);
    UINT8_TO_STREAM(p, NFC_PMID_LB_H_INFO);
    UINT8_TO_STREAM(p, 0);
  }

  /* for Listen F */
  /* NFCC can support NFC-DEP and T3T listening based on NFCID routing
   * regardless of NFC-F tech routing */
  UINT8_TO_STREAM(p, NFC_PMID_LF_PROTOCOL);
  UINT8_TO_STREAM(p, NCI_PARAM_LEN_LF_PROTOCOL);
  if ((tech_proto_mask & NFA_DM_DISC_MASK_LF_NFC_DEP) &&
      !nfa_dm_is_p2p_paused()) {
    UINT8_TO_STREAM(p, NCI_LISTEN_PROTOCOL_NFC_DEP);
  } else {
    UINT8_TO_STREAM(p, 0x00);
  }

  if (p > params) {
    nfa_dm_check_set_config((uint8_t)(p - params), params, false);
  }

  return NFA_STATUS_OK;
}

/*******************************************************************************
**
** Function         nfa_dm_set_total_duration
**
** Description      Update total duration to NFCC
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_set_total_duration(void) {
  uint8_t params[10], *p;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  p = params;

  /* for total duration */
  UINT8_TO_STREAM(p, NFC_PMID_TOTAL_DURATION);
  UINT8_TO_STREAM(p, NCI_PARAM_LEN_TOTAL_DURATION);
  UINT16_TO_STREAM(p, nfa_dm_cb.disc_cb.disc_duration);

  if (p > params) {
    nfa_dm_check_set_config((uint8_t)(p - params), params, false);
  }
}

/*******************************************************************************
**
** Function         nfa_dm_set_rf_listen_mode_raw_config
**
** Description      Set raw listen parameters
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_set_rf_listen_mode_raw_config(
    tNFA_DM_DISC_TECH_PROTO_MASK* p_disc_mask) {
  tNFA_DM_DISC_TECH_PROTO_MASK disc_mask = 0;
  tNFA_LISTEN_CFG* p_cfg = &nfa_dm_cb.disc_cb.excl_listen_config;
  uint8_t params[250], *p, xx;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  /*
  ** Discovery Configuration Parameters for Listen A
  */
  if ((nfa_dm_cb.disc_cb.listen_RT[NFA_DM_DISC_LRT_NFC_A] ==
       NFA_DM_DISC_HOST_ID_DH) &&
      (p_cfg->la_enable)) {
    p = params;

    UINT8_TO_STREAM(p, NFC_PMID_LA_BIT_FRAME_SDD);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LA_BIT_FRAME_SDD);
    UINT8_TO_STREAM(p, p_cfg->la_bit_frame_sdd);

    UINT8_TO_STREAM(p, NFC_PMID_LA_PLATFORM_CONFIG);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LA_PLATFORM_CONFIG);
    UINT8_TO_STREAM(p, p_cfg->la_platform_config);

    UINT8_TO_STREAM(p, NFC_PMID_LA_SEL_INFO);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LA_SEL_INFO);
    UINT8_TO_STREAM(p, p_cfg->la_sel_info);

    if (p_cfg->la_platform_config == NCI_PARAM_PLATFORM_T1T) {
      disc_mask |= NFA_DM_DISC_MASK_LA_T1T;
    } else {
      /* If T4T or NFCDEP */
      if (p_cfg->la_sel_info & NCI_PARAM_SEL_INFO_ISODEP) {
        disc_mask |= NFA_DM_DISC_MASK_LA_ISO_DEP;
      }

      if (p_cfg->la_sel_info & NCI_PARAM_SEL_INFO_NFCDEP) {
        disc_mask |= NFA_DM_DISC_MASK_LA_NFC_DEP;
      }

      /* If neither, T4T nor NFCDEP, then its T2T */
      if (disc_mask == 0) {
        disc_mask |= NFA_DM_DISC_MASK_LA_T2T;
      }
    }

    UINT8_TO_STREAM(p, NFC_PMID_LA_NFCID1);
    UINT8_TO_STREAM(p, p_cfg->la_nfcid1_len);
    ARRAY_TO_STREAM(p, p_cfg->la_nfcid1, p_cfg->la_nfcid1_len);

    nfa_dm_check_set_config((uint8_t)(p - params), params, false);
  }

  /*
  ** Discovery Configuration Parameters for Listen B
  */
  if ((nfa_dm_cb.disc_cb.listen_RT[NFA_DM_DISC_LRT_NFC_B] ==
       NFA_DM_DISC_HOST_ID_DH) &&
      (p_cfg->lb_enable)) {
    p = params;

    UINT8_TO_STREAM(p, NFC_PMID_LB_SENSB_INFO);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LB_SENSB_INFO);
    UINT8_TO_STREAM(p, p_cfg->lb_sensb_info);

    UINT8_TO_STREAM(p, NFC_PMID_LB_NFCID0);
    UINT8_TO_STREAM(p, p_cfg->lb_nfcid0_len);
    ARRAY_TO_STREAM(p, p_cfg->lb_nfcid0, p_cfg->lb_nfcid0_len);

    UINT8_TO_STREAM(p, NFC_PMID_LB_APPDATA);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LB_APPDATA);
    ARRAY_TO_STREAM(p, p_cfg->lb_app_data, NCI_PARAM_LEN_LB_APPDATA);

    UINT8_TO_STREAM(p, NFC_PMID_LB_SFGI);
    UINT8_TO_STREAM(p, 1);
    UINT8_TO_STREAM(p, p_cfg->lb_adc_fo);

    UINT8_TO_STREAM(p, NFC_PMID_LB_ADC_FO);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LB_ADC_FO);
    UINT8_TO_STREAM(p, p_cfg->lb_adc_fo);

    nfa_dm_check_set_config((uint8_t)(p - params), params, false);

    if (p_cfg->lb_sensb_info & NCI_LISTEN_PROTOCOL_ISO_DEP) {
      disc_mask |= NFA_DM_DISC_MASK_LB_ISO_DEP;
    }
  }

  /*
  ** Discovery Configuration Parameters for Listen F
  */
  if ((nfa_dm_cb.disc_cb.listen_RT[NFA_DM_DISC_LRT_NFC_F] ==
       NFA_DM_DISC_HOST_ID_DH) &&
      (p_cfg->lf_enable)) {
    p = params;

    UINT8_TO_STREAM(p, NFC_PMID_LF_CON_BITR_F);
    UINT8_TO_STREAM(p, 1);
    UINT8_TO_STREAM(p, p_cfg->lf_con_bitr_f);

    UINT8_TO_STREAM(p, NFC_PMID_LF_PROTOCOL);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LF_PROTOCOL);
    UINT8_TO_STREAM(p, p_cfg->lf_protocol_type);

    UINT8_TO_STREAM(p, NFC_PMID_LF_T3T_FLAGS2);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LF_T3T_FLAGS2);
    UINT16_TO_STREAM(p, p_cfg->lf_t3t_flags);

    /* if the bit at position X is set to 0, SC/NFCID2 with index X shall be
     * ignored */
    for (xx = 0; xx < NFA_LF_MAX_SC_NFCID2; xx++) {
      if ((p_cfg->lf_t3t_flags & (0x0001 << xx)) != 0x0000) {
        UINT8_TO_STREAM(p, NFC_PMID_LF_T3T_ID1 + xx);
        UINT8_TO_STREAM(p, NCI_SYSTEMCODE_LEN + NCI_NFCID2_LEN);
        ARRAY_TO_STREAM(p, p_cfg->lf_t3t_identifier[xx],
                        NCI_SYSTEMCODE_LEN + NCI_NFCID2_LEN);
      }
    }

    UINT8_TO_STREAM(p, NFC_PMID_LF_T3T_PMM);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_LF_T3T_PMM);
    ARRAY_TO_STREAM(p, p_cfg->lf_t3t_pmm, NCI_PARAM_LEN_LF_T3T_PMM);

    nfa_dm_check_set_config((uint8_t)(p - params), params, false);

    if (p_cfg->lf_t3t_flags != NCI_LF_T3T_FLAGS2_ALL_DISABLED) {
      disc_mask |= NFA_DM_DISC_MASK_LF_T3T;
    }
    if (p_cfg->lf_protocol_type & NCI_LISTEN_PROTOCOL_NFC_DEP) {
      disc_mask |= NFA_DM_DISC_MASK_LF_NFC_DEP;
    }
  }

  /*
  ** Discovery Configuration Parameters for Listen ISO-DEP
  */
  if ((disc_mask &
       (NFA_DM_DISC_MASK_LA_ISO_DEP | NFA_DM_DISC_MASK_LB_ISO_DEP)) &&
      (p_cfg->li_enable)) {
    p = params;

    UINT8_TO_STREAM(p, NFC_PMID_FWI);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_FWI);
    UINT8_TO_STREAM(p, p_cfg->li_fwi);

    if (disc_mask & NFA_DM_DISC_MASK_LA_ISO_DEP) {
      UINT8_TO_STREAM(p, NFC_PMID_LA_HIST_BY);
      UINT8_TO_STREAM(p, p_cfg->la_hist_bytes_len);
      ARRAY_TO_STREAM(p, p_cfg->la_hist_bytes, p_cfg->la_hist_bytes_len);
    }

    if (disc_mask & NFA_DM_DISC_MASK_LB_ISO_DEP) {
      UINT8_TO_STREAM(p, NFC_PMID_LB_H_INFO);
      UINT8_TO_STREAM(p, p_cfg->lb_h_info_resp_len);
      ARRAY_TO_STREAM(p, p_cfg->lb_h_info_resp, p_cfg->lb_h_info_resp_len);
    }

    nfa_dm_check_set_config((uint8_t)(p - params), params, false);
  }

  /*
  ** Discovery Configuration Parameters for Listen NFC-DEP
  */
  if ((disc_mask &
       (NFA_DM_DISC_MASK_LA_NFC_DEP | NFA_DM_DISC_MASK_LF_NFC_DEP)) &&
      (p_cfg->ln_enable)) {
    p = params;

    UINT8_TO_STREAM(p, NFC_PMID_WT);
    UINT8_TO_STREAM(p, NCI_PARAM_LEN_WT);
    UINT8_TO_STREAM(p, p_cfg->ln_wt);

    UINT8_TO_STREAM(p, NFC_PMID_ATR_RES_GEN_BYTES);
    UINT8_TO_STREAM(p, p_cfg->ln_atr_res_gen_bytes_len);
    ARRAY_TO_STREAM(p, p_cfg->ln_atr_res_gen_bytes,
                    p_cfg->ln_atr_res_gen_bytes_len);

    UINT8_TO_STREAM(p, NFC_PMID_ATR_RSP_CONFIG);
    UINT8_TO_STREAM(p, 1);
    UINT8_TO_STREAM(p, p_cfg->ln_atr_res_config);

    nfa_dm_check_set_config((uint8_t)(p - params), params, false);
  }

  *p_disc_mask = disc_mask;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("disc_mask = 0x%x", disc_mask);
}

/*******************************************************************************
**
** Function         nfa_dm_disc_get_disc_mask
**
** Description      Convert RF technology, mode and protocol to bit mask
**
** Returns          tNFA_DM_DISC_TECH_PROTO_MASK
**
*******************************************************************************/
static tNFA_DM_DISC_TECH_PROTO_MASK nfa_dm_disc_get_disc_mask(
    tNFC_RF_TECH_N_MODE tech_n_mode, tNFC_PROTOCOL protocol) {
  /* Set initial disc_mask to legacy poll or listen */
  tNFA_DM_DISC_TECH_PROTO_MASK disc_mask =
      ((tech_n_mode & 0x80) ? NFA_DM_DISC_MASK_L_LEGACY
                            : NFA_DM_DISC_MASK_P_LEGACY);

  if (NFC_DISCOVERY_TYPE_POLL_A == tech_n_mode) {
    switch (protocol) {
      case NFC_PROTOCOL_T1T:
        disc_mask = NFA_DM_DISC_MASK_PA_T1T;
        break;
      case NFC_PROTOCOL_T2T:
        disc_mask = NFA_DM_DISC_MASK_PA_T2T;
        break;
      case NFC_PROTOCOL_ISO_DEP:
        disc_mask = NFA_DM_DISC_MASK_PA_ISO_DEP;
        break;
      case NFC_PROTOCOL_NFC_DEP:
        disc_mask = NFA_DM_DISC_MASK_PA_NFC_DEP;
        break;
    }
  } else if (NFC_DISCOVERY_TYPE_POLL_B == tech_n_mode) {
    if (protocol == NFC_PROTOCOL_ISO_DEP)
      disc_mask = NFA_DM_DISC_MASK_PB_ISO_DEP;
  } else if (NFC_DISCOVERY_TYPE_POLL_F == tech_n_mode) {
    if (protocol == NFC_PROTOCOL_T3T)
      disc_mask = NFA_DM_DISC_MASK_PF_T3T;
    else if (protocol == NFC_PROTOCOL_NFC_DEP)
      disc_mask = NFA_DM_DISC_MASK_PF_NFC_DEP;
  } else if (NFC_DISCOVERY_TYPE_POLL_V == tech_n_mode) {
    disc_mask = NFA_DM_DISC_MASK_P_T5T;
  } else if (NFC_DISCOVERY_TYPE_POLL_B_PRIME == tech_n_mode) {
    disc_mask = NFA_DM_DISC_MASK_P_B_PRIME;
  } else if (NFC_DISCOVERY_TYPE_POLL_KOVIO == tech_n_mode) {
    disc_mask = NFA_DM_DISC_MASK_P_KOVIO;
  } else if (NFC_DISCOVERY_TYPE_LISTEN_A == tech_n_mode) {
    switch (protocol) {
      case NFC_PROTOCOL_T1T:
        disc_mask = NFA_DM_DISC_MASK_LA_T1T;
        break;
      case NFC_PROTOCOL_T2T:
        disc_mask = NFA_DM_DISC_MASK_LA_T2T;
        break;
      case NFC_PROTOCOL_ISO_DEP:
        disc_mask = NFA_DM_DISC_MASK_LA_ISO_DEP;
        break;
      case NFC_PROTOCOL_NFC_DEP:
        disc_mask = NFA_DM_DISC_MASK_LA_NFC_DEP;
        break;
    }
  } else if (NFC_DISCOVERY_TYPE_LISTEN_B == tech_n_mode) {
    if (protocol == NFC_PROTOCOL_ISO_DEP)
      disc_mask = NFA_DM_DISC_MASK_LB_ISO_DEP;
  } else if (NFC_DISCOVERY_TYPE_LISTEN_F == tech_n_mode) {
    if (protocol == NFC_PROTOCOL_T3T)
      disc_mask = NFA_DM_DISC_MASK_LF_T3T;
    else if (protocol == NFC_PROTOCOL_NFC_DEP)
      disc_mask = NFA_DM_DISC_MASK_LF_NFC_DEP;
  } else if (NFC_DISCOVERY_TYPE_LISTEN_ISO15693 == tech_n_mode) {
    disc_mask = NFA_DM_DISC_MASK_L_ISO15693;
  } else if (NFC_DISCOVERY_TYPE_LISTEN_B_PRIME == tech_n_mode) {
    disc_mask = NFA_DM_DISC_MASK_L_B_PRIME;
  }
  if (NFC_GetNCIVersion() == NCI_VERSION_2_0) {
    if (NFC_DISCOVERY_TYPE_POLL_ACTIVE == tech_n_mode) {
      disc_mask = NFA_DM_DISC_MASK_PACM_NFC_DEP;
    } else if (NFC_DISCOVERY_TYPE_LISTEN_ACTIVE == tech_n_mode) {
      disc_mask = NFA_DM_DISC_MASK_LACM_NFC_DEP;
    }
  } else {
    if (NFC_DISCOVERY_TYPE_POLL_A_ACTIVE == tech_n_mode) {
      disc_mask = NFA_DM_DISC_MASK_PAA_NFC_DEP;
    } else if (NFC_DISCOVERY_TYPE_POLL_F_ACTIVE == tech_n_mode) {
      disc_mask = NFA_DM_DISC_MASK_PFA_NFC_DEP;
    } else if (NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE == tech_n_mode) {
      disc_mask = NFA_DM_DISC_MASK_LAA_NFC_DEP;
    } else if (NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE == tech_n_mode) {
      disc_mask = NFA_DM_DISC_MASK_LFA_NFC_DEP;
    }
  }

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
      "tech_n_mode:0x%X, protocol:0x%X, "
      "disc_mask:0x%X",
      tech_n_mode, protocol, disc_mask);
  return (disc_mask);
}

/*******************************************************************************
**
** Function         nfa_dm_disc_discovery_cback
**
** Description      Discovery callback event from NFC
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_discovery_cback(tNFC_DISCOVER_EVT event,
                                        tNFC_DISCOVER* p_data) {
  tNFA_DM_RF_DISC_SM_EVENT dm_disc_event = NFA_DM_DISC_SM_MAX_EVENT;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("event:0x%X", event);

  switch (event) {
    case NFC_START_DEVT:
      dm_disc_event = NFA_DM_RF_DISCOVER_RSP;
      break;
    case NFC_RESULT_DEVT:
      dm_disc_event = NFA_DM_RF_DISCOVER_NTF;
      break;
    case NFC_SELECT_DEVT:
      dm_disc_event = NFA_DM_RF_DISCOVER_SELECT_RSP;
      break;
    case NFC_ACTIVATE_DEVT:
      dm_disc_event = NFA_DM_RF_INTF_ACTIVATED_NTF;
      break;
    case NFC_DEACTIVATE_DEVT:
      if (p_data->deactivate.is_ntf) {
        dm_disc_event = NFA_DM_RF_DEACTIVATE_NTF;
        if ((p_data->deactivate.type == NFC_DEACTIVATE_TYPE_IDLE) ||
            (p_data->deactivate.type == NFC_DEACTIVATE_TYPE_DISCOVERY)) {
          NFC_SetReassemblyFlag(true);
          nfa_dm_cb.flags &= ~NFA_DM_FLAGS_RAW_FRAME;
        }
      } else
        dm_disc_event = NFA_DM_RF_DEACTIVATE_RSP;
      break;
    default:
      LOG(ERROR) << StringPrintf("Unexpected event");
      return;
  }

  tNFA_DM_RF_DISC_DATA nfa_dm_rf_disc_data;
  nfa_dm_rf_disc_data.nfc_discover = *p_data;
  nfa_dm_disc_sm_execute(dm_disc_event, &nfa_dm_rf_disc_data);
}

/*******************************************************************************
**
** Function         nfa_dm_disc_notify_started
**
** Description      Report NFA_EXCLUSIVE_RF_CONTROL_STARTED_EVT or
**                  NFA_RF_DISCOVERY_STARTED_EVT, if needed
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_notify_started(tNFA_STATUS status) {
  tNFA_CONN_EVT_DATA evt_data;

  if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_NOTIFY) {
    nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_NOTIFY;

    evt_data.status = status;

    if (nfa_dm_cb.disc_cb.excl_disc_entry.in_use)
      nfa_dm_conn_cback_event_notify(NFA_EXCLUSIVE_RF_CONTROL_STARTED_EVT,
                                     &evt_data);
    else
      nfa_dm_conn_cback_event_notify(NFA_RF_DISCOVERY_STARTED_EVT, &evt_data);
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_conn_event_notify
**
** Description      Notify application of CONN_CBACK event, using appropriate
**                  callback
**
** Returns          nothing
**
*******************************************************************************/
void nfa_dm_disc_conn_event_notify(uint8_t event, tNFA_STATUS status) {
  tNFA_CONN_EVT_DATA evt_data;

  if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_NOTIFY) {
    nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_NOTIFY;
    evt_data.status = status;

    if (nfa_dm_cb.flags & NFA_DM_FLAGS_EXCL_RF_ACTIVE) {
      /* Use exclusive RF mode callback */
      if (nfa_dm_cb.p_excl_conn_cback)
        (*nfa_dm_cb.p_excl_conn_cback)(event, &evt_data);
    } else {
      (*nfa_dm_cb.p_conn_cback)(event, &evt_data);
    }
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_force_to_idle
**
** Description      Force NFCC to idle state while waiting for deactivation NTF
**
** Returns          tNFC_STATUS
**
*******************************************************************************/
static tNFC_STATUS nfa_dm_disc_force_to_idle(void) {
  tNFC_STATUS status = NFC_STATUS_SEMANTIC_ERROR;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("disc_flags = 0x%x", nfa_dm_cb.disc_cb.disc_flags);

  /* do not execute more than one */
  if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_NTF) {
    nfa_dm_cb.disc_cb.disc_flags &= ~(NFA_DM_DISC_FLAGS_W4_NTF);
    nfa_dm_cb.disc_cb.disc_flags |= (NFA_DM_DISC_FLAGS_W4_RSP);
    nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
    status = NFC_Deactivate(NFC_DEACTIVATE_TYPE_IDLE);
  }

  return (status);
}

/*******************************************************************************
**
** Function         nfa_dm_disc_deact_ntf_timeout_cback
**
** Description      Timeout while waiting for deactivation NTF
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_deact_ntf_timeout_cback(__attribute__((unused))
                                                TIMER_LIST_ENT* p_tle) {
  LOG(ERROR) << __func__;

  nfa_dm_disc_force_to_idle();
}

/*******************************************************************************
**
** Function         nfa_dm_send_deactivate_cmd
**
** Description      Send deactivate command to NFCC, if needed.
**
** Returns          NFC_STATUS_OK             - deactivate cmd is sent
**                  NCI_STATUS_FAILED         - no buffers
**                  NFC_STATUS_SEMANTIC_ERROR - this function does not attempt
**                                              to send deactivate cmd
**
*******************************************************************************/
static tNFC_STATUS nfa_dm_send_deactivate_cmd(tNFC_DEACT_TYPE deactivate_type) {
  tNFC_STATUS status = NFC_STATUS_SEMANTIC_ERROR;
  tNFA_DM_DISC_FLAGS w4_flags =
      nfa_dm_cb.disc_cb.disc_flags &
      (NFA_DM_DISC_FLAGS_W4_RSP | NFA_DM_DISC_FLAGS_W4_NTF);

  if (!w4_flags) {
    /* if deactivate CMD was not sent to NFCC */
    nfa_dm_cb.disc_cb.disc_flags |=
        (NFA_DM_DISC_FLAGS_W4_RSP | NFA_DM_DISC_FLAGS_W4_NTF);

    status = NFC_Deactivate(deactivate_type);

    if (!nfa_dm_cb.disc_cb.tle.in_use) {
      nfa_dm_cb.disc_cb.tle.p_cback =
          (TIMER_CBACK*)nfa_dm_disc_deact_ntf_timeout_cback;
      nfa_sys_start_timer(&nfa_dm_cb.disc_cb.tle, 0,
                          NFA_DM_DISC_TIMEOUT_W4_DEACT_NTF);
    }
  } else {
    if (deactivate_type == NFC_DEACTIVATE_TYPE_SLEEP) {
      status = NFC_STATUS_SEMANTIC_ERROR;
    } else if (nfa_dm_cb.disc_cb.tle.in_use) {
      status = NFC_STATUS_OK;
    } else {
      status = nfa_dm_disc_force_to_idle();
    }
  }

  return status;
}

/*******************************************************************************
**
** Function         nfa_dm_start_rf_discover
**
** Description      Start RF discovery
**
** Returns          void
**
*******************************************************************************/
void nfa_dm_start_rf_discover(void) {
  tNFC_DISCOVER_PARAMS disc_params[NFA_DM_MAX_DISC_PARAMS];
  tNFA_DM_DISC_TECH_PROTO_MASK dm_disc_mask = 0, poll_mask, listen_mask;
  uint8_t config_params[10], *p;
  uint8_t num_params, xx;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;
  /* Make sure that RF discovery was enabled, or some app has exclusive control
   */
  if ((!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_ENABLED)) &&
      (nfa_dm_cb.disc_cb.excl_disc_entry.in_use == false)) {
    return;
  }

  /* get listen mode routing table for technology */
  nfa_ee_get_tech_route(NFA_EE_PWR_STATE_ON, nfa_dm_cb.disc_cb.listen_RT);

  if (nfa_dm_cb.disc_cb.excl_disc_entry.in_use) {
    nfa_dm_set_rf_listen_mode_raw_config(&dm_disc_mask);
    dm_disc_mask |= (nfa_dm_cb.disc_cb.excl_disc_entry.requested_disc_mask &
                     NFA_DM_DISC_MASK_POLL);
    nfa_dm_cb.disc_cb.excl_disc_entry.selected_disc_mask = dm_disc_mask;
  } else {
    /* Collect RF discovery request from sub-modules */
    for (xx = 0; xx < NFA_DM_DISC_NUM_ENTRIES; xx++) {
      if (nfa_dm_cb.disc_cb.entry[xx].in_use) {
        poll_mask = (nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask &
                     NFA_DM_DISC_MASK_POLL);

        /* clear poll mode technolgies and protocols which are already used by
         * others */
        poll_mask &= ~(dm_disc_mask & NFA_DM_DISC_MASK_POLL);

        listen_mask = 0;

        /*
        ** add listen mode technolgies and protocols if host ID is
        ** matched to listen mode routing table
        */

        /* NFC-A */
        if (nfa_dm_cb.disc_cb.entry[xx].host_id ==
            nfa_dm_cb.disc_cb.listen_RT[NFA_DM_DISC_LRT_NFC_A]) {
          listen_mask |=
              nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask &
              (NFA_DM_DISC_MASK_LA_T1T | NFA_DM_DISC_MASK_LA_T2T |
               NFA_DM_DISC_MASK_LA_ISO_DEP | NFA_DM_DISC_MASK_LA_NFC_DEP);
          if (NFC_GetNCIVersion() == NCI_VERSION_2_0) {
            listen_mask |= nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask &
                           NFA_DM_DISC_MASK_LACM_NFC_DEP;
          } else {
            listen_mask |= nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask &
                           NFA_DM_DISC_MASK_LAA_NFC_DEP;
          }
        } else {
          /* host can listen ISO-DEP based on AID routing */
          listen_mask |= (nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask &
                          NFA_DM_DISC_MASK_LA_ISO_DEP);
          if (NFC_GetNCIVersion() == NCI_VERSION_2_0) {
            listen_mask |= (nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask &
                            NFA_DM_DISC_MASK_LACM_NFC_DEP);
          } else {
            /* host can listen NFC-DEP based on protocol routing */
            listen_mask |= (nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask &
                            NFA_DM_DISC_MASK_LA_NFC_DEP);
            listen_mask |= (nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask &
                            NFA_DM_DISC_MASK_LAA_NFC_DEP);
          }
        }

        /* NFC-B */
        /* multiple hosts can listen ISO-DEP based on AID routing */
        listen_mask |= nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask &
                       NFA_DM_DISC_MASK_LB_ISO_DEP;

        /* NFC-F */
        /* NFCC can support NFC-DEP and T3T listening based on NFCID routing
         * regardless of NFC-F tech routing */
        listen_mask |= nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask &
                       (NFA_DM_DISC_MASK_LF_T3T | NFA_DM_DISC_MASK_LF_NFC_DEP);
        if (NFC_GetNCIVersion() != NCI_VERSION_2_0) {
          listen_mask |= nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask &
                         NFA_DM_DISC_MASK_LFA_NFC_DEP;
        }
        /* NFC-B Prime */
        if (nfa_dm_cb.disc_cb.entry[xx].host_id ==
            nfa_dm_cb.disc_cb.listen_RT[NFA_DM_DISC_LRT_NFC_BP]) {
          listen_mask |= nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask &
                         NFA_DM_DISC_MASK_L_B_PRIME;
        }

        /*
        ** clear listen mode technolgies and protocols which are already
        ** used by others
        */

        /* Check if other modules are listening T1T or T2T */
        if (dm_disc_mask &
            (NFA_DM_DISC_MASK_LA_T1T | NFA_DM_DISC_MASK_LA_T2T)) {
          listen_mask &=
              ~(NFA_DM_DISC_MASK_LA_T1T | NFA_DM_DISC_MASK_LA_T2T |
                NFA_DM_DISC_MASK_LA_ISO_DEP | NFA_DM_DISC_MASK_LA_NFC_DEP);
        }

        /* T1T/T2T has priority on NFC-A */
        if ((dm_disc_mask &
             (NFA_DM_DISC_MASK_LA_ISO_DEP | NFA_DM_DISC_MASK_LA_NFC_DEP)) &&
            (listen_mask &
             (NFA_DM_DISC_MASK_LA_T1T | NFA_DM_DISC_MASK_LA_T2T))) {
          dm_disc_mask &=
              ~(NFA_DM_DISC_MASK_LA_ISO_DEP | NFA_DM_DISC_MASK_LA_NFC_DEP);
        }

        /* Don't remove ISO-DEP because multiple hosts can listen ISO-DEP based
         * on AID routing */

        /* Check if other modules are listening NFC-DEP */
        if (NFC_GetNCIVersion() == NCI_VERSION_2_0) {
          if (dm_disc_mask &
              (NFA_DM_DISC_MASK_LA_NFC_DEP | NFA_DM_DISC_MASK_LACM_NFC_DEP)) {
            listen_mask &=
                ~(NFA_DM_DISC_MASK_LA_NFC_DEP | NFA_DM_DISC_MASK_LACM_NFC_DEP);
          }
        } else {
          if (dm_disc_mask &
              (NFA_DM_DISC_MASK_LA_NFC_DEP | NFA_DM_DISC_MASK_LAA_NFC_DEP)) {
            listen_mask &=
                ~(NFA_DM_DISC_MASK_LA_NFC_DEP | NFA_DM_DISC_MASK_LAA_NFC_DEP);
          }
        }

        nfa_dm_cb.disc_cb.entry[xx].selected_disc_mask =
            poll_mask | listen_mask;

        DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
            "nfa_dm_cb.disc_cb.entry[%d].selected_disc_mask = 0x%x", xx,
            nfa_dm_cb.disc_cb.entry[xx].selected_disc_mask);

        dm_disc_mask |= nfa_dm_cb.disc_cb.entry[xx].selected_disc_mask;
      }
    }

    /* Let P2P set GEN bytes for LLCP to NFCC */
    if (dm_disc_mask & NFA_DM_DISC_MASK_NFC_DEP) {
      nfa_p2p_set_config(dm_disc_mask);
    }
    if (NFC_GetNCIVersion() == NCI_VERSION_1_0) {
      if (dm_disc_mask &
          (NFA_DM_DISC_MASK_PF_NFC_DEP | NFA_DM_DISC_MASK_PF_T3T)) {
        /* According to the NFC Forum Activity spec, controllers must:
         * 1) Poll with RC=0 and SC=FFFF to find NFC-DEP targets
         * 2) Poll with RC=1 and SC=FFFF to find T3T targets
         * Many controllers don't do this yet, and seem to be activating
         * NFC-DEP by default.
         *
         * We can at least fix the scenario where we're not interested
         * in NFC-DEP, by setting RC=1 in that case. Otherwise, keep
         * the default of RC=0. */
        p = config_params;
        UINT8_TO_STREAM(p, NFC_PMID_PF_RC);
        UINT8_TO_STREAM(p, NCI_PARAM_LEN_PF_RC);
        if ((dm_disc_mask & NFA_DM_DISC_MASK_PF_NFC_DEP) &&
            !nfa_dm_is_p2p_paused()) {
          UINT8_TO_STREAM(p, 0x00);  // RC=0
        } else {
          UINT8_TO_STREAM(p, 0x01);  // RC=1
        }
        nfa_dm_check_set_config(p - config_params, config_params, false);
      }
    }
  }

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("dm_disc_mask = 0x%x", dm_disc_mask);

  /* Get Discovery Technology parameters */
  num_params = nfa_dm_get_rf_discover_config(dm_disc_mask, disc_params,
                                             NFA_DM_MAX_DISC_PARAMS);

  if (num_params) {
    /*
    ** NFCC will abort programming personality slots if not available.
    ** NFCC programs the personality slots in the following order of RF
    ** technologies: NFC-A, NFC-B, NFC-BP, NFC-I93
    */

    /* if this is not for exclusive control */
    if (!nfa_dm_cb.disc_cb.excl_disc_entry.in_use) {
      /* update listening protocols in each NFC technology */
      nfa_dm_set_rf_listen_mode_config(dm_disc_mask);
    }

    /* Set polling duty cycle */
    nfa_dm_set_total_duration();
    nfa_dm_cb.disc_cb.dm_disc_mask = dm_disc_mask;

    NFC_DiscoveryStart(num_params, disc_params, nfa_dm_disc_discovery_cback);
    /* set flag about waiting for response in IDLE state */
    nfa_dm_cb.disc_cb.disc_flags |= NFA_DM_DISC_FLAGS_W4_RSP;

    /* register callback to get interface error NTF */
    NFC_SetStaticRfCback(nfa_dm_disc_data_cback);
  } else {
    /* RF discovery is started but there is no valid technology or protocol to
     * discover */
    nfa_dm_disc_notify_started(NFA_STATUS_OK);
  }

  /* if Kovio presence check timer is running, timeout callback will reset the
   * activation information */
  if ((nfa_dm_cb.disc_cb.activated_protocol != NFC_PROTOCOL_KOVIO) ||
      (!nfa_dm_cb.disc_cb.kovio_tle.in_use)) {
    /* reset protocol and hanlde of activated sub-module */
    nfa_dm_cb.disc_cb.activated_protocol = NFA_PROTOCOL_INVALID;
    nfa_dm_cb.disc_cb.activated_handle = NFA_HANDLE_INVALID;
  }
}

/*******************************************************************************
**
** Function         nfa_dm_notify_discovery
**
** Description      Send RF discovery notification to upper layer
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_notify_discovery(tNFA_DM_RF_DISC_DATA* p_data) {
  tNFA_CONN_EVT_DATA conn_evt;

  /* let application select a device */
  conn_evt.disc_result.status = NFA_STATUS_OK;
  memcpy(&(conn_evt.disc_result.discovery_ntf), &(p_data->nfc_discover.result),
         sizeof(tNFC_RESULT_DEVT));

  nfa_dm_conn_cback_event_notify(NFA_DISC_RESULT_EVT, &conn_evt);
}

/*******************************************************************************
**
** Function         nfa_dm_disc_handle_kovio_activation
**
** Description      Handle Kovio activation; whether it's new or repeated
**                  activation
**
** Returns          TRUE if repeated activation. No need to notify activated
**                  event to upper layer
**
*******************************************************************************/
bool nfa_dm_disc_handle_kovio_activation(tNFC_DISCOVER* p_data,
                                         tNFA_DISCOVER_CBACK* p_disc_cback) {
  tNFC_DISCOVER disc_data;

  if (nfa_dm_cb.disc_cb.kovio_tle.in_use) {
    /* if this is new Kovio bar code tag */
    if ((nfa_dm_cb.activated_nfcid_len !=
         p_data->activate.rf_tech_param.param.pk.uid_len) ||
        (memcmp(p_data->activate.rf_tech_param.param.pk.uid,
                nfa_dm_cb.activated_nfcid, nfa_dm_cb.activated_nfcid_len))) {
      DLOG_IF(INFO, nfc_debug_enabled)
          << StringPrintf("new Kovio tag is detected");

      /* notify presence check failure for previous tag, if presence check is
       * pending */
      nfa_dm_disc_report_kovio_presence_check(NFA_STATUS_FAILED);

      /* notify deactivation of previous activation before notifying new
       * activation */
      if (p_disc_cback) {
        disc_data.deactivate.type = NFA_DEACTIVATE_TYPE_IDLE;
        (*(p_disc_cback))(NFA_DM_RF_DISC_DEACTIVATED_EVT, &disc_data);
      }

      /* restart timer */
      nfa_sys_start_timer(&nfa_dm_cb.disc_cb.kovio_tle, 0,
                          NFA_DM_DISC_TIMEOUT_KOVIO_PRESENCE_CHECK);
    } else {
      /* notify presence check ok, if presence check is pending */
      nfa_dm_disc_report_kovio_presence_check(NFC_STATUS_OK);

      /* restart timer and do not notify upper layer */
      nfa_sys_start_timer(&nfa_dm_cb.disc_cb.kovio_tle, 0,
                          NFA_DM_DISC_TIMEOUT_KOVIO_PRESENCE_CHECK);
      return true;
    }
  } else {
    /* this is the first activation, so start timer and notify upper layer */
    nfa_dm_cb.disc_cb.kovio_tle.p_cback =
        (TIMER_CBACK*)nfa_dm_disc_kovio_timeout_cback;
    nfa_sys_start_timer(&nfa_dm_cb.disc_cb.kovio_tle, 0,
                        NFA_DM_DISC_TIMEOUT_KOVIO_PRESENCE_CHECK);
  }

  return false;
}

/*******************************************************************************
**
** Function         nfa_dm_disc_notify_activation
**
** Description      Send RF activation notification to sub-module
**
** Returns          NFA_STATUS_OK if success
**
*******************************************************************************/
static tNFA_STATUS nfa_dm_disc_notify_activation(tNFC_DISCOVER* p_data) {
  uint8_t xx, host_id_in_LRT;
  uint8_t iso_dep_t3t__listen = NFA_DM_DISC_NUM_ENTRIES;

  tNFC_RF_TECH_N_MODE tech_n_mode = p_data->activate.rf_tech_param.mode;
  tNFC_PROTOCOL protocol = p_data->activate.protocol;

  tNFA_DM_DISC_TECH_PROTO_MASK activated_disc_mask;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("tech_n_mode:0x%X, proto:0x%X", tech_n_mode, protocol);

  if (nfa_dm_cb.disc_cb.excl_disc_entry.in_use) {
    nfa_dm_cb.disc_cb.activated_tech_mode = tech_n_mode;
    nfa_dm_cb.disc_cb.activated_rf_disc_id = p_data->activate.rf_disc_id;
    nfa_dm_cb.disc_cb.activated_rf_interface = p_data->activate.intf_param.type;
    nfa_dm_cb.disc_cb.activated_protocol = protocol;
    nfa_dm_cb.disc_cb.activated_handle = NFA_HANDLE_INVALID;

    if (protocol == NFC_PROTOCOL_KOVIO) {
      /* check whether it's new or repeated activation */
      if (nfa_dm_disc_handle_kovio_activation(
              p_data, nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback)) {
        /* do not notify activation of Kovio to upper layer */
        return (NFA_STATUS_OK);
      }
    }

    if (nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback)
      (*(nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback))(
          NFA_DM_RF_DISC_ACTIVATED_EVT, p_data);

    return (NFA_STATUS_OK);
  }

  /* if this is NFCEE direct RF interface, notify activation to whoever
   * listening UICC */
  if (p_data->activate.intf_param.type == NFC_INTERFACE_EE_DIRECT_RF) {
    for (xx = 0; xx < NFA_DM_DISC_NUM_ENTRIES; xx++) {
      if ((nfa_dm_cb.disc_cb.entry[xx].in_use) &&
          (nfa_dm_cb.disc_cb.entry[xx].host_id != NFA_DM_DISC_HOST_ID_DH)) {
        nfa_dm_cb.disc_cb.activated_rf_disc_id = p_data->activate.rf_disc_id;
        nfa_dm_cb.disc_cb.activated_rf_interface =
            p_data->activate.intf_param.type;
        nfa_dm_cb.disc_cb.activated_protocol = NFC_PROTOCOL_UNKNOWN;
        nfa_dm_cb.disc_cb.activated_handle = xx;

        DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
            "activated_rf_interface:0x%x, activated_handle: 0x%x",
            nfa_dm_cb.disc_cb.activated_rf_interface,
            nfa_dm_cb.disc_cb.activated_handle);

        if (nfa_dm_cb.disc_cb.entry[xx].p_disc_cback)
          (*(nfa_dm_cb.disc_cb.entry[xx].p_disc_cback))(
              NFA_DM_RF_DISC_ACTIVATED_EVT, p_data);

        return (NFA_STATUS_OK);
      }
    }
    return (NFA_STATUS_FAILED);
  }

  /* get bit mask of technolgies/mode and protocol */
  activated_disc_mask = nfa_dm_disc_get_disc_mask(tech_n_mode, protocol);

  /* get host ID of technology from listen mode routing table */
  if (tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_A) {
    host_id_in_LRT = nfa_dm_cb.disc_cb.listen_RT[NFA_DM_DISC_LRT_NFC_A];
  } else if (tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_B) {
    host_id_in_LRT = nfa_dm_cb.disc_cb.listen_RT[NFA_DM_DISC_LRT_NFC_B];
  } else if (tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_F) {
    host_id_in_LRT = nfa_dm_cb.disc_cb.listen_RT[NFA_DM_DISC_LRT_NFC_F];
  } else if (tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_B_PRIME) {
    host_id_in_LRT = nfa_dm_cb.disc_cb.listen_RT[NFA_DM_DISC_LRT_NFC_BP];
  } else /* DH only */
  {
    host_id_in_LRT = NFA_DM_DISC_HOST_ID_DH;
  }

  if (protocol == NFC_PROTOCOL_NFC_DEP) {
    /* Force NFC-DEP to the host */
    host_id_in_LRT = NFA_DM_DISC_HOST_ID_DH;
  }

  for (xx = 0; xx < NFA_DM_DISC_NUM_ENTRIES; xx++) {
    /* if any matching NFC technology and protocol */
    if (nfa_dm_cb.disc_cb.entry[xx].in_use) {
      if (nfa_dm_cb.disc_cb.entry[xx].host_id == host_id_in_LRT) {
        if (nfa_dm_cb.disc_cb.entry[xx].selected_disc_mask &
            activated_disc_mask)
          break;
      } else {
        /* check ISO-DEP listening even if host in LRT is not matched */
        if (protocol == NFC_PROTOCOL_ISO_DEP) {
          if ((tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_A) &&
              (nfa_dm_cb.disc_cb.entry[xx].selected_disc_mask &
               NFA_DM_DISC_MASK_LA_ISO_DEP)) {
            iso_dep_t3t__listen = xx;
          } else if ((tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_B) &&
                     (nfa_dm_cb.disc_cb.entry[xx].selected_disc_mask &
                      NFA_DM_DISC_MASK_LB_ISO_DEP)) {
            iso_dep_t3t__listen = xx;
          }
        }
        /* check T3T listening even if host in LRT is not matched */
        else if (protocol == NFC_PROTOCOL_T3T) {
          if ((tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_F) &&
              (nfa_dm_cb.disc_cb.entry[xx].selected_disc_mask &
               NFA_DM_DISC_MASK_LF_T3T)) {
            iso_dep_t3t__listen = xx;
          }
        }
      }
    }
  }

  if (xx >= NFA_DM_DISC_NUM_ENTRIES) {
    /* if any ISO-DEP or T3T listening even if host in LRT is not matched */
    xx = iso_dep_t3t__listen;
  }
  if (protocol == NFC_PROTOCOL_NFC_DEP &&
      (tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE ||
       tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE ||
       tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_A)) {
    if (appl_dta_mode_flag == 1 && tech_n_mode == NFC_DISCOVERY_TYPE_LISTEN_A) {
      DLOG_IF(INFO, nfc_debug_enabled)
          << StringPrintf("DTA Mode Enabled : NFC-A Passive Listen Mode");
    }
  }

  if (xx < NFA_DM_DISC_NUM_ENTRIES) {
    nfa_dm_cb.disc_cb.activated_tech_mode = tech_n_mode;
    nfa_dm_cb.disc_cb.activated_rf_disc_id = p_data->activate.rf_disc_id;
    nfa_dm_cb.disc_cb.activated_rf_interface = p_data->activate.intf_param.type;
    nfa_dm_cb.disc_cb.activated_protocol = protocol;
    nfa_dm_cb.disc_cb.activated_handle = xx;

    DLOG_IF(INFO, nfc_debug_enabled)
        << StringPrintf("activated_protocol:0x%x, activated_handle: 0x%x",
                        nfa_dm_cb.disc_cb.activated_protocol,
                        nfa_dm_cb.disc_cb.activated_handle);

    if (protocol == NFC_PROTOCOL_KOVIO) {
      /* check whether it's new or repeated activation */
      if (nfa_dm_disc_handle_kovio_activation(
              p_data, nfa_dm_cb.disc_cb.entry[xx].p_disc_cback)) {
        /* do not notify activation of Kovio to upper layer */
        return (NFA_STATUS_OK);
      }
    }

    if (nfa_dm_cb.disc_cb.entry[xx].p_disc_cback)
      (*(nfa_dm_cb.disc_cb.entry[xx].p_disc_cback))(
          NFA_DM_RF_DISC_ACTIVATED_EVT, p_data);

    return (NFA_STATUS_OK);
  } else {
    nfa_dm_cb.disc_cb.activated_protocol = NFA_PROTOCOL_INVALID;
    nfa_dm_cb.disc_cb.activated_handle = NFA_HANDLE_INVALID;
    return (NFA_STATUS_FAILED);
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_notify_deactivation
**
** Description      Send deactivation notification to sub-module
**
** Returns          None
**
*******************************************************************************/
static void nfa_dm_disc_notify_deactivation(tNFA_DM_RF_DISC_SM_EVENT sm_event,
                                            tNFC_DISCOVER* p_data) {
  tNFA_HANDLE xx;
  tNFA_CONN_EVT_DATA evt_data;
  tNFC_DISCOVER disc_data;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
      "activated_handle=%d", nfa_dm_cb.disc_cb.activated_handle);

  if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_CHECKING) {
    DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("for sleep wakeup");
    return;
  }

  if (sm_event == NFA_DM_RF_DEACTIVATE_RSP) {
    /*
    ** Activation has been aborted by upper layer in
    ** NFA_DM_RFST_W4_ALL_DISCOVERIES or NFA_DM_RFST_W4_HOST_SELECT
    ** Deactivation by upper layer or RF link loss in
    ** NFA_DM_RFST_LISTEN_SLEEP
    ** No sub-module is activated at this state.
    */

    if (nfa_dm_cb.disc_cb.disc_state == NFA_DM_RFST_LISTEN_SLEEP) {
      if (nfa_dm_cb.disc_cb.excl_disc_entry.in_use) {
        if (nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback) {
          disc_data.deactivate.type = NFA_DEACTIVATE_TYPE_IDLE;
          (*(nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback))(
              NFA_DM_RF_DISC_DEACTIVATED_EVT, &disc_data);
        }
      } else {
        /* let each sub-module handle deactivation */
        for (xx = 0; xx < NFA_DM_DISC_NUM_ENTRIES; xx++) {
          if ((nfa_dm_cb.disc_cb.entry[xx].in_use) &&
              (nfa_dm_cb.disc_cb.entry[xx].selected_disc_mask &
               NFA_DM_DISC_MASK_LISTEN)) {
            disc_data.deactivate.type = NFA_DEACTIVATE_TYPE_IDLE;
            (*(nfa_dm_cb.disc_cb.entry[xx].p_disc_cback))(
                NFA_DM_RF_DISC_DEACTIVATED_EVT, &disc_data);
          }
        }
      }
    } else if ((!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_STOPPING)) ||
               (nfa_dm_cb.disc_cb.deact_notify_pending)) {
      xx = nfa_dm_cb.disc_cb.activated_handle;

      /* notify event to activated module if failed while reactivation */
      if (nfa_dm_cb.disc_cb.excl_disc_entry.in_use) {
        if (nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback) {
          disc_data.deactivate.type = NFA_DEACTIVATE_TYPE_IDLE;
          (*(nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback))(
              NFA_DM_RF_DISC_DEACTIVATED_EVT, p_data);
        }
      } else if ((xx < NFA_DM_DISC_NUM_ENTRIES) &&
                 (nfa_dm_cb.disc_cb.entry[xx].in_use) &&
                 (nfa_dm_cb.disc_cb.entry[xx].p_disc_cback)) {
        (*(nfa_dm_cb.disc_cb.entry[xx].p_disc_cback))(
            NFA_DM_RF_DISC_DEACTIVATED_EVT, p_data);
      } else {
        /* notify deactivation to application if there is no activated module */
        evt_data.deactivated.type = NFA_DEACTIVATE_TYPE_IDLE;
        nfa_dm_conn_cback_event_notify(NFA_DEACTIVATED_EVT, &evt_data);
      }
    }
  } else {
    if (nfa_dm_cb.disc_cb.activated_protocol == NFC_PROTOCOL_KOVIO) {
      if (nfa_dm_cb.disc_cb.kovio_tle.in_use) {
        /* restart timer and do not notify upper layer */
        nfa_sys_start_timer(&nfa_dm_cb.disc_cb.kovio_tle, 0,
                            NFA_DM_DISC_TIMEOUT_KOVIO_PRESENCE_CHECK);
        return;
      }
      /* Otherwise, upper layer initiated deactivation. */
    }

    /* notify event to activated module */
    if (nfa_dm_cb.disc_cb.excl_disc_entry.in_use) {
      if (nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback) {
        disc_data.deactivate.type = NFA_DEACTIVATE_TYPE_IDLE;
        (*(nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback))(
            NFA_DM_RF_DISC_DEACTIVATED_EVT, p_data);
      }
    } else {
      xx = nfa_dm_cb.disc_cb.activated_handle;

      if ((xx < NFA_DM_DISC_NUM_ENTRIES) &&
          (nfa_dm_cb.disc_cb.entry[xx].in_use)) {
        if (nfa_dm_cb.disc_cb.entry[xx].p_disc_cback)
          (*(nfa_dm_cb.disc_cb.entry[xx].p_disc_cback))(
              NFA_DM_RF_DISC_DEACTIVATED_EVT, p_data);
      }
    }
  }

  /* clear activated information */
  nfa_dm_cb.disc_cb.activated_tech_mode = 0;
  nfa_dm_cb.disc_cb.activated_rf_disc_id = 0;
  nfa_dm_cb.disc_cb.activated_rf_interface = 0;
  nfa_dm_cb.disc_cb.activated_protocol = NFA_PROTOCOL_INVALID;
  nfa_dm_cb.disc_cb.activated_handle = NFA_HANDLE_INVALID;
  nfa_dm_cb.disc_cb.deact_notify_pending = false;
}

/*******************************************************************************
**
** Function         nfa_dm_disc_sleep_wakeup
**
** Description      Put tag to sleep, then wake it up. Can be used Perform
**                  legacy presence check or to wake up tag that went to HALT
**                  state
**
** Returns          TRUE if operation started
**
*******************************************************************************/
tNFC_STATUS nfa_dm_disc_sleep_wakeup(void) {
  tNFC_STATUS status = NFC_STATUS_FAILED;

  if (nfa_dm_cb.disc_cb.disc_state == NFA_DM_RFST_POLL_ACTIVE) {
    /* Deactivate to sleep mode */
    status = nfa_dm_send_deactivate_cmd(NFC_DEACTIVATE_TYPE_SLEEP);
    if (status == NFC_STATUS_OK) {
      /* deactivate to sleep is sent on behalf of sleep wakeup.
       * set the sleep wakeup information in control block */
      nfa_dm_cb.disc_cb.disc_flags |= NFA_DM_DISC_FLAGS_CHECKING;
      nfa_dm_cb.disc_cb.deact_pending = false;
    }
  }

  return (status);
}

/*******************************************************************************
**
** Function         nfa_dm_is_raw_frame_session
**
** Description      If NFA_SendRawFrame is called since RF activation,
**                  this function returns TRUE.
**
** Returns          TRUE if NFA_SendRawFrame is called
**
*******************************************************************************/
bool nfa_dm_is_raw_frame_session(void) {
  return ((nfa_dm_cb.flags & NFA_DM_FLAGS_RAW_FRAME) ? true : false);
}

/*******************************************************************************
**
** Function         nfa_dm_is_p2p_paused
**
** Description      If NFA_PauseP2p is called sand still effective,
**                  this function returns TRUE.
**
** Returns          TRUE if NFA_SendRawFrame is called
**
*******************************************************************************/
bool nfa_dm_is_p2p_paused(void) {
  return ((nfa_dm_cb.flags & NFA_DM_FLAGS_P2P_PAUSED) ? true : false);
}

/*******************************************************************************
**
** Function         nfa_dm_disc_end_sleep_wakeup
**
** Description      Sleep Wakeup is complete
**
** Returns          None
**
*******************************************************************************/
static void nfa_dm_disc_end_sleep_wakeup(tNFC_STATUS status) {
  if ((nfa_dm_cb.disc_cb.activated_protocol == NFC_PROTOCOL_KOVIO) &&
      (nfa_dm_cb.disc_cb.kovio_tle.in_use)) {
    /* ignore it while doing Kovio presence check */
    return;
  }

  if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_CHECKING) {
    nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_CHECKING;

    /* notify RW module that sleep wakeup is finished */
    nfa_rw_handle_sleep_wakeup_rsp(status);

    if (nfa_dm_cb.disc_cb.deact_pending) {
      nfa_dm_cb.disc_cb.deact_pending = false;
      /* Perform pending deactivate command and on response notfiy deactivation
       */
      nfa_dm_cb.disc_cb.deact_notify_pending = true;
      tNFA_DM_RF_DISC_DATA nfa_dm_rf_disc_data;
      nfa_dm_rf_disc_data.deactivate_type =
          nfa_dm_cb.disc_cb.pending_deact_type;
      nfa_dm_disc_sm_execute(NFA_DM_RF_DEACTIVATE_CMD, &nfa_dm_rf_disc_data);
    }
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_kovio_timeout_cback
**
** Description      Timeout for Kovio bar code tag presence check
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_kovio_timeout_cback(__attribute__((unused))
                                            TIMER_LIST_ENT* p_tle) {
  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  /* notify presence check failure, if presence check is pending */
  nfa_dm_disc_report_kovio_presence_check(NFC_STATUS_FAILED);

  if (nfa_dm_cb.disc_cb.disc_state == NFA_DM_RFST_POLL_ACTIVE) {
    /* restart timer in case that upper layer's presence check interval is too
     * long */
    nfa_sys_start_timer(&nfa_dm_cb.disc_cb.kovio_tle, 0,
                        NFA_DM_DISC_TIMEOUT_KOVIO_PRESENCE_CHECK);
  } else {
    /* notify upper layer deactivated event */
    tNFC_DEACTIVATE_DEVT deact;
    deact.status = NFC_STATUS_OK;
    deact.type = NFC_DEACTIVATE_TYPE_DISCOVERY;
    deact.is_ntf = true;
    tNFC_DISCOVER nfc_discover;
    nfc_discover.deactivate = deact;
    nfa_dm_disc_notify_deactivation(NFA_DM_RF_DEACTIVATE_NTF, &nfc_discover);
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_start_kovio_presence_check
**
** Description      Deactivate to discovery mode and wait for activation
**
** Returns          TRUE if operation started
**
*******************************************************************************/
tNFC_STATUS nfa_dm_disc_start_kovio_presence_check(void) {
  tNFC_STATUS status = NFC_STATUS_FAILED;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  if ((nfa_dm_cb.disc_cb.activated_protocol == NFC_PROTOCOL_KOVIO) &&
      (nfa_dm_cb.disc_cb.kovio_tle.in_use)) {
    if (nfa_dm_cb.disc_cb.disc_state == NFA_DM_RFST_POLL_ACTIVE) {
      /* restart timer */
      nfa_sys_start_timer(&nfa_dm_cb.disc_cb.kovio_tle, 0,
                          NFA_DM_DISC_TIMEOUT_KOVIO_PRESENCE_CHECK);

      /* Deactivate to discovery mode */
      status = nfa_dm_send_deactivate_cmd(NFC_DEACTIVATE_TYPE_DISCOVERY);

      if (status == NFC_STATUS_OK) {
        /* deactivate to sleep is sent on behalf of sleep wakeup.
         * set the sleep wakeup information in control block */
        nfa_dm_cb.disc_cb.disc_flags |= NFA_DM_DISC_FLAGS_CHECKING;
        nfa_dm_cb.disc_cb.deact_pending = false;
      }
    } else {
      /* wait for next activation */
      nfa_dm_cb.disc_cb.disc_flags |= NFA_DM_DISC_FLAGS_CHECKING;
      nfa_dm_cb.disc_cb.deact_pending = false;
      status = NFC_STATUS_OK;
    }
  }

  return (status);
}

/*******************************************************************************
**
** Function         nfa_dm_disc_report_kovio_presence_check
**
** Description      Report Kovio presence check status
**
** Returns          None
**
*******************************************************************************/
static void nfa_dm_disc_report_kovio_presence_check(tNFC_STATUS status) {
  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_CHECKING) {
    nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_CHECKING;

    /* notify RW module that sleep wakeup is finished */
    nfa_rw_handle_presence_check_rsp(status);

    if (nfa_dm_cb.disc_cb.deact_pending) {
      nfa_dm_cb.disc_cb.deact_pending = false;
      tNFA_DM_RF_DISC_DATA nfa_dm_rf_disc_data;
      nfa_dm_rf_disc_data.deactivate_type =
          nfa_dm_cb.disc_cb.pending_deact_type;
      nfa_dm_disc_sm_execute(NFA_DM_RF_DEACTIVATE_CMD, &nfa_dm_rf_disc_data);
    }
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_data_cback
**
** Description      Monitoring interface error through data callback
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_data_cback(__attribute__((unused)) uint8_t conn_id,
                                   tNFC_CONN_EVT event, tNFC_CONN* p_data) {
  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  /* if selection failed */
  if (event == NFC_ERROR_CEVT) {
    nfa_dm_disc_sm_execute(NFA_DM_CORE_INTF_ERROR_NTF, NULL);
  } else if (event == NFC_DATA_CEVT) {
    GKI_freebuf(p_data->data.p_data);
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_new_state
**
** Description      Processing discovery events in NFA_DM_RFST_IDLE state
**
** Returns          void
**
*******************************************************************************/
void nfa_dm_disc_new_state(tNFA_DM_RF_DISC_STATE new_state) {
  tNFA_CONN_EVT_DATA evt_data;
  tNFA_DM_RF_DISC_STATE old_state = nfa_dm_cb.disc_cb.disc_state;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
      "old_state: %s (%d), new_state: %s (%d) "
      "disc_flags: 0x%x",
      nfa_dm_disc_state_2_str(nfa_dm_cb.disc_cb.disc_state).c_str(),
      nfa_dm_cb.disc_cb.disc_state, nfa_dm_disc_state_2_str(new_state).c_str(),
      new_state, nfa_dm_cb.disc_cb.disc_flags);

  nfa_dm_cb.disc_cb.disc_state = new_state;

  /* not error recovering */
  if ((new_state == NFA_DM_RFST_IDLE) &&
      (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_RSP))) {
    if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_STOPPING) {
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_STOPPING;

      /* if exclusive RF control is stopping */
      if (nfa_dm_cb.flags & NFA_DM_FLAGS_EXCL_RF_ACTIVE) {
        if (old_state > NFA_DM_RFST_DISCOVERY) {
          /* notify deactivation to application */
          evt_data.deactivated.type = NFA_DEACTIVATE_TYPE_IDLE;
          nfa_dm_conn_cback_event_notify(NFA_DEACTIVATED_EVT, &evt_data);
        }

        nfa_dm_rel_excl_rf_control_and_notify();
      } else {
        evt_data.status = NFA_STATUS_OK;
        nfa_dm_conn_cback_event_notify(NFA_RF_DISCOVERY_STOPPED_EVT, &evt_data);
      }
    }
    if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_DISABLING) {
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_DISABLING;
      nfa_sys_check_disabled();
    }
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_sm_idle
**
** Description      Processing discovery events in NFA_DM_RFST_IDLE state
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_sm_idle(tNFA_DM_RF_DISC_SM_EVENT event,
                                tNFA_DM_RF_DISC_DATA* p_data) {
  uint8_t xx;

  switch (event) {
    case NFA_DM_RF_DISCOVER_CMD:
      nfa_dm_start_rf_discover();
      break;

    case NFA_DM_RF_DISCOVER_RSP:
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_RSP;

      if (p_data->nfc_discover.status == NFC_STATUS_OK) {
        nfa_dm_disc_new_state(NFA_DM_RFST_DISCOVERY);

        /* if RF discovery was stopped while waiting for response */
        if (nfa_dm_cb.disc_cb.disc_flags &
            (NFA_DM_DISC_FLAGS_STOPPING | NFA_DM_DISC_FLAGS_DISABLING)) {
          /* stop discovery */
          nfa_dm_cb.disc_cb.disc_flags |= NFA_DM_DISC_FLAGS_W4_RSP;
          NFC_Deactivate(NFA_DEACTIVATE_TYPE_IDLE);
          break;
        }

        if (nfa_dm_cb.disc_cb.excl_disc_entry.in_use) {
          if (nfa_dm_cb.disc_cb.excl_disc_entry.disc_flags &
              NFA_DM_DISC_FLAGS_NOTIFY) {
            nfa_dm_cb.disc_cb.excl_disc_entry.disc_flags &=
                ~NFA_DM_DISC_FLAGS_NOTIFY;

            if (nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback)
              (*(nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback))(
                  NFA_DM_RF_DISC_START_EVT, &p_data->nfc_discover);
          }
        } else {
          /* notify event to each module which is waiting for start */
          for (xx = 0; xx < NFA_DM_DISC_NUM_ENTRIES; xx++) {
            /* if registered module is waiting for starting discovery */
            if ((nfa_dm_cb.disc_cb.entry[xx].in_use) &&
                (nfa_dm_cb.disc_cb.dm_disc_mask &
                 nfa_dm_cb.disc_cb.entry[xx].selected_disc_mask) &&
                (nfa_dm_cb.disc_cb.entry[xx].disc_flags &
                 NFA_DM_DISC_FLAGS_NOTIFY)) {
              nfa_dm_cb.disc_cb.entry[xx].disc_flags &=
                  ~NFA_DM_DISC_FLAGS_NOTIFY;

              if (nfa_dm_cb.disc_cb.entry[xx].p_disc_cback)
                (*(nfa_dm_cb.disc_cb.entry[xx].p_disc_cback))(
                    NFA_DM_RF_DISC_START_EVT, &p_data->nfc_discover);
            }
          }
        }
        nfa_dm_disc_notify_started(p_data->nfc_discover.status);
      } else {
        /* in rare case that the discovery states of NFCC and DH mismatch and
         * NFCC rejects Discover Cmd
         * deactivate idle and then start disvocery when got deactivate rsp */
        nfa_dm_cb.disc_cb.disc_flags |= NFA_DM_DISC_FLAGS_W4_RSP;
        NFC_Deactivate(NFA_DEACTIVATE_TYPE_IDLE);
      }
      break;

    case NFA_DM_RF_DEACTIVATE_RSP:
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_RSP;

      /* if NFCC goes to idle successfully */
      if (p_data->nfc_discover.status == NFC_STATUS_OK) {
        /* if DH forced to go idle while waiting for deactivation NTF */
        if (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_NTF)) {
          nfa_dm_disc_notify_deactivation(NFA_DM_RF_DEACTIVATE_NTF,
                                          &(p_data->nfc_discover));

          /* check any pending flags like NFA_DM_DISC_FLAGS_STOPPING or
           * NFA_DM_DISC_FLAGS_DISABLING */
          nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
          /* check if need to restart discovery after resync discovery state
           * with NFCC */
          nfa_dm_start_rf_discover();
        }
        /* Otherwise, deactivating when getting unexpected activation */
      }
      /* Otherwise, wait for deactivation NTF */
      break;

    case NFA_DM_RF_DEACTIVATE_NTF:
      /* if NFCC sent this after NFCC had rejected deactivate CMD to idle while
       * deactivating */
      if (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_NTF)) {
        if (p_data->nfc_discover.deactivate.type ==
            NFC_DEACTIVATE_TYPE_DISCOVERY) {
          /* stop discovery */
          nfa_dm_cb.disc_cb.disc_flags |= NFA_DM_DISC_FLAGS_W4_RSP;
          NFC_Deactivate(NFA_DEACTIVATE_TYPE_IDLE);
        } else {
          nfa_dm_disc_notify_deactivation(NFA_DM_RF_DEACTIVATE_NTF,
                                          &(p_data->nfc_discover));
          /* check any pending flags like NFA_DM_DISC_FLAGS_STOPPING or
           * NFA_DM_DISC_FLAGS_DISABLING */
          nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
          /* check if need to restart discovery after resync discovery state
           * with NFCC */
          nfa_dm_start_rf_discover();
        }
      }
      /* Otherwise, deactivated when received unexpected activation in idle
       * state */
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_NTF;
      break;

    case NFA_DM_RF_INTF_ACTIVATED_NTF:
      /* unexpected activation, deactivate to idle */
      nfa_dm_cb.disc_cb.disc_flags |=
          (NFA_DM_DISC_FLAGS_W4_RSP | NFA_DM_DISC_FLAGS_W4_NTF);
      NFC_Deactivate(NFA_DEACTIVATE_TYPE_IDLE);
      break;

    case NFA_DM_LP_LISTEN_CMD:
      nfa_dm_disc_new_state(NFA_DM_RFST_LP_LISTEN);
      break;

    default:
      LOG(ERROR) << StringPrintf("Unexpected discovery event");
      break;
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_sm_discovery
**
** Description      Processing discovery events in NFA_DM_RFST_DISCOVERY state
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_sm_discovery(tNFA_DM_RF_DISC_SM_EVENT event,
                                     tNFA_DM_RF_DISC_DATA* p_data) {
  switch (event) {
    case NFA_DM_RF_DEACTIVATE_CMD:
      /* if deactivate CMD was not sent to NFCC */
      if (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_RSP)) {
        nfa_dm_cb.disc_cb.disc_flags |= NFA_DM_DISC_FLAGS_W4_RSP;
        NFC_Deactivate(p_data->deactivate_type);
      }
      break;
    case NFA_DM_RF_DEACTIVATE_RSP:
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_RSP;

      /* if it's not race condition between deactivate CMD and activate NTF */
      if (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_NTF)) {
        /* do not notify deactivated to idle in RF discovery state
        ** because it is internal or stopping RF discovery
        */

        /* there was no activation while waiting for deactivation RSP */
        nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
        nfa_dm_start_rf_discover();
      }
      break;
    case NFA_DM_RF_DISCOVER_NTF:
      nfa_dm_disc_new_state(NFA_DM_RFST_W4_ALL_DISCOVERIES);
      nfa_dm_notify_discovery(p_data);
      break;
    case NFA_DM_RF_INTF_ACTIVATED_NTF:
      if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_RSP) {
        DLOG_IF(INFO, nfc_debug_enabled)
            << StringPrintf("RF Activated while waiting for deactivation RSP");
        /* it's race condition. DH has to wait for deactivation NTF */
        nfa_dm_cb.disc_cb.disc_flags |= NFA_DM_DISC_FLAGS_W4_NTF;
      } else {
        if (p_data->nfc_discover.activate.intf_param.type ==
            NFC_INTERFACE_EE_DIRECT_RF) {
          nfa_dm_disc_new_state(NFA_DM_RFST_LISTEN_ACTIVE);
        } else if (p_data->nfc_discover.activate.rf_tech_param.mode & 0x80) {
          /* Listen mode */
          nfa_dm_disc_new_state(NFA_DM_RFST_LISTEN_ACTIVE);
        } else {
          /* Poll mode */
          nfa_dm_disc_new_state(NFA_DM_RFST_POLL_ACTIVE);
        }

        if (nfa_dm_disc_notify_activation(&(p_data->nfc_discover)) ==
            NFA_STATUS_FAILED) {
          DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
              "Not matched, restart discovery after receiving "
              "deactivate ntf");

          /* after receiving deactivate event, restart discovery */
          nfa_dm_cb.disc_cb.disc_flags |=
              (NFA_DM_DISC_FLAGS_W4_RSP | NFA_DM_DISC_FLAGS_W4_NTF);
          NFC_Deactivate(NFA_DEACTIVATE_TYPE_IDLE);
        }
      }
      break;

    case NFA_DM_RF_DEACTIVATE_NTF:
      /* if there was race condition between deactivate CMD and activate NTF */
      if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_NTF) {
        /* race condition is resolved */
        nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_NTF;

        if (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_RSP)) {
          /* do not notify deactivated to idle in RF discovery state
          ** because it is internal or stopping RF discovery
          */

          nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
          nfa_dm_start_rf_discover();
        }
      }
      break;
    case NFA_DM_LP_LISTEN_CMD:
      break;
    case NFA_DM_CORE_INTF_ERROR_NTF:
      break;
    default:
      LOG(ERROR) << StringPrintf("Unexpected discovery event");
      break;
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_sm_w4_all_discoveries
**
** Description      Processing discovery events in
**                  NFA_DM_RFST_W4_ALL_DISCOVERIES state
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_sm_w4_all_discoveries(tNFA_DM_RF_DISC_SM_EVENT event,
                                              tNFA_DM_RF_DISC_DATA* p_data) {
  switch (event) {
    case NFA_DM_RF_DEACTIVATE_CMD:
      /* if deactivate CMD was not sent to NFCC */
      if (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_RSP)) {
        nfa_dm_cb.disc_cb.disc_flags |= NFA_DM_DISC_FLAGS_W4_RSP;
        /* only IDLE mode is allowed */
        NFC_Deactivate(NFA_DEACTIVATE_TYPE_IDLE);
      }
      break;
    case NFA_DM_RF_DEACTIVATE_RSP:
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_RSP;
      /* notify exiting from w4 all discoverie state */
      nfa_dm_disc_notify_deactivation(NFA_DM_RF_DEACTIVATE_RSP,
                                      &(p_data->nfc_discover));

      nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
      nfa_dm_start_rf_discover();
      break;
    case NFA_DM_RF_DISCOVER_NTF:
      /* if deactivate CMD is already sent then ignore discover NTF */
      if (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_RSP)) {
        /* Notification Type = NCI_DISCOVER_NTF_LAST or
         * NCI_DISCOVER_NTF_LAST_ABORT */
        if (p_data->nfc_discover.result.more != NCI_DISCOVER_NTF_MORE) {
          nfa_dm_disc_new_state(NFA_DM_RFST_W4_HOST_SELECT);
        }
        nfa_dm_notify_discovery(p_data);
      }
      break;
    case NFA_DM_RF_INTF_ACTIVATED_NTF:
      /*
      ** This is only for ISO15693.
      ** FW sends activation NTF when all responses are received from tags
      ** without host selecting.
      */
      nfa_dm_disc_new_state(NFA_DM_RFST_POLL_ACTIVE);

      if (nfa_dm_disc_notify_activation(&(p_data->nfc_discover)) ==
          NFA_STATUS_FAILED) {
        DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
            "Not matched, restart discovery after receiving deactivate ntf");

        /* after receiving deactivate event, restart discovery */
        NFC_Deactivate(NFA_DEACTIVATE_TYPE_IDLE);
      }
      break;
    default:
      LOG(ERROR) << StringPrintf("Unexpected discovery event");
      break;
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_sm_w4_host_select
**
** Description      Processing discovery events in NFA_DM_RFST_W4_HOST_SELECT
**                  state
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_sm_w4_host_select(tNFA_DM_RF_DISC_SM_EVENT event,
                                          tNFA_DM_RF_DISC_DATA* p_data) {
  tNFA_CONN_EVT_DATA conn_evt;
  tNFA_DM_DISC_FLAGS old_sleep_wakeup_flag =
      (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_CHECKING);
  bool sleep_wakeup_event = false;
  bool sleep_wakeup_event_processed = false;
  tNFA_STATUS status;

  switch (event) {
    case NFA_DM_RF_DISCOVER_SELECT_CMD:
      /* if not waiting to deactivate */
      if (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_RSP)) {
        NFC_DiscoverySelect(p_data->select.rf_disc_id, p_data->select.protocol,
                            p_data->select.rf_interface);
      } else {
        nfa_dm_disc_conn_event_notify(NFA_SELECT_RESULT_EVT, NFA_STATUS_FAILED);
      }
      break;

    case NFA_DM_RF_DISCOVER_SELECT_RSP:
      sleep_wakeup_event = true;
      /* notify application status of selection */
      if (p_data->nfc_discover.status == NFC_STATUS_OK) {
        sleep_wakeup_event_processed = true;
        conn_evt.status = NFA_STATUS_OK;
        /* register callback to get interface error NTF */
        NFC_SetStaticRfCback(nfa_dm_disc_data_cback);
      } else
        conn_evt.status = NFA_STATUS_FAILED;

      if (!old_sleep_wakeup_flag) {
        nfa_dm_disc_conn_event_notify(NFA_SELECT_RESULT_EVT,
                                      p_data->nfc_discover.status);
      }
      break;
    case NFA_DM_RF_INTF_ACTIVATED_NTF:
      nfa_dm_disc_new_state(NFA_DM_RFST_POLL_ACTIVE);
      /* always call nfa_dm_disc_notify_activation to update protocol/interface
       * information in NFA control blocks */
      status = nfa_dm_disc_notify_activation(&(p_data->nfc_discover));
      if (old_sleep_wakeup_flag) {
        /* Handle sleep wakeup success: notify RW module of sleep wakeup of tag;
         * if deactivation is pending then deactivate  */
        nfa_dm_disc_end_sleep_wakeup(NFC_STATUS_OK);
      } else if (status == NFA_STATUS_FAILED) {
        DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
            "Not matched, restart discovery after receiving deactivate ntf");

        /* after receiving deactivate event, restart discovery */
        NFC_Deactivate(NFA_DEACTIVATE_TYPE_IDLE);
      }
      break;
    case NFA_DM_RF_DEACTIVATE_CMD:
      if (old_sleep_wakeup_flag) {
        nfa_dm_cb.disc_cb.deact_pending = true;
        nfa_dm_cb.disc_cb.pending_deact_type = p_data->deactivate_type;
      }
      /* if deactivate CMD was not sent to NFCC */
      else if (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_RSP)) {
        nfa_dm_cb.disc_cb.disc_flags |= NFA_DM_DISC_FLAGS_W4_RSP;
        /* only IDLE mode is allowed */
        NFC_Deactivate(NFA_DEACTIVATE_TYPE_IDLE);
      }
      break;
    case NFA_DM_RF_DEACTIVATE_RSP:
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_RSP;
      /* notify exiting from host select state */
      nfa_dm_disc_notify_deactivation(NFA_DM_RF_DEACTIVATE_RSP,
                                      &(p_data->nfc_discover));

      nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
      nfa_dm_start_rf_discover();
      break;

    case NFA_DM_CORE_INTF_ERROR_NTF:
      sleep_wakeup_event = true;
      if (!old_sleep_wakeup_flag) {
        /* target activation failed, upper layer may deactivate or select again
         */
        conn_evt.status = NFA_STATUS_FAILED;
        nfa_dm_conn_cback_event_notify(NFA_SELECT_RESULT_EVT, &conn_evt);
      }
      break;
    default:
      LOG(ERROR) << StringPrintf("Unexpected discovery event");
      break;
  }

  if (old_sleep_wakeup_flag && sleep_wakeup_event &&
      !sleep_wakeup_event_processed) {
    /* performing sleep wakeup and exception conditions happened
     * clear sleep wakeup information and report failure */
    nfa_dm_disc_end_sleep_wakeup(NFC_STATUS_FAILED);
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_sm_poll_active
**
** Description      Processing discovery events in NFA_DM_RFST_POLL_ACTIVE state
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_sm_poll_active(tNFA_DM_RF_DISC_SM_EVENT event,
                                       tNFA_DM_RF_DISC_DATA* p_data) {
  tNFC_STATUS status;
  tNFA_DM_DISC_FLAGS old_sleep_wakeup_flag =
      (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_CHECKING);
  bool sleep_wakeup_event = false;
  bool sleep_wakeup_event_processed = false;

  switch (event) {
    case NFA_DM_RF_DEACTIVATE_CMD:
      if (NFC_GetNCIVersion() == NCI_VERSION_2_0) {
        if ((nfa_dm_cb.disc_cb.activated_rf_interface == NFC_INTERFACE_FRAME) &&
            (p_data->deactivate_type == NFC_DEACTIVATE_TYPE_SLEEP)) {
          /* NCI 2.0- DH is responsible for sending deactivation commands before
           * RF_DEACTIVATE_CMD */
          nfa_dm_send_tag_deselect_cmd(nfa_dm_cb.disc_cb.activated_protocol);
        }
      }

      if (nfa_dm_cb.disc_cb.activated_protocol == NCI_PROTOCOL_MIFARE) {
        nfa_dm_cb.disc_cb.deact_pending = true;
        nfa_dm_cb.disc_cb.pending_deact_type = p_data->deactivate_type;
        status = nfa_dm_send_deactivate_cmd(p_data->deactivate_type);
        break;
      }

      if (old_sleep_wakeup_flag) {
        /* sleep wakeup is already enabled when deactivate cmd is requested,
         * keep the information in control block to issue it later */
        nfa_dm_cb.disc_cb.deact_pending = true;
        nfa_dm_cb.disc_cb.pending_deact_type = p_data->deactivate_type;
      } else {
        status = nfa_dm_send_deactivate_cmd(p_data->deactivate_type);
      }

      break;
    case NFA_DM_RF_DEACTIVATE_RSP:
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_RSP;
      /* register callback to get interface error NTF */
      NFC_SetStaticRfCback(nfa_dm_disc_data_cback);

      if (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_NTF)) {
        /* it's race condition. received deactivate NTF before receiving RSP */

        tNFC_DEACTIVATE_DEVT deact;
        deact.status = NFC_STATUS_OK;
        deact.type = NFC_DEACTIVATE_TYPE_IDLE;
        deact.is_ntf = true;
        tNFC_DISCOVER nfc_discover;
        nfc_discover.deactivate = deact;
        nfa_dm_disc_notify_deactivation(NFA_DM_RF_DEACTIVATE_NTF,
                                        &nfc_discover);

        /* NFCC is in IDLE state */
        nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
        nfa_dm_start_rf_discover();
      }
      break;
    case NFA_DM_RF_DEACTIVATE_NTF:
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_NTF;

      nfa_sys_stop_timer(&nfa_dm_cb.disc_cb.tle);

      if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_RSP) {
        /* it's race condition. received deactivate NTF before receiving RSP */
        /* notify deactivation after receiving deactivate RSP */
        DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
            "Rx deactivate NTF while waiting for deactivate RSP");
        break;
      }
      if (p_data->nfc_discover.deactivate.reason !=
          NFC_DEACTIVATE_REASON_DH_REQ_FAILED) {
        sleep_wakeup_event = true;
        nfa_dm_disc_notify_deactivation(NFA_DM_RF_DEACTIVATE_NTF,
                                        &(p_data->nfc_discover));
      }
      if ((p_data->nfc_discover.deactivate.type == NFC_DEACTIVATE_TYPE_SLEEP) ||
          (p_data->nfc_discover.deactivate.type ==
           NFC_DEACTIVATE_TYPE_SLEEP_AF)) {
        if (p_data->nfc_discover.deactivate.reason !=
            NFC_DEACTIVATE_REASON_DH_REQ_FAILED) {
          /* count for number of times deactivate cmd sent */
          nfa_dm_cb.deactivate_cmd_retry_count = 0;
        }
        nfa_dm_disc_new_state(NFA_DM_RFST_W4_HOST_SELECT);
        if (old_sleep_wakeup_flag) {
          sleep_wakeup_event_processed = true;
          /* process pending deactivate request */
          if (nfa_dm_cb.disc_cb.deact_pending) {
            /* notify RW module that sleep wakeup is finished */
            /* if deactivation is pending then deactivate  */
            nfa_dm_disc_end_sleep_wakeup(NFC_STATUS_OK);

            /* Notify NFA RW sub-systems because NFA_DM_RF_DEACTIVATE_RSP will
             * not call this function */
            nfa_rw_proc_disc_evt(NFA_DM_RF_DISC_DEACTIVATED_EVT, NULL, true);
          } else {
            /* Successfully went to sleep mode for sleep wakeup */
            /* Now wake up the tag to complete the operation */
            NFC_DiscoverySelect(nfa_dm_cb.disc_cb.activated_rf_disc_id,
                                nfa_dm_cb.disc_cb.activated_protocol,
                                nfa_dm_cb.disc_cb.activated_rf_interface);
          }
        }
        if (p_data->nfc_discover.deactivate.reason ==
            NFC_DEACTIVATE_REASON_DH_REQ_FAILED) {
          /* in case deactivation is not sucessfull, NFCC shall send
             RF_DEACTIVATE_NTF with DH Req failed due to error.
             MW shall send deactivation cmd again for 3 three times. if
             deactivation is not successfull 3 times also,
             then MW shall send deacivate cmd with deactivate type is
             discovery */
          if (nfa_dm_cb.deactivate_cmd_retry_count == 3) {
            if ((!old_sleep_wakeup_flag) ||
                (!nfa_dm_cb.disc_cb.deact_pending)) {
              nfa_dm_send_deactivate_cmd(NFA_DEACTIVATE_TYPE_DISCOVERY);
            }
            nfa_dm_cb.deactivate_cmd_retry_count = 0;
          } else {
            nfa_dm_cb.deactivate_cmd_retry_count++;
            nfa_dm_send_deactivate_cmd(p_data->nfc_discover.deactivate.type);
          }
        }
      } else if (p_data->nfc_discover.deactivate.type ==
                 NFC_DEACTIVATE_TYPE_IDLE) {
        nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
        nfa_dm_start_rf_discover();
      } else if (p_data->nfc_discover.deactivate.type ==
                 NFC_DEACTIVATE_TYPE_DISCOVERY) {
        nfa_dm_disc_new_state(NFA_DM_RFST_DISCOVERY);
        if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_STOPPING) {
          /* stop discovery */
          NFC_Deactivate(NFA_DEACTIVATE_TYPE_IDLE);
        }
      }
      break;

    case NFA_DM_CORE_INTF_ERROR_NTF:
      sleep_wakeup_event = true;
      if ((!old_sleep_wakeup_flag) || (!nfa_dm_cb.disc_cb.deact_pending)) {
        nfa_dm_send_deactivate_cmd(NFA_DEACTIVATE_TYPE_DISCOVERY);
      }
      break;

    default:
      LOG(ERROR) << StringPrintf("Unexpected discovery event");
      break;
  }

  if (old_sleep_wakeup_flag && sleep_wakeup_event &&
      !sleep_wakeup_event_processed) {
    /* performing sleep wakeup and exception conditions happened
     * clear sleep wakeup information and report failure */
    nfa_dm_disc_end_sleep_wakeup(NFC_STATUS_FAILED);
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_sm_listen_active
**
** Description      Processing discovery events in NFA_DM_RFST_LISTEN_ACTIVE
**                  state
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_sm_listen_active(tNFA_DM_RF_DISC_SM_EVENT event,
                                         tNFA_DM_RF_DISC_DATA* p_data) {
  tNFC_DEACTIVATE_DEVT deact;

  switch (event) {
    case NFA_DM_RF_DEACTIVATE_CMD:
      nfa_dm_send_deactivate_cmd(p_data->deactivate_type);
      break;
    case NFA_DM_RF_DEACTIVATE_RSP:
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_RSP;
      if (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_NTF)) {
        /* it's race condition. received deactivate NTF before receiving RSP */

        deact.status = NFC_STATUS_OK;
        deact.type = NFC_DEACTIVATE_TYPE_IDLE;
        deact.is_ntf = true;
        tNFC_DISCOVER nfc_discover;
        nfc_discover.deactivate = deact;
        nfa_dm_disc_notify_deactivation(NFA_DM_RF_DEACTIVATE_NTF,
                                        &nfc_discover);

        /* NFCC is in IDLE state */
        nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
        nfa_dm_start_rf_discover();
      }
      break;
    case NFA_DM_RF_DEACTIVATE_NTF:
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_NTF;

      nfa_sys_stop_timer(&nfa_dm_cb.disc_cb.tle);

      if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_RSP) {
        /* it's race condition. received deactivate NTF before receiving RSP */
        /* notify deactivation after receiving deactivate RSP */
        DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
            "Rx deactivate NTF while waiting for deactivate RSP");
      } else {
        nfa_dm_disc_notify_deactivation(NFA_DM_RF_DEACTIVATE_NTF,
                                        &(p_data->nfc_discover));

        if (p_data->nfc_discover.deactivate.type == NFC_DEACTIVATE_TYPE_IDLE) {
          nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
          nfa_dm_start_rf_discover();
        } else if ((p_data->nfc_discover.deactivate.type ==
                    NFC_DEACTIVATE_TYPE_SLEEP) ||
                   (p_data->nfc_discover.deactivate.type ==
                    NFC_DEACTIVATE_TYPE_SLEEP_AF)) {
          nfa_dm_disc_new_state(NFA_DM_RFST_LISTEN_SLEEP);
        } else if (p_data->nfc_discover.deactivate.type ==
                   NFC_DEACTIVATE_TYPE_DISCOVERY) {
          /* Discovery */
          nfa_dm_disc_new_state(NFA_DM_RFST_DISCOVERY);
          if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_STOPPING) {
            /* stop discovery */
            NFC_Deactivate(NFA_DEACTIVATE_TYPE_IDLE);
          }
        }
      }
      break;

    case NFA_DM_CORE_INTF_ERROR_NTF:
      break;
    default:
      LOG(ERROR) << StringPrintf("Unexpected discovery event");
      break;
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_sm_listen_sleep
**
** Description      Processing discovery events in NFA_DM_RFST_LISTEN_SLEEP
**                  state
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_sm_listen_sleep(tNFA_DM_RF_DISC_SM_EVENT event,
                                        tNFA_DM_RF_DISC_DATA* p_data) {
  switch (event) {
    case NFA_DM_RF_DEACTIVATE_CMD:
      nfa_dm_send_deactivate_cmd(p_data->deactivate_type);

      /* if deactivate type is not discovery then NFCC will not sent
       * deactivation NTF */
      if (p_data->deactivate_type != NFA_DEACTIVATE_TYPE_DISCOVERY) {
        nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_NTF;
        nfa_sys_stop_timer(&nfa_dm_cb.disc_cb.tle);
      }
      break;
    case NFA_DM_RF_DEACTIVATE_RSP:
      nfa_dm_cb.disc_cb.disc_flags &= ~NFA_DM_DISC_FLAGS_W4_RSP;
      /* if deactivate type in CMD was IDLE */
      if (!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_NTF)) {
        nfa_dm_disc_notify_deactivation(NFA_DM_RF_DEACTIVATE_RSP,
                                        &(p_data->nfc_discover));

        nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
        nfa_dm_start_rf_discover();
      }
      break;
    case NFA_DM_RF_DEACTIVATE_NTF:
      /* clear both W4_RSP and W4_NTF because of race condition between
       * deactivat CMD and link loss */
      nfa_dm_cb.disc_cb.disc_flags &=
          ~(NFA_DM_DISC_FLAGS_W4_RSP | NFA_DM_DISC_FLAGS_W4_NTF);
      nfa_sys_stop_timer(&nfa_dm_cb.disc_cb.tle);

      /* there is no active protocol in this state, so broadcast to all by using
       * NFA_DM_RF_DEACTIVATE_RSP */
      nfa_dm_disc_notify_deactivation(NFA_DM_RF_DEACTIVATE_RSP,
                                      &(p_data->nfc_discover));

      if (p_data->nfc_discover.deactivate.type == NFC_DEACTIVATE_TYPE_IDLE) {
        nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
        nfa_dm_start_rf_discover();
      } else if (p_data->nfc_discover.deactivate.type ==
                 NFA_DEACTIVATE_TYPE_DISCOVERY) {
        nfa_dm_disc_new_state(NFA_DM_RFST_DISCOVERY);
      } else {
        LOG(ERROR) << StringPrintf("Unexpected deactivation type");
        nfa_dm_disc_new_state(NFA_DM_RFST_IDLE);
        nfa_dm_start_rf_discover();
      }
      break;
    case NFA_DM_RF_INTF_ACTIVATED_NTF:
      nfa_dm_disc_new_state(NFA_DM_RFST_LISTEN_ACTIVE);
      if (nfa_dm_disc_notify_activation(&(p_data->nfc_discover)) ==
          NFA_STATUS_FAILED) {
        DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
            "Not matched, restart discovery after receiving deactivate ntf");

        /* after receiving deactivate event, restart discovery */
        NFC_Deactivate(NFA_DEACTIVATE_TYPE_IDLE);
      }
      break;
    default:
      LOG(ERROR) << StringPrintf("Unexpected discovery event");
      break;
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_sm_lp_listen
**
** Description      Processing discovery events in NFA_DM_RFST_LP_LISTEN state
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_sm_lp_listen(tNFA_DM_RF_DISC_SM_EVENT event,
                                     tNFA_DM_RF_DISC_DATA* p_data) {
  switch (event) {
    case NFA_DM_RF_INTF_ACTIVATED_NTF:
      nfa_dm_disc_new_state(NFA_DM_RFST_LP_ACTIVE);
      nfa_dm_disc_notify_activation(&(p_data->nfc_discover));
      if (nfa_dm_disc_notify_activation(&(p_data->nfc_discover)) ==
          NFA_STATUS_FAILED) {
        DLOG_IF(INFO, nfc_debug_enabled)
            << StringPrintf("Not matched, unexpected activation");
      }
      break;

    default:
      LOG(ERROR) << StringPrintf("Unexpected discovery event");
      break;
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_sm_lp_active
**
** Description      Processing discovery events in NFA_DM_RFST_LP_ACTIVE state
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_sm_lp_active(tNFA_DM_RF_DISC_SM_EVENT event,
                                     tNFA_DM_RF_DISC_DATA* p_data) {
  switch (event) {
    case NFA_DM_RF_DEACTIVATE_NTF:
      nfa_dm_disc_new_state(NFA_DM_RFST_LP_LISTEN);
      nfa_dm_disc_notify_deactivation(NFA_DM_RF_DEACTIVATE_NTF,
                                      &(p_data->nfc_discover));
      break;
    default:
      LOG(ERROR) << StringPrintf("Unexpected discovery event");
      break;
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_sm_execute
**
** Description      Processing discovery related events
**
** Returns          void
**
*******************************************************************************/
void nfa_dm_disc_sm_execute(tNFA_DM_RF_DISC_SM_EVENT event,
                            tNFA_DM_RF_DISC_DATA* p_data) {
  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
      "state: %s (%d), event: %s(%d) disc_flags: "
      "0x%x",
      nfa_dm_disc_state_2_str(nfa_dm_cb.disc_cb.disc_state).c_str(),
      nfa_dm_cb.disc_cb.disc_state, nfa_dm_disc_event_2_str(event).c_str(),
      event, nfa_dm_cb.disc_cb.disc_flags);

  switch (nfa_dm_cb.disc_cb.disc_state) {
    /*  RF Discovery State - Idle */
    case NFA_DM_RFST_IDLE:
      nfa_dm_disc_sm_idle(event, p_data);
      break;

    /* RF Discovery State - Discovery */
    case NFA_DM_RFST_DISCOVERY:
      nfa_dm_disc_sm_discovery(event, p_data);
      break;

    /*RF Discovery State - Wait for all discoveries */
    case NFA_DM_RFST_W4_ALL_DISCOVERIES:
      nfa_dm_disc_sm_w4_all_discoveries(event, p_data);
      break;

    /* RF Discovery State - Wait for host selection */
    case NFA_DM_RFST_W4_HOST_SELECT:
      nfa_dm_disc_sm_w4_host_select(event, p_data);
      break;

    /* RF Discovery State - Poll mode activated */
    case NFA_DM_RFST_POLL_ACTIVE:
      nfa_dm_disc_sm_poll_active(event, p_data);
      break;

    /* RF Discovery State - listen mode activated */
    case NFA_DM_RFST_LISTEN_ACTIVE:
      nfa_dm_disc_sm_listen_active(event, p_data);
      break;

    /* RF Discovery State - listen mode sleep */
    case NFA_DM_RFST_LISTEN_SLEEP:
      nfa_dm_disc_sm_listen_sleep(event, p_data);
      break;

    /* Listening in Low Power mode    */
    case NFA_DM_RFST_LP_LISTEN:
      nfa_dm_disc_sm_lp_listen(event, p_data);
      break;

    /* Activated in Low Power mode    */
    case NFA_DM_RFST_LP_ACTIVE:
      nfa_dm_disc_sm_lp_active(event, p_data);
      break;
  }
  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
      "new state: %s (%d), disc_flags: 0x%x",
      nfa_dm_disc_state_2_str(nfa_dm_cb.disc_cb.disc_state).c_str(),
      nfa_dm_cb.disc_cb.disc_state, nfa_dm_cb.disc_cb.disc_flags);
}

/*******************************************************************************
**
** Function         nfa_dm_add_rf_discover
**
** Description      Add discovery configuration and callback function
**
** Returns          valid handle if success
**
*******************************************************************************/
tNFA_HANDLE nfa_dm_add_rf_discover(tNFA_DM_DISC_TECH_PROTO_MASK disc_mask,
                                   tNFA_DM_DISC_HOST_ID host_id,
                                   tNFA_DISCOVER_CBACK* p_disc_cback) {
  uint8_t xx;

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("disc_mask=0x%x", disc_mask);

  for (xx = 0; xx < NFA_DM_DISC_NUM_ENTRIES; xx++) {
    if (!nfa_dm_cb.disc_cb.entry[xx].in_use) {
      nfa_dm_cb.disc_cb.entry[xx].in_use = true;
      nfa_dm_cb.disc_cb.entry[xx].requested_disc_mask = disc_mask;
      nfa_dm_cb.disc_cb.entry[xx].host_id = host_id;
      nfa_dm_cb.disc_cb.entry[xx].p_disc_cback = p_disc_cback;
      nfa_dm_cb.disc_cb.entry[xx].disc_flags = NFA_DM_DISC_FLAGS_NOTIFY;
      return xx;
    }
  }

  return NFA_HANDLE_INVALID;
}

/*******************************************************************************
**
** Function         nfa_dm_start_excl_discovery
**
** Description      Start exclusive RF discovery
**
** Returns          void
**
*******************************************************************************/
void nfa_dm_start_excl_discovery(tNFA_TECHNOLOGY_MASK poll_tech_mask,
                                 tNFA_LISTEN_CFG* p_listen_cfg,
                                 tNFA_DISCOVER_CBACK* p_disc_cback) {
  tNFA_DM_DISC_TECH_PROTO_MASK poll_disc_mask = 0;

  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  if (poll_tech_mask & NFA_TECHNOLOGY_MASK_A) {
    poll_disc_mask |= NFA_DM_DISC_MASK_PA_T1T;
    poll_disc_mask |= NFA_DM_DISC_MASK_PA_T2T;
    poll_disc_mask |= NFA_DM_DISC_MASK_PA_ISO_DEP;
    poll_disc_mask |= NFA_DM_DISC_MASK_PA_NFC_DEP;
    poll_disc_mask |= NFA_DM_DISC_MASK_P_LEGACY;
  }
  if (NFC_GetNCIVersion() == NCI_VERSION_2_0) {
    if (poll_tech_mask & NFA_TECHNOLOGY_MASK_ACTIVE) {
      poll_disc_mask |= NFA_DM_DISC_MASK_PACM_NFC_DEP;
    }
  } else {
    if (poll_tech_mask & NFA_TECHNOLOGY_MASK_A_ACTIVE) {
      poll_disc_mask |= NFA_DM_DISC_MASK_PAA_NFC_DEP;
    }
    if (poll_tech_mask & NFA_TECHNOLOGY_MASK_F_ACTIVE) {
      poll_disc_mask |= NFA_DM_DISC_MASK_PFA_NFC_DEP;
    }
  }

  if (poll_tech_mask & NFA_TECHNOLOGY_MASK_B) {
    poll_disc_mask |= NFA_DM_DISC_MASK_PB_ISO_DEP;
  }
  if (poll_tech_mask & NFA_TECHNOLOGY_MASK_F) {
    poll_disc_mask |= NFA_DM_DISC_MASK_PF_T3T;
    poll_disc_mask |= NFA_DM_DISC_MASK_PF_NFC_DEP;
  }
  if (poll_tech_mask & NFA_TECHNOLOGY_MASK_V) {
    poll_disc_mask |= NFA_DM_DISC_MASK_P_T5T;
  }
  if (poll_tech_mask & NFA_TECHNOLOGY_MASK_B_PRIME) {
    poll_disc_mask |= NFA_DM_DISC_MASK_P_B_PRIME;
  }
  if (poll_tech_mask & NFA_TECHNOLOGY_MASK_KOVIO) {
    poll_disc_mask |= NFA_DM_DISC_MASK_P_KOVIO;
  }

  nfa_dm_cb.disc_cb.excl_disc_entry.in_use = true;
  nfa_dm_cb.disc_cb.excl_disc_entry.requested_disc_mask = poll_disc_mask;
  nfa_dm_cb.disc_cb.excl_disc_entry.host_id = NFA_DM_DISC_HOST_ID_DH;
  nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback = p_disc_cback;
  nfa_dm_cb.disc_cb.excl_disc_entry.disc_flags = NFA_DM_DISC_FLAGS_NOTIFY;

  memcpy(&nfa_dm_cb.disc_cb.excl_listen_config, p_listen_cfg,
         sizeof(tNFA_LISTEN_CFG));

  nfa_dm_disc_sm_execute(NFA_DM_RF_DISCOVER_CMD, NULL);
}

/*******************************************************************************
**
** Function         nfa_dm_stop_excl_discovery
**
** Description      Stop exclusive RF discovery
**
** Returns          void
**
*******************************************************************************/
void nfa_dm_stop_excl_discovery(void) {
  DLOG_IF(INFO, nfc_debug_enabled) << __func__;

  nfa_dm_cb.disc_cb.excl_disc_entry.in_use = false;
  nfa_dm_cb.disc_cb.excl_disc_entry.p_disc_cback = NULL;
}

/*******************************************************************************
**
** Function         nfa_dm_delete_rf_discover
**
** Description      Remove discovery configuration and callback function
**
** Returns          void
**
*******************************************************************************/
void nfa_dm_delete_rf_discover(tNFA_HANDLE handle) {
  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("handle=0x%x", handle);

  if (handle < NFA_DM_DISC_NUM_ENTRIES) {
    nfa_dm_cb.disc_cb.entry[handle].in_use = false;
  } else {
    LOG(ERROR) << StringPrintf("Invalid discovery handle");
  }
}

/*******************************************************************************
**
** Function         nfa_dm_rf_discover_select
**
** Description      Select target, protocol and RF interface
**
** Returns          void
**
*******************************************************************************/
void nfa_dm_rf_discover_select(uint8_t rf_disc_id, tNFA_NFC_PROTOCOL protocol,
                               tNFA_INTF_TYPE rf_interface) {
  tNFA_DM_DISC_SELECT_PARAMS select_params;
  tNFA_CONN_EVT_DATA conn_evt;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("rf_disc_id:0x%X, protocol:0x%X, rf_interface:0x%X",
                      rf_disc_id, protocol, rf_interface);

  if (nfa_dm_cb.disc_cb.disc_state == NFA_DM_RFST_W4_HOST_SELECT) {
    /* state is OK: notify the status when the response is received from NFCC */
    select_params.rf_disc_id = rf_disc_id;
    select_params.protocol = protocol;
    select_params.rf_interface = rf_interface;

    nfa_dm_cb.disc_cb.disc_flags |= NFA_DM_DISC_FLAGS_NOTIFY;
    tNFA_DM_RF_DISC_DATA nfa_dm_rf_disc_data;
    nfa_dm_rf_disc_data.select = select_params;
    nfa_dm_disc_sm_execute(NFA_DM_RF_DISCOVER_SELECT_CMD, &nfa_dm_rf_disc_data);
  } else {
    /* Wrong state: notify failed status right away */
    conn_evt.status = NFA_STATUS_FAILED;
    nfa_dm_conn_cback_event_notify(NFA_SELECT_RESULT_EVT, &conn_evt);
  }
}

/*******************************************************************************
**
** Function         nfa_dm_rf_deactivate
**
** Description      Deactivate NFC link
**
** Returns          NFA_STATUS_OK if success
**
*******************************************************************************/
tNFA_STATUS nfa_dm_rf_deactivate(tNFA_DEACTIVATE_TYPE deactivate_type) {
  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("deactivate_type:0x%X", deactivate_type);

  if (deactivate_type == NFA_DEACTIVATE_TYPE_SLEEP) {
    if (nfa_dm_cb.disc_cb.activated_protocol == NFA_PROTOCOL_NFC_DEP)
      deactivate_type = NFC_DEACTIVATE_TYPE_SLEEP_AF;
    else
      deactivate_type = NFC_DEACTIVATE_TYPE_SLEEP;
  }

  if (nfa_dm_cb.disc_cb.disc_state == NFA_DM_RFST_IDLE) {
    return NFA_STATUS_FAILED;
  } else if (nfa_dm_cb.disc_cb.disc_state == NFA_DM_RFST_DISCOVERY) {
    if (deactivate_type == NFA_DEACTIVATE_TYPE_DISCOVERY) {
      if (nfa_dm_cb.disc_cb.kovio_tle.in_use) {
        nfa_sys_stop_timer(&nfa_dm_cb.disc_cb.kovio_tle);
        nfa_dm_disc_kovio_timeout_cback(&nfa_dm_cb.disc_cb.kovio_tle);
        return NFA_STATUS_OK;
      } else {
        /* it could be race condition. */
        DLOG_IF(INFO, nfc_debug_enabled)
            << StringPrintf("already in discovery state");
        return NFA_STATUS_FAILED;
      }
    } else if (deactivate_type == NFA_DEACTIVATE_TYPE_IDLE) {
      if (nfa_dm_cb.disc_cb.kovio_tle.in_use) {
        nfa_sys_stop_timer(&nfa_dm_cb.disc_cb.kovio_tle);
        nfa_dm_disc_kovio_timeout_cback(&nfa_dm_cb.disc_cb.kovio_tle);
      }
      tNFA_DM_RF_DISC_DATA nfa_dm_rf_disc_data;
      nfa_dm_rf_disc_data.deactivate_type = deactivate_type;
      nfa_dm_disc_sm_execute(NFA_DM_RF_DEACTIVATE_CMD, &nfa_dm_rf_disc_data);
      return NFA_STATUS_OK;
    } else {
      return NFA_STATUS_FAILED;
    }
  } else {
    tNFA_DM_RF_DISC_DATA nfa_dm_rf_disc_data;
    nfa_dm_rf_disc_data.deactivate_type = deactivate_type;
    nfa_dm_disc_sm_execute(NFA_DM_RF_DEACTIVATE_CMD, &nfa_dm_rf_disc_data);
    return NFA_STATUS_OK;
  }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_state_2_str
**
** Description      convert nfc discovery state to string
**
*******************************************************************************/
static std::string nfa_dm_disc_state_2_str(uint8_t state) {
  switch (state) {
    case NFA_DM_RFST_IDLE:
      return "IDLE";

    case NFA_DM_RFST_DISCOVERY:
      return "DISCOVERY";

    case NFA_DM_RFST_W4_ALL_DISCOVERIES:
      return "W4_ALL_DISCOVERIES";

    case NFA_DM_RFST_W4_HOST_SELECT:
      return "W4_HOST_SELECT";

    case NFA_DM_RFST_POLL_ACTIVE:
      return "POLL_ACTIVE";

    case NFA_DM_RFST_LISTEN_ACTIVE:
      return "LISTEN_ACTIVE";

    case NFA_DM_RFST_LISTEN_SLEEP:
      return "LISTEN_SLEEP";

    case NFA_DM_RFST_LP_LISTEN:
      return "LP_LISTEN";

    case NFA_DM_RFST_LP_ACTIVE:
      return "LP_ACTIVE";
  }
  return "Unknown";
}

/*******************************************************************************
**
** Function         nfa_dm_disc_event_2_str
**
** Description      convert nfc discovery RSP/NTF to string
**
*******************************************************************************/
static std::string nfa_dm_disc_event_2_str(uint8_t event) {
  switch (event) {
    case NFA_DM_RF_DISCOVER_CMD:
      return "DISCOVER_CMD";
    case NFA_DM_RF_DISCOVER_RSP:
      return "DISCOVER_RSP";
    case NFA_DM_RF_DISCOVER_NTF:
      return "DISCOVER_NTF";
    case NFA_DM_RF_DISCOVER_SELECT_CMD:
      return "SELECT_CMD";
    case NFA_DM_RF_DISCOVER_SELECT_RSP:
      return "SELECT_RSP";
    case NFA_DM_RF_INTF_ACTIVATED_NTF:
      return "ACTIVATED_NTF";
    case NFA_DM_RF_DEACTIVATE_CMD:
      return "DEACTIVATE_CMD";
    case NFA_DM_RF_DEACTIVATE_RSP:
      return "DEACTIVATE_RSP";
    case NFA_DM_RF_DEACTIVATE_NTF:
      return "DEACTIVATE_NTF";
    case NFA_DM_LP_LISTEN_CMD:
      return "NFA_DM_LP_LISTEN_CMD";
    case NFA_DM_CORE_INTF_ERROR_NTF:
      return "INTF_ERROR_NTF";
    default:
      return "Unknown";
  }
}

/*******************************************************************************
**
** Function         P2P_Prio_Logic
**
** Description      Implements algorithm for NFC-DEP protocol priority over
**                  ISO-DEP protocol.
**
** Returns          True if success
**
*******************************************************************************/
bool nfa_dm_p2p_prio_logic(uint8_t event, uint8_t* p, uint8_t event_type) {
  if (!nfa_poll_bail_out_mode) {
    DLOG_IF(INFO, nfc_debug_enabled)
        << StringPrintf("p2p priority is running under bail out mode ONLY.");
    return true;
  }

  if ((nfa_dm_cb.flags & NFA_DM_FLAGS_P2P_PAUSED) &&
      (nfa_dm_cb.flags & NFA_DM_FLAGS_LISTEN_DISABLED)) {
    DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
        "returning from nfa_dm_p2p_prio_logic  Disable p2p_prio_logic");
    return true;
  }
  if (appl_dta_mode_flag == 0x01) {
    /*Disable the P2P Prio Logic when DTA is running*/
    return TRUE;
  }
  if (event == NCI_MSG_RF_DISCOVER &&
      p2p_prio_logic_data.timer_expired == true &&
      event_type == NFA_DM_P2P_PRIO_RSP) {
    DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
        "nfa_dm_p2p_prio_logic starting a timer for next rf intf activated "
        "ntf");
    nfc_start_quick_timer(&p2p_prio_logic_data.timer_list,
                          NFC_TTYPE_P2P_PRIO_LOGIC_CLEANUP,
                          ((uint32_t)nfa_dm_act_get_rf_disc_duration() *
                           QUICK_TIMER_TICKS_PER_SEC) /
                              1000);
    return true;
  }

  if (event == NCI_MSG_RF_INTF_ACTIVATED &&
      p2p_prio_logic_data.timer_expired == true) {
    DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
        "nfa_dm_p2p_prio_logic stopping a timer for next rf intf activated "
        "ntf");
    nfc_stop_quick_timer(&p2p_prio_logic_data.timer_list);
  }

  if (nfa_dm_cb.disc_cb.disc_state == NFA_DM_RFST_DISCOVERY) {
    uint8_t rf_disc_id = 0xFF;
    uint8_t type = 0xFF;
    uint8_t protocol = 0xFF;
    uint8_t tech_mode = 0xFF;

    DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("P2P_Prio_Logic");

    if (event == NCI_MSG_RF_INTF_ACTIVATED) {
      rf_disc_id = *p++;
      type = *p++;
      protocol = *p++;
      tech_mode = *p++;
    }
    DLOG_IF(INFO, nfc_debug_enabled)
        << StringPrintf("nfa_dm_p2p_prio_logic event_type = 0x%x", event_type);

    if (event == NCI_MSG_RF_INTF_ACTIVATED && tech_mode >= 0x80) {
      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
          "nfa_dm_p2p_prio_logic listen mode activated reset all the "
          "nfa_dm_p2p_prio_logic variables ");
      nfa_dm_p2p_prio_logic_cleanup();
    }

    if ((tech_mode < 0x80) && event == NCI_MSG_RF_INTF_ACTIVATED &&
        protocol == NCI_PROTOCOL_ISO_DEP &&
        p2p_prio_logic_data.isodep_detected == false) {
      nfa_dm_p2p_prio_logic_cleanup();
      p2p_prio_logic_data.isodep_detected = true;
      p2p_prio_logic_data.first_tech_mode = tech_mode;
      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
          "ISO-DEP Detected First Time  Resume the Polling Loop");
      nci_snd_deactivate_cmd(NFA_DEACTIVATE_TYPE_DISCOVERY);
      return false;
    }

    else if (event == NCI_MSG_RF_INTF_ACTIVATED &&
             protocol == NCI_PROTOCOL_ISO_DEP &&
             p2p_prio_logic_data.isodep_detected == true &&
             p2p_prio_logic_data.first_tech_mode != tech_mode) {
      p2p_prio_logic_data.isodep_detected = true;
      p2p_prio_logic_data.timer_expired = false;
      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
          "ISO-DEP Detected Second Time Other Techmode  Resume the Polling "
          "Loop");
      nfc_stop_quick_timer(&p2p_prio_logic_data.timer_list);
      nci_snd_deactivate_cmd(NFA_DEACTIVATE_TYPE_DISCOVERY);
      return false;
    }

    else if (event == NCI_MSG_RF_INTF_ACTIVATED &&
             protocol == NCI_PROTOCOL_ISO_DEP &&
             p2p_prio_logic_data.isodep_detected == true &&
             p2p_prio_logic_data.timer_expired == true) {
      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
          "ISO-DEP Detected TimerExpired, Final Notifying the Event");
      nfc_stop_quick_timer(&p2p_prio_logic_data.timer_list);
      nfa_dm_p2p_prio_logic_cleanup();
    }

    else if (event == NCI_MSG_RF_INTF_ACTIVATED &&
             protocol == NCI_PROTOCOL_ISO_DEP &&
             p2p_prio_logic_data.isodep_detected == true &&
             p2p_prio_logic_data.first_tech_mode == tech_mode) {
      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
          "ISO-DEP Detected Same Techmode, Final Notifying the Event");
      nfc_stop_quick_timer(&p2p_prio_logic_data.timer_list);
      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("P2P_Stop_Timer");
      nfa_dm_p2p_prio_logic_cleanup();
    }

    else if (event == NCI_MSG_RF_INTF_ACTIVATED &&
             protocol != NCI_PROTOCOL_ISO_DEP &&
             p2p_prio_logic_data.isodep_detected == true) {
      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf(
          "ISO-DEP Not Detected  Giving Priority for other Technology");
      nfc_stop_quick_timer(&p2p_prio_logic_data.timer_list);
      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("P2P_Stop_Timer");
      nfa_dm_p2p_prio_logic_cleanup();
    }

    else if (event == NCI_MSG_RF_DEACTIVATE &&
             p2p_prio_logic_data.isodep_detected == true &&
             p2p_prio_logic_data.timer_expired == false &&
             event_type == NFA_DM_P2P_PRIO_RSP) {
      DLOG_IF(INFO, nfc_debug_enabled)
          << StringPrintf("NFA_DM_RF_DEACTIVATE_RSP");
      return false;
    }

    else if (event == NCI_MSG_RF_DEACTIVATE &&
             p2p_prio_logic_data.isodep_detected == true &&
             p2p_prio_logic_data.timer_expired == false &&
             event_type == NFA_DM_P2P_PRIO_NTF) {
      DLOG_IF(INFO, nfc_debug_enabled)
          << StringPrintf("NFA_DM_RF_DEACTIVATE_NTF");

      nfc_start_quick_timer(&p2p_prio_logic_data.timer_list,
                            NFC_TTYPE_P2P_PRIO_RESPONSE,
                            ((uint32_t)160 * QUICK_TIMER_TICKS_PER_SEC) / 1000);

      DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("P2P_Start_Timer");

      return false;
    }
  }

  DLOG_IF(INFO, nfc_debug_enabled) << StringPrintf("returning TRUE");
  return true;
}

/*******************************************************************************
**
** Function         p2p_prio_logic_timeout
**
** Description      Callback function for p2p timer
**
** Returns          void
**
*******************************************************************************/
void nfa_dm_p2p_timer_event() {
  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("P2P_Timer_timeout NFC-DEP Not Discovered!!");

  p2p_prio_logic_data.timer_expired = true;

  if (p2p_prio_logic_data.isodep_detected == true) {
    DLOG_IF(INFO, nfc_debug_enabled)
        << StringPrintf("Deactivate and Restart RF discovery");
    nci_snd_deactivate_cmd(NFC_DEACTIVATE_TYPE_IDLE);
  }
}

/*******************************************************************************
**
** Function         nfa_dm_p2p_prio_logic_cleanup
**
** Description      Callback function for p2p prio logic cleanup timer
**
** Returns          void
**
*******************************************************************************/
void nfa_dm_p2p_prio_logic_cleanup() {
  memset(&p2p_prio_logic_data, 0x00, sizeof(nfa_dm_p2p_prio_logic_t));
}

/*******************************************************************************
**
** Function         nfa_dm_send_tag_deselect_cmd
**
** Description      Send command to send tag in sleep state
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_send_tag_deselect_cmd(tNFA_NFC_PROTOCOL protocol) {
  NFC_HDR* p_msg;
  uint8_t* p;

  DLOG_IF(INFO, nfc_debug_enabled)
      << StringPrintf("nfa_dm_send_tag_deselect_cmd");
  p_msg = (NFC_HDR*)GKI_getpoolbuf(NFC_RW_POOL_ID);

  if (p_msg) {
    if (protocol == NFC_PROTOCOL_ISO_DEP) {
      /* send one byte of 0xc2 as as deselect command to Tag */
      p_msg->len = 1;
      p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
      p = (uint8_t*)(p_msg + 1) + p_msg->offset;
      *p = NFA_RW_TAG_DESELECT_CMD;
    } else if (protocol == NFC_PROTOCOL_T2T) {
      p_msg->len = NFA_RW_TAG_SLP_REQ_LEN;
      p_msg->offset = NCI_MSG_OFFSET_SIZE + NCI_DATA_HDR_SIZE;
      p = (uint8_t*)(p_msg + 1) + p_msg->offset;
      memcpy((uint8_t*)(p_msg + 1) + p_msg->offset, NFA_RW_TAG_SLP_REQ,
             p_msg->len);
    } else {
      GKI_freebuf(p_msg);
      return;
    }
    NFC_SendData(NFC_RF_CONN_ID, p_msg);
  }
}