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 #define MAX_READ_RETRY_DELAY_IN_MILLISEC (150U)
34 /* Retry Count = Standby Recovery time of NFCC / Retransmission time + 1 */
35 static uint8_t bCurrentRetryCount = (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1;
36 
37 /* Value to reset variables of TML  */
38 #define PH_TMLNFC_RESET_VALUE (0x00)
39 
40 /* Indicates a Initial or offset value */
41 #define PH_TMLNFC_VALUE_ONE (0x01)
42 
43 /* Initialize Context structure pointer used to access context structure */
44 phTmlNfc_Context_t* gpphTmlNfc_Context = NULL;
45 /* Local Function prototypes */
46 static NFCSTATUS phTmlNfc_StartThread(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) != 0) {
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   uint8_t readRetryDelay = 0;
304   /* Transaction info buffer to be passed to Callback Thread */
305   static phTmlNfc_TransactInfo_t tTransactionInfo;
306   /* Structure containing Tml callback function and parameters to be invoked
307      by the callback thread */
308   static phLibNfc_DeferredCall_t tDeferredInfo;
309   /* Initialize Message structure to post message onto Callback Thread */
310   static phLibNfc_Message_t tMsg;
311   UNUSED(pParam);
312   NXPLOG_TML_D("PN54X - Tml Reader Thread Started................\n");
313 
314   /* Writer thread loop shall be running till shutdown is invoked */
315   while (gpphTmlNfc_Context->bThreadDone) {
316     /* If Tml write is requested */
317     /* Set the variable to success initially */
318     wStatus = NFCSTATUS_SUCCESS;
319     sem_wait(&gpphTmlNfc_Context->rxSemaphore);
320 
321     /* If Tml read is requested */
322     if (1 == gpphTmlNfc_Context->tReadInfo.bEnable) {
323       NXPLOG_TML_D("PN54X - Read requested.....\n");
324       /* Set the variable to success initially */
325       wStatus = NFCSTATUS_SUCCESS;
326 
327       /* Variable to fetch the actual number of bytes read */
328       dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
329 
330       /* Read the data from the file onto the buffer */
331       if (NULL != gpphTmlNfc_Context->pDevHandle) {
332         NXPLOG_TML_D("PN54X - Invoking I2C Read.....\n");
333         dwNoBytesWrRd =
334             phTmlNfc_i2c_read(gpphTmlNfc_Context->pDevHandle, temp, 260);
335 
336         if (-1 == dwNoBytesWrRd) {
337           NXPLOG_TML_E("PN54X - Error in I2C Read.....\n");
338           if (readRetryDelay < MAX_READ_RETRY_DELAY_IN_MILLISEC) {
339             /*sleep for 30/60/90/120/150 msec between each read trial incase of read error*/
340             readRetryDelay += 30 ;
341           }
342           usleep(readRetryDelay * 1000);
343           sem_post(&gpphTmlNfc_Context->rxSemaphore);
344         } else if (dwNoBytesWrRd > 260) {
345           NXPLOG_TML_E("Numer of bytes read exceeds the limit 260.....\n");
346           readRetryDelay = 0;
347           sem_post(&gpphTmlNfc_Context->rxSemaphore);
348         } else {
349           pthread_mutex_lock(&gpphTmlNfc_Context->readInfoUpdateMutex);
350           memcpy(gpphTmlNfc_Context->tReadInfo.pBuffer, temp, dwNoBytesWrRd);
351           readRetryDelay =0;
352 
353           NXPLOG_TML_D("PN54X - I2C Read successful.....\n");
354           /* This has to be reset only after a successful read */
355           gpphTmlNfc_Context->tReadInfo.bEnable = 0;
356           if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
357               (0x00 != (gpphTmlNfc_Context->tReadInfo.pBuffer[0] & 0xE0))) {
358             NXPLOG_TML_D("PN54X - Retransmission timer stopped.....\n");
359             /* Stop Timer to prevent Retransmission */
360             uint32_t timerStatus =
361                 phOsalNfc_Timer_Stop(gpphTmlNfc_Context->dwTimerId);
362             if (NFCSTATUS_SUCCESS != timerStatus) {
363               NXPLOG_TML_E("PN54X - timer stopped returned failure.....\n");
364             } else {
365               gpphTmlNfc_Context->bWriteCbInvoked = false;
366             }
367           }
368           if (gpphTmlNfc_Context->tWriteInfo.bThreadBusy) {
369             NXPLOG_TML_D("Delay Read if write thread is busy");
370             usleep(2000); /*2ms delay to give prio to write complete */
371           }
372           /* Update the actual number of bytes read including header */
373           gpphTmlNfc_Context->tReadInfo.wLength = (uint16_t)(dwNoBytesWrRd);
374           phNxpNciHal_print_packet("RECV",
375                                    gpphTmlNfc_Context->tReadInfo.pBuffer,
376                                    gpphTmlNfc_Context->tReadInfo.wLength);
377 
378           dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
379 
380           /* Fill the Transaction info structure to be passed to Callback
381            * Function */
382           tTransactionInfo.wStatus = wStatus;
383           tTransactionInfo.pBuff = gpphTmlNfc_Context->tReadInfo.pBuffer;
384           /* Actual number of bytes read is filled in the structure */
385           tTransactionInfo.wLength = gpphTmlNfc_Context->tReadInfo.wLength;
386 
387           /* Read operation completed successfully. Post a Message onto Callback
388            * Thread*/
389           /* Prepare the message to be posted on User thread */
390           tDeferredInfo.pCallback = &phTmlNfc_ReadDeferredCb;
391           tDeferredInfo.pParameter = &tTransactionInfo;
392           tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG;
393           tMsg.pMsgData = &tDeferredInfo;
394           tMsg.Size = sizeof(tDeferredInfo);
395           pthread_mutex_unlock(&gpphTmlNfc_Context->readInfoUpdateMutex);
396           NXPLOG_TML_D("PN54X - Posting read message.....\n");
397           phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg);
398         }
399       } else {
400         NXPLOG_TML_D("PN54X -gpphTmlNfc_Context->pDevHandle is NULL");
401       }
402     } else {
403       NXPLOG_TML_D("PN54X - read request NOT enabled");
404       usleep(10 * 1000);
405     }
406   } /* End of While loop */
407 
408   return NULL;
409 }
410 
411 /*******************************************************************************
412 **
413 ** Function         phTmlNfc_TmlWriterThread
414 **
415 ** Description      Writes the requested data onto the lower layer driver
416 **
417 ** Parameters       pParam  - context provided by upper layer
418 **
419 ** Returns          None
420 **
421 *******************************************************************************/
phTmlNfc_TmlWriterThread(void * pParam)422 static void * phTmlNfc_TmlWriterThread(void* pParam) {
423   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
424   int32_t dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
425   /* Transaction info buffer to be passed to Callback Thread */
426   static phTmlNfc_TransactInfo_t tTransactionInfo;
427   /* Structure containing Tml callback function and parameters to be invoked
428      by the callback thread */
429   static phLibNfc_DeferredCall_t tDeferredInfo;
430   /* Initialize Message structure to post message onto Callback Thread */
431   static phLibNfc_Message_t tMsg;
432   /* In case of I2C Write Retry */
433   static uint16_t retry_cnt;
434   UNUSED(pParam);
435   NXPLOG_TML_D("PN54X - Tml Writer Thread Started................\n");
436 
437   /* Writer thread loop shall be running till shutdown is invoked */
438   while (gpphTmlNfc_Context->bThreadDone) {
439     NXPLOG_TML_D("PN54X - Tml Writer Thread Running................\n");
440     sem_wait(&gpphTmlNfc_Context->txSemaphore);
441     /* If Tml write is requested */
442     if (1 == gpphTmlNfc_Context->tWriteInfo.bEnable) {
443       NXPLOG_TML_D("PN54X - Write requested.....\n");
444       /* Set the variable to success initially */
445       wStatus = NFCSTATUS_SUCCESS;
446       if (NULL != gpphTmlNfc_Context->pDevHandle) {
447       retry:
448         gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
449         /* Variable to fetch the actual number of bytes written */
450         dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE;
451         /* Write the data in the buffer onto the file */
452         NXPLOG_TML_D("PN54X - Invoking I2C Write.....\n");
453         dwNoBytesWrRd =
454             phTmlNfc_i2c_write(gpphTmlNfc_Context->pDevHandle,
455                                gpphTmlNfc_Context->tWriteInfo.pBuffer,
456                                gpphTmlNfc_Context->tWriteInfo.wLength);
457 
458         /* Try I2C Write Five Times, if it fails : Raju */
459         if (-1 == dwNoBytesWrRd) {
460           if (getDownloadFlag() == true) {
461             if (retry_cnt++ < MAX_WRITE_RETRY_COUNT) {
462               NXPLOG_TML_D("PN54X - Error in I2C Write  - Retry 0x%x",
463                               retry_cnt);
464               // Add a 10 ms delay to ensure NFCC is not still in stand by mode.
465               usleep(10 * 1000);
466               goto retry;
467             }
468           }
469           NXPLOG_TML_D("PN54X - Error in I2C Write.....\n");
470           wStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED);
471         } else {
472           phNxpNciHal_print_packet("SEND",
473                                    gpphTmlNfc_Context->tWriteInfo.pBuffer,
474                                    gpphTmlNfc_Context->tWriteInfo.wLength);
475         }
476         retry_cnt = 0;
477         if (NFCSTATUS_SUCCESS == wStatus) {
478           NXPLOG_TML_D("PN54X - I2C Write successful.....\n");
479           dwNoBytesWrRd = PH_TMLNFC_VALUE_ONE;
480         }
481         /* Fill the Transaction info structure to be passed to Callback Function
482          */
483         tTransactionInfo.wStatus = wStatus;
484         tTransactionInfo.pBuff = gpphTmlNfc_Context->tWriteInfo.pBuffer;
485         /* Actual number of bytes written is filled in the structure */
486         tTransactionInfo.wLength = (uint16_t)dwNoBytesWrRd;
487 
488         /* Prepare the message to be posted on the User thread */
489         tDeferredInfo.pCallback = &phTmlNfc_WriteDeferredCb;
490         tDeferredInfo.pParameter = &tTransactionInfo;
491         /* Write operation completed successfully. Post a Message onto Callback
492          * Thread*/
493         tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG;
494         tMsg.pMsgData = &tDeferredInfo;
495         tMsg.Size = sizeof(tDeferredInfo);
496 
497         /* Check whether Retransmission needs to be started,
498          * If yes, Post message only if
499          * case 1. Message is not posted &&
500          * case 11. Write status is success ||
501          * case 12. Last retry of write is also failure
502          */
503         if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
504             (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) {
505           if (gpphTmlNfc_Context->bWriteCbInvoked == false) {
506             if ((NFCSTATUS_SUCCESS == wStatus) || (bCurrentRetryCount == 0)) {
507               NXPLOG_TML_D("PN54X - Posting Write message.....\n");
508               phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId,
509                                     &tMsg);
510               gpphTmlNfc_Context->bWriteCbInvoked = true;
511             }
512           }
513         } else {
514           NXPLOG_TML_D("PN54X - Posting Fresh Write message.....\n");
515           phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg);
516         }
517       } else {
518         NXPLOG_TML_D("PN54X - gpphTmlNfc_Context->pDevHandle is NULL");
519       }
520 
521       /* If Data packet is sent, then NO retransmission */
522       if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) &&
523           (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) {
524         NXPLOG_TML_D("PN54X - Starting timer for Retransmission case");
525         wStatus = phTmlNfc_InitiateTimer();
526         if (NFCSTATUS_SUCCESS != wStatus) {
527           /* Reset Variables used for Retransmission */
528           NXPLOG_TML_D("PN54X - Retransmission timer initiate failed");
529           gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
530           bCurrentRetryCount = 0;
531         }
532       }
533     } else {
534       NXPLOG_TML_D("PN54X - Write request NOT enabled");
535       usleep(10000);
536     }
537 
538   } /* End of While loop */
539 
540   return NULL;
541 }
542 
543 /*******************************************************************************
544 **
545 ** Function         phTmlNfc_CleanUp
546 **
547 ** Description      Clears all handles opened during TML initialization
548 **
549 ** Parameters       None
550 **
551 ** Returns          None
552 **
553 *******************************************************************************/
phTmlNfc_CleanUp(void)554 void phTmlNfc_CleanUp(void) {
555   if (NULL == gpphTmlNfc_Context) {
556     return;
557   }
558   if (NULL != gpphTmlNfc_Context->pDevHandle) {
559     (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
560     gpphTmlNfc_Context->bThreadDone = 0;
561   }
562   sem_destroy(&gpphTmlNfc_Context->rxSemaphore);
563   sem_destroy(&gpphTmlNfc_Context->txSemaphore);
564   sem_destroy(&gpphTmlNfc_Context->postMsgSemaphore);
565   phTmlNfc_i2c_close(gpphTmlNfc_Context->pDevHandle);
566   gpphTmlNfc_Context->pDevHandle = NULL;
567   /* Clear memory allocated for storing Context variables */
568   free((void*)gpphTmlNfc_Context);
569   /* Set the pointer to NULL to indicate De-Initialization */
570   gpphTmlNfc_Context = NULL;
571 
572   return;
573 }
574 
575 /*******************************************************************************
576 **
577 ** Function         phTmlNfc_Shutdown
578 **
579 ** Description      Uninitializes TML layer and hardware interface
580 **
581 ** Parameters       None
582 **
583 ** Returns          NFC status:
584 **                  NFCSTATUS_SUCCESS - TML configuration released successfully
585 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
586 **                                                invalid
587 **                  NFCSTATUS_FAILED - un-initialization failed (example: unable
588 **                                     to close interface)
589 **
590 *******************************************************************************/
phTmlNfc_Shutdown(void)591 NFCSTATUS phTmlNfc_Shutdown(void) {
592   NFCSTATUS wShutdownStatus = NFCSTATUS_SUCCESS;
593 
594   /* Check whether TML is Initialized */
595   if (NULL != gpphTmlNfc_Context) {
596     /* Reset thread variable to terminate the thread */
597     gpphTmlNfc_Context->bThreadDone = 0;
598     usleep(1000);
599     /* Clear All the resources allocated during initialization */
600     sem_post(&gpphTmlNfc_Context->rxSemaphore);
601     usleep(1000);
602     sem_post(&gpphTmlNfc_Context->txSemaphore);
603     usleep(1000);
604     sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
605     usleep(1000);
606     sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
607     usleep(1000);
608     pthread_mutex_destroy(&gpphTmlNfc_Context->readInfoUpdateMutex);
609     if (0 != pthread_join(gpphTmlNfc_Context->readerThread, (void**)NULL)) {
610       NXPLOG_TML_E("Fail to kill reader thread!");
611     }
612     if (0 != pthread_join(gpphTmlNfc_Context->writerThread, (void**)NULL)) {
613       NXPLOG_TML_E("Fail to kill writer thread!");
614     }
615     NXPLOG_TML_D("bThreadDone == 0");
616 
617   } else {
618     wShutdownStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
619   }
620 
621   return wShutdownStatus;
622 }
623 
624 /*******************************************************************************
625 **
626 ** Function         phTmlNfc_Write
627 **
628 ** Description      Asynchronously writes given data block to hardware
629 **                  interface/driver. Enables writer thread if there are no
630 **                  write requests pending. Returns successfully once writer
631 **                  thread completes write operation. Notifies upper layer using
632 **                  callback mechanism.
633 **
634 **                  NOTE:
635 **                  * it is important to post a message with id
636 **                    PH_TMLNFC_WRITE_MESSAGE to IntegrationThread after data
637 **                    has been written to PN54X
638 **                  * if CRC needs to be computed, then input buffer should be
639 **                    capable to store two more bytes apart from length of
640 **                    packet
641 **
642 ** Parameters       pBuffer - data to be sent
643 **                  wLength - length of data buffer
644 **                  pTmlWriteComplete - pointer to the function to be invoked
645 **                                      upon completion
646 **                  pContext - context provided by upper layer
647 **
648 ** Returns          NFC status:
649 **                  NFCSTATUS_PENDING - command is yet to be processed
650 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
651 **                                                invalid
652 **                  NFCSTATUS_BUSY - write request is already in progress
653 **
654 *******************************************************************************/
phTmlNfc_Write(uint8_t * pBuffer,uint16_t wLength,pphTmlNfc_TransactCompletionCb_t pTmlWriteComplete,void * pContext)655 NFCSTATUS phTmlNfc_Write(uint8_t* pBuffer, uint16_t wLength,
656                          pphTmlNfc_TransactCompletionCb_t pTmlWriteComplete,
657                          void* pContext) {
658   NFCSTATUS wWriteStatus;
659 
660   /* Check whether TML is Initialized */
661 
662   if (NULL != gpphTmlNfc_Context) {
663     if ((NULL != gpphTmlNfc_Context->pDevHandle) && (NULL != pBuffer) &&
664         (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlWriteComplete)) {
665       if (!gpphTmlNfc_Context->tWriteInfo.bThreadBusy) {
666         /* Setting the flag marks beginning of a Write Operation */
667         gpphTmlNfc_Context->tWriteInfo.bThreadBusy = true;
668         /* Copy the buffer, length and Callback function,
669            This shall be utilized while invoking the Callback function in thread
670            */
671         gpphTmlNfc_Context->tWriteInfo.pBuffer = pBuffer;
672         gpphTmlNfc_Context->tWriteInfo.wLength = wLength;
673         gpphTmlNfc_Context->tWriteInfo.pThread_Callback = pTmlWriteComplete;
674         gpphTmlNfc_Context->tWriteInfo.pContext = pContext;
675 
676         wWriteStatus = NFCSTATUS_PENDING;
677         // FIXME: If retry is going on. Stop the retry thread/timer
678         if (phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) {
679           /* Set retry count to default value */
680           // FIXME: If the timer expired there, and meanwhile we have created
681           // a new request. The expired timer will think that retry is still
682           // ongoing.
683           bCurrentRetryCount = gpphTmlNfc_Context->bRetryCount;
684           gpphTmlNfc_Context->bWriteCbInvoked = false;
685         }
686         /* Set event to invoke Writer Thread */
687         gpphTmlNfc_Context->tWriteInfo.bEnable = 1;
688         sem_post(&gpphTmlNfc_Context->txSemaphore);
689       } else {
690         wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY);
691       }
692     } else {
693       wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
694     }
695   } else {
696     wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
697   }
698 
699   return wWriteStatus;
700 }
701 
702 /*******************************************************************************
703 **
704 ** Function         phTmlNfc_UpdateReadCompleteCallback
705 **
706 ** Description      Updates the callback to be invoked after read completed
707 **
708 ** Parameters       pTmlReadComplete - pointer to the function to be invoked
709 **                                     upon completion of read operation
710 **
711 ** Returns          NFC status:
712 **                  NFCSTATUS_SUCCESS - if TmlNfc context available
713 **                  NFCSTATUS_FAILED - otherwise
714 **
715 *******************************************************************************/
phTmlNfc_UpdateReadCompleteCallback(pphTmlNfc_TransactCompletionCb_t pTmlReadComplete)716 NFCSTATUS phTmlNfc_UpdateReadCompleteCallback (
717     pphTmlNfc_TransactCompletionCb_t pTmlReadComplete) {
718   NFCSTATUS wStatus = NFCSTATUS_FAILED;
719   if ((NULL != gpphTmlNfc_Context) && (NULL != pTmlReadComplete)) {
720     gpphTmlNfc_Context->tReadInfo.pThread_Callback = pTmlReadComplete;
721     wStatus = NFCSTATUS_SUCCESS;
722   }
723   return wStatus;
724 }
725 
726 /*******************************************************************************
727 **
728 ** Function         phTmlNfc_Read
729 **
730 ** Description      Asynchronously reads data from the driver
731 **                  Number of bytes to be read and buffer are passed by upper
732 **                  layer.
733 **                  Enables reader thread if there are no read requests pending
734 **                  Returns successfully once read operation is completed
735 **                  Notifies upper layer using callback mechanism
736 **
737 ** Parameters       pBuffer - location to send read data to the upper layer via
738 **                            callback
739 **                  wLength - length of read data buffer passed by upper layer
740 **                  pTmlReadComplete - pointer to the function to be invoked
741 **                                     upon completion of read operation
742 **                  pContext - context provided by upper layer
743 **
744 ** Returns          NFC status:
745 **                  NFCSTATUS_PENDING - command is yet to be processed
746 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
747 **                                                invalid
748 **                  NFCSTATUS_BUSY - read request is already in progress
749 **
750 *******************************************************************************/
phTmlNfc_Read(uint8_t * pBuffer,uint16_t wLength,pphTmlNfc_TransactCompletionCb_t pTmlReadComplete,void * pContext)751 NFCSTATUS phTmlNfc_Read(uint8_t* pBuffer, uint16_t wLength,
752                         pphTmlNfc_TransactCompletionCb_t pTmlReadComplete,
753                         void* pContext) {
754   NFCSTATUS wReadStatus;
755 
756   /* Check whether TML is Initialized */
757   if (NULL != gpphTmlNfc_Context) {
758     if ((gpphTmlNfc_Context->pDevHandle != NULL) && (NULL != pBuffer) &&
759         (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlReadComplete)) {
760       if (!gpphTmlNfc_Context->tReadInfo.bThreadBusy) {
761         pthread_mutex_lock(&gpphTmlNfc_Context->readInfoUpdateMutex);
762         /* Setting the flag marks beginning of a Read Operation */
763         gpphTmlNfc_Context->tReadInfo.bThreadBusy = true;
764         /* Copy the buffer, length and Callback function,
765            This shall be utilized while invoking the Callback function in thread
766            */
767         gpphTmlNfc_Context->tReadInfo.pBuffer = pBuffer;
768         gpphTmlNfc_Context->tReadInfo.wLength = wLength;
769         gpphTmlNfc_Context->tReadInfo.pThread_Callback = pTmlReadComplete;
770         gpphTmlNfc_Context->tReadInfo.pContext = pContext;
771         wReadStatus = NFCSTATUS_PENDING;
772 
773         /* Set event to invoke Reader Thread */
774         gpphTmlNfc_Context->tReadInfo.bEnable = 1;
775         pthread_mutex_unlock(&gpphTmlNfc_Context->readInfoUpdateMutex);
776 
777         sem_post(&gpphTmlNfc_Context->rxSemaphore);
778       } else {
779         wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY);
780       }
781     } else {
782       wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER);
783     }
784   } else {
785     wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED);
786   }
787 
788   return wReadStatus;
789 }
790 
791 /*******************************************************************************
792 **
793 ** Function         phTmlNfc_ReadAbort
794 **
795 ** Description      Aborts pending read request (if any)
796 **
797 ** Parameters       None
798 **
799 ** Returns          NFC status:
800 **                  NFCSTATUS_SUCCESS - ongoing read operation aborted
801 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
802 **                                                invalid
803 **                  NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized
804 **                  NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel read
805 **                                                        operation
806 **
807 *******************************************************************************/
phTmlNfc_ReadAbort(void)808 NFCSTATUS phTmlNfc_ReadAbort(void) {
809   NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER;
810   gpphTmlNfc_Context->tReadInfo.bEnable = 0;
811 
812   /*Reset the flag to accept another Read Request */
813   gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
814   wStatus = NFCSTATUS_SUCCESS;
815 
816   return wStatus;
817 }
818 
819 /*******************************************************************************
820 **
821 ** Function         phTmlNfc_WriteAbort
822 **
823 ** Description      Aborts pending write request (if any)
824 **
825 ** Parameters       None
826 **
827 ** Returns          NFC status:
828 **                  NFCSTATUS_SUCCESS - ongoing write operation aborted
829 **                  NFCSTATUS_INVALID_PARAMETER - at least one parameter is
830 **                                                invalid
831 **                  NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized
832 **                  NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel write
833 **                                                        operation
834 **
835 *******************************************************************************/
phTmlNfc_WriteAbort(void)836 NFCSTATUS phTmlNfc_WriteAbort(void) {
837   NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER;
838 
839   gpphTmlNfc_Context->tWriteInfo.bEnable = 0;
840   /* Stop if any retransmission is in progress */
841   bCurrentRetryCount = 0;
842 
843   /* Reset the flag to accept another Write Request */
844   gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
845   wStatus = NFCSTATUS_SUCCESS;
846 
847   return wStatus;
848 }
849 
850 /*******************************************************************************
851 **
852 ** Function         phTmlNfc_IoCtl
853 **
854 ** Description      Resets device when insisted by upper layer
855 **                  Number of bytes to be read and buffer are passed by upper
856 **                  layer
857 **                  Enables reader thread if there are no read requests pending
858 **                  Returns successfully once read operation is completed
859 **                  Notifies upper layer using callback mechanism
860 **
861 ** Parameters       eControlCode       - control code for a specific operation
862 **
863 ** Returns          NFC status:
864 **                  NFCSTATUS_SUCCESS  - ioctl command completed successfully
865 **                  NFCSTATUS_FAILED   - ioctl command request failed
866 **
867 *******************************************************************************/
phTmlNfc_IoCtl(phTmlNfc_ControlCode_t eControlCode)868 NFCSTATUS phTmlNfc_IoCtl(phTmlNfc_ControlCode_t eControlCode) {
869   NFCSTATUS wStatus = NFCSTATUS_SUCCESS;
870 
871   if (NULL == gpphTmlNfc_Context) {
872     wStatus = NFCSTATUS_FAILED;
873   } else {
874     switch (eControlCode) {
875       case phTmlNfc_e_ResetDevice: {
876         /*Reset PN54X*/
877         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
878         usleep(100 * 1000);
879         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
880         usleep(100 * 1000);
881         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
882         break;
883       }
884       case phTmlNfc_e_EnableNormalMode: {
885         /*Reset PN54X*/
886         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0);
887         usleep(10 * 1000);
888         phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1);
889         usleep(100 * 1000);
890         break;
891       }
892       case phTmlNfc_e_EnableDownloadMode: {
893         phTmlNfc_ConfigNciPktReTx(phTmlNfc_e_DisableRetrans, 0);
894         (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 2);
895         usleep(100 * 1000);
896         break;
897       }
898       default: {
899         wStatus = NFCSTATUS_INVALID_PARAMETER;
900         break;
901       }
902     }
903   }
904 
905   return wStatus;
906 }
907 
908 /*******************************************************************************
909 **
910 ** Function         phTmlNfc_DeferredCall
911 **
912 ** Description      Posts message on upper layer thread
913 **                  upon successful read or write operation
914 **
915 ** Parameters       dwThreadId  - id of the thread posting message
916 **                  ptWorkerMsg - message to be posted
917 **
918 ** Returns          None
919 **
920 *******************************************************************************/
phTmlNfc_DeferredCall(uintptr_t dwThreadId,phLibNfc_Message_t * ptWorkerMsg)921 void phTmlNfc_DeferredCall(uintptr_t dwThreadId,
922                            phLibNfc_Message_t* ptWorkerMsg) {
923   intptr_t bPostStatus;
924   UNUSED(dwThreadId);
925   /* Post message on the user thread to invoke the callback function */
926   sem_wait(&gpphTmlNfc_Context->postMsgSemaphore);
927   bPostStatus =
928       phDal4Nfc_msgsnd(gpphTmlNfc_Context->dwCallbackThreadId, ptWorkerMsg, 0);
929   sem_post(&gpphTmlNfc_Context->postMsgSemaphore);
930 }
931 
932 /*******************************************************************************
933 **
934 ** Function         phTmlNfc_ReadDeferredCb
935 **
936 ** Description      Read thread call back function
937 **
938 ** Parameters       pParams - context provided by upper layer
939 **
940 ** Returns          None
941 **
942 *******************************************************************************/
phTmlNfc_ReadDeferredCb(void * pParams)943 static void phTmlNfc_ReadDeferredCb(void* pParams) {
944   /* Transaction info buffer to be passed to Callback Function */
945   phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams;
946 
947   /* Reset the flag to accept another Read Request */
948   gpphTmlNfc_Context->tReadInfo.bThreadBusy = false;
949   gpphTmlNfc_Context->tReadInfo.pThread_Callback(
950       gpphTmlNfc_Context->tReadInfo.pContext, pTransactionInfo);
951 
952   return;
953 }
954 
955 /*******************************************************************************
956 **
957 ** Function         phTmlNfc_WriteDeferredCb
958 **
959 ** Description      Write thread call back function
960 **
961 ** Parameters       pParams - context provided by upper layer
962 **
963 ** Returns          None
964 **
965 *******************************************************************************/
phTmlNfc_WriteDeferredCb(void * pParams)966 static void phTmlNfc_WriteDeferredCb(void* pParams) {
967   /* Transaction info buffer to be passed to Callback Function */
968   phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams;
969 
970   /* Reset the flag to accept another Write Request */
971   gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false;
972   gpphTmlNfc_Context->tWriteInfo.pThread_Callback(
973       gpphTmlNfc_Context->tWriteInfo.pContext, pTransactionInfo);
974 
975   return;
976 }
977 
phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result)978 void phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result) {
979   fragmentation_enabled = result;
980 }
981 
phTmlNfc_get_fragmentation_enabled()982 phTmlNfc_i2cfragmentation_t phTmlNfc_get_fragmentation_enabled() {
983   return fragmentation_enabled;
984 }
985 
986 /*******************************************************************************
987 **
988 ** Function         phTmlNfc_Shutdown_CleanUp
989 **
990 ** Description      wrapper function  for shutdown  and cleanup of resources
991 **
992 ** Parameters       None
993 **
994 ** Returns          NFCSTATUS
995 **
996 *******************************************************************************/
phTmlNfc_Shutdown_CleanUp()997 NFCSTATUS phTmlNfc_Shutdown_CleanUp() {
998   NFCSTATUS wShutdownStatus = phTmlNfc_Shutdown();
999   phTmlNfc_CleanUp();
1000   return wShutdownStatus;
1001 }
1002