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 *******************************************************************************/
phTmlNfc_Init(pphTmlNfc_Config_t pConfig)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 *******************************************************************************/
phTmlNfc_ConfigNciPktReTx(phTmlNfc_ConfigRetrans_t eConfiguration,uint8_t bRetryCounter)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 *******************************************************************************/
phTmlNfc_StartThread(void)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 *******************************************************************************/
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           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 *******************************************************************************/
phTmlNfc_TmlWriterThread(void * pParam)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 *******************************************************************************/
phTmlNfc_CleanUp(void)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 *******************************************************************************/
phTmlNfc_Shutdown(void)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 *******************************************************************************/
phTmlNfc_Write(uint8_t * pBuffer,uint16_t wLength,pphTmlNfc_TransactCompletionCb_t pTmlWriteComplete,void * pContext)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 *******************************************************************************/
phTmlNfc_Read(uint8_t * pBuffer,uint16_t wLength,pphTmlNfc_TransactCompletionCb_t pTmlReadComplete,void * pContext)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 *******************************************************************************/
phTmlNfc_ReadAbort(void)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 *******************************************************************************/
phTmlNfc_WriteAbort(void)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 *******************************************************************************/
phTmlNfc_IoCtl(phTmlNfc_ControlCode_t eControlCode)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 *******************************************************************************/
phTmlNfc_DeferredCall(uintptr_t dwThreadId,phLibNfc_Message_t * ptWorkerMsg)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 *******************************************************************************/
phTmlNfc_ReadDeferredCb(void * pParams)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 *******************************************************************************/
phTmlNfc_WriteDeferredCb(void * pParams)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 
phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result)941 void phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result) {
942   fragmentation_enabled = result;
943 }
944 
phTmlNfc_get_fragmentation_enabled()945 phTmlNfc_i2cfragmentation_t phTmlNfc_get_fragmentation_enabled() {
946   return fragmentation_enabled;
947 }
948