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 phTmlNfc_i2cfragmentation_t fragmentation_enabled = I2C_FRAGMENATATION_DISABLED;
     45 /* Local Function prototypes */
     46 static NFCSTATUS phTmlNfc_StartThread(void);
     47 static void phTmlNfc_CleanUp(void);
     48 static void phTmlNfc_ReadDeferredCb(void* pParams);
     49 static void phTmlNfc_WriteDeferredCb(void* pParams);
     50 static void phTmlNfc_TmlThread(void* pParam);
     51 static void phTmlNfc_TmlWriterThread(void* pParam);
     52 static void phTmlNfc_ReTxTimerCb(uint32_t dwTimerId, void* pContext);
     53 static NFCSTATUS phTmlNfc_InitiateTimer(void);
     54 
     55 /* Function definitions */
     56 
     57 /*******************************************************************************
     58 **
     59 ** Function         phTmlNfc_Init
     60 **
     61 ** Description      Provides initialization of TML layer and hardware interface
     62 **                  Configures given hardware interface and sends handle to the
     63 **                  caller
     64 **
     65 ** Parameters       pConfig - TML configuration details as provided by the upper
     66 **                            layer
     67 **
     68 ** Returns          NFC status:
     69 **                  NFCSTATUS_SUCCESS - initialization successful
     70 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
     71 **                                                invalid
     72 **                  NFCSTATUS_FAILED - initialization failed (for example,
     73 **                                     unable to open hardware interface)
     74 **                  NFCSTATUS_INVALID_DEVICE - device has not been opened or has
     75 **                                             been disconnected
     76 **
     77 *******************************************************************************/
     78 NFCSTATUS phTmlNfc_Init(pphTmlNfc_Config_t pConfig) {
     79   NFCSTATUS wInitStatus = NFCSTATUS_SUCCESS;
     80 
     81   /* Check if TML layer is already Initialized */
     82   if (NULL != gpphTmlNfc_Context) {
     83     /* TML initialization is already completed */
     84     wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_ALREADY_INITIALISED);
     85   }
     86   /* Validate Input parameters */
     87   else if ((NULL == pConfig) ||
     88            (PH_TMLNFC_RESET_VALUE == pConfig->dwGetMsgThreadId)) {
     89     /*Parameters passed to TML init are wrong */
     90     wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
     91   } else {
     92     /* Allocate memory for TML context */
     93     gpphTmlNfc_Context = malloc(sizeof(phTmlNfc_Context_t));
     94 
     95     if (NULL == gpphTmlNfc_Context) {
     96       wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
     97     } else {
     98       /* Initialise all the internal TML variables */
     99       memset(gpphTmlNfc_Context, PH_TMLNFC_RESET_VALUE,
    100              sizeof(phTmlNfc_Context_t));
    101       /* Make sure that the thread runs once it is created */
    102       gpphTmlNfc_Context->bThreadDone = 1;
    103 
    104       /* Open the device file to which data is read/written */
    105       wInitStatus = phTmlNfc_i2c_open_and_configure(
    106           pConfig, &(gpphTmlNfc_Context->pDevHandle));
    107 
    108       if (NFCSTATUS_SUCCESS != wInitStatus) {
    109         wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_DEVICE);
    110         gpphTmlNfc_Context->pDevHandle = NULL;
    111       } else {
    112         gpphTmlNfc_Context->tReadInfo.bEnable = 0;
    113         gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
    114         gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
    115         gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
    116 
    117         if (0 != sem_init(&gpphTmlNfc_Context->rxSemaphore, 0, 0)) {
    118           wInitStatus = NFCSTATUS_FAILED;
    119         } else if (0 != sem_init(&gpphTmlNfc_Context->txSemaphore, 0, 0)) {
    120           wInitStatus = NFCSTATUS_FAILED;
    121         } else if (0 != sem_init(&gpphTmlNfc_Context->postMsgSemaphore, 0, 0)) {
    122           wInitStatus = NFCSTATUS_FAILED;
    123         } else {
    124           sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
    125           /* Start TML thread (to handle write and read operations) */
    126           if (NFCSTATUS_SUCCESS != phTmlNfc_StartThread()) {
    127             wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
    128           } else {
    129             /* Create Timer used for Retransmission of NCI packets */
    130             gpphTmlNfc_Context->dwTimerId = phOsalNfc_Timer_Create();
    131             if (PH_OSALNFC_TIMER_ID_INVALID != gpphTmlNfc_Context->dwTimerId) {
    132               /* Store the Thread Identifier to which Message is to be posted */
    133               gpphTmlNfc_Context->dwCallbackThreadId =
    134                   pConfig->dwGetMsgThreadId;
    135               /* Enable retransmission of Nci packet & set retry count to
    136                * default */
    137               gpphTmlNfc_Context->eConfig = phTmlNfc_e_DisableRetrans;
    138               /* Retry Count = Standby Recovery time of NFCC / Retransmission
    139                * time + 1 */
    140               gpphTmlNfc_Context->bRetryCount =
    141                   (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1;
    142               gpphTmlNfc_Context->bWriteCbInvoked = false;
    143             } else {
    144               wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
    145             }
    146           }
    147         }
    148       }
    149     }
    150   }
    151   /* Clean up all the TML resources if any error */
    152   if (NFCSTATUS_SUCCESS != wInitStatus) {
    153     /* Clear all handles and memory locations initialized during init */
    154     phTmlNfc_CleanUp();
    155   }
    156 
    157   return wInitStatus;
    158 }
    159 
    160 /*******************************************************************************
    161 **
    162 ** Function         phTmlNfc_ConfigNciPktReTx
    163 **
    164 ** Description      Provides Enable/Disable Retransmission of NCI packets
    165 **                  Needed in case of Timeout between Transmission and Reception
    166 **                  of NCI packets. Retransmission can be enabled only if
    167 **                  standby mode is enabled
    168 **
    169 ** Parameters       eConfig - values from phTmlNfc_ConfigRetrans_t
    170 **                  bRetryCount - Number of times Nci packets shall be
    171 **                                retransmitted (default = 3)
    172 **
    173 ** Returns          None
    174 **
    175 *******************************************************************************/
    176 void phTmlNfc_ConfigNciPktReTx(phTmlNfc_ConfigRetrans_t eConfiguration,
    177                                uint8_t bRetryCounter) {
    178   /* Enable/Disable Retransmission */
    179 
    180   gpphTmlNfc_Context->eConfig = eConfiguration;
    181   if (phTmlNfc_e_EnableRetrans == eConfiguration) {
    182     /* Check whether Retry counter passed is valid */
    183     if (0 != bRetryCounter) {
    184       gpphTmlNfc_Context->bRetryCount = bRetryCounter;
    185     }
    186     /* Set retry counter to its default value */
    187     else {
    188       /* Retry Count = Standby Recovery time of NFCC / Retransmission time + 1
    189        */
    190       gpphTmlNfc_Context->bRetryCount =
    191           (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1;
    192     }
    193   }
    194 
    195   return;
    196 }
    197 
    198 /*******************************************************************************
    199 **
    200 ** Function         phTmlNfc_StartThread
    201 **
    202 ** Description      Initializes comport, reader and writer threads
    203 **
    204 ** Parameters       None
    205 **
    206 ** Returns          NFC status:
    207 **                  NFCSTATUS_SUCCESS - threads initialized successfully
    208 **                  NFCSTATUS_FAILED - initialization failed due to system error
    209 **
    210 *******************************************************************************/
    211 static NFCSTATUS phTmlNfc_StartThread(void) {
    212   NFCSTATUS wStartStatus = NFCSTATUS_SUCCESS;
    213   void* h_threadsEvent = 0x00;
    214   uint32_t dwEvent;
    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                      (void*)&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                        (void*)&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           memcpy(gpphTmlNfc_Context->tReadInfo.pBuffer, temp, dwNoBytesWrRd);
    343 
    344           NXPLOG_TML_D("PN54X - I2C Read successful.....\n");
    345           /* This has to be reset only after a successful read */
    346           gpphTmlNfc_Context->tReadInfo.bEnable = 0;
    347           if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
    348               (0x00 != (gpphTmlNfc_Context->tReadInfo.pBuffer[0] & 0xE0))) {
    349             NXPLOG_TML_D("PN54X - Retransmission timer stopped.....\n");
    350             /* Stop Timer to prevent Retransmission */
    351             uint32_t timerStatus =
    352                 phOsalNfc_Timer_Stop(gpphTmlNfc_Context->dwTimerId);
    353             if (NFCSTATUS_SUCCESS != timerStatus) {
    354               NXPLOG_TML_E("PN54X - timer stopped returned failure.....\n");
    355             } else {
    356               gpphTmlNfc_Context->bWriteCbInvoked = false;
    357             }
    358           }
    359           if (gpphTmlNfc_Context->tWriteInfo.bThreadBusy) {
    360             NXPLOG_TML_D("Delay Read if write thread is busy");
    361             usleep(2000); /*2ms delay to give prio to write complete */
    362           }
    363           /* Update the actual number of bytes read including header */
    364           gpphTmlNfc_Context->tReadInfo.wLength = (uint16_t)(dwNoBytesWrRd);
    365           phNxpNciHal_print_packet("RECV",
    366                                    gpphTmlNfc_Context->tReadInfo.pBuffer,
    367                                    gpphTmlNfc_Context->tReadInfo.wLength);
    368 
    369           dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
    370 
    371           /* Fill the Transaction info structure to be passed to Callback
    372            * Function */
    373           tTransactionInfo.wStatus = wStatus;
    374           tTransactionInfo.pBuff = gpphTmlNfc_Context->tReadInfo.pBuffer;
    375           /* Actual number of bytes read is filled in the structure */
    376           tTransactionInfo.wLength = gpphTmlNfc_Context->tReadInfo.wLength;
    377 
    378           /* Read operation completed successfully. Post a Message onto Callback
    379            * Thread*/
    380           /* Prepare the message to be posted on User thread */
    381           tDeferredInfo.pCallback = &phTmlNfc_ReadDeferredCb;
    382           tDeferredInfo.pParameter = &tTransactionInfo;
    383           tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG;
    384           tMsg.pMsgData = &tDeferredInfo;
    385           tMsg.Size = sizeof(tDeferredInfo);
    386           NXPLOG_TML_D("PN54X - Posting read message.....\n");
    387           phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg);
    388         }
    389       } else {
    390         NXPLOG_TML_D("PN54X -gpphTmlNfc_Context->pDevHandle is NULL");
    391       }
    392     } else {
    393       NXPLOG_TML_D("PN54X - read request NOT enabled");
    394       usleep(10 * 1000);
    395     }
    396   } /* End of While loop */
    397 
    398   return;
    399 }
    400 
    401 /*******************************************************************************
    402 **
    403 ** Function         phTmlNfc_TmlWriterThread
    404 **
    405 ** Description      Writes the requested data onto the lower layer driver
    406 **
    407 ** Parameters       pParam  - context provided by upper layer
    408 **
    409 ** Returns          None
    410 **
    411 *******************************************************************************/
    412 static void phTmlNfc_TmlWriterThread(void* pParam) {
    413   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
    414   int32_t dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
    415   /* Transaction info buffer to be passed to Callback Thread */
    416   static phTmlNfc_TransactInfo_t tTransactionInfo;
    417   /* Structure containing Tml callback function and parameters to be invoked
    418      by the callback thread */
    419   static phLibNfc_DeferredCall_t tDeferredInfo;
    420   /* Initialize Message structure to post message onto Callback Thread */
    421   static phLibNfc_Message_t tMsg;
    422   /* In case of I2C Write Retry */
    423   static uint16_t retry_cnt;
    424   UNUSED(pParam);
    425   NXPLOG_TML_D("PN54X - Tml Writer Thread Started................\n");
    426 
    427   /* Writer thread loop shall be running till shutdown is invoked */
    428   while (gpphTmlNfc_Context->bThreadDone) {
    429     NXPLOG_TML_D("PN54X - Tml Writer Thread Running................\n");
    430     sem_wait(&gpphTmlNfc_Context->txSemaphore);
    431     /* If Tml write is requested */
    432     if (1 == gpphTmlNfc_Context->tWriteInfo.bEnable) {
    433       NXPLOG_TML_D("PN54X - Write requested.....\n");
    434       /* Set the variable to success initially */
    435       wStatus = NFCSTATUS_SUCCESS;
    436       if (NULL != gpphTmlNfc_Context->pDevHandle) {
    437       retry:
    438         gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
    439         /* Variable to fetch the actual number of bytes written */
    440         dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
    441         /* Write the data in the buffer onto the file */
    442         NXPLOG_TML_D("PN54X - Invoking I2C Write.....\n");
    443         dwNoBytesWrRd =
    444             phTmlNfc_i2c_write(gpphTmlNfc_Context->pDevHandle,
    445                                gpphTmlNfc_Context->tWriteInfo.pBuffer,
    446                                gpphTmlNfc_Context->tWriteInfo.wLength);
    447 
    448         /* Try I2C Write Five Times, if it fails : Raju */
    449         if (-1 == dwNoBytesWrRd) {
    450           if (getDownloadFlag() == true) {
    451             if (retry_cnt++ < MAX_WRITE_RETRY_COUNT) {
    452               NXPLOG_NCIHAL_E("PN54X - Error in I2C Write  - Retry 0x%x",
    453                               retry_cnt);
    454               // Add a 10 ms delay to ensure NFCC is not still in stand by mode.
    455               usleep(10 * 1000);
    456               goto retry;
    457             }
    458           }
    459           NXPLOG_TML_E("PN54X - Error in I2C Write.....\n");
    460           wStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
    461         } else {
    462           phNxpNciHal_print_packet("SEND",
    463                                    gpphTmlNfc_Context->tWriteInfo.pBuffer,
    464                                    gpphTmlNfc_Context->tWriteInfo.wLength);
    465         }
    466         retry_cnt = 0;
    467         if (NFCSTATUS_SUCCESS == wStatus) {
    468           NXPLOG_TML_D("PN54X - I2C Write successful.....\n");
    469           dwNoBytesWrRd = PH_TMLNFC_VALUE_ONE;
    470         }
    471         /* Fill the Transaction info structure to be passed to Callback Function
    472          */
    473         tTransactionInfo.wStatus = wStatus;
    474         tTransactionInfo.pBuff = gpphTmlNfc_Context->tWriteInfo.pBuffer;
    475         /* Actual number of bytes written is filled in the structure */
    476         tTransactionInfo.wLength = (uint16_t)dwNoBytesWrRd;
    477 
    478         /* Prepare the message to be posted on the User thread */
    479         tDeferredInfo.pCallback = &phTmlNfc_WriteDeferredCb;
    480         tDeferredInfo.pParameter = &tTransactionInfo;
    481         /* Write operation completed successfully. Post a Message onto Callback
    482          * Thread*/
    483         tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG;
    484         tMsg.pMsgData = &tDeferredInfo;
    485         tMsg.Size = sizeof(tDeferredInfo);
    486 
    487         /* Check whether Retransmission needs to be started,
    488          * If yes, Post message only if
    489          * case 1. Message is not posted &&
    490          * case 11. Write status is success ||
    491          * case 12. Last retry of write is also failure
    492          */
    493         if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
    494             (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) {
    495           if (gpphTmlNfc_Context->bWriteCbInvoked == false) {
    496             if ((NFCSTATUS_SUCCESS == wStatus) || (bCurrentRetryCount == 0)) {
    497               NXPLOG_TML_D("PN54X - Posting Write message.....\n");
    498               phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId,
    499                                     &tMsg);
    500               gpphTmlNfc_Context->bWriteCbInvoked = true;
    501             }
    502           }
    503         } else {
    504           NXPLOG_TML_D("PN54X - Posting Fresh Write message.....\n");
    505           phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg);
    506         }
    507       } else {
    508         NXPLOG_TML_D("PN54X - gpphTmlNfc_Context->pDevHandle is NULL");
    509       }
    510 
    511       /* If Data packet is sent, then NO retransmission */
    512       if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
    513           (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) {
    514         NXPLOG_TML_D("PN54X - Starting timer for Retransmission case");
    515         wStatus = phTmlNfc_InitiateTimer();
    516         if (NFCSTATUS_SUCCESS != wStatus) {
    517           /* Reset Variables used for Retransmission */
    518           NXPLOG_TML_D("PN54X - Retransmission timer initiate failed");
    519           gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
    520           bCurrentRetryCount = 0;
    521         }
    522       }
    523     } else {
    524       NXPLOG_TML_D("PN54X - Write request NOT enabled");
    525       usleep(10000);
    526     }
    527 
    528   } /* End of While loop */
    529 
    530   return;
    531 }
    532 
    533 /*******************************************************************************
    534 **
    535 ** Function         phTmlNfc_CleanUp
    536 **
    537 ** Description      Clears all handles opened during TML initialization
    538 **
    539 ** Parameters       None
    540 **
    541 ** Returns          None
    542 **
    543 *******************************************************************************/
    544 static void phTmlNfc_CleanUp(void) {
    545   NFCSTATUS wRetval = NFCSTATUS_SUCCESS;
    546 
    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     if (0 != pthread_join(gpphTmlNfc_Context->readerThread, (void**)NULL)) {
    601       NXPLOG_TML_E("Fail to kill reader thread!");
    602     }
    603     if (0 != pthread_join(gpphTmlNfc_Context->writerThread, (void**)NULL)) {
    604       NXPLOG_TML_E("Fail to kill writer thread!");
    605     }
    606     NXPLOG_TML_D("bThreadDone == 0");
    607 
    608     phTmlNfc_CleanUp();
    609   } else {
    610     wShutdownStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
    611   }
    612 
    613   return wShutdownStatus;
    614 }
    615 
    616 /*******************************************************************************
    617 **
    618 ** Function         phTmlNfc_Write
    619 **
    620 ** Description      Asynchronously writes given data block to hardware
    621 **                  interface/driver. Enables writer thread if there are no
    622 **                  write requests pending. Returns successfully once writer
    623 **                  thread completes write operation. Notifies upper layer using
    624 **                  callback mechanism.
    625 **
    626 **                  NOTE:
    627 **                  * it is important to post a message with id
    628 **                    PH_TMLNFC_WRITE_MESSAGE to IntegrationThread after data
    629 **                    has been written to PN54X
    630 **                  * if CRC needs to be computed, then input buffer should be
    631 **                    capable to store two more bytes apart from length of
    632 **                    packet
    633 **
    634 ** Parameters       pBuffer - data to be sent
    635 **                  wLength - length of data buffer
    636 **                  pTmlWriteComplete - pointer to the function to be invoked
    637 **                                      upon completion
    638 **                  pContext - context provided by upper layer
    639 **
    640 ** Returns          NFC status:
    641 **                  NFCSTATUS_PENDING - command is yet to be processed
    642 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    643 **                                                invalid
    644 **                  NFCSTATUS_BUSY - write request is already in progress
    645 **
    646 *******************************************************************************/
    647 NFCSTATUS phTmlNfc_Write(uint8_t* pBuffer, uint16_t wLength,
    648                          pphTmlNfc_TransactCompletionCb_t pTmlWriteComplete,
    649                          void* pContext) {
    650   NFCSTATUS wWriteStatus;
    651 
    652   /* Check whether TML is Initialized */
    653 
    654   if (NULL != gpphTmlNfc_Context) {
    655     if ((NULL != gpphTmlNfc_Context->pDevHandle) && (NULL != pBuffer) &&
    656         (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlWriteComplete)) {
    657       if (!gpphTmlNfc_Context->tWriteInfo.bThreadBusy) {
    658         /* Setting the flag marks beginning of a Write Operation */
    659         gpphTmlNfc_Context->tWriteInfo.bThreadBusy = true;
    660         /* Copy the buffer, length and Callback function,
    661            This shall be utilized while invoking the Callback function in thread
    662            */
    663         gpphTmlNfc_Context->tWriteInfo.pBuffer = pBuffer;
    664         gpphTmlNfc_Context->tWriteInfo.wLength = wLength;
    665         gpphTmlNfc_Context->tWriteInfo.pThread_Callback = pTmlWriteComplete;
    666         gpphTmlNfc_Context->tWriteInfo.pContext = pContext;
    667 
    668         wWriteStatus = NFCSTATUS_PENDING;
    669         // FIXME: If retry is going on. Stop the retry thread/timer
    670         if (phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) {
    671           /* Set retry count to default value */
    672           // FIXME: If the timer expired there, and meanwhile we have created
    673           // a new request. The expired timer will think that retry is still
    674           // ongoing.
    675           bCurrentRetryCount = gpphTmlNfc_Context->bRetryCount;
    676           gpphTmlNfc_Context->bWriteCbInvoked = false;
    677         }
    678         /* Set event to invoke Writer Thread */
    679         gpphTmlNfc_Context->tWriteInfo.bEnable = 1;
    680         sem_post(&gpphTmlNfc_Context->txSemaphore);
    681       } else {
    682         wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY);
    683       }
    684     } else {
    685       wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
    686     }
    687   } else {
    688     wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
    689   }
    690 
    691   return wWriteStatus;
    692 }
    693 
    694 /*******************************************************************************
    695 **
    696 ** Function         phTmlNfc_Read
    697 **
    698 ** Description      Asynchronously reads data from the driver
    699 **                  Number of bytes to be read and buffer are passed by upper
    700 **                  layer.
    701 **                  Enables reader thread if there are no read requests pending
    702 **                  Returns successfully once read operation is completed
    703 **                  Notifies upper layer using callback mechanism
    704 **
    705 ** Parameters       pBuffer - location to send read data to the upper layer via
    706 **                            callback
    707 **                  wLength - length of read data buffer passed by upper layer
    708 **                  pTmlReadComplete - pointer to the function to be invoked
    709 **                                     upon completion of read operation
    710 **                  pContext - context provided by upper layer
    711 **
    712 ** Returns          NFC status:
    713 **                  NFCSTATUS_PENDING - command is yet to be processed
    714 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    715 **                                                invalid
    716 **                  NFCSTATUS_BUSY - read request is already in progress
    717 **
    718 *******************************************************************************/
    719 NFCSTATUS phTmlNfc_Read(uint8_t* pBuffer, uint16_t wLength,
    720                         pphTmlNfc_TransactCompletionCb_t pTmlReadComplete,
    721                         void* pContext) {
    722   NFCSTATUS wReadStatus;
    723 
    724   /* Check whether TML is Initialized */
    725   if (NULL != gpphTmlNfc_Context) {
    726     if ((gpphTmlNfc_Context->pDevHandle != NULL) && (NULL != pBuffer) &&
    727         (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlReadComplete)) {
    728       if (!gpphTmlNfc_Context->tReadInfo.bThreadBusy) {
    729         /* Setting the flag marks beginning of a Read Operation */
    730         gpphTmlNfc_Context->tReadInfo.bThreadBusy = true;
    731         /* Copy the buffer, length and Callback function,
    732            This shall be utilized while invoking the Callback function in thread
    733            */
    734         gpphTmlNfc_Context->tReadInfo.pBuffer = pBuffer;
    735         gpphTmlNfc_Context->tReadInfo.wLength = wLength;
    736         gpphTmlNfc_Context->tReadInfo.pThread_Callback = pTmlReadComplete;
    737         gpphTmlNfc_Context->tReadInfo.pContext = pContext;
    738         wReadStatus = NFCSTATUS_PENDING;
    739 
    740         /* Set event to invoke Reader Thread */
    741         gpphTmlNfc_Context->tReadInfo.bEnable = 1;
    742         sem_post(&gpphTmlNfc_Context->rxSemaphore);
    743       } else {
    744         wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY);
    745       }
    746     } else {
    747       wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
    748     }
    749   } else {
    750     wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
    751   }
    752 
    753   return wReadStatus;
    754 }
    755 
    756 /*******************************************************************************
    757 **
    758 ** Function         phTmlNfc_ReadAbort
    759 **
    760 ** Description      Aborts pending read request (if any)
    761 **
    762 ** Parameters       None
    763 **
    764 ** Returns          NFC status:
    765 **                  NFCSTATUS_SUCCESS - ongoing read operation aborted
    766 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    767 **                                                invalid
    768 **                  NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized
    769 **                  NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel read
    770 **                                                        operation
    771 **
    772 *******************************************************************************/
    773 NFCSTATUS phTmlNfc_ReadAbort(void) {
    774   NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER;
    775   gpphTmlNfc_Context->tReadInfo.bEnable = 0;
    776 
    777   /*Reset the flag to accept another Read Request */
    778   gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
    779   wStatus = NFCSTATUS_SUCCESS;
    780 
    781   return wStatus;
    782 }
    783 
    784 /*******************************************************************************
    785 **
    786 ** Function         phTmlNfc_WriteAbort
    787 **
    788 ** Description      Aborts pending write request (if any)
    789 **
    790 ** Parameters       None
    791 **
    792 ** Returns          NFC status:
    793 **                  NFCSTATUS_SUCCESS - ongoing write 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 write
    798 **                                                        operation
    799 **
    800 *******************************************************************************/
    801 NFCSTATUS phTmlNfc_WriteAbort(void) {
    802   NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER;
    803 
    804   gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
    805   /* Stop if any retransmission is in progress */
    806   bCurrentRetryCount = 0;
    807 
    808   /* Reset the flag to accept another Write Request */
    809   gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
    810   wStatus = NFCSTATUS_SUCCESS;
    811 
    812   return wStatus;
    813 }
    814 
    815 /*******************************************************************************
    816 **
    817 ** Function         phTmlNfc_IoCtl
    818 **
    819 ** Description      Resets device when insisted by upper layer
    820 **                  Number of bytes to be read and buffer are passed by upper
    821 **                  layer
    822 **                  Enables reader thread if there are no read requests pending
    823 **                  Returns successfully once read operation is completed
    824 **                  Notifies upper layer using callback mechanism
    825 **
    826 ** Parameters       eControlCode       - control code for a specific operation
    827 **
    828 ** Returns          NFC status:
    829 **                  NFCSTATUS_SUCCESS  - ioctl command completed successfully
    830 **                  NFCSTATUS_FAILED   - ioctl command request failed
    831 **
    832 *******************************************************************************/
    833 NFCSTATUS phTmlNfc_IoCtl(phTmlNfc_ControlCode_t eControlCode) {
    834   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
    835 
    836   if (NULL == gpphTmlNfc_Context) {
    837     wStatus = NFCSTATUS_FAILED;
    838   } else {
    839     switch (eControlCode) {
    840       case phTmlNfc_e_ResetDevice: {
    841         /*Reset PN54X*/
    842         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
    843         usleep(100 * 1000);
    844         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
    845         usleep(100 * 1000);
    846         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
    847         break;
    848       }
    849       case phTmlNfc_e_EnableNormalMode: {
    850         /*Reset PN54X*/
    851         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
    852         usleep(10 * 1000);
    853         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
    854         usleep(100 * 1000);
    855         break;
    856       }
    857       case phTmlNfc_e_EnableDownloadMode: {
    858         phTmlNfc_ConfigNciPktReTx(phTmlNfc_e_DisableRetrans, 0);
    859         (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 2);
    860         usleep(100 * 1000);
    861         break;
    862       }
    863       default: {
    864         wStatus = NFCSTATUS_INVALID_PARAMETER;
    865         break;
    866       }
    867     }
    868   }
    869 
    870   return wStatus;
    871 }
    872 
    873 /*******************************************************************************
    874 **
    875 ** Function         phTmlNfc_DeferredCall
    876 **
    877 ** Description      Posts message on upper layer thread
    878 **                  upon successful read or write operation
    879 **
    880 ** Parameters       dwThreadId  - id of the thread posting message
    881 **                  ptWorkerMsg - message to be posted
    882 **
    883 ** Returns          None
    884 **
    885 *******************************************************************************/
    886 void phTmlNfc_DeferredCall(uintptr_t dwThreadId,
    887                            phLibNfc_Message_t* ptWorkerMsg) {
    888   intptr_t bPostStatus;
    889   UNUSED(dwThreadId);
    890   /* Post message on the user thread to invoke the callback function */
    891   sem_wait(&gpphTmlNfc_Context->postMsgSemaphore);
    892   bPostStatus =
    893       phDal4Nfc_msgsnd(gpphTmlNfc_Context->dwCallbackThreadId, ptWorkerMsg, 0);
    894   sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
    895 }
    896 
    897 /*******************************************************************************
    898 **
    899 ** Function         phTmlNfc_ReadDeferredCb
    900 **
    901 ** Description      Read thread call back function
    902 **
    903 ** Parameters       pParams - context provided by upper layer
    904 **
    905 ** Returns          None
    906 **
    907 *******************************************************************************/
    908 static void phTmlNfc_ReadDeferredCb(void* pParams) {
    909   /* Transaction info buffer to be passed to Callback Function */
    910   phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams;
    911 
    912   /* Reset the flag to accept another Read Request */
    913   gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
    914   gpphTmlNfc_Context->tReadInfo.pThread_Callback(
    915       gpphTmlNfc_Context->tReadInfo.pContext, pTransactionInfo);
    916 
    917   return;
    918 }
    919 
    920 /*******************************************************************************
    921 **
    922 ** Function         phTmlNfc_WriteDeferredCb
    923 **
    924 ** Description      Write thread call back function
    925 **
    926 ** Parameters       pParams - context provided by upper layer
    927 **
    928 ** Returns          None
    929 **
    930 *******************************************************************************/
    931 static void phTmlNfc_WriteDeferredCb(void* pParams) {
    932   /* Transaction info buffer to be passed to Callback Function */
    933   phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams;
    934 
    935   /* Reset the flag to accept another Write Request */
    936   gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
    937   gpphTmlNfc_Context->tWriteInfo.pThread_Callback(
    938       gpphTmlNfc_Context->tWriteInfo.pContext, pTransactionInfo);
    939 
    940   return;
    941 }
    942 
    943 void phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result) {
    944   fragmentation_enabled = result;
    945 }
    946 
    947 phTmlNfc_i2cfragmentation_t phTmlNfc_get_fragmentation_enabled() {
    948   return fragmentation_enabled;
    949 }
    950