/*
 * Copyright 2021-2024 NXP
 *
 * 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.
 */

#if (NXP_NFC_RECOVERY == TRUE)

#include "phNxpNciHal_Recovery.h"

#include <phDnldNfc.h>
#include <phNfcStatus.h>
#include <phNfcTypes.h>
#include <phNxpLog.h>
#include <phNxpNciHal.h>
#include <phNxpNciHal_Dnld.h>
#include <phNxpNciHal_ext.h>
#include <phOsalNfc_Timer.h>
#include <phTmlNfc.h>
#undef property_set
#undef PROPERTY_VALUE_MAX
#undef property_get
#include <cutils/properties.h>
#define MAX_CORE_RESET 3

extern phNxpNciProfile_Control_t nxpprofile_ctrl;
extern phNxpNciHal_Control_t nxpncihal_ctrl;
extern phTmlNfc_Context_t* gpphTmlNfc_Context;
extern void* phNxpNciHal_client_thread(void* arg);

static void phnxpNciHal_partialClose();
static NFCSTATUS phnxpNciHal_partialOpen();

// property name for storing boot time init status
const char* halInitProperty = "vendor.nfc.min_firmware";

/******************************************************************************
 * Function         getHalInitStatus
 *
 * Description      Get property whether it is boot init/not
 *
 * Parameters       Parameter to return the hal status is boot init/not.
 *
 * Returns          None
 *
 ******************************************************************************/
static void getHalInitStatus(char* halInitStatus) {
  NXPLOG_NCIHAL_D("Enter : %s", __func__);
  if (property_get(halInitProperty, halInitStatus, "Boot-time") != 0) {
    NXPLOG_NCIHAL_E("Error in property_get : %s", __func__);
  }
}

/******************************************************************************
 * Function         setHalInitStatus
 *
 * Description      To set property as per input whether it is boot init/not
 *
 * Parameters       status to be updated in property
 *
 * Returns          void
 *
 ******************************************************************************/
static void setHalInitStatus(const char* status) {
  NXPLOG_NCIHAL_E("Enter : %s", __func__);
  if (property_set(halInitProperty, status) != 0) {
    NXPLOG_NCIHAL_E("Error in property_set : %s", __func__);
  }
}

/******************************************************************************
 * Function         phNxpNciHal_read_callback
 *
 * Description      Callback function for read request to tml reader thread
 *
 * Parameters       pContext - context value passed while callback register
 *                  pInfo    - Information which contains status and response
 *                             buffers.
 *
 * Returns          void
 *
 ******************************************************************************/
static void phNxpNciHal_read_callback(void* pContext,
                                      phTmlNfc_TransactInfo_t* pInfo) {
  UNUSED_PROP(pContext);
  if (pInfo != NULL) {
    NXPLOG_NCIHAL_E("%s Status %d", __func__, pInfo->wStatus);
    if (pInfo->wStatus == NFCSTATUS_SUCCESS) {
      nxpncihal_ctrl.p_rx_data = pInfo->pBuff;
      nxpncihal_ctrl.rx_data_len = pInfo->wLength;
    }
    nxpncihal_ctrl.ext_cb_data.status = pInfo->wStatus;
  } else {
    nxpncihal_ctrl.ext_cb_data.status = NFCSTATUS_FAILED;
  }
  SEM_POST(&(nxpncihal_ctrl.ext_cb_data));
}

/******************************************************************************
 * Function         phNxpNciHal_write_callback
 *
 * Description      Callback function for write request to tml writer thread
 *
 * Parameters       pContext - context value passed while callback register
 *                  pInfo    - Information which contains status and response
 *                             buffers.
 *
 * Returns          void
 *
 ******************************************************************************/
static void phNxpNciHal_write_callback(void* pContext,
                                       phTmlNfc_TransactInfo_t* pInfo) {
  UNUSED_PROP(pContext);
  if (pInfo != NULL) {
    if (pInfo->wStatus != NFCSTATUS_SUCCESS) {
      NXPLOG_NCIHAL_E("write error status = 0x%x", pInfo->wStatus);
    }
    nxpncihal_ctrl.ext_cb_data.status = pInfo->wStatus;
  } else {
    nxpncihal_ctrl.ext_cb_data.status = NFCSTATUS_FAILED;
  }
  SEM_POST(&(nxpncihal_ctrl.ext_cb_data));
}

/******************************************************************************
 * Function         phNxpNciHal_semWaitTimeout
 *
 * Description      Helper function for global sem wait with timeout value
 *
 * Parameters       timeout - wait timeout in nanoseconds
 *
 * Returns          NFCSTATUS
 *
 ******************************************************************************/
static NFCSTATUS phNxpNciHal_semWaitTimeout(long timeout) {
  NFCSTATUS status = NFCSTATUS_FAILED;
  int retVal = 0;
  struct timespec ts;
  clock_gettime(CLOCK_MONOTONIC, &ts);
  ts.tv_nsec += timeout;
  ts.tv_sec += ts.tv_nsec / 1000000000;
  ts.tv_nsec %= 1000000000;
  while ((retVal = sem_timedwait_monotonic_np(&nxpncihal_ctrl.ext_cb_data.sem, &ts)) == -1 &&
         errno == EINTR) {
    continue; /* Restart if interrupted by handler */
  }
  if (retVal == -1 && errno != ETIMEDOUT) {
    NXPLOG_NCIHAL_E("%s : sem_timedwait failed : errno = 0x%x", __func__,
                    errno);
  }
  if (retVal != -1) {
    status = nxpncihal_ctrl.ext_cb_data.status;
  } else if (errno == ETIMEDOUT && retVal == -1) {
    NXPLOG_NCIHAL_E("%s :timed out errno = 0x%x", __func__, errno);
  }
  return status;
}

/******************************************************************************
 * Function         phNxpNciHal_writeCmd
 *
 * Description      Helper function to write command to NFCC
 *
 * Parameters       timeout - wait timeout in nanoseconds
 *
 * Returns          NFCSTATUS
 *
 ******************************************************************************/
static NFCSTATUS phNxpNciHal_writeCmd(uint16_t data_len, const uint8_t* p_data,
                                      long timeout) {
  NFCSTATUS status = NFCSTATUS_FAILED;
  const char context[] = "RecoveryWrite";

  if (p_data == NULL) {
    NXPLOG_NCIHAL_E("Invalid Command Buffer");
    return NFCSTATUS_INVALID_PARAMETER;
  }
  /* Create local copy of cmd_data */
  memcpy(nxpncihal_ctrl.p_cmd_data, p_data, data_len);
  nxpncihal_ctrl.cmd_len = data_len;
  status = phTmlNfc_Write(
      (uint8_t*)nxpncihal_ctrl.p_cmd_data, (uint16_t)nxpncihal_ctrl.cmd_len,
      (pphTmlNfc_TransactCompletionCb_t)&phNxpNciHal_write_callback,
      (void*)context);
  if (status == NFCSTATUS_PENDING) {
    return phNxpNciHal_semWaitTimeout(timeout);
  }
  NXPLOG_NCIHAL_E("tml write request failed");
  return status;
}

/******************************************************************************
 * Function         phNxpNciHal_ReadResponse
 *
 * Description      Helper function to read response from NFCC
 *
 * Parameters       len - response buffer len
 *                  rsp_buffer - Ptr to the response buffer
 *                  timeout - wait timeout in nanoseconds
 *
 * Returns          NFCSTATUS
 *
 ******************************************************************************/
static NFCSTATUS phNxpNciHal_ReadResponse(uint16_t* len, uint8_t** rsp_buffer,
                                          long timeout) {
  NFCSTATUS status = NFCSTATUS_FAILED;
  const char context[] = "RecoveryRead";

  if (len == NULL) {
    NXPLOG_NCIHAL_E("%s Invalid Parameters", __func__);
    return NFCSTATUS_INVALID_PARAMETER;
  }
  status = phTmlNfc_Read(
      nxpncihal_ctrl.p_rsp_data, NCI_MAX_DATA_LEN,
      (pphTmlNfc_TransactCompletionCb_t)&phNxpNciHal_read_callback,
      (void*)context);
  if (phNxpNciHal_semWaitTimeout(timeout) == NFCSTATUS_SUCCESS) {
    if (nxpncihal_ctrl.p_rx_data != NULL && nxpncihal_ctrl.rx_data_len > 0) {
      *rsp_buffer = nxpncihal_ctrl.p_rx_data;
      *len = nxpncihal_ctrl.rx_data_len;
      status = NFCSTATUS_SUCCESS;
    } else
      status = NFCSTATUS_FAILED;
  }
  return status;
}

/******************************************************************************
 * Function         phNxpNciHal_readNFCCClockCfgValues
 *
 * Description      Helper function to read clock configuration from
 *                  nfcc configuration file and stores value in global strcture
 *
 * Returns          void
 *
 ******************************************************************************/
static void phNxpNciHal_readNFCCClockCfgValues(void) {
  unsigned long num = 0;
  int isfound = 0;

  isfound = GetNxpNumValue(NAME_NXP_SYS_CLK_SRC_SEL, &num, sizeof(num));
  if (isfound > 0) nxpprofile_ctrl.bClkSrcVal = num;
  num = 0;
  isfound = 0;
  isfound = GetNxpNumValue(NAME_NXP_SYS_CLK_FREQ_SEL, &num, sizeof(num));
  if (isfound > 0) nxpprofile_ctrl.bClkFreqVal = num;
}

/******************************************************************************
 * Function         phNxpNciHal_determineChipType
 *
 * Description      Helper function to determine the chip info in nci mode
 *                  from NCI command and stores value in global strcture
 *
 * Returns          bool
 *
 ******************************************************************************/
static bool phNxpNciHal_determineChipType(void) {
  const uint8_t cmd_reset_nci[] = {0x20, 0x00, 0x01, 0x00};
  uint8_t* rsp_buffer = NULL;
  uint16_t rsp_len = 0;
  uint8_t retry = 0;
  bool status = false;

  do {
    if ((phNxpNciHal_writeCmd(sizeof(cmd_reset_nci), cmd_reset_nci,
                              WRITE_TIMEOUT_NS) != NFCSTATUS_SUCCESS)) {
      NXPLOG_NCIHAL_E("NCI_CORE_RESET Write Failure ");
      break;
    }
    // 10ms delay  for first core reset response to avoid nfcc standby
    usleep(NCI_RESET_RESP_READ_DELAY_US);
    if ((phNxpNciHal_ReadResponse(&rsp_len, &rsp_buffer,
                                  RESPONSE_READ_TIMEOUT_NS) !=
         NFCSTATUS_SUCCESS) ||
        (rsp_buffer == NULL)) {
      NXPLOG_NCIHAL_E("NCI_CORE_RESET read response failed");
      break;
    }
    if (rsp_buffer[NCI_RSP_IDX] == NCI_MSG_RSP) {
      if ((phNxpNciHal_ReadResponse(&rsp_len, &rsp_buffer,
                                    RESPONSE_READ_TIMEOUT_NS) !=
           NFCSTATUS_SUCCESS) ||
          (rsp_buffer == NULL)) {
        NXPLOG_NCIHAL_E("NCI_CORE_RESET NTF read failed");
        break;
      }
      if (rsp_buffer[NCI_RSP_IDX] == NCI_MSG_NTF) {
        phNxpNciHal_configFeatureList(rsp_buffer, rsp_len);
        status = true;
        break;
      }
    } else {
      NXPLOG_NCIHAL_E("NCI_CORE_RESPONSE Wrong Status");
    }
  } while (retry++ < MAX_CORE_RESET);
  return status;
}

/******************************************************************************
 * Function         phNxpNciHal_isSessionClosed
 *
 * Description      Helper function to determine download session state
 *
 * Returns          true means session closed
 *
 ******************************************************************************/
bool phNxpNciHal_isSessionClosed(void) {
  const uint8_t get_session_cmd[] = {0x00, 0x04, 0xF2, 0x00,
                                     0x00, 0x00, 0xF5, 0x33};
  uint8_t* rsp_buffer = NULL;
  uint16_t rsp_len = 0;

  if ((phNxpNciHal_writeCmd(sizeof(get_session_cmd), get_session_cmd,
                            WRITE_TIMEOUT_NS) == NFCSTATUS_SUCCESS)) {
    if ((phNxpNciHal_ReadResponse(&rsp_len, &rsp_buffer,
                                  RESPONSE_READ_TIMEOUT_NS) !=
         NFCSTATUS_SUCCESS) ||
        (rsp_buffer == NULL)) {
      NXPLOG_NCIHAL_E("Get Session read response failed");
    } else if (rsp_buffer[DL_RSP_STAT_IDX] == DL_MSG_STAT_RSP &&
               rsp_buffer[DL_RSP_IDX] == DL_MSG_RSP) {
      if (rsp_buffer[DL_RSP_SESS_IDX] == DL_SESSION_CLOSE_TAG) {
        return true;
      }
    }
  }
  return false;
}

/******************************************************************************
 * Function         phNxpNciHal_determineChipTypeDlMode
 *
 * Description      Helper function to determine the chip info in download mode
 *                  from get version command and stores value in global strcture
 *
 * Returns          bool
 *
 ******************************************************************************/
static bool phNxpNciHal_determineChipTypeDlMode(void) {
  const uint8_t get_version_cmd[] = {0x00, 0x04, 0xF1, 0x00,
                                     0x00, 0x00, 0x6E, 0xEF};
  uint8_t* rsp_buffer = NULL;
  uint16_t rsp_len = 0;

  if ((phNxpNciHal_writeCmd(sizeof(get_version_cmd), get_version_cmd,
                            WRITE_TIMEOUT_NS) == NFCSTATUS_SUCCESS)) {
    if ((phNxpNciHal_ReadResponse(&rsp_len, &rsp_buffer,
                                  RESPONSE_READ_TIMEOUT_NS) !=
         NFCSTATUS_SUCCESS) ||
        (rsp_buffer == NULL)) {
      NXPLOG_NCIHAL_E("Get Version read response failed");
    } else if (rsp_buffer[DL_RSP_STAT_IDX] == DL_MSG_STAT_RSP &&
               rsp_buffer[DL_RSP_IDX] == DL_MSG_RSP) {
      phNxpNciHal_configFeatureList(rsp_buffer, rsp_len);
      return true;
    }
  }
  return false;
}

/******************************************************************************
 * Function        phNxpNciHal_RecoverFWTearDown
 *
 * Description     Function to determine the NFCC state and recovery using
 *                 minimal fw download.
 *
 * Parameters      None
 *
 * Returns         SUCCESS if recovery is successful else FAIL.
 *
 ******************************************************************************/
void phNxpNciHal_RecoverFWTearDown(void) {
  uint8_t nfcc_recovery_support = 0x00;
  // status post boot completed
  const char* status = "Boot-completed";
  char halInitStatus[PROPERTY_VALUE_MAX] = {0};

  NXPLOG_NCIHAL_D("phNxpNciHal_RecoverFWTearDown(): enter \n");
  if (!GetNxpNumValue(NAME_NXP_NFCC_RECOVERY_SUPPORT, &nfcc_recovery_support,
                      sizeof(nfcc_recovery_support))) {
    NXPLOG_NCIHAL_E("Failed to read NXP_NFC_RECOVERY_SUPPORT config :");
  }
  if (nfcc_recovery_support == 0x00) {
    NXPLOG_NCIHAL_D("NFCC Recovery not supported");
    return;
  }

  // If this is not boot time invocation return
  getHalInitStatus(halInitStatus);
  if (strncmp(halInitStatus, status, PROPERTY_VALUE_MAX) == 0) {
    NXPLOG_NCIHAL_D("Not boot time, skip minimal FW download");
    return;
  } else {
    NXPLOG_NCIHAL_D("boot time, check minimal FW download required");
  }

  if (phnxpNciHal_partialOpen() != NFCSTATUS_SUCCESS) {
    NXPLOG_NCIHAL_E("Failed to Initialize Partial HAL for NFCC recovery \n");
    return;
  }
  if (phTmlNfc_IoCtl(phTmlNfc_e_PowerReset) != NFCSTATUS_SUCCESS) {
    NXPLOG_NCIHAL_E("Failed to Perform VEN RESET \n");
    phnxpNciHal_partialClose();
    return;
  }
  if (phNxpNciHal_determineChipType()) {
    NXPLOG_NCIHAL_D("Recovery not required \n");
    phnxpNciHal_partialClose();
    setHalInitStatus(status);
    return;
  }
  if (phTmlNfc_IoCtl(phTmlNfc_e_EnableDownloadModeWithVenRst) !=
      NFCSTATUS_SUCCESS) {
    NXPLOG_NCIHAL_E("Enable Download mode failed");
    phnxpNciHal_partialClose();
    setHalInitStatus(status);
    return;
  }

  phTmlNfc_EnableFwDnldMode(true);
  bool bEnableNormalMode = true;
  if (!phNxpNciHal_determineChipTypeDlMode()) {
    NXPLOG_NCIHAL_E("Not able to determine chiptype");
  } else if (IS_CHIP_TYPE_NE(sn100u)) {
    NXPLOG_NCIHAL_E("Recovery not supported for chiptype (%d)", nfcFL.chipType);
  } else if (phNxpNciHal_isSessionClosed()) {
    NXPLOG_NCIHAL_D("FW Dnld session is closed");
  } else if (phNxpNciHal_fw_download_seq(nxpprofile_ctrl.bClkSrcVal,
                                         nxpprofile_ctrl.bClkFreqVal, 0,
                                         true) != NFCSTATUS_SUCCESS) {
    NXPLOG_NCIHAL_E("Minimal FW Update failed \n");
  } else {
    /* In the success case, the phNxpNciHal_fw_download_seq() will enable normal
     * mode */
    bEnableNormalMode = false;
  }
  if (bEnableNormalMode) {
    phTmlNfc_IoCtl(phTmlNfc_e_EnableNormalMode);
  }
  phTmlNfc_IoCtl(phTmlNfc_e_PowerReset);
  phnxpNciHal_partialClose();
  // Minimal FW not required in this boot session
  setHalInitStatus(status);
}

/*******************************************************************************
 *
 * Function         phnxpNciHal_partialOpenCleanUp
 *
 * Description      Helper function to cleanUp the Memory and flags from
 *                  phnxpNciHal_partialOpen
 *
 * Parameters       nfc_dev_node - dev node to be freed
 *
 * Returns          NFCSTATUS
 *******************************************************************************/
static int phnxpNciHal_partialOpenCleanUp(char* nfc_dev_node) {
  if (nfc_dev_node != NULL) {
    free(nfc_dev_node);
    nfc_dev_node = NULL;
  }
  /* Report error status */
  phNxpNciHal_cleanup_monitor();
  nxpncihal_ctrl.halStatus = HAL_STATUS_CLOSE;
  return NFCSTATUS_FAILED;
}

/*******************************************************************************
 *
 * Function         phnxpNciHal_partialOpen
 *
 * Description      Initialize the Minimal HAL
 *
 * Parameters       none
 *
 * Returns          NFCSTATUS
 *******************************************************************************/
static NFCSTATUS phnxpNciHal_partialOpen(void) {
  phOsalNfc_Config_t tOsalConfig;
  phTmlNfc_Config_t tTmlConfig;
  char* nfc_dev_node = NULL;

  CONCURRENCY_LOCK();
  NXPLOG_NCIHAL_D("phnxpNciHal_partialOpen(): enter");
  if (nxpncihal_ctrl.halStatus == HAL_STATUS_MIN_OPEN) {
    NXPLOG_NCIHAL_D("phNxpNciHal: already open");
    CONCURRENCY_UNLOCK();
    return NFCSTATUS_SUCCESS;
  }
  /* initialize trace level */
  phNxpLog_InitializeLogLevel();
  if (phNxpNciHal_init_monitor() == NULL) {
    NXPLOG_NCIHAL_E("Init monitor failed");
    CONCURRENCY_UNLOCK();
    return NFCSTATUS_FAILED;
  }
  /* Create the local semaphore */
  if (phNxpNciHal_init_cb_data(&nxpncihal_ctrl.ext_cb_data, NULL) !=
      NFCSTATUS_SUCCESS) {
    NXPLOG_NCIHAL_D("Create ext_cb_data failed");
    CONCURRENCY_UNLOCK();
    return NFCSTATUS_FAILED;
  }
  memset(&tOsalConfig, 0x00, sizeof(tOsalConfig));
  memset(&tTmlConfig, 0x00, sizeof(tTmlConfig));
  memset(&nxpprofile_ctrl, 0, sizeof(phNxpNciProfile_Control_t));

  /* By default HAL status is HAL_STATUS_OPEN */
  nxpncihal_ctrl.halStatus = HAL_STATUS_OPEN;

  /*nci version NCI_VERSION_2_0 version by default for SN100 chip type*/
  nxpncihal_ctrl.nci_info.nci_version = NCI_VERSION_2_0;
  /* Read the nfc device node name */
  nfc_dev_node = (char*)malloc(NXP_MAX_CONFIG_STRING_LEN * sizeof(char));
  if (nfc_dev_node == NULL) {
    NXPLOG_NCIHAL_D("malloc of nfc_dev_node failed ");
    CONCURRENCY_UNLOCK();
    return phnxpNciHal_partialOpenCleanUp(nfc_dev_node);
  } else if (!GetNxpStrValue(NAME_NXP_NFC_DEV_NODE, nfc_dev_node,
                             NXP_MAX_CONFIG_STRING_LEN)) {
    NXPLOG_NCIHAL_D(
        "Invalid nfc device node name keeping the default device node "
        "/dev/nxp-nci");
    strlcpy(nfc_dev_node, "/dev/nxp-nci",
            (NXP_MAX_CONFIG_STRING_LEN * sizeof(char)));
  }
  /* Configure hardware link */
  nxpncihal_ctrl.gDrvCfg.nClientId = phDal4Nfc_msgget(0, 0600);
  nxpncihal_ctrl.gDrvCfg.nLinkType = ENUM_LINK_TYPE_I2C; /* For NFCC */
  tTmlConfig.pDevName = (int8_t*)nfc_dev_node;
  tOsalConfig.dwCallbackThreadId = (uintptr_t)nxpncihal_ctrl.gDrvCfg.nClientId;
  tOsalConfig.pLogFile = NULL;
  tTmlConfig.dwGetMsgThreadId = (uintptr_t)nxpncihal_ctrl.gDrvCfg.nClientId;

  /* Initialize TML layer */
  if (phTmlNfc_Init(&tTmlConfig) != NFCSTATUS_SUCCESS) {
    NXPLOG_NCIHAL_E("phTmlNfc_Init Failed");
    CONCURRENCY_UNLOCK();
    return phnxpNciHal_partialOpenCleanUp(nfc_dev_node);
  } else {
    if (nfc_dev_node != NULL) {
      free(nfc_dev_node);
      nfc_dev_node = NULL;
    }
  }
  /* Create the client thread */
  if (pthread_create(&nxpncihal_ctrl.client_thread, NULL,
                     phNxpNciHal_client_thread, &nxpncihal_ctrl) != 0) {
    NXPLOG_NCIHAL_E("pthread_create failed");
    if (phTmlNfc_Shutdown_CleanUp() != NFCSTATUS_SUCCESS) {
      NXPLOG_NCIHAL_E("phTmlNfc_Shutdown_CleanUp: Failed");
    }
    CONCURRENCY_UNLOCK();
    return phnxpNciHal_partialOpenCleanUp(nfc_dev_node);
  }
  phNxpNciHal_readNFCCClockCfgValues();
  CONCURRENCY_UNLOCK();
  return NFCSTATUS_SUCCESS;
}

/*******************************************************************************
 *
 * Function         phnxpNciHal_partialClose
 *
 * Description      close the Minimal HAL
 *
 * Parameters       none
 *
 * Returns          void
 *******************************************************************************/
static void phnxpNciHal_partialClose(void) {
  phLibNfc_Message_t msg;
  nxpncihal_ctrl.halStatus = HAL_STATUS_CLOSE;

  if (NULL != gpphTmlNfc_Context->pDevHandle) {
    msg.eMsgType = NCI_HAL_CLOSE_CPLT_MSG;
    msg.pMsgData = NULL;
    msg.Size = 0;
    phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &msg);
    /* Abort any pending read and write */
    phTmlNfc_ReadAbort();
    phTmlNfc_WriteAbort();
    phTmlNfc_Shutdown();
    if (0 != pthread_join(nxpncihal_ctrl.client_thread, (void**)NULL)) {
      NXPLOG_TML_E("Fail to kill client thread!");
    }
    phTmlNfc_CleanUp();
    phDal4Nfc_msgrelease(nxpncihal_ctrl.gDrvCfg.nClientId);
    phNxpNciHal_cleanup_cb_data(&nxpncihal_ctrl.ext_cb_data);
    memset(&nxpncihal_ctrl, 0x00, sizeof(nxpncihal_ctrl));
    NXPLOG_NCIHAL_D("phnxpNciHal_partialClose - phOsalNfc_DeInit completed");
  }
  CONCURRENCY_UNLOCK();
  phNxpNciHal_cleanup_monitor();
}

#endif
