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               goto retry;
    455             }
    456           }
    457           NXPLOG_TML_E("PN54X - Error in I2C Write.....\n");
    458           wStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
    459         } else {
    460           phNxpNciHal_print_packet("SEND",
    461                                    gpphTmlNfc_Context->tWriteInfo.pBuffer,
    462                                    gpphTmlNfc_Context->tWriteInfo.wLength);
    463         }
    464         retry_cnt = 0;
    465         if (NFCSTATUS_SUCCESS == wStatus) {
    466           NXPLOG_TML_D("PN54X - I2C Write successful.....\n");
    467           dwNoBytesWrRd = PH_TMLNFC_VALUE_ONE;
    468         }
    469         /* Fill the Transaction info structure to be passed to Callback Function
    470          */
    471         tTransactionInfo.wStatus = wStatus;
    472         tTransactionInfo.pBuff = gpphTmlNfc_Context->tWriteInfo.pBuffer;
    473         /* Actual number of bytes written is filled in the structure */
    474         tTransactionInfo.wLength = (uint16_t)dwNoBytesWrRd;
    475 
    476         /* Prepare the message to be posted on the User thread */
    477         tDeferredInfo.pCallback = &phTmlNfc_WriteDeferredCb;
    478         tDeferredInfo.pParameter = &tTransactionInfo;
    479         /* Write operation completed successfully. Post a Message onto Callback
    480          * Thread*/
    481         tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG;
    482         tMsg.pMsgData = &tDeferredInfo;
    483         tMsg.Size = sizeof(tDeferredInfo);
    484 
    485         /* Check whether Retransmission needs to be started,
    486          * If yes, Post message only if
    487          * case 1. Message is not posted &&
    488          * case 11. Write status is success ||
    489          * case 12. Last retry of write is also failure
    490          */
    491         if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
    492             (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) {
    493           if (gpphTmlNfc_Context->bWriteCbInvoked == false) {
    494             if ((NFCSTATUS_SUCCESS == wStatus) || (bCurrentRetryCount == 0)) {
    495               NXPLOG_TML_D("PN54X - Posting Write message.....\n");
    496               phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId,
    497                                     &tMsg);
    498               gpphTmlNfc_Context->bWriteCbInvoked = true;
    499             }
    500           }
    501         } else {
    502           NXPLOG_TML_D("PN54X - Posting Fresh Write message.....\n");
    503           phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg);
    504         }
    505       } else {
    506         NXPLOG_TML_D("PN54X - gpphTmlNfc_Context->pDevHandle is NULL");
    507       }
    508 
    509       /* If Data packet is sent, then NO retransmission */
    510       if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
    511           (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) {
    512         NXPLOG_TML_D("PN54X - Starting timer for Retransmission case");
    513         wStatus = phTmlNfc_InitiateTimer();
    514         if (NFCSTATUS_SUCCESS != wStatus) {
    515           /* Reset Variables used for Retransmission */
    516           NXPLOG_TML_D("PN54X - Retransmission timer initiate failed");
    517           gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
    518           bCurrentRetryCount = 0;
    519         }
    520       }
    521     } else {
    522       NXPLOG_TML_D("PN54X - Write request NOT enabled");
    523       usleep(10000);
    524     }
    525 
    526   } /* End of While loop */
    527 
    528   return;
    529 }
    530 
    531 /*******************************************************************************
    532 **
    533 ** Function         phTmlNfc_CleanUp
    534 **
    535 ** Description      Clears all handles opened during TML initialization
    536 **
    537 ** Parameters       None
    538 **
    539 ** Returns          None
    540 **
    541 *******************************************************************************/
    542 static void phTmlNfc_CleanUp(void) {
    543   NFCSTATUS wRetval = NFCSTATUS_SUCCESS;
    544 
    545   if (NULL == gpphTmlNfc_Context) {
    546     return;
    547   }
    548   if (NULL != gpphTmlNfc_Context->pDevHandle) {
    549     (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
    550     gpphTmlNfc_Context->bThreadDone = 0;
    551   }
    552   sem_destroy(&gpphTmlNfc_Context->rxSemaphore);
    553   sem_destroy(&gpphTmlNfc_Context->txSemaphore);
    554   sem_destroy(&gpphTmlNfc_Context->postMsgSemaphore);
    555   phTmlNfc_i2c_close(gpphTmlNfc_Context->pDevHandle);
    556   gpphTmlNfc_Context->pDevHandle = NULL;
    557   /* Clear memory allocated for storing Context variables */
    558   free((void*)gpphTmlNfc_Context);
    559   /* Set the pointer to NULL to indicate De-Initialization */
    560   gpphTmlNfc_Context = NULL;
    561 
    562   return;
    563 }
    564 
    565 /*******************************************************************************
    566 **
    567 ** Function         phTmlNfc_Shutdown
    568 **
    569 ** Description      Uninitializes TML layer and hardware interface
    570 **
    571 ** Parameters       None
    572 **
    573 ** Returns          NFC status:
    574 **                  NFCSTATUS_SUCCESS - TML configuration released successfully
    575 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    576 **                                                invalid
    577 **                  NFCSTATUS_FAILED - un-initialization failed (example: unable
    578 **                                     to close interface)
    579 **
    580 *******************************************************************************/
    581 NFCSTATUS phTmlNfc_Shutdown(void) {
    582   NFCSTATUS wShutdownStatus = NFCSTATUS_SUCCESS;
    583 
    584   /* Check whether TML is Initialized */
    585   if (NULL != gpphTmlNfc_Context) {
    586     /* Reset thread variable to terminate the thread */
    587     gpphTmlNfc_Context->bThreadDone = 0;
    588     usleep(1000);
    589     /* Clear All the resources allocated during initialization */
    590     sem_post(&gpphTmlNfc_Context->rxSemaphore);
    591     usleep(1000);
    592     sem_post(&gpphTmlNfc_Context->txSemaphore);
    593     usleep(1000);
    594     sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
    595     usleep(1000);
    596     sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
    597     usleep(1000);
    598     if (0 != pthread_join(gpphTmlNfc_Context->readerThread, (void**)NULL)) {
    599       NXPLOG_TML_E("Fail to kill reader thread!");
    600     }
    601     if (0 != pthread_join(gpphTmlNfc_Context->writerThread, (void**)NULL)) {
    602       NXPLOG_TML_E("Fail to kill writer thread!");
    603     }
    604     NXPLOG_TML_D("bThreadDone == 0");
    605 
    606     phTmlNfc_CleanUp();
    607   } else {
    608     wShutdownStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
    609   }
    610 
    611   return wShutdownStatus;
    612 }
    613 
    614 /*******************************************************************************
    615 **
    616 ** Function         phTmlNfc_Write
    617 **
    618 ** Description      Asynchronously writes given data block to hardware
    619 **                  interface/driver. Enables writer thread if there are no
    620 **                  write requests pending. Returns successfully once writer
    621 **                  thread completes write operation. Notifies upper layer using
    622 **                  callback mechanism.
    623 **
    624 **                  NOTE:
    625 **                  * it is important to post a message with id
    626 **                    PH_TMLNFC_WRITE_MESSAGE to IntegrationThread after data
    627 **                    has been written to PN54X
    628 **                  * if CRC needs to be computed, then input buffer should be
    629 **                    capable to store two more bytes apart from length of
    630 **                    packet
    631 **
    632 ** Parameters       pBuffer - data to be sent
    633 **                  wLength - length of data buffer
    634 **                  pTmlWriteComplete - pointer to the function to be invoked
    635 **                                      upon completion
    636 **                  pContext - context provided by upper layer
    637 **
    638 ** Returns          NFC status:
    639 **                  NFCSTATUS_PENDING - command is yet to be processed
    640 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    641 **                                                invalid
    642 **                  NFCSTATUS_BUSY - write request is already in progress
    643 **
    644 *******************************************************************************/
    645 NFCSTATUS phTmlNfc_Write(uint8_t* pBuffer, uint16_t wLength,
    646                          pphTmlNfc_TransactCompletionCb_t pTmlWriteComplete,
    647                          void* pContext) {
    648   NFCSTATUS wWriteStatus;
    649 
    650   /* Check whether TML is Initialized */
    651 
    652   if (NULL != gpphTmlNfc_Context) {
    653     if ((NULL != gpphTmlNfc_Context->pDevHandle) && (NULL != pBuffer) &&
    654         (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlWriteComplete)) {
    655       if (!gpphTmlNfc_Context->tWriteInfo.bThreadBusy) {
    656         /* Setting the flag marks beginning of a Write Operation */
    657         gpphTmlNfc_Context->tWriteInfo.bThreadBusy = true;
    658         /* Copy the buffer, length and Callback function,
    659            This shall be utilized while invoking the Callback function in thread
    660            */
    661         gpphTmlNfc_Context->tWriteInfo.pBuffer = pBuffer;
    662         gpphTmlNfc_Context->tWriteInfo.wLength = wLength;
    663         gpphTmlNfc_Context->tWriteInfo.pThread_Callback = pTmlWriteComplete;
    664         gpphTmlNfc_Context->tWriteInfo.pContext = pContext;
    665 
    666         wWriteStatus = NFCSTATUS_PENDING;
    667         // FIXME: If retry is going on. Stop the retry thread/timer
    668         if (phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) {
    669           /* Set retry count to default value */
    670           // FIXME: If the timer expired there, and meanwhile we have created
    671           // a new request. The expired timer will think that retry is still
    672           // ongoing.
    673           bCurrentRetryCount = gpphTmlNfc_Context->bRetryCount;
    674           gpphTmlNfc_Context->bWriteCbInvoked = false;
    675         }
    676         /* Set event to invoke Writer Thread */
    677         gpphTmlNfc_Context->tWriteInfo.bEnable = 1;
    678         sem_post(&gpphTmlNfc_Context->txSemaphore);
    679       } else {
    680         wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY);
    681       }
    682     } else {
    683       wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
    684     }
    685   } else {
    686     wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
    687   }
    688 
    689   return wWriteStatus;
    690 }
    691 
    692 /*******************************************************************************
    693 **
    694 ** Function         phTmlNfc_Read
    695 **
    696 ** Description      Asynchronously reads data from the driver
    697 **                  Number of bytes to be read and buffer are passed by upper
    698 **                  layer.
    699 **                  Enables reader thread if there are no read requests pending
    700 **                  Returns successfully once read operation is completed
    701 **                  Notifies upper layer using callback mechanism
    702 **
    703 ** Parameters       pBuffer - location to send read data to the upper layer via
    704 **                            callback
    705 **                  wLength - length of read data buffer passed by upper layer
    706 **                  pTmlReadComplete - pointer to the function to be invoked
    707 **                                     upon completion of read operation
    708 **                  pContext - context provided by upper layer
    709 **
    710 ** Returns          NFC status:
    711 **                  NFCSTATUS_PENDING - command is yet to be processed
    712 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    713 **                                                invalid
    714 **                  NFCSTATUS_BUSY - read request is already in progress
    715 **
    716 *******************************************************************************/
    717 NFCSTATUS phTmlNfc_Read(uint8_t* pBuffer, uint16_t wLength,
    718                         pphTmlNfc_TransactCompletionCb_t pTmlReadComplete,
    719                         void* pContext) {
    720   NFCSTATUS wReadStatus;
    721 
    722   /* Check whether TML is Initialized */
    723   if (NULL != gpphTmlNfc_Context) {
    724     if ((gpphTmlNfc_Context->pDevHandle != NULL) && (NULL != pBuffer) &&
    725         (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlReadComplete)) {
    726       if (!gpphTmlNfc_Context->tReadInfo.bThreadBusy) {
    727         /* Setting the flag marks beginning of a Read Operation */
    728         gpphTmlNfc_Context->tReadInfo.bThreadBusy = true;
    729         /* Copy the buffer, length and Callback function,
    730            This shall be utilized while invoking the Callback function in thread
    731            */
    732         gpphTmlNfc_Context->tReadInfo.pBuffer = pBuffer;
    733         gpphTmlNfc_Context->tReadInfo.wLength = wLength;
    734         gpphTmlNfc_Context->tReadInfo.pThread_Callback = pTmlReadComplete;
    735         gpphTmlNfc_Context->tReadInfo.pContext = pContext;
    736         wReadStatus = NFCSTATUS_PENDING;
    737 
    738         /* Set event to invoke Reader Thread */
    739         gpphTmlNfc_Context->tReadInfo.bEnable = 1;
    740         sem_post(&gpphTmlNfc_Context->rxSemaphore);
    741       } else {
    742         wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY);
    743       }
    744     } else {
    745       wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
    746     }
    747   } else {
    748     wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
    749   }
    750 
    751   return wReadStatus;
    752 }
    753 
    754 /*******************************************************************************
    755 **
    756 ** Function         phTmlNfc_ReadAbort
    757 **
    758 ** Description      Aborts pending read request (if any)
    759 **
    760 ** Parameters       None
    761 **
    762 ** Returns          NFC status:
    763 **                  NFCSTATUS_SUCCESS - ongoing read operation aborted
    764 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    765 **                                                invalid
    766 **                  NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized
    767 **                  NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel read
    768 **                                                        operation
    769 **
    770 *******************************************************************************/
    771 NFCSTATUS phTmlNfc_ReadAbort(void) {
    772   NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER;
    773   gpphTmlNfc_Context->tReadInfo.bEnable = 0;
    774 
    775   /*Reset the flag to accept another Read Request */
    776   gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
    777   wStatus = NFCSTATUS_SUCCESS;
    778 
    779   return wStatus;
    780 }
    781 
    782 /*******************************************************************************
    783 **
    784 ** Function         phTmlNfc_WriteAbort
    785 **
    786 ** Description      Aborts pending write request (if any)
    787 **
    788 ** Parameters       None
    789 **
    790 ** Returns          NFC status:
    791 **                  NFCSTATUS_SUCCESS - ongoing write operation aborted
    792 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
    793 **                                                invalid
    794 **                  NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized
    795 **                  NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel write
    796 **                                                        operation
    797 **
    798 *******************************************************************************/
    799 NFCSTATUS phTmlNfc_WriteAbort(void) {
    800   NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER;
    801 
    802   gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
    803   /* Stop if any retransmission is in progress */
    804   bCurrentRetryCount = 0;
    805 
    806   /* Reset the flag to accept another Write Request */
    807   gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
    808   wStatus = NFCSTATUS_SUCCESS;
    809 
    810   return wStatus;
    811 }
    812 
    813 /*******************************************************************************
    814 **
    815 ** Function         phTmlNfc_IoCtl
    816 **
    817 ** Description      Resets device when insisted by upper layer
    818 **                  Number of bytes to be read and buffer are passed by upper
    819 **                  layer
    820 **                  Enables reader thread if there are no read requests pending
    821 **                  Returns successfully once read operation is completed
    822 **                  Notifies upper layer using callback mechanism
    823 **
    824 ** Parameters       eControlCode       - control code for a specific operation
    825 **
    826 ** Returns          NFC status:
    827 **                  NFCSTATUS_SUCCESS  - ioctl command completed successfully
    828 **                  NFCSTATUS_FAILED   - ioctl command request failed
    829 **
    830 *******************************************************************************/
    831 NFCSTATUS phTmlNfc_IoCtl(phTmlNfc_ControlCode_t eControlCode) {
    832   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
    833 
    834   if (NULL == gpphTmlNfc_Context) {
    835     wStatus = NFCSTATUS_FAILED;
    836   } else {
    837     switch (eControlCode) {
    838       case phTmlNfc_e_ResetDevice: {
    839         /*Reset PN54X*/
    840         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
    841         usleep(100 * 1000);
    842         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
    843         usleep(100 * 1000);
    844         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
    845         break;
    846       }
    847       case phTmlNfc_e_EnableNormalMode: {
    848         /*Reset PN54X*/
    849         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
    850         usleep(10 * 1000);
    851         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
    852         usleep(100 * 1000);
    853         break;
    854       }
    855       case phTmlNfc_e_EnableDownloadMode: {
    856         phTmlNfc_ConfigNciPktReTx(phTmlNfc_e_DisableRetrans, 0);
    857         (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 2);
    858         usleep(100 * 1000);
    859         break;
    860       }
    861       default: {
    862         wStatus = NFCSTATUS_INVALID_PARAMETER;
    863         break;
    864       }
    865     }
    866   }
    867 
    868   return wStatus;
    869 }
    870 
    871 /*******************************************************************************
    872 **
    873 ** Function         phTmlNfc_DeferredCall
    874 **
    875 ** Description      Posts message on upper layer thread
    876 **                  upon successful read or write operation
    877 **
    878 ** Parameters       dwThreadId  - id of the thread posting message
    879 **                  ptWorkerMsg - message to be posted
    880 **
    881 ** Returns          None
    882 **
    883 *******************************************************************************/
    884 void phTmlNfc_DeferredCall(uintptr_t dwThreadId,
    885                            phLibNfc_Message_t* ptWorkerMsg) {
    886   intptr_t bPostStatus;
    887   UNUSED(dwThreadId);
    888   /* Post message on the user thread to invoke the callback function */
    889   sem_wait(&gpphTmlNfc_Context->postMsgSemaphore);
    890   bPostStatus =
    891       phDal4Nfc_msgsnd(gpphTmlNfc_Context->dwCallbackThreadId, ptWorkerMsg, 0);
    892   sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
    893 }
    894 
    895 /*******************************************************************************
    896 **
    897 ** Function         phTmlNfc_ReadDeferredCb
    898 **
    899 ** Description      Read thread call back function
    900 **
    901 ** Parameters       pParams - context provided by upper layer
    902 **
    903 ** Returns          None
    904 **
    905 *******************************************************************************/
    906 static void phTmlNfc_ReadDeferredCb(void* pParams) {
    907   /* Transaction info buffer to be passed to Callback Function */
    908   phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams;
    909 
    910   /* Reset the flag to accept another Read Request */
    911   gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
    912   gpphTmlNfc_Context->tReadInfo.pThread_Callback(
    913       gpphTmlNfc_Context->tReadInfo.pContext, pTransactionInfo);
    914 
    915   return;
    916 }
    917 
    918 /*******************************************************************************
    919 **
    920 ** Function         phTmlNfc_WriteDeferredCb
    921 **
    922 ** Description      Write thread call back function
    923 **
    924 ** Parameters       pParams - context provided by upper layer
    925 **
    926 ** Returns          None
    927 **
    928 *******************************************************************************/
    929 static void phTmlNfc_WriteDeferredCb(void* pParams) {
    930   /* Transaction info buffer to be passed to Callback Function */
    931   phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams;
    932 
    933   /* Reset the flag to accept another Write Request */
    934   gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
    935   gpphTmlNfc_Context->tWriteInfo.pThread_Callback(
    936       gpphTmlNfc_Context->tWriteInfo.pContext, pTransactionInfo);
    937 
    938   return;
    939 }
    940 
    941 void phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result) {
    942   fragmentation_enabled = result;
    943 }
    944 
    945 phTmlNfc_i2cfragmentation_t phTmlNfc_get_fragmentation_enabled() {
    946   return fragmentation_enabled;
    947 }
    948