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