/* * Copyright (C) 2012-2014 NXP Semiconductors * * 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. */ #include #include /* Timeout value to wait for RF INTF Activated NTF.*/ #define KOVIO_TIMEOUT 1000 #define KOVIO_ACT_NTF_TEMP_BUFF_LEN \ 64 /* length of temp buffer to manipulate \ the activated notification to match BCM format*/ #define MAX_WRITE_RETRY 5 /******************* Global variables *****************************************/ extern phNxpNciHal_Control_t nxpncihal_ctrl; extern NFCSTATUS phNxpNciHal_send_ext_cmd(uint16_t cmd_len, uint8_t* p_cmd); int kovio_detected = 0x00; int send_to_upper_kovio = 0x01; int disable_kovio = 0x00; bool_t rf_deactive_cmd = false; static uint8_t rf_deactivate_cmd[] = {0x21, 0x06, 0x01, 0x03}; /* discovery */ static uint8_t rf_deactivated_ntf[] = {0x61, 0x06, 0x02, 0x03, 0x01}; static uint8_t reset_ntf[] = {0x60, 0x00, 0x06, 0xA0, 0x00, 0xC7, 0xD4, 0x00, 0x00}; static uint32_t kovio_timer; /************** Kovio functions ***************************************/ static NFCSTATUS phNxpNciHal_rf_deactivate(void); /******************************************************************************* ** ** Function hal_write_cb ** ** Description Callback function for hal write. ** ** Returns None ** *******************************************************************************/ static void hal_write_cb(void* pContext, phTmlNfc_TransactInfo_t* pInfo) { UNUSED(pContext); UNUSED(pInfo); return; } /******************************************************************************* ** ** Function kovio_timer_handler ** ** Description Callback function for kovio timer. ** ** Returns None ** *******************************************************************************/ static void kovio_timer_handler(uint32_t timerId, void* pContext) { UNUSED(timerId); UNUSED(pContext); NXPLOG_NCIHAL_D( ">> kovio_timer_handler. Did not receive RF_INTF_ACTIVATED_NTF, Kovio " "TAG must be removed."); phOsalNfc_Timer_Delete(kovio_timer); kovio_detected = 0x00; send_to_upper_kovio = 0x01; disable_kovio = 0x00; /* * send kovio deactivated ntf to upper layer. */ NXPLOG_NCIHAL_D(">> send kovio deactivated ntf to upper layer."); if (nxpncihal_ctrl.p_nfc_stack_data_cback != NULL) { (*nxpncihal_ctrl.p_nfc_stack_data_cback)(sizeof(rf_deactivated_ntf), rf_deactivated_ntf); } return; } /******************************************************************************* ** ** Function phNxpNciHal_rf_deactivate ** ** Description Sends rf deactivate cmd to NFCC ** ** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED ** *******************************************************************************/ static NFCSTATUS phNxpNciHal_rf_deactivate() { NFCSTATUS status = NFCSTATUS_SUCCESS; int cb_data; int retryCnt = 0; do { retryCnt++; status = phTmlNfc_Write(rf_deactivate_cmd, sizeof(rf_deactivate_cmd), (pphTmlNfc_TransactCompletionCb_t)&hal_write_cb, &cb_data); } while (status != NFCSTATUS_PENDING && retryCnt <= MAX_WRITE_RETRY); if (status != NFCSTATUS_PENDING) { // phNxpNciHal_emergency_recovery(); if (nxpncihal_ctrl.p_nfc_stack_data_cback != NULL && nxpncihal_ctrl.hal_open_status == true) { NXPLOG_NCIHAL_D( "Send the Core Reset NTF to upper layer, which will trigger the " "recovery\n"); // Send the Core Reset NTF to upper layer, which will trigger the // recovery. send_to_upper_kovio = 0; nxpncihal_ctrl.rx_data_len = sizeof(reset_ntf); memcpy(nxpncihal_ctrl.p_rx_data, reset_ntf, sizeof(reset_ntf)); (*nxpncihal_ctrl.p_nfc_stack_data_cback)(nxpncihal_ctrl.rx_data_len, nxpncihal_ctrl.p_rx_data); } } return status; } /******************************************************************************* ** ** Function phNxpNciHal_kovio_rsp_ext ** ** Description Implements kovio presence check. In BCM controller this is ** managed by NFCC. But since PN54X does not handle this, the ** presence check is mimiced here. ** For the very first time Kovio is detected, NTF has to be ** passed on to upper layer. for every NTF, DH send a ** deactivated command to NFCC and NFCC follows this up with ** another activated notification. When the tag is removed, ** activated notification stops coming and this is indicated to ** upper layer with a HAL generated deactivated notification. ** ** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED ** *******************************************************************************/ NFCSTATUS phNxpNciHal_kovio_rsp_ext(uint8_t* p_ntf, uint16_t* p_len) { NFCSTATUS status = NFCSTATUS_SUCCESS; uint8_t tBuff[KOVIO_ACT_NTF_TEMP_BUFF_LEN]; send_to_upper_kovio = 1; if ((p_ntf[0] == 0x61) && (p_ntf[1] == 0x05)) { #if (NFC_NXP_CHIP_TYPE != PN547C2) if ((p_ntf[5] == 0x81) && (p_ntf[6] == 0x70)) #else if ((p_ntf[5] == 0x8A) && (p_ntf[6] == 0x77)) #endif { if (kovio_detected == 0) { if ((*p_len - 9) < KOVIO_ACT_NTF_TEMP_BUFF_LEN) { p_ntf[2] += 1; memcpy(tBuff, &p_ntf[9], *p_len - 9); p_ntf[9] = p_ntf[9] + 1; memcpy(&p_ntf[10], tBuff, *p_len - 9); *p_len += 1; } else { NXPLOG_NCIHAL_D("Kovio Act ntf payload exceeded temp buffer size"); } kovio_detected = 1; kovio_timer = phOsalNfc_Timer_Create(); NXPLOG_NCIHAL_D("custom kovio timer Created - %d", kovio_timer); } else { send_to_upper_kovio = 0; } if (!rf_deactive_cmd) { NXPLOG_NCIHAL_D("Send RF deactivate command to NFCC"); status = phNxpNciHal_rf_deactivate(); } else { NXPLOG_NCIHAL_D("RF deactivate command is already sent to NFCC"); disable_kovio = true; send_to_upper_kovio = 0; } status = phOsalNfc_Timer_Start(kovio_timer, KOVIO_TIMEOUT, &kovio_timer_handler, NULL); if (NFCSTATUS_SUCCESS == status) { NXPLOG_NCIHAL_D("kovio timer started"); } else { NXPLOG_NCIHAL_E("kovio timer not started!!!"); status = NFCSTATUS_FAILED; } } else { if (kovio_detected == 1) { phNxpNciHal_clean_Kovio_Ext(); NXPLOG_NCIHAL_D( "Disabling Kovio detection logic as another tag type detected"); } } } else if ((p_ntf[0] == 0x41) && (p_ntf[1] == 0x06) && (p_ntf[2] == 0x01)) { rf_deactive_cmd = false; if (kovio_detected == 1) send_to_upper_kovio = 0; if ((kovio_detected == 1) && (disable_kovio == 0x01)) { NXPLOG_NCIHAL_D("Disabling Kovio detection logic"); phNxpNciHal_clean_Kovio_Ext(); disable_kovio = 0x00; } } else if ((p_ntf[0] == 0x61) && (p_ntf[1] == 0x06) && (p_ntf[2] == 0x02) && (p_ntf[3] == 0x03) && (p_ntf[4] == 0x00)) { if (kovio_detected == 1) send_to_upper_kovio = 0; } else if ((p_ntf[0] == 0x61) && (p_ntf[1] == 0x03)) { if (kovio_detected == 1) send_to_upper_kovio = 0; } return status; } /******************************************************************************* ** ** Function phNxpNciHal_clean_Kovio_Ext ** ** Description Clean up Kovio extension state machine. ** Returns NFCSTATUS_SUCCESS if successful,otherwise NFCSTATUS_FAILED ** *******************************************************************************/ void phNxpNciHal_clean_Kovio_Ext() { NXPLOG_NCIHAL_D(">> Cleaning up Kovio State machine and timer."); phOsalNfc_Timer_Delete(kovio_timer); kovio_detected = 0x00; send_to_upper_kovio = 0x01; disable_kovio = 0x00; /* * send kovio deactivated ntf to upper layer. */ NXPLOG_NCIHAL_D(">> send kovio deactivated ntf to upper layer."); if (nxpncihal_ctrl.p_nfc_stack_data_cback != NULL) { (*nxpncihal_ctrl.p_nfc_stack_data_cback)(sizeof(rf_deactivated_ntf), rf_deactivated_ntf); } return; }