/*
* 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 phFriNfc_Desfire.c
* \brief This component encapsulates read/write/check ndef/process functionalities,
* for the Desfire Card.
*
* Project: NFC-FRI
*
* $Date: Tue Jul 27 08:58:22 2010 $
* $Author: ing02260 $
* $Revision: 1.11 $
* $Aliases: $
*
*/
#ifndef PH_FRINFC_MAP_DESFIRE_DISABLED
#include <phFriNfc_OvrHal.h>
#include <phFriNfc_DesfireMap.h>
#include <phFriNfc_MapTools.h>
/*! \ingroup grp_file_attributes
* \name NDEF Mapping
*
* File: \ref phFriNfc_Desfire.c
*
*/
/*@{*/
#define PHFRINFCNDEFMAP_FILEREVISION "$Revision: 1.11 $"
#define PHFRINFCNDEFMAP_FILEALIASES "$Aliases: $"
/*@}*/
/***************** Start of MACROS ********************/
#ifdef DESFIRE_EV1
#define DESFIRE_EV1_P2_OFFSET_VALUE (0x0CU)
#endif /* #ifdef DESFIRE_EV1 */
/***************** End of MACROS ********************/
/*@}*/
/*!
* \name Desfire Mapping - Helper Functions
*
*/
/*@{*/
/*!
* \brief \copydoc page_ovr Helper function for Desfire. This function specifies
* the card is a Desfire card or not.
*/
static NFCSTATUS phFriNfc_Desfire_SelectSmartTag( phFriNfc_NdefMap_t *NdefMap);
/*!
* \brief \copydoc page_ovr Helper function for Desfire. This function is used
* to selct a file in the card.
*/
static NFCSTATUS phFriNfc_Desfire_SelectFile ( phFriNfc_NdefMap_t *NdefMap);
/*!
* \brief \copydoc page_ovr Helper function for Desfire. This function is to
* read the card.
*/
static NFCSTATUS phFriNfc_Desfire_ReadBinary( phFriNfc_NdefMap_t *NdefMap);
/*!
* \brief \copydoc page_ovr Helper function for Desfire. This function is to
* write to the card.
*/
static NFCSTATUS phFriNfc_Desfire_UpdateBinary( phFriNfc_NdefMap_t *NdefMap);
/*!
* \brief \copydoc page_ovr Helper function for Desfire. This function is to
* update the capability container of the card.
*/
static NFCSTATUS phFriNfc_Desfire_Update_SmartTagCapContainer( phFriNfc_NdefMap_t *NdefMap);
/* Completion Helper*/
static void phFriNfc_Desfire_HCrHandler( phFriNfc_NdefMap_t *NdefMap,
NFCSTATUS Status);
/* Calculates the Le Bytes for Read Operation*/
static uint32_t phFriNfc_Desfire_HGetLeBytes( phFriNfc_NdefMap_t *NdefMap);
static NFCSTATUS phFriNfc_Desf_HChkAndParseTLV( phFriNfc_NdefMap_t *NdefMap,
uint8_t BuffIndex);
static NFCSTATUS phFriNfc_Desfire_HSetGet_NLEN( phFriNfc_NdefMap_t *NdefMap);
static void phFriNfc_Desfire_HProcReadData( phFriNfc_NdefMap_t *NdefMap);
static void phFriNfc_Desfire_HChkNDEFFileAccessRights( phFriNfc_NdefMap_t *NdefMap);
static NFCSTATUS phFriNfc_Desfire_HSendTransCmd(phFriNfc_NdefMap_t *NdefMap,uint8_t SendRecvLen);
#ifdef PH_HAL4_ENABLE
#else
/* Following are the API's are used to get the version of the desfire card*/
static NFCSTATUS phFriNfc_Desfire_HGetHWVersion(phFriNfc_NdefMap_t *NdefMap);
static NFCSTATUS phFriNfc_Desfire_HGetSWVersion(phFriNfc_NdefMap_t *NdefMap);
static NFCSTATUS phFriNfc_Desfire_HGetUIDDetails(phFriNfc_NdefMap_t *NdefMap);
static NFCSTATUS phFriNfc_Desfire_HUpdateVersionDetails(const phFriNfc_NdefMap_t *NdefMap);
#endif /* #ifdef PH_HAL4_ENABLE */
#ifdef PH_HAL4_ENABLE
#else
static NFCSTATUS phFriNfc_Desfire_HGetHWVersion(phFriNfc_NdefMap_t *NdefMap)
{
NFCSTATUS status = NFCSTATUS_PENDING;
/*set the state*/
NdefMap->State = PH_FRINFC_DESF_STATE_GET_HW_VERSION;
/* Helper routine to wrap the native desfire cmds*/
PH_FRINFC_DESF_ISO_NATIVE_WRAPPER();
status = phFriNfc_Desfire_HSendTransCmd(NdefMap,PH_FRINFC_NDEFMAP_MAX_SEND_RECV_BUF_SIZE);
return (status);
}
static NFCSTATUS phFriNfc_Desfire_HGetSWVersion(phFriNfc_NdefMap_t *NdefMap)
{
NFCSTATUS status = NFCSTATUS_PENDING;
if( ( NdefMap->SendRecvBuf[*(NdefMap->SendRecvLength)- 1] == PH_FRINFC_DESF_NATIVE_GETVER_RESP) )
{
/*set the state*/
NdefMap->State = PH_FRINFC_DESF_STATE_GET_SW_VERSION;
/* Helper routine to wrap the native desfire commands*/
PH_FRINFC_DESF_ISO_NATIVE_WRAPPER();
status = phFriNfc_Desfire_HSendTransCmd(NdefMap,PH_FRINFC_NDEFMAP_MAX_SEND_RECV_BUF_SIZE);
}
#ifdef PH_HAL4_ENABLE
else
{
status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_INVALID_PARAMETER);
}
#endif /* #ifdef PH_HAL4_ENABLE */
return status;
}
static NFCSTATUS phFriNfc_Desfire_HGetUIDDetails(phFriNfc_NdefMap_t *NdefMap)
{
NFCSTATUS status = NFCSTATUS_PENDING;
if( ( NdefMap->SendRecvBuf[*(NdefMap->SendRecvLength)- 1] == PH_FRINFC_DESF_NATIVE_GETVER_RESP) )
{
/*set the state*/
NdefMap->State = PH_FRINFC_DESF_STATE_GET_UID;
/* Helper routine to wrap the native desfire commands*/
PH_FRINFC_DESF_ISO_NATIVE_WRAPPER();
status = phFriNfc_Desfire_HSendTransCmd(NdefMap,PH_FRINFC_NDEFMAP_MAX_SEND_RECV_BUF_SIZE);
}
#ifdef PH_HAL4_ENABLE
else
{
status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_INVALID_PARAMETER);
}
#endif /* #ifdef PH_HAL4_ENABLE */
return status;
}
static NFCSTATUS phFriNfc_Desfire_HUpdateVersionDetails(const phFriNfc_NdefMap_t *NdefMap)
{
NFCSTATUS status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_INVALID_PARAMETER);
if( ( NdefMap->SendRecvBuf[*(NdefMap->SendRecvLength)- 1] == 0xAF) )
{
status = NFCSTATUS_SUCCESS;
/* We do not need the following details presently.Retained for future use*/
#if 0
NdefMap->AddInfo.Type4Info.MajorVersion = NdefSmtCrdFmt->SendRecvBuf[3];
NdefMap->AddInfo.Type4Info.MinorVersion = NdefSmtCrdFmt->SendRecvBuf[4];
if ( ( NdefMap->AddInfo.Type4Info.MajorVersion == 0x00 )&&
( NdefMap->AddInfo.Type4Info.MinorVersion == 0x06 ))
{
/* card size of DESFire4 type */
//NdefMap->AddInfo.Type4Info.CardSize = 0xEDE;
}
else
{
// need to handle the Desfire8 type cards
// need to use get free memory
}
#endif
}
return status;
}
#endif /* #ifdef PH_HAL4_ENABLE */
/*!
* \brief Initiates Reading of NDEF information from the Desfire Card.
*
* The function initiates the reading of NDEF information from a Remote Device.
* It performs a reset of the state and starts the action (state machine).
* A periodic call of the \ref phFriNfcNdefMap_Process has to be
* done once the action has been triggered.
*/
NFCSTATUS phFriNfc_Desfire_RdNdef( phFriNfc_NdefMap_t *NdefMap,
uint8_t *PacketData,
uint32_t *PacketDataLength,
uint8_t Offset)
{
NFCSTATUS status = NFCSTATUS_PENDING;
NdefMap->ApduBufferSize = *PacketDataLength;
/* To return actual number of bytes read to the caller */
NdefMap->NumOfBytesRead = PacketDataLength ;
*NdefMap->NumOfBytesRead = 0;
/* store the offset in to map context*/
NdefMap->Offset = Offset;
if( (Offset == PH_FRINFC_NDEFMAP_SEEK_CUR) &&
(*NdefMap->DataCount == NdefMap->DesfireCapContainer.NdefDataLen))
{
/* No space on card for Reading : we have already
reached the end of file !
Offset is set to Continue Operation */
status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_EOF_NDEF_CONTAINER_REACHED);
}
else
{
/* reset the inter flag*/
NdefMap->DesfireCapContainer.IsNlenPresentFlag = 0;
NdefMap->DesfireCapContainer.SkipNlenBytesFlag = 0;
/* Set the desfire read operation */
NdefMap->DespOpFlag = PH_FRINFC_NDEFMAP_DESF_READ_OP;
/* Save the packet data buffer address in the context */
NdefMap->ApduBuffer = PacketData;
NdefMap->PrevOperation = PH_FRINFC_NDEFMAP_READ_OPE;
#ifdef DESFIRE_EV1
/* Select smart tag operation. First step for the read operation. */
if (PH_FRINFC_NDEFMAP_ISO14443_4A_CARD_EV1 == NdefMap->CardType)
{
status = phFriNfc_Desfire_SelectFile(NdefMap);
}
else
#endif /* #ifdef DESFIRE_EV1 */
{
status = phFriNfc_Desfire_SelectSmartTag(NdefMap);
}
}
return status;
}
/*!
* \brief Initiates Writing of NDEF information to the Remote Device.
*
* The function initiates the writing of NDEF information to a Remote Device.
* It performs a reset of the state and starts the action (state machine).
* A periodic call of the \ref phFriNfcNdefMap_Process has to be done once the action
* has been triggered.
*/
NFCSTATUS phFriNfc_Desfire_WrNdef( phFriNfc_NdefMap_t *NdefMap,
uint8_t *PacketData,
uint32_t *PacketDataLength,
uint8_t Offset)
{
NFCSTATUS status = NFCSTATUS_PENDING;
NdefMap->ApduBufferSize = *PacketDataLength;
NdefMap->WrNdefPacketLength = PacketDataLength;
/* Now, let's initialize *NdefMap->WrNdefPacketLength to zero.
In case we get an error, this will be correctly set to "no byte written".
In case there is no error, this will be updated later on, in the _process function.
*/
*NdefMap->WrNdefPacketLength = 0;
/* we have write access. */
if( *NdefMap->DataCount >= PH_NFCFRI_NDEFMAP_DESF_NDEF_FILE_SIZE)
{
/* No space on card for writing : we have already
reached the end of file !
Offset is set to Continue Operation */
status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_EOF_NDEF_CONTAINER_REACHED);
}
else
{
/* Adapt the nb of bytes that the user would like to write */
/*set the defire write operation*/
NdefMap->DespOpFlag = PH_FRINFC_NDEFMAP_DESF_WRITE_OP;
NdefMap->PrevOperation = PH_FRINFC_NDEFMAP_WRITE_OPE;
NdefMap->Offset = Offset;
/*Store the packet data buffer*/
NdefMap->ApduBuffer = PacketData;
#ifdef DESFIRE_EV1
if (PH_FRINFC_NDEFMAP_ISO14443_4A_CARD_EV1 == NdefMap->CardType)
{
status = phFriNfc_Desfire_SelectFile(NdefMap);
}
else
#endif /* #ifdef DESFIRE_EV1 */
{
/* Select smart tag operation. First step for the write operation. */
status = phFriNfc_Desfire_SelectSmartTag (NdefMap);
}
}
return status;
}
/*!
* \brief Check whether a particular Remote Device is NDEF compliant.
*
* The function checks whether the peer device is NDEF compliant.
*
*/
NFCSTATUS phFriNfc_Desfire_ChkNdef( phFriNfc_NdefMap_t *NdefMap)
{
NFCSTATUS status = NFCSTATUS_PENDING;
#ifdef PH_HAL4_ENABLE
#ifdef DESFIRE_EV1
/* Reset card type */
NdefMap->CardType = 0;
#endif /* #ifdef DESFIRE_EV1 */
/*Set the desfire operation flag*/
NdefMap->DespOpFlag = PH_FRINFC_NDEFMAP_DESF_NDEF_CHK_OP;
/*Call Select Smart tag Functinality*/
status = phFriNfc_Desfire_SelectSmartTag(NdefMap);
#else
/* Need to get the version details of the card, to
identify the the desfire4card type */
status = phFriNfc_Desfire_HGetHWVersion(NdefMap);
#endif
return (status);
}
static NFCSTATUS phFriNfc_Desf_HChkAndParseTLV(phFriNfc_NdefMap_t *NdefMap, uint8_t BuffIndex)
{
NFCSTATUS status = NFCSTATUS_SUCCESS;
if((NdefMap->SendRecvBuf[BuffIndex] <= 0x03) ||
(NdefMap->SendRecvBuf[BuffIndex] >= 0x06) )
{
status = PHNFCSTVAL( CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_NO_NDEF_SUPPORT);
}
else
{
/* check for the type of TLV*/
NdefMap->TLVFoundFlag =
((NdefMap->SendRecvBuf[BuffIndex] == 0x04)?
PH_FRINFC_NDEFMAP_DESF_NDEF_CNTRL_TLV:
PH_FRINFC_NDEFMAP_DESF_PROP_CNTRL_TLV);
status = PHNFCSTVAL( CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_SUCCESS);
}
return status;
}
static NFCSTATUS phFriNfc_Desfire_HSetGet_NLEN(phFriNfc_NdefMap_t *NdefMap)
{
NFCSTATUS status = NFCSTATUS_PENDING;
if ( PH_FRINFC_NDEFMAP_DESF_GET_LEN_OP == NdefMap->DespOpFlag)
{
/*Call Select Smart tag Functinality*/
status = phFriNfc_Desfire_SelectSmartTag(NdefMap);
}
else
{
/* Get the Data Count and set it to NoOfBytesWritten
Update the NLEN using Transceive cmd*/
/*Form the packet for the update binary command*/
NdefMap->SendRecvBuf[0] = 0x00;
NdefMap->SendRecvBuf[1] = 0xD6;
/* As we need to set the NLEN @ first 2 bytes of NDEF File*/
/* set the p1/p2 offsets */
NdefMap->SendRecvBuf[2] = 0x00; /* p1 */
NdefMap->SendRecvBuf[3] = 0x00; /* p2 */
/* Set only two bytes as NLEN*/
NdefMap->SendRecvBuf[4] = 0x02;
/* update NLEN */
NdefMap->SendRecvBuf[5] = (uint8_t)(*NdefMap->DataCount >> PH_FRINFC_NDEFMAP_DESF_SHL8);
NdefMap->SendRecvBuf[6] = (uint8_t)(*NdefMap->DataCount & (0x00ff));
NdefMap->SendLength = 0x07 ;
/* Change the state to Write */
NdefMap->State = PH_FRINFC_NDEFMAP_DESF_STATE_UPDATE_BIN_END;
status = phFriNfc_Desfire_HSendTransCmd(NdefMap,PH_FRINFC_NDEFMAP_DESF_RESP_OFFSET);
}
return status;
}
static void phFriNfc_Desfire_HProcReadData(phFriNfc_NdefMap_t *NdefMap)
{
NFCSTATUS Result = NFCSTATUS_PENDING;
uint32_t BufferSize = 0;
uint8_t BufIndex=0;
uint16_t SizeToCpy=0;
/* Need to check the Actual Ndef Length before copying the data to buffer*/
/* Only NDEF data should be copied , rest all the data should be ignored*/
/* Ex : Ndef File Size 50 bytes , but only 5 bytes(NLEN) are relavent to NDEF data*/
/* component should only copy 5 bytes to user buffer*/
/* Data has been read successfully in the TRX buffer. */
/* copy it to the user buffer. */
/* while copying need check the offset if its begin need to skip the first 2 bytes
while copying. If its current no need to skip the first 2 bytes*/
if ( NdefMap->Offset == PH_FRINFC_NDEFMAP_SEEK_BEGIN )
{
BufIndex = (uint8_t)(( NdefMap->DesfireCapContainer.IsNlenPresentFlag == 1 )?
0:PH_FRINFC_NDEFMAP_DESF_NLEN_SIZE_IN_BYTES);
/* Update the latest NLEN to context*/
NdefMap->DesfireCapContainer.NdefDataLen = ((*NdefMap->DataCount == 0)?
( (((uint16_t)NdefMap->SendRecvBuf[
PH_FRINFC_NDEFMAP_DESF_CCLEN_BYTE_FIRST_INDEX])<<8)+ \
NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_CCLEN_BYTE_SECOND_INDEX]):
NdefMap->DesfireCapContainer.NdefDataLen);
/* Decide how many byes to be copied into user buffer: depending upon the actual NDEF
size need to copy the content*/
if ( (NdefMap->DesfireCapContainer.NdefDataLen) <= (*NdefMap->SendRecvLength - \
(PH_FRINFC_NDEFMAP_DESF_RESP_OFFSET + BufIndex)))
{
SizeToCpy = NdefMap->DesfireCapContainer.NdefDataLen;
}
else
{
SizeToCpy = ((*NdefMap->SendRecvLength)-(PH_FRINFC_NDEFMAP_DESF_RESP_OFFSET+BufIndex));
}
/* Check do we have Ndef Data len > 0 present in the card.If No Ndef Data
present in the card , set the card state to Initalised and set an Error*/
if ( NdefMap->DesfireCapContainer.NdefDataLen == 0x00 )
{
NdefMap->CardState = PH_NDEFMAP_CARD_STATE_INITIALIZED;
Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_EOF_NDEF_CONTAINER_REACHED);
#ifdef PH_HAL4_ENABLE
#else
NdefMap->PrevOperation = 0;
#endif /* #ifdef PH_HAL4_ENABLE */
phFriNfc_Desfire_HCrHandler(NdefMap,Result);
}
else
{
(void)memcpy( (&(NdefMap->ApduBuffer[
NdefMap->ApduBuffIndex])),
(&(NdefMap->SendRecvBuf[BufIndex])),
(SizeToCpy));
/* Increment the Number of Bytes Read, which will be returned to the caller. */
*NdefMap->NumOfBytesRead = (uint32_t)(*NdefMap->NumOfBytesRead + SizeToCpy);
/*update the data count*/
*NdefMap->DataCount = (uint16_t)(*NdefMap->DataCount + SizeToCpy);
/*update the buffer index of the apdu buffer*/
NdefMap->ApduBuffIndex = (uint16_t)(NdefMap->ApduBuffIndex + SizeToCpy);
}
}
else
{
(void)memcpy( (&(NdefMap->ApduBuffer[
NdefMap->ApduBuffIndex])),
(NdefMap->SendRecvBuf),/* to avoid the length of the NDEF File*/
(*(NdefMap->SendRecvLength)-(PH_FRINFC_NDEFMAP_DESF_RESP_OFFSET)));
/* Increment the Number of Bytes Read, which will be returned to the caller. */
*NdefMap->NumOfBytesRead +=( *NdefMap->SendRecvLength - \
(PH_FRINFC_NDEFMAP_DESF_RESP_OFFSET));
/*update the data count*/
*NdefMap->DataCount += \
(*NdefMap->SendRecvLength - (PH_FRINFC_NDEFMAP_DESF_RESP_OFFSET));
/*update the buffer index of the apdu buffer*/
NdefMap->ApduBuffIndex += \
*NdefMap->SendRecvLength - (PH_FRINFC_NDEFMAP_DESF_RESP_OFFSET );
}
/* check whether we still have to read some more data. */
if (*NdefMap->DataCount < NdefMap->DesfireCapContainer.NdefDataLen )
{
/* we have some bytes to read. */
/* Now check, we still have bytes left in the user buffer. */
BufferSize = NdefMap->ApduBufferSize - NdefMap->ApduBuffIndex;
if(BufferSize != 0)
{
/* Before read need to set the flag to intimate the module to
dont skip the first 2 bytes as we are in mode reading next
continues available bytes, which will not contain the NLEN
information in the begining part that is 2 bytes*/
NdefMap->DesfireCapContainer.IsNlenPresentFlag = 1;
/* Read Operation is not complete */
Result = phFriNfc_Desfire_ReadBinary( NdefMap );
/* handle the error in Transc function*/
if ( (Result & PHNFCSTBLOWER) != (NFCSTATUS_PENDING & PHNFCSTBLOWER) )
{
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Result);
}
}
else
{
/* There are some more bytes to read, but
no space in the user buffer */
Result = PHNFCSTVAL(CID_NFC_NONE,NFCSTATUS_SUCCESS);
NdefMap->ApduBuffIndex =0;
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Result);
}
}
else
{
if (*NdefMap->DataCount == NdefMap->DesfireCapContainer.NdefDataLen )
{
/* we have read all the bytes available in the card. */
Result = PHNFCSTVAL(CID_NFC_NONE,NFCSTATUS_SUCCESS);
#ifdef PH_HAL4_ENABLE
/* Do nothing */
#else
NdefMap->PrevOperation = 0;
#endif /* #ifndef PH_HAL4_ENABLE */
}
else
{
/* The control should not come here. */
/* we have actually read more byte than available in the card. */
NdefMap->PrevOperation = 0;
#ifndef PH_HAL4_ENABLE
Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_CMD_ABORTED);
#else
Result = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_FAILED);
#endif
}
NdefMap->ApduBuffIndex = 0;
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Result);
}
}
/*!
* \brief Completion Routine, Processing function, needed to avoid long blocking.
* \note The lower (Overlapped HAL) layer must register a pointer to this function as a Completion
* Routine in order to be able to notify the component that an I/O has finished and data are
* ready to be processed.
*
*/
void phFriNfc_Desfire_Process(void *Context,
NFCSTATUS Status)
{
/*Set the context to Map Module*/
phFriNfc_NdefMap_t *NdefMap = (phFriNfc_NdefMap_t *)Context;
uint8_t ErrFlag = 0;
uint16_t NLength = 0,
SendRecLen=0;
uint32_t BytesRead = 0;
/* Sujatha P: Fix for 0000255/0000257:[gk] MAP:Handling HAL Errors */
if ( Status == NFCSTATUS_SUCCESS )
{
switch (NdefMap->State)
{
#ifdef PH_HAL4_ENABLE
#else
case PH_FRINFC_DESF_STATE_GET_HW_VERSION :
/* Check and store the h/w and s/w specific details.
Ex: Major/Minor version, memory storage info. */
Status = phFriNfc_Desfire_HGetSWVersion(NdefMap);
/* handle the error in Transc function*/
if ( (Status & PHNFCSTBLOWER) != (NFCSTATUS_PENDING & PHNFCSTBLOWER))
{
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
break;
case PH_FRINFC_DESF_STATE_GET_SW_VERSION :
/* Check and store the h/w and s/w specific details.
Ex: Major/Minor version, memory storage info. */
Status = phFriNfc_Desfire_HUpdateVersionDetails(NdefMap);
if ( Status == NFCSTATUS_SUCCESS )
{
Status = phFriNfc_Desfire_HGetUIDDetails(NdefMap);
/* handle the error in Transc function*/
if ( (Status & PHNFCSTBLOWER) != (NFCSTATUS_PENDING & PHNFCSTBLOWER))
{
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
}
break;
case PH_FRINFC_DESF_STATE_GET_UID :
/*Set the desfire operation flag*/
NdefMap->DespOpFlag = PH_FRINFC_NDEFMAP_DESF_NDEF_CHK_OP;
/*Call Select Smart tag Functinality*/
Status = phFriNfc_Desfire_SelectSmartTag(NdefMap);
break;
#endif /* #ifdef PH_HAL4_ENABLE */
#ifdef DESFIRE_EV1
case PH_FRINFC_NDEFMAP_DESF_STATE_SELECT_SMART_TAG_EV1:
{
if(( NdefMap->SendRecvBuf[(*(NdefMap->SendRecvLength) - 2)] ==
PH_FRINFC_NDEFMAP_DESF_RAPDU_SW1_BYTE) &&
(NdefMap->SendRecvBuf[(*(NdefMap->SendRecvLength) - 1)] ==
PH_FRINFC_NDEFMAP_DESF_RAPDU_SW2_BYTE))
{
NdefMap->CardType = PH_FRINFC_NDEFMAP_ISO14443_4A_CARD_EV1;
Status = phFriNfc_Desfire_SelectFile(NdefMap);
/* handle the error in Transc function*/
if ((Status & PHNFCSTBLOWER) != (NFCSTATUS_PENDING & PHNFCSTBLOWER))
{
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
}
else
{
NdefMap->CardType = PH_FRINFC_NDEFMAP_ISO14443_4A_CARD;
/* The card is not the new desfire, so send select smart tag command
of the old desfire */
Status = phFriNfc_Desfire_SelectSmartTag(NdefMap);
}
break;
}
#endif /* #ifdef DESFIRE_EV1 */
case PH_FRINFC_NDEFMAP_DESF_STATE_SELECT_SMART_TAG:
#ifdef DESFIRE_EV1
if(( NdefMap->SendRecvBuf[(*(NdefMap->SendRecvLength) - 2)] ==
PH_FRINFC_NDEFMAP_DESF_RAPDU_SW1_BYTE) &&
(NdefMap->SendRecvBuf[(*(NdefMap->SendRecvLength) - 1)] ==
PH_FRINFC_NDEFMAP_DESF_RAPDU_SW2_BYTE))
#else
if(( NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_SW1_INDEX] ==
PH_FRINFC_NDEFMAP_DESF_RAPDU_SW1_BYTE) &&
(NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_SW2_INDEX] ==
PH_FRINFC_NDEFMAP_DESF_RAPDU_SW2_BYTE))
#endif /* #ifdef DESFIRE_EV1 */
{
Status = phFriNfc_Desfire_SelectFile(NdefMap);
/* handle the error in Transc function*/
if ( (Status & PHNFCSTBLOWER) != (NFCSTATUS_PENDING & PHNFCSTBLOWER))
{
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
}
else
{
/*Error " Smart Tag Functionality Not Supported"*/
Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,\
NFCSTATUS_SMART_TAG_FUNC_NOT_SUPPORTED);
#ifdef DESFIRE_EV1
NdefMap->CardType = 0;
#endif /* #ifdef DESFIRE_EV1 */
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
break;
case PH_FRINFC_NDEFMAP_DESF_STATE_SELECT_FILE :
if(( NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_SW1_INDEX] == PH_FRINFC_NDEFMAP_DESF_RAPDU_SW1_BYTE) &&
(NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_SW2_INDEX] == PH_FRINFC_NDEFMAP_DESF_RAPDU_SW2_BYTE))
{
/*check for the which operation */
if( (NdefMap->DespOpFlag == PH_FRINFC_NDEFMAP_DESF_READ_OP) ||
(NdefMap->DespOpFlag == PH_FRINFC_NDEFMAP_DESF_NDEF_CHK_OP) ||
(NdefMap->DespOpFlag == PH_FRINFC_NDEFMAP_DESF_GET_LEN_OP ))
{
/* call for read binary operation*/
Status = phFriNfc_Desfire_ReadBinary(NdefMap);
/* handle the error in Transc function*/
if ( (Status & PHNFCSTBLOWER) != (NFCSTATUS_PENDING & PHNFCSTBLOWER) )
{
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
}
/*its a write Operation*/
else if(NdefMap->DespOpFlag == PH_FRINFC_NDEFMAP_DESF_WRITE_OP )
{
Status = phFriNfc_Desfire_UpdateBinary (NdefMap);
/* handle the error in Transc function*/
if ( (Status & PHNFCSTBLOWER) != (NFCSTATUS_PENDING & PHNFCSTBLOWER))
{
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
}
else
{
/* unknown/invalid desfire operations*/
Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,\
NFCSTATUS_INVALID_REMOTE_DEVICE);
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
}
else
{
/*return Error " Select File Operation Failed"*/
Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,\
NFCSTATUS_INVALID_REMOTE_DEVICE);
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
break;
case PH_FRINFC_NDEFMAP_DESF_STATE_READ_CAP_CONT:
if( (NdefMap->SendRecvBuf[(*(NdefMap->SendRecvLength)-2)] == PH_FRINFC_NDEFMAP_DESF_RAPDU_SW1_BYTE) &&
(NdefMap->SendRecvBuf[(*(NdefMap->SendRecvLength)-1)] == PH_FRINFC_NDEFMAP_DESF_RAPDU_SW2_BYTE))
{
/* Read successful. */
/*Update the smart tag capability container*/
Status = phFriNfc_Desfire_Update_SmartTagCapContainer(NdefMap);
if ( Status == NFCSTATUS_SUCCESS)
{
NdefMap->DespOpFlag = PH_FRINFC_NDEFMAP_DESF_GET_LEN_OP;
#ifdef DESFIRE_EV1
if (PH_FRINFC_NDEFMAP_ISO14443_4A_CARD_EV1 == NdefMap->CardType)
{
Status = phFriNfc_Desfire_SelectFile(NdefMap);
}
else
#endif /* #ifdef DESFIRE_EV1 */
{
Status = phFriNfc_Desfire_HSetGet_NLEN(NdefMap);
}
/* handle the error in Transc function*/
if ( (Status & PHNFCSTBLOWER) != (NFCSTATUS_PENDING & PHNFCSTBLOWER))
{
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
}
else
{
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
}
else
{
/*return Error " Capability Container Not Found"*/
Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_INVALID_REMOTE_DEVICE);
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
break;
case PH_FRINFC_NDEFMAP_DESF_STATE_READ_BIN:
/* Check how many bytes have been read/returned from the card*/
BytesRead = phFriNfc_Desfire_HGetLeBytes(NdefMap);
/* set the send recev len*/
SendRecLen = *NdefMap->SendRecvLength - (PH_FRINFC_NDEFMAP_DESF_RESP_OFFSET );
if ( (NdefMap->DesfireCapContainer.SkipNlenBytesFlag == 1) && ((BytesRead == 1) || (BytesRead == 2 )))
{
BytesRead += PH_FRINFC_NDEFMAP_DESF_NLEN_SIZE_IN_BYTES; /* to take care of first 2 len bytes*/
}
else
{
/* Nothing to process*/
;
}
/* Read More Number Of Bytes than Expected*/
if ( ( BytesRead == SendRecLen ) &&
((NdefMap->SendRecvBuf[(*NdefMap->SendRecvLength-2)] == PH_FRINFC_NDEFMAP_DESF_RAPDU_SW1_BYTE) &&
(NdefMap->SendRecvBuf[(*NdefMap->SendRecvLength-1)] == PH_FRINFC_NDEFMAP_DESF_RAPDU_SW2_BYTE)))
{
/* this is to check the card state in first Read Operation*/
if ( NdefMap->DespOpFlag == PH_FRINFC_NDEFMAP_DESF_GET_LEN_OP )
{
/* check the actual length of the ndef data : NLEN*/
NLength = ( (((uint16_t)NdefMap->SendRecvBuf[0])<<PH_FRINFC_NDEFMAP_DESF_SHL8)+ \
NdefMap->SendRecvBuf[1]);
if (( NLength > PH_NFCFRI_NDEFMAP_DESF_NDEF_FILE_SIZE )||
( NLength == 0xFFFF))
{
ErrFlag = 1;
Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_NO_NDEF_SUPPORT);
}
else
{
/* Store the NLEN into the context */
NdefMap->DesfireCapContainer.NdefDataLen = NLength;
Status = phFriNfc_MapTool_SetCardState( NdefMap,
NLength);
if ( Status == NFCSTATUS_SUCCESS )
{
/*Set the card type to Desfire*/
#ifndef DESFIRE_EV1
NdefMap->CardType = PH_FRINFC_NDEFMAP_ISO14443_4A_CARD;
#endif /* #ifdef DESFIRE_EV1 */
/*Set the state to specify True for Ndef Compliant*/
NdefMap->State = PH_FRINFC_NDEFMAP_DESF_STATE_CHK_NDEF;
/*set the data count back to zero*/;
*NdefMap->DataCount = 0;
/*set the apdu buffer index to zero*/
NdefMap->ApduBuffIndex = 0;
/* Set the Operationg flag to Complete check NDEF Operation*/
NdefMap->DespOpFlag = PH_FRINFC_NDEFMAP_DESF_NDEF_CHK_OP;
}
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}/* End ofNdefMap->DespOpFlag == PH_FRINFC_NDEFMAP_DESF_GET_LEN_OP*/
}
else if ( NdefMap->DespOpFlag == PH_FRINFC_NDEFMAP_DESF_READ_OP )
{
phFriNfc_Desfire_HProcReadData(NdefMap);
}
else
{
/* Invalid Desfire Operation */
Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_INVALID_REMOTE_DEVICE);
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
}
else
{
/*handle the Error case*/
Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,\
NFCSTATUS_READ_FAILED);
ErrFlag =1;
}
if( ErrFlag == 1)
{
*NdefMap->DataCount = 0;
/*set the buffer index back to zero*/
NdefMap->ApduBuffIndex = 0;
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
break;
case PH_FRINFC_NDEFMAP_DESF_STATE_UPDATE_BIN_BEGIN:
if( (NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_SW1_INDEX] == PH_FRINFC_NDEFMAP_DESF_RAPDU_SW1_BYTE) &&
(NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_SW2_INDEX] == PH_FRINFC_NDEFMAP_DESF_RAPDU_SW2_BYTE))
{
/* Write operation was successful. */
/* NdefMap->NumOfBytesWritten have been written on to the card.
Update the DataCount and the ApduBufferIndex */
*NdefMap->DataCount = (uint16_t)(*NdefMap->DataCount +
NdefMap->NumOfBytesWritten);
NdefMap->ApduBuffIndex = (uint16_t)(NdefMap->ApduBuffIndex +
NdefMap->NumOfBytesWritten);
/* Update the user-provided buffer size to write */
*NdefMap->WrNdefPacketLength += NdefMap->NumOfBytesWritten;
/* Call Upadte Binary function to check if some more bytes are to be written. */
Status = phFriNfc_Desfire_UpdateBinary( NdefMap );
}
else
{
/*handle the Error case*/
Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,\
NFCSTATUS_WRITE_FAILED);
/*set the buffer index back to zero*/
NdefMap->ApduBuffIndex = 0;
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
break;
case PH_FRINFC_NDEFMAP_DESF_STATE_UPDATE_BIN_END :
if((NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_SW1_INDEX] == PH_FRINFC_NDEFMAP_DESF_RAPDU_SW1_BYTE) &&
(NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_SW2_INDEX] == PH_FRINFC_NDEFMAP_DESF_RAPDU_SW2_BYTE))
{
/* Updating NLEN operation was successful. */
/* Entire Write Operation is complete*/
/* Reset the relevant parameters. */
Status = PHNFCSTVAL(CID_NFC_NONE,\
NFCSTATUS_SUCCESS);
/* set the state & Data len into context*/
NdefMap->CardState = (uint8_t)((NdefMap->CardState ==
PH_NDEFMAP_CARD_STATE_INITIALIZED)?
PH_NDEFMAP_CARD_STATE_READ_WRITE :
NdefMap->CardState);
NdefMap->DesfireCapContainer.NdefDataLen = (uint16_t)(*NdefMap->WrNdefPacketLength);
#ifdef PH_HAL4_ENABLE
/* Do nothing */
#else
NdefMap->PrevOperation = 0;
#endif /* #ifndef PH_HAL4_ENABLE */
}
else
{
NdefMap->PrevOperation = 0;
/*handle the Error case*/
Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,\
NFCSTATUS_WRITE_FAILED);
}
/*set the buffer index back to zero*/
NdefMap->ApduBuffIndex = 0;
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
break;
default:
/*define the invalid state*/
Status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,\
NFCSTATUS_INVALID_DEVICE_REQUEST);
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
break;
}
}
else
{
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,Status);
}
}
/*!
* \brief this shall select the smart tag functinality of the Desfire card.
*
* Only when this command returns command completed it is a Smart Tag
* compatible product.
*
*/
static
NFCSTATUS phFriNfc_Desfire_SelectSmartTag(phFriNfc_NdefMap_t *NdefMap)
{
NFCSTATUS status = NFCSTATUS_PENDING;
#ifdef DESFIRE_EV1
uint8_t card_type = PH_FRINFC_NDEFMAP_ISO14443_4A_CARD_EV1;
#endif /* #ifdef DESFIRE_EV1 */
/*form the packet for Select smart tag command*/
NdefMap->SendRecvBuf[0] = 0x00; /* cls */
NdefMap->SendRecvBuf[1] = 0xa4; /* ins */
NdefMap->SendRecvBuf[2] = 0x04; /* p1 */
NdefMap->SendRecvBuf[3] = 0x00; /* p2 */
NdefMap->SendRecvBuf[4] = 0x07; /* lc */
/* next 7 bytes specify the DF Name*/
NdefMap->SendRecvBuf[5] = 0xd2;
NdefMap->SendRecvBuf[6] = 0x76;
NdefMap->SendRecvBuf[7] = 0x00;
NdefMap->SendRecvBuf[8] = 0x00;
NdefMap->SendRecvBuf[9] = 0x85;
NdefMap->SendRecvBuf[10] = 0x01;
#ifdef DESFIRE_EV1
switch (NdefMap->DespOpFlag)
{
case PH_FRINFC_NDEFMAP_DESF_NDEF_CHK_OP:
{
/* First select the smart tag using the new desfire EV1 and increment the
"sel_index" and if it fails then try the old desfire select smart tag
command */
if (0 == NdefMap->CardType)
{
/* p2
NdefMap->SendRecvBuf[3] = DESFIRE_EV1_P2_OFFSET_VALUE; */
NdefMap->SendRecvBuf[11] = 0x01;
/* Le */
NdefMap->SendRecvBuf[12] = 0x00;
NdefMap->State = PH_FRINFC_NDEFMAP_DESF_STATE_SELECT_SMART_TAG_EV1;
card_type = PH_FRINFC_NDEFMAP_ISO14443_4A_CARD_EV1;
}
else
{
NdefMap->SendRecvBuf[3] = 0x00; /* p2 */
NdefMap->SendRecvBuf[11] = 0x00;
NdefMap->State = PH_FRINFC_NDEFMAP_DESF_STATE_SELECT_SMART_TAG;
card_type = PH_FRINFC_NDEFMAP_ISO14443_4A_CARD;
}
break;
}
case PH_FRINFC_NDEFMAP_DESF_READ_OP:
default :
{
if (PH_FRINFC_NDEFMAP_ISO14443_4A_CARD_EV1 == NdefMap->CardType)
{
NdefMap->SendRecvBuf[11] = 0x01;
NdefMap->SendRecvBuf[12] = 0x00;
NdefMap->State = (uint8_t)PH_FRINFC_NDEFMAP_DESF_STATE_SELECT_SMART_TAG_EV1;
card_type = PH_FRINFC_NDEFMAP_ISO14443_4A_CARD_EV1;
}
else
{
NdefMap->SendRecvBuf[11] = 0x00;
NdefMap->State = (uint8_t)PH_FRINFC_NDEFMAP_DESF_STATE_SELECT_SMART_TAG;
card_type = PH_FRINFC_NDEFMAP_ISO14443_4A_CARD;
}
break;
}
}
#else /* #ifdef DESFIRE_EV1 */
NdefMap->SendRecvBuf[11] = 0x00;
#endif /* #ifdef DESFIRE_EV1 */
/*Set the Send length*/
NdefMap->SendLength = PH_FRINFC_NDEFMAP_DESF_CAPDU_SMARTTAG_PKT_SIZE;
#ifdef DESFIRE_EV1
if (PH_FRINFC_NDEFMAP_ISO14443_4A_CARD_EV1 == card_type)
{
/* Send length is updated for the NEW DESFIRE EV1 */
NdefMap->SendLength = (uint16_t)(NdefMap->SendLength + 1);
}
#else
/* Change the state to Select Smart Tag */
NdefMap->State = PH_FRINFC_NDEFMAP_DESF_STATE_SELECT_SMART_TAG;
#endif /* #ifdef DESFIRE_EV1 */
status = phFriNfc_Desfire_HSendTransCmd(NdefMap,PH_FRINFC_NDEFMAP_DESF_RESP_OFFSET);
return status;
}
/*!
* \brief this shall select/access the capability container of the Desfire
* card.
*
* This shall be used to identify, if NDEF data structure do exist on
* the smart tag, we receive command completed status.
*
*/
static
NFCSTATUS phFriNfc_Desfire_SelectFile (phFriNfc_NdefMap_t *NdefMap)
{
NFCSTATUS status = NFCSTATUS_PENDING;
/* check for the invalid/unknown desfire operations*/
if ((NdefMap->DespOpFlag != PH_FRINFC_NDEFMAP_DESF_NDEF_CHK_OP)&& \
(NdefMap->DespOpFlag != PH_FRINFC_NDEFMAP_DESF_READ_OP)&&\
( NdefMap->DespOpFlag != PH_FRINFC_NDEFMAP_DESF_WRITE_OP) &&
( NdefMap->DespOpFlag != PH_FRINFC_NDEFMAP_DESF_GET_LEN_OP))
{
status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP, NFCSTATUS_INVALID_REMOTE_DEVICE);
}
else
{
/* Set the command*/
//NdefMap->Cmd.Iso144434Cmd = phHal_eIso14443_4_CmdListTClCmd;
/* Form the packet for select file command either for the
Check Ndef/Read/Write functionalities*/
NdefMap->SendRecvBuf[0] = 0x00; /* cls */
NdefMap->SendRecvBuf[1] = 0xa4; /* ins */
NdefMap->SendRecvBuf[2] = 0x00; /* p1 */
NdefMap->SendRecvBuf[3] = 0x00; /* p2 */
NdefMap->SendRecvBuf[4] = 0x02; /* lc */
#ifdef DESFIRE_EV1
if (PH_FRINFC_NDEFMAP_ISO14443_4A_CARD_EV1 == NdefMap->CardType)
{
NdefMap->SendRecvBuf[3] = DESFIRE_EV1_P2_OFFSET_VALUE; /* p2 */
}
#endif /* #ifdef DESFIRE_EV1 */
if ( (NdefMap->DespOpFlag == PH_FRINFC_NDEFMAP_DESF_NDEF_CHK_OP))
{
/* cap container file identifier*/
NdefMap->SendRecvBuf[5] = 0xe1;
NdefMap->SendRecvBuf[6] = 0x03;
}
/* Mantis entry 0394 fixed */
else
{
NdefMap->SendRecvBuf[5] = (uint8_t)((NdefMap->DesfireCapContainer.NdefMsgFid) >> PH_FRINFC_NDEFMAP_DESF_SHL8);
NdefMap->SendRecvBuf[6] = (uint8_t)((NdefMap->DesfireCapContainer.NdefMsgFid) & (0x00ff));
}
/*Set the Send length*/
NdefMap->SendLength = PH_FRINFC_NDEFMAP_DESF_CAPDU_SELECT_FILE_PKT_SIZE;
/* Change the state to Select File */
NdefMap->State = PH_FRINFC_NDEFMAP_DESF_STATE_SELECT_FILE;
status = phFriNfc_Desfire_HSendTransCmd(NdefMap,PH_FRINFC_NDEFMAP_DESF_RESP_OFFSET);
}
return status;
}
/*!
* \brief this shall read the data from Desfire card.
*
* This is used in two cases namely Reading the Capability container
* data( le == 0 ) and reading the file data.Maximum bytes to be read during
* a single read binary is known after the reading the data from the capability
* conatainer.
*
*/
static
NFCSTATUS phFriNfc_Desfire_ReadBinary(phFriNfc_NdefMap_t *NdefMap)
{
NFCSTATUS status = NFCSTATUS_PENDING;
uint32_t BytesToRead = 0;
uint8_t BufIndex=0,OperFlag=0;
uint16_t DataCnt=0;
/* to read the capability container data*/
if (NdefMap->DespOpFlag == PH_FRINFC_NDEFMAP_DESF_NDEF_CHK_OP )
{
/*specifies capability container shall be read*/
NdefMap->SendRecvBuf[0] = 0x00;
NdefMap->SendRecvBuf[1] = 0xb0;
NdefMap->SendRecvBuf[2] = 0x00; /* p1 */
NdefMap->SendRecvBuf[3] = 0x00; /* p2 */
NdefMap->SendRecvBuf[4] = 0x0F; /* le */
NdefMap->SendLength = PH_FRINFC_NDEFMAP_DESF_CAPDU_READ_BIN_PKT_SIZE;
/* Change the state to Cap Container Read */
NdefMap->State = PH_FRINFC_NDEFMAP_DESF_STATE_READ_CAP_CONT;
/* set the send receive buffer length*/
OperFlag = 1;
}
/*desfire file read operation*/
else
{
NdefMap->SendRecvBuf[0] = 0x00;
NdefMap->SendRecvBuf[1] = 0xb0;
/*TBD the NLEN bytes*/
if( *NdefMap->DataCount == 0 )
{
/* first read */
/* set the offset p1 and p2*/
NdefMap->SendRecvBuf[2] = 0;
NdefMap->SendRecvBuf[3] = 0;
}
else
{
/* as the p1 of the 8bit is 0, p1 and p2 are used to store the
ofset value*/
DataCnt = *NdefMap->DataCount;
DataCnt += PH_FRINFC_NDEFMAP_DESF_NLEN_SIZE_IN_BYTES;
NdefMap->SendRecvBuf[2] = (uint8_t)((DataCnt)>> PH_FRINFC_NDEFMAP_DESF_SHL8);
NdefMap->SendRecvBuf[3] = (uint8_t)((DataCnt)& (0x00ff));
}
/* calculate the Le Byte*/
BytesToRead = phFriNfc_Desfire_HGetLeBytes(NdefMap);
if ( NdefMap->Offset == PH_FRINFC_NDEFMAP_SEEK_BEGIN )
{
/* BufIndex represents the 2 NLEN bytes and decides about the presence of
2 bytes NLEN data*/
BufIndex = (uint8_t)(( NdefMap->DesfireCapContainer.SkipNlenBytesFlag == 1 ) ?
PH_FRINFC_NDEFMAP_DESF_NLEN_SIZE_IN_BYTES:0);
if( ((BytesToRead == 1) || (BytesToRead == 2)) && (NdefMap->DesfireCapContainer.SkipNlenBytesFlag == 1))
{
BytesToRead += BufIndex;
}
}
/* set the Le byte*/
/* This following code is true for get nlen and current offset set*/
NdefMap->SendRecvBuf[4]=(uint8_t) BytesToRead ;
/* Change the state to Read */
NdefMap->State = PH_FRINFC_NDEFMAP_DESF_STATE_READ_BIN;
/*set the send length*/
NdefMap->SendLength = PH_FRINFC_NDEFMAP_DESF_CAPDU_READ_BIN_PKT_SIZE;
OperFlag = 2;
}
if (OperFlag == 1 )
{
status = phFriNfc_Desfire_HSendTransCmd(NdefMap,PH_FRINFC_NDEFMAP_MAX_SEND_RECV_BUF_SIZE);
}
else
{
status = phFriNfc_Desfire_HSendTransCmd(NdefMap,(uint8_t)(BytesToRead +PH_FRINFC_NDEFMAP_DESF_RESP_OFFSET));
}
return (status);
}
/*!
* \brief this shall write the data to Desfire card.
* Maximum bytes to be written during a single update binary
* is known after the reading the data from the capability
* conatainer.
*
* le filed specifes , how many bytes of data to be written to the
* Card.
*
*/
static
NFCSTATUS phFriNfc_Desfire_UpdateBinary(phFriNfc_NdefMap_t *NdefMap)
{
NFCSTATUS status = NFCSTATUS_PENDING;
uint16_t noOfBytesToWrite = 0, DataCnt=0,
index=0;
/* Do we have space in the file to write? */
if ( (*NdefMap->DataCount < PH_NFCFRI_NDEFMAP_DESF_NDEF_FILE_SIZE) &&
(NdefMap->ApduBuffIndex < NdefMap->ApduBufferSize))
{
/* Yes, we have some bytes to write */
/* Check and set the card memory size , if user sent bytes are more than the
card memory size*/
if( (uint16_t)(NdefMap->ApduBufferSize - NdefMap->ApduBuffIndex) >\
(uint16_t)(PH_NFCFRI_NDEFMAP_DESF_NDEF_FILE_SIZE - *NdefMap->DataCount))
{
NdefMap->ApduBufferSize =( (PH_NFCFRI_NDEFMAP_DESF_NDEF_FILE_SIZE) - (*NdefMap->DataCount + NdefMap->ApduBuffIndex));
}
/* Now, we have space in the card to write the data, */
/*Form the packet for the update binary command*/
NdefMap->SendRecvBuf[0] = 0x00;
NdefMap->SendRecvBuf[1] = 0xD6;
if( *NdefMap->DataCount == 0)
{
/* set the p1/p2 offsets */
NdefMap->SendRecvBuf[2] = 0x00; /* p1 */
NdefMap->SendRecvBuf[3] = 0x00; /* p2 */
NdefMap->DesfireCapContainer.SkipNlenBytesFlag = 0;
}
else
{
/* as the p1 of the 8bit is 0, p1 and p2 are used to store the
ofset value*/
/* This sets card offset in a card for a write operation. + 2 is
added as first 2 offsets represents the size of the NDEF Len present
in the file*/
DataCnt = *NdefMap->DataCount;
DataCnt += PH_FRINFC_NDEFMAP_DESF_NLEN_SIZE_IN_BYTES;
NdefMap->SendRecvBuf[2] = (uint8_t)((DataCnt)>> PH_FRINFC_NDEFMAP_DESF_SHL8);
NdefMap->SendRecvBuf[3] = (uint8_t)((DataCnt)& (0x00ff));
/* No need to attach 2 NLEN bytes at the begining.
as we have already attached in the first write operation.*/
NdefMap->DesfireCapContainer.SkipNlenBytesFlag = 1;
}
/* Calculate the bytes to write */
if( (NdefMap->ApduBufferSize - NdefMap->ApduBuffIndex) >= (uint32_t)( NdefMap->DesfireCapContainer.MaxCmdSize ))
{
noOfBytesToWrite = ( ( NdefMap->DesfireCapContainer.SkipNlenBytesFlag == 1) ?
NdefMap->DesfireCapContainer.MaxCmdSize :
(NdefMap->DesfireCapContainer.MaxCmdSize - PH_FRINFC_NDEFMAP_DESF_NLEN_SIZE_IN_BYTES));
}
else
{
/* Read only till the available buffer space */
noOfBytesToWrite = (uint16_t)(NdefMap->ApduBufferSize - NdefMap->ApduBuffIndex);
}
if ( NdefMap->Offset == PH_FRINFC_NDEFMAP_SEEK_BEGIN )
{
if ( NdefMap->DesfireCapContainer.SkipNlenBytesFlag == 1 )
{
index = 5;
/* To Specify the NDEF data len written : updated at the of write cycle*/
NdefMap->SendRecvBuf[4] = (uint8_t)noOfBytesToWrite;
}
else
{
/* Leave space to update NLEN */
NdefMap->SendRecvBuf[5] = 0x00;
NdefMap->SendRecvBuf[6] = 0x00;
index =7;
/* To Specify the NDEF data len written : updated at the of write cycle*/
NdefMap->SendRecvBuf[4] = (uint8_t)noOfBytesToWrite + PH_FRINFC_NDEFMAP_DESF_NLEN_SIZE_IN_BYTES;
}
/* copy the data to SendRecvBuf from the apdu buffer*/
(void)memcpy( &NdefMap->SendRecvBuf[index],
&NdefMap->ApduBuffer[NdefMap->ApduBuffIndex],
noOfBytesToWrite);
NdefMap->SendLength = (noOfBytesToWrite + index);
}
else
{
NdefMap->SendRecvBuf[4] = (uint8_t)noOfBytesToWrite;
/* copy the data to SendRecvBuf from the apdu buffer*/
(void)memcpy( &NdefMap->SendRecvBuf[5],
&NdefMap->ApduBuffer[NdefMap->ApduBuffIndex],
noOfBytesToWrite);
NdefMap->SendLength = (noOfBytesToWrite + 5);
}
/* Store the number of bytes being written in the context structure, so that
the parameters can be updated, after a successful write operation. */
NdefMap->NumOfBytesWritten = noOfBytesToWrite;
/* Change the state to Write */
NdefMap->State = PH_FRINFC_NDEFMAP_DESF_STATE_UPDATE_BIN_BEGIN;
status = phFriNfc_Desfire_HSendTransCmd(NdefMap,PH_FRINFC_NDEFMAP_DESF_RESP_OFFSET);
} /* if(NdefMap->ApduBuffIndex < NdefMap->ApduBufferSize) */
else
{
if ( (*NdefMap->DataCount == PH_NFCFRI_NDEFMAP_DESF_NDEF_FILE_SIZE) ||
(NdefMap->ApduBuffIndex == NdefMap->ApduBufferSize))
{
/* The NdefMap->DespOpFlag = PH_FRINFC_NDEFMAP_DESF_SET_LEN_OP is not
required, because the DespOpFlag shall be WRITE_OP
*/
/* Update the NLEN Bytes*/
#ifdef PH_HAL4_ENABLE
/* Do nothing */
#else
NdefMap->DespOpFlag = PH_FRINFC_NDEFMAP_DESF_SET_LEN_OP;
#endif /* #ifdef PH_HAL4_ENABLE */
status = phFriNfc_Desfire_HSetGet_NLEN(NdefMap);
}
else
{
/* The control should not come here.
wrong internal calculation.
we have actually written more than the space available
in the card ! */
#ifndef PH_HAL4_ENABLE
status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_CMD_ABORTED);
#else
status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_FAILED);
#endif
/* Reset the relevant parameters. */
NdefMap->ApduBuffIndex = 0;
NdefMap->PrevOperation = 0;
/* call respective CR */
phFriNfc_Desfire_HCrHandler(NdefMap,status);
}
}
/* if(*NdefMap->DataCount < PH_NFCFRI_NDEFMAP_DESF_NDEF_FILE_SIZE) */
return status;
}
static void phFriNfc_Desfire_HChkNDEFFileAccessRights(phFriNfc_NdefMap_t *NdefMap)
{
if ( (NdefMap->DesfireCapContainer.ReadAccess == 0x00) &&
(NdefMap->DesfireCapContainer.WriteAccess == 0x00 ))
{
/* Set the card state to Read/write State*/
/* This state can be either INITIALISED or READWRITE. but default
is INITIALISED */
NdefMap->CardState = PH_NDEFMAP_CARD_STATE_READ_WRITE;
}
else if((NdefMap->DesfireCapContainer.ReadAccess == 0x00) &&
(NdefMap->DesfireCapContainer.WriteAccess == 0xFF ))
{
/* Set the card state to Read Only State*/
NdefMap->CardState = PH_NDEFMAP_CARD_STATE_READ_ONLY;
}
else
{
/* Set the card state to invalid State*/
NdefMap->CardState = PH_NDEFMAP_CARD_STATE_INVALID;
}
}
/*!
* \brief this shall update the Desfire capability container structure.
*
* This function shall store version,maximum Ndef data structure size,
* Read Access permissions, Write Access permissions , Maximum data size
* that can be sent using a single Update Binary, maximum data size that
* can be read from the Desfire using a singlr read binary.
* These vaues shall be stored and used during the read/update binary
* operations.
*
*/
static
NFCSTATUS phFriNfc_Desfire_Update_SmartTagCapContainer(phFriNfc_NdefMap_t *NdefMap)
{
uint16_t CapContSize = 0,
/* this is initalised 2 because CCLEN includes the field size bytes i.e 2bytes*/
CCLen= 0;
uint8_t ErrFlag = 0;
NFCSTATUS status= NFCSTATUS_SUCCESS;
/*Check the Size of Cap Container */
CapContSize = ( (((uint16_t)NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_CCLEN_BYTE_FIRST_INDEX])<<8)+ \
NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_CCLEN_BYTE_SECOND_INDEX]);
CCLen += 2;
if ( (CapContSize < 0x0f) || (CapContSize == 0xffff))
{
ErrFlag =1;
}
else
{
/*Version : Smart Tag Spec version */
/* check for the validity of Major and Minor Version numbers*/
status = phFriNfc_MapTool_ChkSpcVer ( NdefMap,
PH_FRINFC_NDEFMAP_DESF_VER_INDEX);
if ( status != NFCSTATUS_SUCCESS )
{
ErrFlag =1;
}
else
{
CCLen += 1;
/*Get Response APDU data size
to check the integration s/w response size*/
#ifdef PH_HAL4_ENABLE
{
uint16_t max_rsp_size =
((((uint16_t)NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_MLE_BYTE_FIRST_INDEX]) << 8)\
+ NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_MLE_BYTE_SECOND_INDEX]);
NdefMap->DesfireCapContainer.MaxRespSize =
((max_rsp_size > PHHAL_MAX_DATASIZE)?
(PHHAL_MAX_DATASIZE) : max_rsp_size);
}
#else
NdefMap->DesfireCapContainer.MaxRespSize =
((((uint16_t)NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_MLE_BYTE_FIRST_INDEX]) << 8)\
+NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_MLE_BYTE_SECOND_INDEX]);
#endif /* #ifdef PH_HAL4_ENABLE */
/*Get Command APDU data size*/
#ifdef PH_HAL4_ENABLE
{
uint16_t max_cmd_size =
((((uint16_t)NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_MLC_BYTE_FIRST_INDEX])<<8)\
+ NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_MLC_BYTE_SECOND_INDEX]);
NdefMap->DesfireCapContainer.MaxCmdSize =
((max_cmd_size > PHHAL_MAX_DATASIZE)?
(PHHAL_MAX_DATASIZE): max_cmd_size);
}
#else
NdefMap->DesfireCapContainer.MaxCmdSize =
((((uint16_t)NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_MLC_BYTE_FIRST_INDEX])<<8)\
+NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_MLC_BYTE_SECOND_INDEX]);
#endif /* #ifdef PH_HAL4_ENABLE */
/* Check for the Validity of Cmd & Resp Size*/
/* check the Validity of the Cmd Size*/
if( (NdefMap->DesfireCapContainer.MaxRespSize < 0x0f) ||
( NdefMap->DesfireCapContainer.MaxCmdSize == 0x00))
{
ErrFlag=1;
}
else
{
CCLen += 4;
/* Check and Parse the TLV structure */
/* In future this chk can be extended to Propritery TLV */
//status = phFriNfc_ChkAndParseTLV(NdefMap);
status = phFriNfc_Desf_HChkAndParseTLV(NdefMap,PH_FRINFC_NDEFMAP_DESF_TLV_INDEX);
if ( (status == NFCSTATUS_SUCCESS) && (NdefMap->TLVFoundFlag == PH_FRINFC_NDEFMAP_DESF_NDEF_CNTRL_TLV))
{
CCLen += 1;
/* check the TLV length*/
if ( (( NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_TLV_LEN_INDEX]) > 0x00 ) &&
(( NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_TLV_LEN_INDEX]) <= 0xFE )&&
(( NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_TLV_LEN_INDEX]) == 0x06 ))
{
CCLen +=1;
/* store the contents in to the container structure*/
NdefMap->DesfireCapContainer.NdefMsgFid = ( (((uint16_t)NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_NDEF_FILEID_BYTE_FIRST_INDEX])<<PH_FRINFC_NDEFMAP_DESF_SHL8)+ \
NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_NDEF_FILEID_BYTE_SECOND_INDEX]);
CCLen +=2;
/* Invalid Msg File Id : User Can't Have read/write Opeartion*/
if ( (NdefMap->DesfireCapContainer.NdefMsgFid == 0xFFFF) ||
(NdefMap->DesfireCapContainer.NdefMsgFid == 0xE102) ||
(NdefMap->DesfireCapContainer.NdefMsgFid == 0xE103) ||
(NdefMap->DesfireCapContainer.NdefMsgFid == 0x3F00) ||
(NdefMap->DesfireCapContainer.NdefMsgFid == 0x3FFF ) )
{
ErrFlag=1;
}
else
{
/*Get Ndef Size*/
NdefMap->DesfireCapContainer.NdefFileSize =
((((uint16_t)NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_NDEF_FILESZ_BYTE_FIRST_INDEX])<<8)
| (NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_NDEF_FILESZ_BYTE_SECOND_INDEX] & 0x00ff));
/*Check Ndef Size*/
/* TBD : Do we need to minus 2 bytes of size it self?*/
if ( ((NdefMap->DesfireCapContainer.NdefFileSize -2) <= 0x0004 ) ||
((NdefMap->DesfireCapContainer.NdefFileSize -2) == 0xFFFD ) )
{
ErrFlag=1;
}
else
{
CCLen +=2;
/*Ndef File Read Access*/
NdefMap->DesfireCapContainer.ReadAccess = NdefMap->\
SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_NDEF_FILERD_ACCESS_INDEX] ;
/*Ndef File Write Access*/
NdefMap->DesfireCapContainer.WriteAccess = NdefMap->SendRecvBuf[PH_FRINFC_NDEFMAP_DESF_NDEF_FILEWR_ACCESS_INDEX];
CCLen +=2;
phFriNfc_Desfire_HChkNDEFFileAccessRights(NdefMap);
}
}
}
else
{
/* TLV Lenth is of two byte value
TBD: As the length of TLV is fixed for 6 bytes. We need not
handle the 2 byte value*/
}
}
else
{
if ( NdefMap->TLVFoundFlag == PH_FRINFC_NDEFMAP_DESF_PROP_CNTRL_TLV )
{
/*TBD: To Handle The Proprietery TLV*/
}
else
{
/*Invalid T found case*/
ErrFlag =1;
}
}
/* check for the entire LENGTH Validity
CCLEN + TLV L value == CCLEN*/
if ( CapContSize != CCLen )
{
ErrFlag=1;
}
}/* if NdefMap->DesfireCapContainer.MaxRespSize < 0x0f */
}/* Chkeck Map Version*/
}/* CC size invalid*/
if( ErrFlag == 1 )
{
status = PHNFCSTVAL(CID_FRI_NFC_NDEF_MAP,
NFCSTATUS_NO_NDEF_SUPPORT);
}
return ( status );
}
static uint32_t phFriNfc_Desfire_HGetLeBytes(phFriNfc_NdefMap_t *NdefMap)
{
/*Represents the LE byte*/
uint16_t BytesToRead =0;
if ( NdefMap->DespOpFlag == PH_FRINFC_NDEFMAP_DESF_GET_LEN_OP )
{
BytesToRead = PH_FRINFC_NDEFMAP_DESF_NLEN_SIZE_IN_BYTES;
NdefMap->DesfireCapContainer.SkipNlenBytesFlag =0;
}
else
{
/* Calculate Le bytes : No of bytes to read*/
/* Check for User Apdu Buffer Size and Msg Size of Desfire Capability container */
if((NdefMap->ApduBufferSize - NdefMap->ApduBuffIndex) >= NdefMap->DesfireCapContainer.MaxRespSize)
{
/* We have enough buffer space to read the whole capability container
size bytes
Now, check do we have NdefMap->DesfireCapContainer.MaxRespSize to read ? */
BytesToRead = (((NdefMap->DesfireCapContainer.NdefDataLen - *NdefMap->DataCount) >=
NdefMap->DesfireCapContainer.MaxRespSize) ?
NdefMap->DesfireCapContainer.MaxRespSize :
(NdefMap->DesfireCapContainer.NdefDataLen -
*NdefMap->DataCount));
}
else
{
/* Read only till the available buffer space */
BytesToRead = (uint16_t)(NdefMap->ApduBufferSize - NdefMap->ApduBuffIndex);
if(BytesToRead >= (uint16_t)(NdefMap->DesfireCapContainer.NdefDataLen - *NdefMap->DataCount))
{
BytesToRead = (NdefMap->DesfireCapContainer.NdefDataLen - *NdefMap->DataCount);
}
}
NdefMap->DesfireCapContainer.SkipNlenBytesFlag =
(uint8_t)(((NdefMap->Offset == PH_FRINFC_NDEFMAP_SEEK_BEGIN )&&( *NdefMap->DataCount == 0 )) ?
1 : 0);
}
return (BytesToRead);
}
/*!
* \brief this shall notify the integration software with respective
* success/error status along with the completion routines.
*
* This routine is called from the desfire process function.
*
*/
static void phFriNfc_Desfire_HCrHandler( phFriNfc_NdefMap_t *NdefMap,
NFCSTATUS Status)
{
/* set the state back to the Reset_Init state*/
NdefMap->State = PH_FRINFC_NDEFMAP_STATE_RESET_INIT;
switch(NdefMap->DespOpFlag)
{
/* check which routine has the problem and set the CR*/
case PH_FRINFC_NDEFMAP_DESF_NDEF_CHK_OP :
/* set the completion routine*/
NdefMap->CompletionRoutine[PH_FRINFC_NDEFMAP_CR_CHK_NDEF].\
CompletionRoutine(NdefMap->CompletionRoutine->Context,\
Status);
break;
case PH_FRINFC_NDEFMAP_DESF_READ_OP :
/* set the completion routine*/
NdefMap->CompletionRoutine[PH_FRINFC_NDEFMAP_CR_RD_NDEF].\
CompletionRoutine(NdefMap->CompletionRoutine->Context,\
Status);
break;
case PH_FRINFC_NDEFMAP_DESF_WRITE_OP :
/* set the completion routine*/
NdefMap->CompletionRoutine[PH_FRINFC_NDEFMAP_CR_WR_NDEF].\
CompletionRoutine(NdefMap->CompletionRoutine->Context,\
Status);
break;
default :
/* set the completion routine*/
NdefMap->CompletionRoutine[PH_FRINFC_NDEFMAP_CR_INVALID_OPE].\
CompletionRoutine(NdefMap->CompletionRoutine->Context,\
Status);
break;
}
}
static NFCSTATUS phFriNfc_Desfire_HSendTransCmd(phFriNfc_NdefMap_t *NdefMap,uint8_t SendRecvLen)
{
NFCSTATUS status = NFCSTATUS_SUCCESS;
/* set the command type*/
#ifndef PH_HAL4_ENABLE
NdefMap->Cmd.Iso144434Cmd = phHal_eIso14443_4_CmdListTClCmd;
#else
NdefMap->Cmd.Iso144434Cmd = phHal_eIso14443_4_Raw;
#endif
/* set the Additional Info*/
NdefMap->psDepAdditionalInfo.DepFlags.MetaChaining = 0;
NdefMap->psDepAdditionalInfo.DepFlags.NADPresent = 0;
/*set the completion routines for the desfire card operations*/
NdefMap->MapCompletionInfo.CompletionRoutine = phFriNfc_Desfire_Process;
NdefMap->MapCompletionInfo.Context = NdefMap;
/* set the receive length */
*NdefMap->SendRecvLength = ((uint16_t)(SendRecvLen));
/*Call the Overlapped HAL Transceive function */
status = phFriNfc_OvrHal_Transceive(NdefMap->LowerDevice,
&NdefMap->MapCompletionInfo,
NdefMap->psRemoteDevInfo,
NdefMap->Cmd,
&NdefMap->psDepAdditionalInfo,
NdefMap->SendRecvBuf,
NdefMap->SendLength,
NdefMap->SendRecvBuf,
NdefMap->SendRecvLength);
return (status);
}
#ifdef UNIT_TEST
#include <phUnitTestNfc_Desfire_static.c>
#endif
#endif /* PH_FRINFC_MAP_DESFIRE_DISABLED */