C++程序  |  2965行  |  105.19 KB

/******************************************************************************
 *
 *  Copyright (C) 2010-2014 Broadcom Corporation
 *
 *  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.h>
#include "nfa_sys.h"
#include "nfa_api.h"
#include "nfa_dm_int.h"
#include "nfa_p2p_int.h"
#include "nfa_sys_int.h"
#if (NFC_NFCEE_INCLUDED == TRUE)
#include "nfa_ee_api.h"
#include "nfa_ee_int.h"
#endif
#include "nfa_rw_int.h"

/*
**  static functions
*/

static UINT8 nfa_dm_get_rf_discover_config (tNFA_DM_DISC_TECH_PROTO_MASK dm_disc_mask,
                                            tNFC_DISCOVER_PARAMS disc_params[],
                                            UINT8 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 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);

#if (BT_TRACE_VERBOSE == TRUE)
static char *nfa_dm_disc_state_2_str (UINT8 state);
static char *nfa_dm_disc_event_2_str (UINT8 event);
#endif


/*******************************************************************************
**
** 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 nfa_dm_get_rf_discover_config (tNFA_DM_DISC_TECH_PROTO_MASK dm_disc_mask,
                                            tNFC_DISCOVER_PARAMS         disc_params[],
                                            UINT8 max_params)
{
    UINT8 num_params = 0;

    if (nfa_dm_cb.flags & NFA_DM_FLAGS_LISTEN_DISABLED)
    {
        NFA_TRACE_DEBUG1 ("nfa_dm_get_rf_discover_config () 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;
    }

    /* 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;
    }

    /* 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_ISO15693)
    {
        disc_params[num_params].type      = NFC_DISCOVERY_TYPE_POLL_ISO15693;
        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 params[40], *p;
    UINT8 platform  = 0;
    UINT8 sens_info = 0;

    NFA_TRACE_DEBUG1 ("nfa_dm_set_rf_listen_mode_config () 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) (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 params[10], *p;

    NFA_TRACE_DEBUG0 ("nfa_dm_set_total_duration ()");

    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) (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 params[250], *p, xx;

    NFA_TRACE_DEBUG0 ("nfa_dm_set_rf_listen_mode_raw_config ()");

    /*
    ** 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) (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) (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) (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) (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) (p - params), params, FALSE);
    }

    *p_disc_mask = disc_mask;

    NFA_TRACE_DEBUG1 ("nfa_dm_set_rf_listen_mode_raw_config () 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);

    switch (tech_n_mode)
    {
    case NFC_DISCOVERY_TYPE_POLL_A:
        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;
        }
        break;
    case NFC_DISCOVERY_TYPE_POLL_B:
        if (protocol == NFC_PROTOCOL_ISO_DEP)
            disc_mask = NFA_DM_DISC_MASK_PB_ISO_DEP;
        break;
    case NFC_DISCOVERY_TYPE_POLL_F:
        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;
        break;
    case NFC_DISCOVERY_TYPE_POLL_ISO15693:
        disc_mask = NFA_DM_DISC_MASK_P_ISO15693;
        break;
    case NFC_DISCOVERY_TYPE_POLL_B_PRIME:
        disc_mask = NFA_DM_DISC_MASK_P_B_PRIME;
        break;
    case NFC_DISCOVERY_TYPE_POLL_KOVIO:
        disc_mask = NFA_DM_DISC_MASK_P_KOVIO;
        break;
    case NFC_DISCOVERY_TYPE_POLL_A_ACTIVE:
        disc_mask = NFA_DM_DISC_MASK_PAA_NFC_DEP;
        break;
    case NFC_DISCOVERY_TYPE_POLL_F_ACTIVE:
        disc_mask = NFA_DM_DISC_MASK_PFA_NFC_DEP;
        break;

    case NFC_DISCOVERY_TYPE_LISTEN_A:
        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;
        }
        break;
    case NFC_DISCOVERY_TYPE_LISTEN_B:
        if (protocol == NFC_PROTOCOL_ISO_DEP)
            disc_mask = NFA_DM_DISC_MASK_LB_ISO_DEP;
        break;
    case NFC_DISCOVERY_TYPE_LISTEN_F:
        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;
        break;
    case NFC_DISCOVERY_TYPE_LISTEN_ISO15693:
        disc_mask = NFA_DM_DISC_MASK_L_ISO15693;
        break;
    case NFC_DISCOVERY_TYPE_LISTEN_B_PRIME:
        disc_mask = NFA_DM_DISC_MASK_L_B_PRIME;
        break;
    case NFC_DISCOVERY_TYPE_LISTEN_A_ACTIVE:
        disc_mask = NFA_DM_DISC_MASK_LAA_NFC_DEP;
        break;
    case NFC_DISCOVERY_TYPE_LISTEN_F_ACTIVE:
        disc_mask = NFA_DM_DISC_MASK_LFA_NFC_DEP;
        break;
    }

    NFA_TRACE_DEBUG3 ("nfa_dm_disc_get_disc_mask (): 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;

    NFA_TRACE_DEBUG1 ("nfa_dm_disc_discovery_cback (): 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:
        NFA_TRACE_ERROR0 ("Unexpected event");
        return;
    }

    nfa_dm_disc_sm_execute (dm_disc_event, (tNFA_DM_RF_DISC_DATA *) p_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 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;

    NFA_TRACE_DEBUG1 ("nfa_dm_disc_force_to_idle() disc_flags = 0x%x", nfa_dm_cb.disc_cb.disc_flags);

    if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_NTF) /* do not execute more than one */
    {
        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 (TIMER_LIST_ENT *p_tle)
{
    NFA_TRACE_ERROR0 ("nfa_dm_disc_deact_ntf_timeout_cback()");

    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                   num_params, xx;

    NFA_TRACE_DEBUG0 ("nfa_dm_start_rf_discover ()");
    /* 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
                                      |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);

                    /* 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
                                  |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 (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;

                NFA_TRACE_DEBUG2 ("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);
        }
    }

    NFA_TRACE_DEBUG1 ("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
**
*******************************************************************************/
BOOLEAN 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)))
        {
            NFA_TRACE_DEBUG0 ("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   xx, host_id_in_LRT;
    UINT8   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;

    NFA_TRACE_DEBUG2 ("nfa_dm_disc_notify_activation (): 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;

                NFA_TRACE_DEBUG2 ("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 (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;

        NFA_TRACE_DEBUG2 ("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;

    NFA_TRACE_DEBUG1 ("nfa_dm_disc_notify_deactivation (): activated_handle=%d",
                       nfa_dm_cb.disc_cb.activated_handle);

    if (nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_CHECKING)
    {
        NFA_TRACE_DEBUG0 ("nfa_dm_disc_notify_deactivation (): 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
**
*******************************************************************************/
BOOLEAN 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
**
*******************************************************************************/
BOOLEAN 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;
            nfa_dm_disc_sm_execute (NFA_DM_RF_DEACTIVATE_CMD,
                                   (tNFA_DM_RF_DISC_DATA *) &nfa_dm_cb.disc_cb.pending_deact_type);
        }
    }
}

/*******************************************************************************
**
** 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 (TIMER_LIST_ENT *p_tle)
{
    tNFC_DEACTIVATE_DEVT deact;

    NFA_TRACE_DEBUG0 ("nfa_dm_disc_kovio_timeout_cback()");

    /* 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 */
        deact.status = NFC_STATUS_OK;
        deact.type   = NFC_DEACTIVATE_TYPE_DISCOVERY;
        deact.is_ntf = TRUE;
        nfa_dm_disc_notify_deactivation (NFA_DM_RF_DEACTIVATE_NTF, (tNFC_DISCOVER*)&deact);
    }
}

/*******************************************************************************
**
** 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;

    NFA_TRACE_DEBUG0 ("nfa_dm_disc_start_kovio_presence_check ()");

    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)
{
    NFA_TRACE_DEBUG0 ("nfa_dm_disc_report_kovio_presence_check ()");

    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;
            nfa_dm_disc_sm_execute (NFA_DM_RF_DEACTIVATE_CMD,
                                   (tNFA_DM_RF_DISC_DATA *) &nfa_dm_cb.disc_cb.pending_deact_type);
        }
    }
}

/*******************************************************************************
**
** Function         nfa_dm_disc_data_cback
**
** Description      Monitoring interface error through data callback
**
** Returns          void
**
*******************************************************************************/
static void nfa_dm_disc_data_cback (UINT8 conn_id, tNFC_CONN_EVT event, tNFC_CONN *p_data)
{
    NFA_TRACE_DEBUG0 ("nfa_dm_disc_data_cback ()");

    /* 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;

#if (BT_TRACE_VERBOSE == TRUE)
    NFA_TRACE_DEBUG5 ("nfa_dm_disc_new_state (): 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), nfa_dm_cb.disc_cb.disc_state,
                       nfa_dm_disc_state_2_str (new_state), new_state, nfa_dm_cb.disc_cb.disc_flags);
#else
    NFA_TRACE_DEBUG3 ("nfa_dm_disc_new_state(): old_state: %d, new_state: %d disc_flags: 0x%x",
                       nfa_dm_cb.disc_cb.disc_state, new_state, nfa_dm_cb.disc_cb.disc_flags);
#endif

    nfa_dm_cb.disc_cb.disc_state = new_state;

    if (  (new_state == NFA_DM_RFST_IDLE)
        &&(!(nfa_dm_cb.disc_cb.disc_flags & NFA_DM_DISC_FLAGS_W4_RSP))  ) /* not error recovering */
    {
        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              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, (tNFC_DISCOVER*) p_data);
                }
            }
            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, (tNFC_DISCOVER*) p_data);
                    }
                }

            }
            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:
        NFA_TRACE_ERROR0 ("nfa_dm_disc_sm_idle (): 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)
        {
            NFA_TRACE_DEBUG0 ("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)
            {
                NFA_TRACE_DEBUG0 ("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:
        NFA_TRACE_ERROR0 ("nfa_dm_disc_sm_discovery (): 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)
        {
            NFA_TRACE_DEBUG0 ("Not matched, restart discovery after receiving deactivate ntf");

            /* after receiving deactivate event, restart discovery */
            NFC_Deactivate (NFA_DEACTIVATE_TYPE_IDLE);
        }
        break;
    default:
        NFA_TRACE_ERROR0 ("nfa_dm_disc_sm_w4_all_discoveries (): 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);
    BOOLEAN             sleep_wakeup_event = FALSE;
    BOOLEAN             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)
        {
            NFA_TRACE_DEBUG0 ("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:
        NFA_TRACE_ERROR0 ("nfa_dm_disc_sm_w4_host_select (): 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);
    BOOLEAN             sleep_wakeup_event = FALSE;
    BOOLEAN             sleep_wakeup_event_processed = FALSE;
    tNFC_DEACTIVATE_DEVT deact;

    switch (event)
    {
    case NFA_DM_RF_DEACTIVATE_CMD:
        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 */

            deact.status = NFC_STATUS_OK;
            deact.type   = NFC_DEACTIVATE_TYPE_IDLE;
            deact.is_ntf = TRUE;
            nfa_dm_disc_notify_deactivation (NFA_DM_RF_DEACTIVATE_NTF, (tNFC_DISCOVER*)&deact);

            /* 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 */
            NFA_TRACE_DEBUG0 ("Rx deactivate NTF while waiting for deactivate RSP");
            break;
        }

        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)  )
        {
            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);
                }

            }
        }
        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:
        NFA_TRACE_ERROR0 ("nfa_dm_disc_sm_poll_active (): 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;
            nfa_dm_disc_notify_deactivation (NFA_DM_RF_DEACTIVATE_NTF, (tNFC_DISCOVER*)&deact);

            /* 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 */
            NFA_TRACE_DEBUG0 ("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:
        NFA_TRACE_ERROR0 ("nfa_dm_disc_sm_listen_active (): 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
        {
            NFA_TRACE_ERROR0 ("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)
        {
            NFA_TRACE_DEBUG0 ("Not matched, restart discovery after receiving deactivate ntf");

            /* after receiving deactivate event, restart discovery */
            NFC_Deactivate (NFA_DEACTIVATE_TYPE_IDLE);
        }
        break;
    default:
        NFA_TRACE_ERROR0 ("nfa_dm_disc_sm_listen_sleep (): 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)
        {
            NFA_TRACE_DEBUG0 ("Not matched, unexpected activation");
        }
        break;

    default:
        NFA_TRACE_ERROR0 ("nfa_dm_disc_sm_lp_listen (): 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:
        NFA_TRACE_ERROR0 ("nfa_dm_disc_sm_lp_active (): 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)
{
#if (BT_TRACE_VERBOSE == TRUE)
    NFA_TRACE_DEBUG5 ("nfa_dm_disc_sm_execute (): state: %s (%d), event: %s(%d) disc_flags: 0x%x",
                       nfa_dm_disc_state_2_str (nfa_dm_cb.disc_cb.disc_state), nfa_dm_cb.disc_cb.disc_state,
                       nfa_dm_disc_event_2_str (event), event, nfa_dm_cb.disc_cb.disc_flags);
#else
    NFA_TRACE_DEBUG3 ("nfa_dm_disc_sm_execute(): state: %d, event:%d disc_flags: 0x%x",
                       nfa_dm_cb.disc_cb.disc_state, event, nfa_dm_cb.disc_cb.disc_flags);
#endif

    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;
    }
#if (BT_TRACE_VERBOSE == TRUE)
    NFA_TRACE_DEBUG3 ("nfa_dm_disc_sm_execute (): new state: %s (%d), disc_flags: 0x%x",
                       nfa_dm_disc_state_2_str (nfa_dm_cb.disc_cb.disc_state), nfa_dm_cb.disc_cb.disc_state,
                       nfa_dm_cb.disc_cb.disc_flags);
#else
    NFA_TRACE_DEBUG2 ("nfa_dm_disc_sm_execute(): new state: %d,  disc_flags: 0x%x",
                       nfa_dm_cb.disc_cb.disc_state, nfa_dm_cb.disc_cb.disc_flags);
#endif
}

/*******************************************************************************
**
** 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       xx;

    NFA_TRACE_DEBUG1 ("nfa_dm_add_rf_discover () 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;

    NFA_TRACE_DEBUG0 ("nfa_dm_start_excl_discovery ()");

    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 (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_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_F_ACTIVE)
    {
        poll_disc_mask |= NFA_DM_DISC_MASK_PFA_NFC_DEP;
    }
    if (poll_tech_mask & NFA_TECHNOLOGY_MASK_ISO15693)
    {
        poll_disc_mask |= NFA_DM_DISC_MASK_P_ISO15693;
    }
    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)
{
    NFA_TRACE_DEBUG0 ("nfa_dm_stop_excl_discovery ()");

    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)
{
    NFA_TRACE_DEBUG1 ("nfa_dm_delete_rf_discover () handle=0x%x", handle);

    if (handle < NFA_DM_DISC_NUM_ENTRIES)
    {
        nfa_dm_cb.disc_cb.entry[handle].in_use = FALSE;
    }
    else
    {
        NFA_TRACE_ERROR0 ("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             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;

    NFA_TRACE_DEBUG3 ("nfa_dm_disc_select () 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;
        nfa_dm_disc_sm_execute (NFA_DM_RF_DISCOVER_SELECT_CMD, (tNFA_DM_RF_DISC_DATA *) &select_params);
    }
    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)
{
    NFA_TRACE_DEBUG1 ("nfa_dm_rf_deactivate () 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. */
                NFA_TRACE_DEBUG0 ("nfa_dm_rf_deactivate (): 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);
            }
            nfa_dm_disc_sm_execute (NFA_DM_RF_DEACTIVATE_CMD, (tNFA_DM_RF_DISC_DATA *) &deactivate_type);
            return NFA_STATUS_OK;
        }
        else
        {
            return NFA_STATUS_FAILED;
        }
    }
    else
    {
        nfa_dm_disc_sm_execute (NFA_DM_RF_DEACTIVATE_CMD, (tNFA_DM_RF_DISC_DATA *) &deactivate_type);
        return NFA_STATUS_OK;
    }
}

#if (BT_TRACE_VERBOSE == TRUE)
/*******************************************************************************
**
** Function         nfa_dm_disc_state_2_str
**
** Description      convert nfc discovery state to string
**
*******************************************************************************/
static char *nfa_dm_disc_state_2_str (UINT8 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 char *nfa_dm_disc_event_2_str (UINT8 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";

    }
    return "Unknown";
}
#endif /* BT_TRACE_VERBOSE */