/* * Copyright (C) 2010 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. */ /*! * =========================================================================== * * * * * * \file phHciNfc_CE_A.c * * \brief HCI card emulation A management routines. * * * * * * Project: NFC-FRI-1.1 * * * * $Date: Fri Aug 21 18:35:05 2009 $ * * $Author: ing04880 $ * * $Revision: 1.14 $ * * $Aliases: NFC_FRI1.1_WK934_R31_1,NFC_FRI1.1_WK941_PREP1,NFC_FRI1.1_WK941_PREP2,NFC_FRI1.1_WK941_1,NFC_FRI1.1_WK943_R32_1,NFC_FRI1.1_WK949_PREP1,NFC_FRI1.1_WK943_R32_10,NFC_FRI1.1_WK943_R32_13,NFC_FRI1.1_WK943_R32_14,NFC_FRI1.1_WK1007_R33_1,NFC_FRI1.1_WK1007_R33_4,NFC_FRI1.1_WK1017_PREP1,NFC_FRI1.1_WK1017_R34_1,NFC_FRI1.1_WK1017_R34_2,NFC_FRI1.1_WK1023_R35_1 $ * * * =========================================================================== * */ /* ***************************** Header File Inclusion **************************** */ #include <phNfcCompId.h> #include <phNfcHalTypes.h> #include <phHciNfc_Pipe.h> #include <phHciNfc_Emulation.h> #include <phOsalNfc.h> /* ****************************** Macro Definitions ******************************* */ #if defined (HOST_EMULATION) #include <phHciNfc_CE_A.h> #define CE_A_EVT_NFC_SEND_DATA 0x10U #define CE_A_EVT_NFC_FIELD_ON 0x11U #define CE_A_EVT_NFC_DEACTIVATED 0x12U #define CE_A_EVT_NFC_ACTIVATED 0x13U #define CE_A_EVT_NFC_FIELD_OFF 0x14U /* *************************** Structure and Enumeration *************************** */ /* *************************** Static Function Declaration ************************** */ static NFCSTATUS phHciNfc_Recv_CE_A_Event( void *psContext, void *pHwRef, uint8_t *pEvent, #ifdef ONE_BYTE_LEN uint8_t length #else uint16_t length #endif ); static NFCSTATUS phHciNfc_Recv_CE_A_Response( void *psContext, void *pHwRef, uint8_t *pResponse, #ifdef ONE_BYTE_LEN uint8_t length #else uint16_t length #endif ); #if defined (SEND_DATA_EVENT) static NFCSTATUS phHciNfc_CE_A_ProcessData( phHciNfc_sContext_t *psHciContext, void *pHwRef, uint8_t *pData, uint8_t length ); #endif /* #if defined (SEND_DATA_EVENT) */ /* *************************** Function Definitions *************************** */ NFCSTATUS phHciNfc_CE_A_Init_Resources( phHciNfc_sContext_t *psHciContext ) { NFCSTATUS status = NFCSTATUS_SUCCESS; phHciNfc_CE_A_Info_t *ps_ce_a_info=NULL; if( NULL == psHciContext ) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER); } else { if( ( NULL == psHciContext->p_ce_a_info ) && (phHciNfc_Allocate_Resource((void **)(&ps_ce_a_info), sizeof(phHciNfc_CE_A_Info_t))== NFCSTATUS_SUCCESS) ) { psHciContext->p_ce_a_info = ps_ce_a_info; ps_ce_a_info->current_seq = HOST_CE_A_INVALID_SEQ; ps_ce_a_info->next_seq = HOST_CE_A_INVALID_SEQ; ps_ce_a_info->pipe_id = (uint8_t)HCI_UNKNOWN_PIPE_ID; } else { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INSUFFICIENT_RESOURCES); } } return status; } NFCSTATUS phHciNfc_CE_A_Initialise( phHciNfc_sContext_t *psHciContext, void *pHwRef ) { /* 1. Open Pipe, 2. Set all parameters */ NFCSTATUS status = NFCSTATUS_SUCCESS; static uint8_t sak = HOST_CE_A_SAK_DEFAULT; static uint8_t atqa_info[] = { NXP_CE_A_ATQA_HIGH, NXP_CE_A_ATQA_LOW}; if ((NULL == psHciContext) || (NULL == pHwRef)) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER); } else if(NULL == psHciContext->p_ce_a_info) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED); } else { phHciNfc_CE_A_Info_t *ps_ce_a_info = ((phHciNfc_CE_A_Info_t *) psHciContext->p_ce_a_info ); phHciNfc_Pipe_Info_t *ps_pipe_info = NULL; ps_pipe_info = ps_ce_a_info->p_pipe_info; if(NULL == ps_pipe_info ) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_HCI_INFORMATION); } else { switch(ps_ce_a_info->current_seq) { case HOST_CE_A_PIPE_OPEN: { status = phHciNfc_Open_Pipe( psHciContext, pHwRef, ps_pipe_info ); if(status == NFCSTATUS_SUCCESS) { ps_ce_a_info->next_seq = HOST_CE_A_SAK_SEQ; status = NFCSTATUS_PENDING; } break; } case HOST_CE_A_SAK_SEQ: { /* HOST Card Emulation A SAK Configuration */ ps_pipe_info->reg_index = HOST_CE_A_SAK_INDEX; /* Configure the SAK of Host Card Emulation A */ sak = (uint8_t)HOST_CE_A_SAK_DEFAULT; ps_pipe_info->param_info =(void*)&sak ; ps_pipe_info->param_length = sizeof(sak) ; status = phHciNfc_Send_Generic_Cmd(psHciContext,pHwRef, ps_pipe_info->pipe.pipe_id, (uint8_t)ANY_SET_PARAMETER); if(status == NFCSTATUS_PENDING) { ps_ce_a_info->next_seq = HOST_CE_A_ATQA_SEQ; } break; } case HOST_CE_A_ATQA_SEQ: { /* HOST Card Emulation A ATQA Configuration */ ps_pipe_info->reg_index = HOST_CE_A_ATQA_INDEX; /* Configure the ATQA of Host Card Emulation A */ ps_pipe_info->param_info = (void*)atqa_info ; ps_pipe_info->param_length = sizeof(atqa_info) ; status = phHciNfc_Send_Generic_Cmd(psHciContext,pHwRef, ps_pipe_info->pipe.pipe_id, (uint8_t)ANY_SET_PARAMETER); if(status == NFCSTATUS_PENDING) { ps_ce_a_info->next_seq = HOST_CE_A_ENABLE_SEQ; } break; } case HOST_CE_A_ENABLE_SEQ: { status = phHciNfc_CE_A_Mode( psHciContext, pHwRef, HOST_CE_MODE_ENABLE ); if(status == NFCSTATUS_PENDING) { ps_ce_a_info->next_seq = HOST_CE_A_DISABLE_SEQ; status = NFCSTATUS_SUCCESS; } break; } default : { break; } } } } return status; } NFCSTATUS phHciNfc_CE_A_Release( phHciNfc_sContext_t *psHciContext, void *pHwRef ) { /* 1. Close pipe */ NFCSTATUS status = NFCSTATUS_SUCCESS; if ((NULL == psHciContext) || (NULL == pHwRef)) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER); } else if(NULL == psHciContext->p_ce_a_info) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED); } else { phHciNfc_CE_A_Info_t *ps_ce_a_info = ((phHciNfc_CE_A_Info_t *) psHciContext->p_ce_a_info ); phHciNfc_Pipe_Info_t *ps_pipe_info = NULL; ps_pipe_info = ps_ce_a_info->p_pipe_info; if(NULL == ps_pipe_info ) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_NOT_ALLOWED); } else { switch(ps_ce_a_info->current_seq) { case HOST_CE_A_DISABLE_SEQ: { status = phHciNfc_CE_A_Mode( psHciContext, pHwRef, HOST_CE_MODE_DISABLE ); if(status == NFCSTATUS_PENDING) { ps_ce_a_info->next_seq = HOST_CE_A_PIPE_CLOSE; } break; } case HOST_CE_A_PIPE_CLOSE: { /* HOST Card Emulation A pipe close sequence */ status = phHciNfc_Close_Pipe( psHciContext, pHwRef, ps_pipe_info ); if(status == NFCSTATUS_SUCCESS) { ps_ce_a_info->next_seq = HOST_CE_A_PIPE_DELETE; status = NFCSTATUS_PENDING; } break; } case HOST_CE_A_PIPE_DELETE: { /* HOST Card Emulation A pipe delete sequence */ status = phHciNfc_Delete_Pipe( psHciContext, pHwRef, ps_pipe_info ); if(status == NFCSTATUS_SUCCESS) { #if 0 ps_ce_a_info->pipe_id = HCI_UNKNOWN_PIPE_ID; psHciContext->p_pipe_list[ps_ce_a_info->pipe_id] = NULL; phOsalNfc_FreeMemory((void *)ps_ce_a_info->p_pipe_info); ps_ce_a_info->p_pipe_info = NULL; #endif ps_ce_a_info->next_seq = HOST_CE_A_PIPE_OPEN; } break; } default : { break; } } } } return status; } NFCSTATUS phHciNfc_CE_A_Update_PipeInfo( phHciNfc_sContext_t *psHciContext, uint8_t pipeID, phHciNfc_Pipe_Info_t *pPipeInfo ) { NFCSTATUS status = NFCSTATUS_SUCCESS; if( NULL == psHciContext ) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER); } else if(NULL == psHciContext->p_ce_a_info) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED); } else { phHciNfc_CE_A_Info_t *ps_ce_a_info=NULL; ps_ce_a_info = (phHciNfc_CE_A_Info_t *) psHciContext->p_ce_a_info ; ps_ce_a_info->current_seq = HOST_CE_A_PIPE_OPEN; ps_ce_a_info->next_seq = HOST_CE_A_PIPE_OPEN; /* Update the pipe_id of the card emulation A Gate o btained from the HCI Response */ ps_ce_a_info->pipe_id = pipeID; if (HCI_UNKNOWN_PIPE_ID != pipeID) { ps_ce_a_info->p_pipe_info = pPipeInfo; if (NULL != pPipeInfo) { /* Update the Response Receive routine of the card emulation A Gate */ pPipeInfo->recv_resp = &phHciNfc_Recv_CE_A_Response; /* Update the event Receive routine of the card emulation A Gate */ pPipeInfo->recv_event = &phHciNfc_Recv_CE_A_Event; } } else { ps_ce_a_info->p_pipe_info = NULL; } } return status; } NFCSTATUS phHciNfc_CE_A_Get_PipeID( phHciNfc_sContext_t *psHciContext, uint8_t *ppipe_id ) { NFCSTATUS status = NFCSTATUS_SUCCESS; if( (NULL != psHciContext) && ( NULL != ppipe_id ) && ( NULL != psHciContext->p_ce_a_info ) ) { phHciNfc_CE_A_Info_t *ps_ce_a_info=NULL; ps_ce_a_info = (phHciNfc_CE_A_Info_t *) psHciContext->p_ce_a_info ; *ppipe_id = ps_ce_a_info->pipe_id ; } else { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER); } return status; } #ifdef CE_A_SEND_EVENT NFCSTATUS phHciNfc_CE_A_SendData_Event( void *psContext, void *pHwRef, uint8_t *pEvent, uint8_t length ) { NFCSTATUS status = NFCSTATUS_SUCCESS; phHciNfc_sContext_t *psHciContext = (phHciNfc_sContext_t *)psContext ; return status; } #endif /* #ifdef CE_A_SEND_EVENT */ static NFCSTATUS phHciNfc_Recv_CE_A_Response( void *psContext, void *pHwRef, uint8_t *pResponse, #ifdef ONE_BYTE_LEN uint8_t length #else uint16_t length #endif ) { NFCSTATUS status = NFCSTATUS_SUCCESS; phHciNfc_sContext_t *psHciContext = (phHciNfc_sContext_t *)psContext ; if( (NULL == psHciContext) || (NULL == pHwRef) || (NULL == pResponse) || (length == 0)) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER); } else if(NULL == psHciContext->p_ce_a_info) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED); } else { phHciNfc_CE_A_Info_t *ps_ce_a_info=NULL; uint8_t prev_cmd = ANY_GET_PARAMETER; ps_ce_a_info = (phHciNfc_CE_A_Info_t *) psHciContext->p_ce_a_info ; if( NULL == ps_ce_a_info->p_pipe_info) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_HCI_SEQUENCE); } else { prev_cmd = ps_ce_a_info->p_pipe_info->prev_msg ; switch(prev_cmd) { case ANY_GET_PARAMETER: { #if 0 status = phHciNfc_CE_A_InfoUpdate(psHciContext, ps_ce_a_info->p_pipe_info->reg_index, &pResponse[HCP_HEADER_LEN], (length - HCP_HEADER_LEN)); #endif /* #if 0 */ break; } case ANY_SET_PARAMETER: { HCI_PRINT("CE A Parameter Set \n"); break; } case ANY_OPEN_PIPE: { HCI_PRINT("CE A open pipe complete\n"); break; } case ANY_CLOSE_PIPE: { HCI_PRINT("CE A close pipe complete\n"); break; } default: { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_HCI_RESPONSE); break; } } if( NFCSTATUS_SUCCESS == status ) { status = phHciNfc_CE_A_Update_Seq(psHciContext, UPDATE_SEQ); ps_ce_a_info->p_pipe_info->prev_status = NFCSTATUS_SUCCESS; } } } return status; } NFCSTATUS phHciNfc_CE_A_Update_Seq( phHciNfc_sContext_t *psHciContext, phHciNfc_eSeqType_t seq_type ) { phHciNfc_CE_A_Info_t *ps_ce_a_info=NULL; NFCSTATUS status = NFCSTATUS_SUCCESS; if( NULL == psHciContext ) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER); } else if( NULL == psHciContext->p_ce_a_info ) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED); } else { ps_ce_a_info = (phHciNfc_CE_A_Info_t *) psHciContext->p_ce_a_info ; switch(seq_type) { case RESET_SEQ: case INIT_SEQ: { ps_ce_a_info->next_seq = HOST_CE_A_PIPE_OPEN; ps_ce_a_info->current_seq = HOST_CE_A_PIPE_OPEN; break; } case UPDATE_SEQ: { ps_ce_a_info->current_seq = ps_ce_a_info->next_seq; break; } case INFO_SEQ: { break; } case REL_SEQ: { ps_ce_a_info->next_seq = HOST_CE_A_DISABLE_SEQ; ps_ce_a_info->current_seq = HOST_CE_A_DISABLE_SEQ; break; } default: { break; } } } return status; } NFCSTATUS phHciNfc_CE_A_Mode( void *psHciHandle, void *pHwRef, uint8_t enable_type ) { NFCSTATUS status = NFCSTATUS_SUCCESS; static uint8_t param = 0 ; phHciNfc_sContext_t *psHciContext = ((phHciNfc_sContext_t *)psHciHandle); if((NULL == psHciContext)||(NULL == pHwRef)) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER); } else if(NULL == psHciContext->p_ce_a_info) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED); } else { phHciNfc_CE_A_Info_t *ps_ce_a_info = (phHciNfc_CE_A_Info_t *) psHciContext->p_ce_a_info ; phHciNfc_Pipe_Info_t *p_pipe_info = ps_ce_a_info->p_pipe_info; if (NULL != p_pipe_info) { p_pipe_info->reg_index = HOST_CE_A_MODE_INDEX; /* Enable/Disable Host Card Emulation A */ param = (uint8_t)enable_type; p_pipe_info->param_info =(void*)¶m ; p_pipe_info->param_length = sizeof(param) ; status = phHciNfc_Send_Generic_Cmd(psHciContext,pHwRef, ps_ce_a_info->pipe_id,(uint8_t)ANY_SET_PARAMETER); } else { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_HCI_GATE_NOT_SUPPORTED); } } return status; } static NFCSTATUS phHciNfc_Recv_CE_A_Event( void *psContext, void *pHwRef, uint8_t *pEvent, #ifdef ONE_BYTE_LEN uint8_t length #else uint16_t length #endif ) { NFCSTATUS status = NFCSTATUS_SUCCESS; phHciNfc_sContext_t *psHciContext = (phHciNfc_sContext_t *)psContext ; if( (NULL == psHciContext) || (NULL == pHwRef) || (NULL == pEvent) || (length == 0)) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_PARAMETER); } else if(NULL == psHciContext->p_ce_a_info) { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_FEATURE_NOT_SUPPORTED); } else { phHciNfc_HCP_Packet_t *p_packet = NULL; phHciNfc_CE_A_Info_t *ps_ce_a_info=NULL; phHciNfc_HCP_Message_t *message = NULL; static phHal_sEventInfo_t event_info; uint8_t instruction=0; ps_ce_a_info = (phHciNfc_CE_A_Info_t *) psHciContext->p_ce_a_info ; /* Variable was set but never used (ARM warning) */ PHNFC_UNUSED_VARIABLE(ps_ce_a_info); p_packet = (phHciNfc_HCP_Packet_t *)pEvent; message = &p_packet->msg.message; /* Get the instruction bits from the Message Header */ instruction = (uint8_t) GET_BITS8( message->msg_header, HCP_MSG_INSTRUCTION_OFFSET, HCP_MSG_INSTRUCTION_LEN); psHciContext->host_rf_type = phHal_eISO14443_A_PICC; event_info.eventHost = phHal_eHostController; event_info.eventSource = phHal_eISO14443_A_PICC; switch(instruction) { case CE_A_EVT_NFC_ACTIVATED: { event_info.eventType = NFC_EVT_ACTIVATED; /* Notify to the HCI Generic layer To Update the FSM */ break; } case CE_A_EVT_NFC_DEACTIVATED: { event_info.eventType = NFC_EVT_DEACTIVATED; HCI_PRINT("CE A Target Deactivated\n"); break; } case CE_A_EVT_NFC_SEND_DATA: { HCI_PRINT("CE A data is received from the PN544\n"); #if defined (SEND_DATA_EVENT) if(length > HCP_HEADER_LEN) { status = phHciNfc_CE_A_ProcessData( psHciContext, pHwRef, &pEvent[HCP_HEADER_LEN], (length - HCP_HEADER_LEN)); } else { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_HCI_RESPONSE); } #endif /* #if defined (SEND_DATA_EVENT) */ break; } case CE_A_EVT_NFC_FIELD_ON: { HCI_PRINT("CE A field on\n"); event_info.eventType = NFC_EVT_FIELD_ON; break; } case CE_A_EVT_NFC_FIELD_OFF: { HCI_PRINT("CE A field off\n"); event_info.eventType = NFC_EVT_FIELD_OFF; break; } default: { status = PHNFCSTVAL(CID_NFC_HCI, NFCSTATUS_INVALID_HCI_INSTRUCTION); break; } } if(NFCSTATUS_SUCCESS == status) { phHciNfc_Notify_Event(psHciContext, pHwRef, NFC_NOTIFY_EVENT, &event_info); } } return status; } #if defined (SEND_DATA_EVENT) static NFCSTATUS phHciNfc_CE_A_ProcessData( phHciNfc_sContext_t *psHciContext, void *pHwRef, uint8_t *pData, uint8_t length ) { NFCSTATUS status = NFCSTATUS_SUCCESS; static uint8_t send_data[] = {0x6D, 0x80}; status = phHciNfc_CE_A_SendData_Event( (void *)psHciContext, pHwRef, send_data, sizeof(send_data)); return status; } #endif /* #if defined (SEND_DATA_EVENT) */ #endif /* #if defined (HOST_EMULATION) */