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 *******************************************************************************/
phTmlNfc_Init(pphTmlNfc_Config_t pConfig)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 *******************************************************************************/
phTmlNfc_ConfigNciPktReTx(phTmlNfc_ConfigRetrans_t eConfiguration,uint8_t bRetryCounter)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 *******************************************************************************/
phTmlNfc_StartThread(void)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 *******************************************************************************/
phTmlNfc_ReTxTimerCb(uint32_t dwTimerId,void * pContext)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 *******************************************************************************/
phTmlNfc_InitiateTimer(void)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 *******************************************************************************/
phTmlNfc_TmlThread(void * pParam)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 *******************************************************************************/
phTmlNfc_TmlWriterThread(void * pParam)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 *******************************************************************************/
phTmlNfc_CleanUp(void)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 *******************************************************************************/
phTmlNfc_Shutdown(void)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 *******************************************************************************/
phTmlNfc_Write(uint8_t * pBuffer,uint16_t wLength,pphTmlNfc_TransactCompletionCb_t pTmlWriteComplete,void * pContext)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 *******************************************************************************/
phTmlNfc_UpdateReadCompleteCallback(pphTmlNfc_TransactCompletionCb_t pTmlReadComplete)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 *******************************************************************************/
phTmlNfc_Read(uint8_t * pBuffer,uint16_t wLength,pphTmlNfc_TransactCompletionCb_t pTmlReadComplete,void * pContext)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 *******************************************************************************/
phTmlNfc_ReadAbort(void)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 *******************************************************************************/
phTmlNfc_WriteAbort(void)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 *******************************************************************************/
phTmlNfc_IoCtl(phTmlNfc_ControlCode_t eControlCode)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 *******************************************************************************/
phTmlNfc_DeferredCall(uintptr_t dwThreadId,phLibNfc_Message_t * ptWorkerMsg)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 *******************************************************************************/
phTmlNfc_ReadDeferredCb(void * pParams)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 *******************************************************************************/
phTmlNfc_WriteDeferredCb(void * pParams)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 
phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result)971 void phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result) {
972   fragmentation_enabled = result;
973 }
974 
phTmlNfc_get_fragmentation_enabled()975 phTmlNfc_i2cfragmentation_t phTmlNfc_get_fragmentation_enabled() {
976   return fragmentation_enabled;
977 }
978