Home | History | Annotate | Download | only in tml
      1 /*
      2  * Copyright (C) 2010-2014 NXP Semiconductors
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /*
     18  * TML Implementation.
     19  */
     20 
     21 #include <phDal4Nfc_messageQueueLib.h>
     22 #include <phNxpLog.h>
     23 #include <phNxpNciHal_utils.h>
     24 #include <phOsalNfc_Timer.h>
     25 #include <phTmlNfc.h>
     26 #include <phTmlNfc_i2c.h>
     27 
     28 /*
     29  * Duration of Timer to wait after sending an Nci packet
     30  */
     31 #define PHTMLNFC_MAXTIME_RETRANSMIT (200U)
     32 #define MAX_WRITE_RETRY_COUNT 0x03
     33 /* Retry Count = Standby Recovery time of NFCC / Retransmission time + 1 */
     34 static uint8_t bCurrentRetryCount = (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1;
     35 
     36 /* Value to reset variables of TML  */
     37 #define PH_TMLNFC_RESET_VALUE (0x00)
     38 
     39 /* Indicates a Initial or offset value */
     40 #define PH_TMLNFC_VALUE_ONE (0x01)
     41 
     42 /* Initialize Context structure pointer used to access context structure */
     43 phTmlNfc_Context_t* gpphTmlNfc_Context = NULL;
     44 /* Local Function prototypes */
     45 static NFCSTATUS phTmlNfc_StartThread(void);
     46 static void phTmlNfc_CleanUp(void);
     47 static void phTmlNfc_ReadDeferredCb(void* pParams);
     48 static void phTmlNfc_WriteDeferredCb(void* pParams);
     49 static void * phTmlNfc_TmlThread(void* pParam);
     50 static void * phTmlNfc_TmlWriterThread(void* pParam);
     51 static void phTmlNfc_ReTxTimerCb(uint32_t dwTimerId, void* pContext);
     52 static NFCSTATUS phTmlNfc_InitiateTimer(void);
     53 
     54 /* Function definitions */
     55 
     56 /*******************************************************************************
     57 **
     58 ** Function         phTmlNfc_Init
     59 **
     60 ** Description      Provides initialization of TML layer and hardware interface
     61 **                  Configures given hardware interface and sends handle to the
     62 **                  caller
     63 **
     64 ** Parameters       pConfig - TML configuration details as provided by the upper
     65 **                            layer
     66 **
     67 ** Returns          NFC status:
     68 **                  NFCSTATUS_SUCCESS - initialization successful
     69 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
     70 **                                                invalid
     71 **                  NFCSTATUS_FAILED - initialization failed (for example,
     72 **                                     unable to open hardware interface)
     73 **                  NFCSTATUS_INVALID_DEVICE - device has not been opened or has
     74 **                                             been disconnected
     75 **
     76 *******************************************************************************/
     77 NFCSTATUS phTmlNfc_Init(pphTmlNfc_Config_t pConfig) {
     78   NFCSTATUS wInitStatus = NFCSTATUS_SUCCESS;
     79 
     80   /* Check if TML layer is already Initialized */
     81   if (NULL != gpphTmlNfc_Context) {
     82     /* TML initialization is already completed */
     83     wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_ALREADY_INITIALISED);
     84   }
     85   /* Validate Input parameters */
     86   else if ((NULL == pConfig) ||
     87            (PH_TMLNFC_RESET_VALUE == pConfig->dwGetMsgThreadId)) {
     88     /*Parameters passed to TML init are wrong */
     89     wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
     90   } else {
     91     /* Allocate memory for TML context */
     92     gpphTmlNfc_Context = (phTmlNfc_Context_t *)malloc(sizeof(phTmlNfc_Context_t));
     93 
     94     if (NULL == gpphTmlNfc_Context) {
     95       wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
     96     } else {
     97       /* Initialise all the internal TML variables */
     98       memset(gpphTmlNfc_Context, PH_TMLNFC_RESET_VALUE,
     99              sizeof(phTmlNfc_Context_t));
    100       /* Make sure that the thread runs once it is created */
    101       gpphTmlNfc_Context->bThreadDone = 1;
    102 
    103       /* Open the device file to which data is read/written */
    104       wInitStatus = phTmlNfc_i2c_open_and_configure(
    105           pConfig, &(gpphTmlNfc_Context->pDevHandle));
    106 
    107       if (NFCSTATUS_SUCCESS != wInitStatus) {
    108         wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_DEVICE);
    109         gpphTmlNfc_Context->pDevHandle = NULL;
    110       } else {
    111         gpphTmlNfc_Context->tReadInfo.bEnable = 0;
    112         gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
    113         gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
    114         gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
    115         if (pthread_mutex_init(&gpphTmlNfc_Context->readInfoUpdateMutex,
    116                                NULL) == -1) {
    117           wInitStatus = NFCSTATUS_FAILED;
    118         } else if (0 != sem_init(&gpphTmlNfc_Context->rxSemaphore, 0, 0)) {
    119           wInitStatus = NFCSTATUS_FAILED;
    120         } else if (0 != sem_init(&gpphTmlNfc_Context->txSemaphore, 0, 0)) {
    121           wInitStatus = NFCSTATUS_FAILED;
    122         } else if (0 != sem_init(&gpphTmlNfc_Context->postMsgSemaphore, 0, 0)) {
    123           wInitStatus = NFCSTATUS_FAILED;
    124         } else {
    125           sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
    126           /* Start TML thread (to handle write and read operations) */
    127           if (NFCSTATUS_SUCCESS != phTmlNfc_StartThread()) {
    128             wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
    129           } else {
    130             /* Create Timer used for Retransmission of NCI packets */
    131             gpphTmlNfc_Context->dwTimerId = phOsalNfc_Timer_Create();
    132             if (PH_OSALNFC_TIMER_ID_INVALID != gpphTmlNfc_Context->dwTimerId) {
    133               /* Store the Thread Identifier to which Message is to be posted */
    134               gpphTmlNfc_Context->dwCallbackThreadId =
    135                   pConfig->dwGetMsgThreadId;
    136               /* Enable retransmission of Nci packet & set retry count to
    137                * default */
    138               gpphTmlNfc_Context->eConfig = phTmlNfc_e_DisableRetrans;
    139               /* Retry Count = Standby Recovery time of NFCC / Retransmission
    140                * time + 1 */
    141               gpphTmlNfc_Context->bRetryCount =
    142                   (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1;
    143               gpphTmlNfc_Context->bWriteCbInvoked = false;
    144             } else {
    145               wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
    146             }
    147           }
    148         }
    149       }
    150     }
    151   }
    152   /* Clean up all the TML resources if any error */
    153   if (NFCSTATUS_SUCCESS != wInitStatus) {
    154     /* Clear all handles and memory locations initialized during init */
    155     phTmlNfc_CleanUp();
    156   }
    157 
    158   return wInitStatus;
    159 }
    160 
    161 /*******************************************************************************
    162 **
    163 ** Function         phTmlNfc_ConfigNciPktReTx
    164 **
    165 ** Description      Provides Enable/Disable Retransmission of NCI packets
    166 **                  Needed in case of Timeout between Transmission and Reception
    167 **                  of NCI packets. Retransmission can be enabled only if
    168 **                  standby mode is enabled
    169 **
    170 ** Parameters       eConfig - values from phTmlNfc_ConfigRetrans_t
    171 **                  bRetryCount - Number of times Nci packets shall be
    172 **                                retransmitted (default = 3)
    173 **
    174 ** Returns          None
    175 **
    176 *******************************************************************************/
    177 void phTmlNfc_ConfigNciPktReTx(phTmlNfc_ConfigRetrans_t eConfiguration,
    178                                uint8_t bRetryCounter) {
    179   /* Enable/Disable Retransmission */
    180 
    181   gpphTmlNfc_Context->eConfig = eConfiguration;
    182   if (phTmlNfc_e_EnableRetrans == eConfiguration) {
    183     /* Check whether Retry counter passed is valid */
    184     if (0 != bRetryCounter) {
    185       gpphTmlNfc_Context->bRetryCount = bRetryCounter;
    186     }
    187     /* Set retry counter to its default value */
    188     else {
    189       /* Retry Count = Standby Recovery time of NFCC / Retransmission time + 1
    190        */
    191       gpphTmlNfc_Context->bRetryCount =
    192           (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1;
    193     }
    194   }
    195 
    196   return;
    197 }
    198 
    199 /*******************************************************************************
    200 **
    201 ** Function         phTmlNfc_StartThread
    202 **
    203 ** Description      Initializes comport, reader and writer threads
    204 **
    205 ** Parameters       None
    206 **
    207 ** Returns          NFC status:
    208 **                  NFCSTATUS_SUCCESS - threads initialized successfully
    209 **                  NFCSTATUS_FAILED - initialization failed due to system error
    210 **
    211 *******************************************************************************/
    212 static NFCSTATUS phTmlNfc_StartThread(void) {
    213   NFCSTATUS wStartStatus = NFCSTATUS_SUCCESS;
    214   void* h_threadsEvent = 0x00;
    215   int pthread_create_status = 0;
    216 
    217   /* Create Reader and Writer threads */
    218   pthread_create_status =
    219       pthread_create(&gpphTmlNfc_Context->readerThread, NULL,
    220                      &phTmlNfc_TmlThread, (void*)h_threadsEvent);
    221   if (0 != pthread_create_status) {
    222     wStartStatus = NFCSTATUS_FAILED;
    223   } else {
    224     /*Start Writer Thread*/
    225     pthread_create_status =
    226         pthread_create(&gpphTmlNfc_Context->writerThread, NULL,
    227                        &phTmlNfc_TmlWriterThread, (void*)h_threadsEvent);
    228     if (0 != pthread_create_status) {
    229       wStartStatus = NFCSTATUS_FAILED;
    230     }
    231   }
    232 
    233   return wStartStatus;
    234 }
    235 
    236 /*******************************************************************************
    237 **
    238 ** Function         phTmlNfc_ReTxTimerCb
    239 **
    240 ** Description      This is the timer callback function after timer expiration.
    241 **
    242 ** Parameters       dwThreadId  - id of the thread posting message
    243 **                  pContext    - context provided by upper layer
    244 **
    245 ** Returns          None
    246 **
    247 *******************************************************************************/
    248 static void phTmlNfc_ReTxTimerCb(uint32_t dwTimerId, void* pContext) {
    249   if ((gpphTmlNfc_Context->dwTimerId == dwTimerId) && (NULL == pContext)) {
    250     /* If Retry Count has reached its limit,Retransmit Nci
    251        packet */
    252     if (0 == bCurrentRetryCount) {
    253       /* Since the count has reached its limit,return from timer callback
    254          Upper layer Timeout would have happened */
    255     } else {
    256       bCurrentRetryCount--;
    257       gpphTmlNfc_Context->tWriteInfo.bThreadBusy = true;
    258       gpphTmlNfc_Context->tWriteInfo.bEnable = 1;
    259     }
    260     sem_post(&gpphTmlNfc_Context->txSemaphore);
    261   }
    262 
    263   return;
    264 }
    265 
    266 /*******************************************************************************
    267 **
    268 ** Function         phTmlNfc_InitiateTimer
    269 **
    270 ** Description      Start a timer for Tx and Rx thread.
    271 **
    272 ** Parameters       void
    273 **
    274 ** Returns          NFC status
    275 **
    276 *******************************************************************************/
    277 static NFCSTATUS phTmlNfc_InitiateTimer(void) {
    278   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
    279 
    280   /* Start Timer once Nci packet is sent */
    281   wStatus = phOsalNfc_Timer_Start(gpphTmlNfc_Context->dwTimerId,
    282                                   (uint32_t)PHTMLNFC_MAXTIME_RETRANSMIT,
    283                                   phTmlNfc_ReTxTimerCb, NULL);
    284 
    285   return wStatus;
    286 }
    287 
    288 /*******************************************************************************
    289 **
    290 ** Function         phTmlNfc_TmlThread
    291 **
    292 ** Description      Read the data from the lower layer driver
    293 **
    294 ** Parameters       pParam  - parameters for Writer thread function
    295 **
    296 ** Returns          None
    297 **
    298 *******************************************************************************/
    299 static void * phTmlNfc_TmlThread(void* pParam) {
    300   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
    301   int32_t dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
    302   uint8_t temp[260];
    303   /* Transaction info buffer to be passed to Callback Thread */
    304   static phTmlNfc_TransactInfo_t tTransactionInfo;
    305   /* Structure containing Tml callback function and parameters to be invoked
    306      by the callback thread */
    307   static phLibNfc_DeferredCall_t tDeferredInfo;
    308   /* Initialize Message structure to post message onto Callback Thread */
    309   static phLibNfc_Message_t tMsg;
    310   UNUSED(pParam);
    311   NXPLOG_TML_D("PN54X - Tml Reader Thread Started................\n");
    312 
    313   /* Writer thread loop shall be running till shutdown is invoked */
    314   while (gpphTmlNfc_Context->bThreadDone) {
    315     /* If Tml write is requested */
    316     /* Set the variable to success initially */
    317     wStatus = NFCSTATUS_SUCCESS;
    318     sem_wait(&gpphTmlNfc_Context->rxSemaphore);
    319 
    320     /* If Tml read is requested */
    321     if (1 == gpphTmlNfc_Context->tReadInfo.bEnable) {
    322       NXPLOG_TML_D("PN54X - Read requested.....\n");
    323       /* Set the variable to success initially */
    324       wStatus = NFCSTATUS_SUCCESS;
    325 
    326       /* Variable to fetch the actual number of bytes read */
    327       dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
    328 
    329       /* Read the data from the file onto the buffer */
    330       if (NULL != gpphTmlNfc_Context->pDevHandle) {
    331         NXPLOG_TML_D("PN54X - Invoking I2C Read.....\n");
    332         dwNoBytesWrRd =
    333             phTmlNfc_i2c_read(gpphTmlNfc_Context->pDevHandle, temp, 260);
    334 
    335         if (-1 == dwNoBytesWrRd) {
    336           NXPLOG_TML_E("PN54X - Error in I2C Read.....\n");
    337           sem_post(&gpphTmlNfc_Context->rxSemaphore);
    338         } else if (dwNoBytesWrRd > 260) {
    339           NXPLOG_TML_E("Numer of bytes read exceeds the limit 260.....\n");
    340           sem_post(&gpphTmlNfc_Context->rxSemaphore);
    341         } else {
    342           pthread_mutex_lock(&gpphTmlNfc_Context->readInfoUpdateMutex);
    343           memcpy(gpphTmlNfc_Context->tReadInfo.pBuffer, temp, dwNoBytesWrRd);
    344 
    345           NXPLOG_TML_D("PN54X - I2C Read successful.....\n");
    346           /* This has to be reset only after a successful read */
    347           gpphTmlNfc_Context->tReadInfo.bEnable = 0;
    348           if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
    349               (0x00 != (gpphTmlNfc_Context->tReadInfo.pBuffer[0] & 0xE0))) {
    350             NXPLOG_TML_D("PN54X - Retransmission timer stopped.....\n");
    351             /* Stop Timer to prevent Retransmission */
    352             uint32_t timerStatus =
    353                 phOsalNfc_Timer_Stop(gpphTmlNfc_Context->dwTimerId);
    354             if (NFCSTATUS_SUCCESS != timerStatus) {
    355               NXPLOG_TML_E("PN54X - timer stopped returned failure.....\n");
    356             } else {
    357               gpphTmlNfc_Context->bWriteCbInvoked = false;
    358             }
    359           }
    360           if (gpphTmlNfc_Context->tWriteInfo.bThreadBusy) {
    361             NXPLOG_TML_D("Delay Read if write thread is busy");
    362             usleep(2000); /*2ms delay to give prio to write complete */
    363           }
    364           /* Update the actual number of bytes read including header */
    365           gpphTmlNfc_Context->tReadInfo.wLength = (uint16_t)(dwNoBytesWrRd);
    366           phNxpNciHal_print_packet("RECV",
    367                                    gpphTmlNfc_Context->tReadInfo.pBuffer,
    368                                    gpphTmlNfc_Context->tReadInfo.wLength);
    369 
    370           dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
    371 
    372           /* Fill the Transaction info structure to be passed to Callback
    373            * Function */
    374           tTransactionInfo.wStatus = wStatus;
    375           tTransactionInfo.pBuff = gpphTmlNfc_Context->tReadInfo.pBuffer;
    376           /* Actual number of bytes read is filled in the structure */
    377           tTransactionInfo.wLength = gpphTmlNfc_Context->tReadInfo.wLength;
    378 
    379           /* Read operation completed successfully. Post a Message onto Callback
    380            * Thread*/
    381           /* Prepare the message to be posted on User thread */
    382           tDeferredInfo.pCallback = &phTmlNfc_ReadDeferredCb;
    383           tDeferredInfo.pParameter = &tTransactionInfo;
    384           tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG;
    385           tMsg.pMsgData = &tDeferredInfo;
    386           tMsg.Size = sizeof(tDeferredInfo);
    387           pthread_mutex_unlock(&gpphTmlNfc_Context->readInfoUpdateMutex);
    388           NXPLOG_TML_D("PN54X - Posting read message.....\n");
    389           phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg);
    390         }
    391       } else {
    392         NXPLOG_TML_D("PN54X -gpphTmlNfc_Context->pDevHandle is NULL");
    393       }
    394     } else {
    395       NXPLOG_TML_D("PN54X - read request NOT enabled");
    396       usleep(10 * 1000);
    397     }
    398   } /* End of While loop */
    399 
    400   return NULL;
    401 }
    402 
    403 /*******************************************************************************
    404 **
    405 ** Function         phTmlNfc_TmlWriterThread
    406 **
    407 ** Description      Writes the requested data onto the lower layer driver
    408 **
    409 ** Parameters       pParam  - context provided by upper layer
    410 **
    411 ** Returns          None
    412 **
    413 *******************************************************************************/
    414 static void * phTmlNfc_TmlWriterThread(void* pParam) {
    415   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
    416   int32_t dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
    417   /* Transaction info buffer to be passed to Callback Thread */
    418   static phTmlNfc_TransactInfo_t tTransactionInfo;
    419   /* Structure containing Tml callback function and parameters to be invoked
    420      by the callback thread */
    421   static phLibNfc_DeferredCall_t tDeferredInfo;
    422   /* Initialize Message structure to post message onto Callback Thread */
    423   static phLibNfc_Message_t tMsg;
    424   /* In case of I2C Write Retry */
    425   static uint16_t retry_cnt;
    426   UNUSED(pParam);
    427   NXPLOG_TML_D("PN54X - Tml Writer Thread Started................\n");
    428 
    429   /* Writer thread loop shall be running till shutdown is invoked */
    430   while (gpphTmlNfc_Context->bThreadDone) {
    431     NXPLOG_TML_D("PN54X - Tml Writer Thread Running................\n");
    432     sem_wait(&gpphTmlNfc_Context->txSemaphore);
    433     /* If Tml write is requested */
    434     if (1 == gpphTmlNfc_Context->tWriteInfo.bEnable) {
    435       NXPLOG_TML_D("PN54X - Write requested.....\n");
    436       /* Set the variable to success initially */
    437       wStatus = NFCSTATUS_SUCCESS;
    438       if (NULL != gpphTmlNfc_Context->pDevHandle) {
    439       retry:
    440         gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
    441         /* Variable to fetch the actual number of bytes written */
    442         dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
    443         /* Write the data in the buffer onto the file */
    444         NXPLOG_TML_D("PN54X - Invoking I2C Write.....\n");
    445         dwNoBytesWrRd =
    446             phTmlNfc_i2c_write(gpphTmlNfc_Context->pDevHandle,
    447                                gpphTmlNfc_Context->tWriteInfo.pBuffer,
    448                                gpphTmlNfc_Context->tWriteInfo.wLength);
    449 
    450         /* Try I2C Write Five Times, if it fails : Raju */
    451         if (-1 == dwNoBytesWrRd) {
    452           if (getDownloadFlag() == true) {
    453             if (retry_cnt++ < MAX_WRITE_RETRY_COUNT) {
    454               NXPLOG_NCIHAL_E("PN54X - Error in I2C Write  - Retry 0x%x",
    455                               retry_cnt);
    456               // Add a 10 ms delay to ensure NFCC is not still in stand by mode.
    457               usleep(10 * 1000);
    458               goto retry;
    459             }
    460           }
    461           NXPLOG_TML_E("PN54X - Error in I2C Write.....\n");
    462           wStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
    463         } else {
    464           phNxpNciHal_print_packet("SEND",
    465                                    gpphTmlNfc_Context->tWriteInfo.pBuffer,
    466                                    gpphTmlNfc_Context->tWriteInfo.wLength);
    467         }
    468         retry_cnt = 0;
    469         if (NFCSTATUS_SUCCESS == wStatus) {
    470           NXPLOG_TML_D("PN54X - I2C Write successful.....\n");
    471           dwNoBytesWrRd = PH_TMLNFC_VALUE_ONE;
    472         }
    473         /* Fill the Transaction info structure to be passed to Callback Function
    474          */
    475         tTransactionInfo.wStatus = wStatus;
    476         tTransactionInfo.pBuff = gpphTmlNfc_Context->tWriteInfo.pBuffer;
    477         /* Actual number of bytes written is filled in the structure */
    478         tTransactionInfo.wLength = (uint16_t)dwNoBytesWrRd;
    479 
    480         /* Prepare the message to be posted on the User thread */
    481         tDeferredInfo.pCallback = &phTmlNfc_WriteDeferredCb;
    482         tDeferredInfo.pParameter = &tTransactionInfo;
    483         /* Write operation completed successfully. Post a Message onto Callback
    484          * Thread*/
    485         tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG;
    486         tMsg.pMsgData = &tDeferredInfo;
    487         tMsg.Size = sizeof(tDeferredInfo);
    488 
    489         /* Check whether Retransmission needs to be started,
    490          * If yes, Post message only if
    491          * case 1. Message is not posted &&
    492          * case 11. Write status is success ||
    493          * case 12. Last retry of write is also failure
    494          */
    495         if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
    496             (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) {
    497           if (gpphTmlNfc_Context->bWriteCbInvoked == false) {
    498             if ((NFCSTATUS_SUCCESS == wStatus) || (bCurrentRetryCount == 0)) {
    499               NXPLOG_TML_D("PN54X - Posting Write message.....\n");
    500               phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId,
    501                                     &tMsg);
    502               gpphTmlNfc_Context->bWriteCbInvoked = true;
    503             }
    504           }
    505         } else {
    506           NXPLOG_TML_D("PN54X - Posting Fresh Write message.....\n");
    507           phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg);
    508         }
    509       } else {
    510         NXPLOG_TML_D("PN54X - gpphTmlNfc_Context->pDevHandle is NULL");
    511       }
    512 
    513       /* If Data packet is sent, then NO retransmission */
    514       if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
    515           (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) {
    516         NXPLOG_TML_D("PN54X - Starting timer for Retransmission case");
    517         wStatus = phTmlNfc_InitiateTimer();
    518         if (NFCSTATUS_SUCCESS != wStatus) {
    519           /* Reset Variables used for Retransmission */
    520           NXPLOG_TML_D("PN54X - Retransmission timer initiate failed");
    521           gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
    522           bCurrentRetryCount = 0;
    523         }
    524       }
    525     } else {
    526       NXPLOG_TML_D("PN54X - Write request NOT enabled");
    527       usleep(10000);
    528     }
    529 
    530   } /* End of While loop */
    531 
    532   return NULL;
    533 }
    534 
    535 /*******************************************************************************
    536 **
    537 ** Function         phTmlNfc_CleanUp
    538 **
    539 ** Description      Clears all handles opened during TML initialization
    540 **
    541 ** Parameters       None
    542 **
    543 ** Returns          None
    544 **
    545 *******************************************************************************/
    546 static void phTmlNfc_CleanUp(void) {
    547   if (NULL == gpphTmlNfc_Context) {
    548     return;
    549   }
    550   if (NULL != gpphTmlNfc_Context->pDevHandle) {
    551     (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
    552     gpphTmlNfc_Context->bThreadDone = 0;
    553   }
    554   sem_destroy(&gpphTmlNfc_Context->rxSemaphore);
    555   sem_destroy(&gpphTmlNfc_Context->txSemaphore);
    556   sem_destroy(&gpphTmlNfc_Context->postMsgSemaphore);
    557   phTmlNfc_i2c_close(gpphTmlNfc_Context->pDevHandle);
    558   gpphTmlNfc_Context->pDevHandle = NULL;
    559   /* Clear memory allocated for storing Context variables */
    560   free((void*)gpphTmlNfc_Context);
    561   /* Set the pointer to NULL to indicate De-Initialization */
    562   gpphTmlNfc_Context = NULL;
    563 
    564   return;
    565 }
    566 
    567 /*******************************************************************************
    568 **
    569 ** Function         phTmlNfc_Shutdown
    570 **
    571 ** Description      Uninitializes TML layer and hardware interface
    572 **
    573 ** Parameters       None
    574 **
    575 ** Returns          NFC status:
    576 **                  NFCSTATUS_SUCCESS - TML configuration released successfully
    577 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    578 **                                                invalid
    579 **                  NFCSTATUS_FAILED - un-initialization failed (example: unable
    580 **                                     to close interface)
    581 **
    582 *******************************************************************************/
    583 NFCSTATUS phTmlNfc_Shutdown(void) {
    584   NFCSTATUS wShutdownStatus = NFCSTATUS_SUCCESS;
    585 
    586   /* Check whether TML is Initialized */
    587   if (NULL != gpphTmlNfc_Context) {
    588     /* Reset thread variable to terminate the thread */
    589     gpphTmlNfc_Context->bThreadDone = 0;
    590     usleep(1000);
    591     /* Clear All the resources allocated during initialization */
    592     sem_post(&gpphTmlNfc_Context->rxSemaphore);
    593     usleep(1000);
    594     sem_post(&gpphTmlNfc_Context->txSemaphore);
    595     usleep(1000);
    596     sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
    597     usleep(1000);
    598     sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
    599     usleep(1000);
    600     pthread_mutex_destroy(&gpphTmlNfc_Context->readInfoUpdateMutex);
    601     if (0 != pthread_join(gpphTmlNfc_Context->readerThread, (void**)NULL)) {
    602       NXPLOG_TML_E("Fail to kill reader thread!");
    603     }
    604     if (0 != pthread_join(gpphTmlNfc_Context->writerThread, (void**)NULL)) {
    605       NXPLOG_TML_E("Fail to kill writer thread!");
    606     }
    607     NXPLOG_TML_D("bThreadDone == 0");
    608 
    609     phTmlNfc_CleanUp();
    610   } else {
    611     wShutdownStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
    612   }
    613 
    614   return wShutdownStatus;
    615 }
    616 
    617 /*******************************************************************************
    618 **
    619 ** Function         phTmlNfc_Write
    620 **
    621 ** Description      Asynchronously writes given data block to hardware
    622 **                  interface/driver. Enables writer thread if there are no
    623 **                  write requests pending. Returns successfully once writer
    624 **                  thread completes write operation. Notifies upper layer using
    625 **                  callback mechanism.
    626 **
    627 **                  NOTE:
    628 **                  * it is important to post a message with id
    629 **                    PH_TMLNFC_WRITE_MESSAGE to IntegrationThread after data
    630 **                    has been written to PN54X
    631 **                  * if CRC needs to be computed, then input buffer should be
    632 **                    capable to store two more bytes apart from length of
    633 **                    packet
    634 **
    635 ** Parameters       pBuffer - data to be sent
    636 **                  wLength - length of data buffer
    637 **                  pTmlWriteComplete - pointer to the function to be invoked
    638 **                                      upon completion
    639 **                  pContext - context provided by upper layer
    640 **
    641 ** Returns          NFC status:
    642 **                  NFCSTATUS_PENDING - command is yet to be processed
    643 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    644 **                                                invalid
    645 **                  NFCSTATUS_BUSY - write request is already in progress
    646 **
    647 *******************************************************************************/
    648 NFCSTATUS phTmlNfc_Write(uint8_t* pBuffer, uint16_t wLength,
    649                          pphTmlNfc_TransactCompletionCb_t pTmlWriteComplete,
    650                          void* pContext) {
    651   NFCSTATUS wWriteStatus;
    652 
    653   /* Check whether TML is Initialized */
    654 
    655   if (NULL != gpphTmlNfc_Context) {
    656     if ((NULL != gpphTmlNfc_Context->pDevHandle) && (NULL != pBuffer) &&
    657         (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlWriteComplete)) {
    658       if (!gpphTmlNfc_Context->tWriteInfo.bThreadBusy) {
    659         /* Setting the flag marks beginning of a Write Operation */
    660         gpphTmlNfc_Context->tWriteInfo.bThreadBusy = true;
    661         /* Copy the buffer, length and Callback function,
    662            This shall be utilized while invoking the Callback function in thread
    663            */
    664         gpphTmlNfc_Context->tWriteInfo.pBuffer = pBuffer;
    665         gpphTmlNfc_Context->tWriteInfo.wLength = wLength;
    666         gpphTmlNfc_Context->tWriteInfo.pThread_Callback = pTmlWriteComplete;
    667         gpphTmlNfc_Context->tWriteInfo.pContext = pContext;
    668 
    669         wWriteStatus = NFCSTATUS_PENDING;
    670         // FIXME: If retry is going on. Stop the retry thread/timer
    671         if (phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) {
    672           /* Set retry count to default value */
    673           // FIXME: If the timer expired there, and meanwhile we have created
    674           // a new request. The expired timer will think that retry is still
    675           // ongoing.
    676           bCurrentRetryCount = gpphTmlNfc_Context->bRetryCount;
    677           gpphTmlNfc_Context->bWriteCbInvoked = false;
    678         }
    679         /* Set event to invoke Writer Thread */
    680         gpphTmlNfc_Context->tWriteInfo.bEnable = 1;
    681         sem_post(&gpphTmlNfc_Context->txSemaphore);
    682       } else {
    683         wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY);
    684       }
    685     } else {
    686       wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
    687     }
    688   } else {
    689     wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
    690   }
    691 
    692   return wWriteStatus;
    693 }
    694 
    695 /*******************************************************************************
    696 **
    697 ** Function         phTmlNfc_UpdateReadCompleteCallback
    698 **
    699 ** Description      Updates the callback to be invoked after read completed
    700 **
    701 ** Parameters       pTmlReadComplete - pointer to the function to be invoked
    702 **                                     upon completion of read operation
    703 **
    704 ** Returns          NFC status:
    705 **                  NFCSTATUS_SUCCESS - if TmlNfc context available
    706 **                  NFCSTATUS_FAILED - otherwise
    707 **
    708 *******************************************************************************/
    709 NFCSTATUS phTmlNfc_UpdateReadCompleteCallback (
    710     pphTmlNfc_TransactCompletionCb_t pTmlReadComplete) {
    711   NFCSTATUS wStatus = NFCSTATUS_FAILED;
    712   if ((NULL != gpphTmlNfc_Context) && (NULL != pTmlReadComplete)) {
    713     gpphTmlNfc_Context->tReadInfo.pThread_Callback = pTmlReadComplete;
    714     wStatus = NFCSTATUS_SUCCESS;
    715   }
    716   return wStatus;
    717 }
    718 
    719 /*******************************************************************************
    720 **
    721 ** Function         phTmlNfc_Read
    722 **
    723 ** Description      Asynchronously reads data from the driver
    724 **                  Number of bytes to be read and buffer are passed by upper
    725 **                  layer.
    726 **                  Enables reader thread if there are no read requests pending
    727 **                  Returns successfully once read operation is completed
    728 **                  Notifies upper layer using callback mechanism
    729 **
    730 ** Parameters       pBuffer - location to send read data to the upper layer via
    731 **                            callback
    732 **                  wLength - length of read data buffer passed by upper layer
    733 **                  pTmlReadComplete - pointer to the function to be invoked
    734 **                                     upon completion of read operation
    735 **                  pContext - context provided by upper layer
    736 **
    737 ** Returns          NFC status:
    738 **                  NFCSTATUS_PENDING - command is yet to be processed
    739 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    740 **                                                invalid
    741 **                  NFCSTATUS_BUSY - read request is already in progress
    742 **
    743 *******************************************************************************/
    744 NFCSTATUS phTmlNfc_Read(uint8_t* pBuffer, uint16_t wLength,
    745                         pphTmlNfc_TransactCompletionCb_t pTmlReadComplete,
    746                         void* pContext) {
    747   NFCSTATUS wReadStatus;
    748 
    749   /* Check whether TML is Initialized */
    750   if (NULL != gpphTmlNfc_Context) {
    751     if ((gpphTmlNfc_Context->pDevHandle != NULL) && (NULL != pBuffer) &&
    752         (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlReadComplete)) {
    753       if (!gpphTmlNfc_Context->tReadInfo.bThreadBusy) {
    754         pthread_mutex_lock(&gpphTmlNfc_Context->readInfoUpdateMutex);
    755         /* Setting the flag marks beginning of a Read Operation */
    756         gpphTmlNfc_Context->tReadInfo.bThreadBusy = true;
    757         /* Copy the buffer, length and Callback function,
    758            This shall be utilized while invoking the Callback function in thread
    759            */
    760         gpphTmlNfc_Context->tReadInfo.pBuffer = pBuffer;
    761         gpphTmlNfc_Context->tReadInfo.wLength = wLength;
    762         gpphTmlNfc_Context->tReadInfo.pThread_Callback = pTmlReadComplete;
    763         gpphTmlNfc_Context->tReadInfo.pContext = pContext;
    764         wReadStatus = NFCSTATUS_PENDING;
    765 
    766         /* Set event to invoke Reader Thread */
    767         gpphTmlNfc_Context->tReadInfo.bEnable = 1;
    768         pthread_mutex_unlock(&gpphTmlNfc_Context->readInfoUpdateMutex);
    769 
    770         sem_post(&gpphTmlNfc_Context->rxSemaphore);
    771       } else {
    772         wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY);
    773       }
    774     } else {
    775       wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
    776     }
    777   } else {
    778     wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
    779   }
    780 
    781   return wReadStatus;
    782 }
    783 
    784 /*******************************************************************************
    785 **
    786 ** Function         phTmlNfc_ReadAbort
    787 **
    788 ** Description      Aborts pending read request (if any)
    789 **
    790 ** Parameters       None
    791 **
    792 ** Returns          NFC status:
    793 **                  NFCSTATUS_SUCCESS - ongoing read operation aborted
    794 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    795 **                                                invalid
    796 **                  NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized
    797 **                  NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel read
    798 **                                                        operation
    799 **
    800 *******************************************************************************/
    801 NFCSTATUS phTmlNfc_ReadAbort(void) {
    802   NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER;
    803   gpphTmlNfc_Context->tReadInfo.bEnable = 0;
    804 
    805   /*Reset the flag to accept another Read Request */
    806   gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
    807   wStatus = NFCSTATUS_SUCCESS;
    808 
    809   return wStatus;
    810 }
    811 
    812 /*******************************************************************************
    813 **
    814 ** Function         phTmlNfc_WriteAbort
    815 **
    816 ** Description      Aborts pending write request (if any)
    817 **
    818 ** Parameters       None
    819 **
    820 ** Returns          NFC status:
    821 **                  NFCSTATUS_SUCCESS - ongoing write operation aborted
    822 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    823 **                                                invalid
    824 **                  NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized
    825 **                  NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel write
    826 **                                                        operation
    827 **
    828 *******************************************************************************/
    829 NFCSTATUS phTmlNfc_WriteAbort(void) {
    830   NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER;
    831 
    832   gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
    833   /* Stop if any retransmission is in progress */
    834   bCurrentRetryCount = 0;
    835 
    836   /* Reset the flag to accept another Write Request */
    837   gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
    838   wStatus = NFCSTATUS_SUCCESS;
    839 
    840   return wStatus;
    841 }
    842 
    843 /*******************************************************************************
    844 **
    845 ** Function         phTmlNfc_IoCtl
    846 **
    847 ** Description      Resets device when insisted by upper layer
    848 **                  Number of bytes to be read and buffer are passed by upper
    849 **                  layer
    850 **                  Enables reader thread if there are no read requests pending
    851 **                  Returns successfully once read operation is completed
    852 **                  Notifies upper layer using callback mechanism
    853 **
    854 ** Parameters       eControlCode       - control code for a specific operation
    855 **
    856 ** Returns          NFC status:
    857 **                  NFCSTATUS_SUCCESS  - ioctl command completed successfully
    858 **                  NFCSTATUS_FAILED   - ioctl command request failed
    859 **
    860 *******************************************************************************/
    861 NFCSTATUS phTmlNfc_IoCtl(phTmlNfc_ControlCode_t eControlCode) {
    862   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
    863 
    864   if (NULL == gpphTmlNfc_Context) {
    865     wStatus = NFCSTATUS_FAILED;
    866   } else {
    867     switch (eControlCode) {
    868       case phTmlNfc_e_ResetDevice: {
    869         /*Reset PN54X*/
    870         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
    871         usleep(100 * 1000);
    872         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
    873         usleep(100 * 1000);
    874         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
    875         break;
    876       }
    877       case phTmlNfc_e_EnableNormalMode: {
    878         /*Reset PN54X*/
    879         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
    880         usleep(10 * 1000);
    881         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
    882         usleep(100 * 1000);
    883         break;
    884       }
    885       case phTmlNfc_e_EnableDownloadMode: {
    886         phTmlNfc_ConfigNciPktReTx(phTmlNfc_e_DisableRetrans, 0);
    887         (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 2);
    888         usleep(100 * 1000);
    889         break;
    890       }
    891       default: {
    892         wStatus = NFCSTATUS_INVALID_PARAMETER;
    893         break;
    894       }
    895     }
    896   }
    897 
    898   return wStatus;
    899 }
    900 
    901 /*******************************************************************************
    902 **
    903 ** Function         phTmlNfc_DeferredCall
    904 **
    905 ** Description      Posts message on upper layer thread
    906 **                  upon successful read or write operation
    907 **
    908 ** Parameters       dwThreadId  - id of the thread posting message
    909 **                  ptWorkerMsg - message to be posted
    910 **
    911 ** Returns          None
    912 **
    913 *******************************************************************************/
    914 void phTmlNfc_DeferredCall(uintptr_t dwThreadId,
    915                            phLibNfc_Message_t* ptWorkerMsg) {
    916   intptr_t bPostStatus;
    917   UNUSED(dwThreadId);
    918   /* Post message on the user thread to invoke the callback function */
    919   sem_wait(&gpphTmlNfc_Context->postMsgSemaphore);
    920   bPostStatus =
    921       phDal4Nfc_msgsnd(gpphTmlNfc_Context->dwCallbackThreadId, ptWorkerMsg, 0);
    922   sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
    923 }
    924 
    925 /*******************************************************************************
    926 **
    927 ** Function         phTmlNfc_ReadDeferredCb
    928 **
    929 ** Description      Read thread call back function
    930 **
    931 ** Parameters       pParams - context provided by upper layer
    932 **
    933 ** Returns          None
    934 **
    935 *******************************************************************************/
    936 static void phTmlNfc_ReadDeferredCb(void* pParams) {
    937   /* Transaction info buffer to be passed to Callback Function */
    938   phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams;
    939 
    940   /* Reset the flag to accept another Read Request */
    941   gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
    942   gpphTmlNfc_Context->tReadInfo.pThread_Callback(
    943       gpphTmlNfc_Context->tReadInfo.pContext, pTransactionInfo);
    944 
    945   return;
    946 }
    947 
    948 /*******************************************************************************
    949 **
    950 ** Function         phTmlNfc_WriteDeferredCb
    951 **
    952 ** Description      Write thread call back function
    953 **
    954 ** Parameters       pParams - context provided by upper layer
    955 **
    956 ** Returns          None
    957 **
    958 *******************************************************************************/
    959 static void phTmlNfc_WriteDeferredCb(void* pParams) {
    960   /* Transaction info buffer to be passed to Callback Function */
    961   phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams;
    962 
    963   /* Reset the flag to accept another Write Request */
    964   gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
    965   gpphTmlNfc_Context->tWriteInfo.pThread_Callback(
    966       gpphTmlNfc_Context->tWriteInfo.pContext, pTransactionInfo);
    967 
    968   return;
    969 }
    970 
    971 void phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result) {
    972   fragmentation_enabled = result;
    973 }
    974 
    975 phTmlNfc_i2cfragmentation_t phTmlNfc_get_fragmentation_enabled() {
    976   return fragmentation_enabled;
    977 }
    978