1 /*
2  *
3  *  Copyright 2013-2023 NXP
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 #include <errno.h>
19 #include <log/log.h>
20 #include <pthread.h>
21 
22 #include <phNxpLog.h>
23 #include <phNxpNciHal.h>
24 #include <phNxpNciHal_utils.h>
25 #include "phNxpNciHal_extOperations.h"
26 
27 extern phNxpNciHal_Control_t nxpncihal_ctrl;
28 /*********************** Link list functions **********************************/
29 
30 /*******************************************************************************
31 **
32 ** Function         listInit
33 **
34 ** Description      List initialization
35 **
36 ** Returns          1, if list initialized, 0 otherwise
37 **
38 *******************************************************************************/
listInit(struct listHead * pList)39 int listInit(struct listHead* pList) {
40   pList->pFirst = NULL;
41   if (pthread_mutex_init(&pList->mutex, NULL) != 0) {
42     NXPLOG_NCIHAL_E("Mutex creation failed (errno=0x%08x)", errno);
43     return 0;
44   }
45 
46   return 1;
47 }
48 
49 /*******************************************************************************
50 **
51 ** Function         listDestroy
52 **
53 ** Description      List destruction
54 **
55 ** Returns          1, if list destroyed, 0 if failed
56 **
57 *******************************************************************************/
listDestroy(struct listHead * pList)58 int listDestroy(struct listHead* pList) {
59   int bListNotEmpty = 1;
60   while (bListNotEmpty) {
61     bListNotEmpty = listGetAndRemoveNext(pList, NULL);
62   }
63 
64   if (pthread_mutex_destroy(&pList->mutex) == -1) {
65     NXPLOG_NCIHAL_E("Mutex destruction failed (errno=0x%08x)", errno);
66     return 0;
67   }
68 
69   return 1;
70 }
71 
72 /*******************************************************************************
73 **
74 ** Function         listAdd
75 **
76 ** Description      Add a node to the list
77 **
78 ** Returns          1, if added, 0 if otherwise
79 **
80 *******************************************************************************/
listAdd(struct listHead * pList,void * pData)81 int listAdd(struct listHead* pList, void* pData) {
82   struct listNode* pNode;
83   struct listNode* pLastNode;
84   int result;
85 
86   /* Create node */
87   pNode = (struct listNode*)malloc(sizeof(struct listNode));
88   if (pNode == NULL) {
89     result = 0;
90     NXPLOG_NCIHAL_E("Failed to malloc");
91     goto clean_and_return;
92   }
93   pNode->pData = pData;
94   pNode->pNext = NULL;
95   pthread_mutex_lock(&pList->mutex);
96 
97   /* Add the node to the list */
98   if (pList->pFirst == NULL) {
99     /* Set the node as the head */
100     pList->pFirst = pNode;
101   } else {
102     /* Seek to the end of the list */
103     pLastNode = pList->pFirst;
104     while (pLastNode->pNext != NULL) {
105       pLastNode = pLastNode->pNext;
106     }
107 
108     /* Add the node to the current list */
109     pLastNode->pNext = pNode;
110   }
111 
112   result = 1;
113 
114 clean_and_return:
115   pthread_mutex_unlock(&pList->mutex);
116   return result;
117 }
118 
119 /*******************************************************************************
120 **
121 ** Function         listRemove
122 **
123 ** Description      Remove node from the list
124 **
125 ** Returns          1, if removed, 0 if otherwise
126 **
127 *******************************************************************************/
listRemove(struct listHead * pList,void * pData)128 int listRemove(struct listHead* pList, void* pData) {
129   struct listNode* pNode;
130   struct listNode* pRemovedNode;
131   int result;
132 
133   pthread_mutex_lock(&pList->mutex);
134 
135   if (pList->pFirst == NULL) {
136     /* Empty list */
137     NXPLOG_NCIHAL_D("Failed to deallocate (list empty)");
138     result = 0;
139     goto clean_and_return;
140   }
141 
142   pNode = pList->pFirst;
143   if (pList->pFirst->pData == pData) {
144     /* Get the removed node */
145     pRemovedNode = pNode;
146 
147     /* Remove the first node */
148     pList->pFirst = pList->pFirst->pNext;
149   } else {
150     while (pNode->pNext != NULL) {
151       if (pNode->pNext->pData == pData) {
152         /* Node found ! */
153         break;
154       }
155       pNode = pNode->pNext;
156     }
157 
158     if (pNode->pNext == NULL) {
159       /* Node not found */
160       result = 0;
161       NXPLOG_NCIHAL_E("Failed to deallocate (not found %8p)", pData);
162       goto clean_and_return;
163     }
164 
165     /* Get the removed node */
166     pRemovedNode = pNode->pNext;
167 
168     /* Remove the node from the list */
169     pNode->pNext = pNode->pNext->pNext;
170   }
171 
172   /* Deallocate the node */
173   free(pRemovedNode);
174 
175   result = 1;
176 
177 clean_and_return:
178   pthread_mutex_unlock(&pList->mutex);
179   return result;
180 }
181 
182 /*******************************************************************************
183 **
184 ** Function         listGetAndRemoveNext
185 **
186 ** Description      Get next node on the list and remove it
187 **
188 ** Returns          1, if successful, 0 if otherwise
189 **
190 *******************************************************************************/
listGetAndRemoveNext(struct listHead * pList,void ** ppData)191 int listGetAndRemoveNext(struct listHead* pList, void** ppData) {
192   struct listNode* pNode;
193   int result;
194 
195   pthread_mutex_lock(&pList->mutex);
196 
197   if (pList->pFirst == NULL) {
198     /* Empty list */
199     NXPLOG_NCIHAL_D("Failed to deallocate (list empty)");
200     result = 0;
201     goto clean_and_return;
202   }
203 
204   /* Work on the first node */
205   pNode = pList->pFirst;
206 
207   /* Return the data */
208   if (ppData != NULL) {
209     *ppData = pNode->pData;
210   }
211 
212   /* Remove and deallocate the node */
213   pList->pFirst = pNode->pNext;
214   free(pNode);
215 
216   result = 1;
217 
218 clean_and_return:
219   listDump(pList);
220   pthread_mutex_unlock(&pList->mutex);
221   return result;
222 }
223 
224 /*******************************************************************************
225 **
226 ** Function         listDump
227 **
228 ** Description      Dump list information
229 **
230 ** Returns          None
231 **
232 *******************************************************************************/
listDump(struct listHead * pList)233 void listDump(struct listHead* pList) {
234   struct listNode* pNode = pList->pFirst;
235 
236   NXPLOG_NCIHAL_D("Node dump:");
237   while (pNode != NULL) {
238     NXPLOG_NCIHAL_D("- %8p (%8p)", pNode, pNode->pData);
239     pNode = pNode->pNext;
240   }
241 
242   return;
243 }
244 
245 /* END Linked list source code */
246 
247 /****************** Semaphore and mutex helper functions **********************/
248 
249 static phNxpNciHal_Monitor_t* nxpncihal_monitor = NULL;
250 
251 /*******************************************************************************
252 **
253 ** Function         phNxpNciHal_init_monitor
254 **
255 ** Description      Initialize the semaphore monitor
256 **
257 ** Returns          Pointer to monitor, otherwise NULL if failed
258 **
259 *******************************************************************************/
phNxpNciHal_init_monitor(void)260 phNxpNciHal_Monitor_t* phNxpNciHal_init_monitor(void) {
261   NXPLOG_NCIHAL_D("Entering phNxpNciHal_init_monitor");
262 
263   if (nxpncihal_monitor == NULL) {
264     nxpncihal_monitor =
265         (phNxpNciHal_Monitor_t*)malloc(sizeof(phNxpNciHal_Monitor_t));
266   }
267 
268   if (nxpncihal_monitor != NULL) {
269     memset(nxpncihal_monitor, 0x00, sizeof(phNxpNciHal_Monitor_t));
270 
271     if (pthread_mutex_init(&nxpncihal_monitor->reentrance_mutex, NULL) != 0) {
272       NXPLOG_NCIHAL_E("reentrance_mutex creation returned 0x%08x", errno);
273       goto clean_and_return;
274     }
275 
276     if (pthread_mutex_init(&nxpncihal_monitor->concurrency_mutex, NULL) != 0) {
277       NXPLOG_NCIHAL_E("concurrency_mutex creation returned 0x%08x", errno);
278       pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex);
279       goto clean_and_return;
280     }
281 
282     if (listInit(&nxpncihal_monitor->sem_list) != 1) {
283       NXPLOG_NCIHAL_E("Semaphore List creation failed");
284       pthread_mutex_destroy(&nxpncihal_monitor->concurrency_mutex);
285       pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex);
286       goto clean_and_return;
287     }
288   } else {
289     NXPLOG_NCIHAL_E("nxphal_monitor creation failed");
290     goto clean_and_return;
291   }
292 
293   NXPLOG_NCIHAL_D("Returning with SUCCESS");
294 
295   return nxpncihal_monitor;
296 
297 clean_and_return:
298   NXPLOG_NCIHAL_D("Returning with FAILURE");
299 
300   if (nxpncihal_monitor != NULL) {
301     free(nxpncihal_monitor);
302     nxpncihal_monitor = NULL;
303   }
304 
305   return NULL;
306 }
307 
308 /*******************************************************************************
309 **
310 ** Function         phNxpNciHal_cleanup_monitor
311 **
312 ** Description      Clean up semaphore monitor
313 **
314 ** Returns          None
315 **
316 *******************************************************************************/
phNxpNciHal_cleanup_monitor(void)317 void phNxpNciHal_cleanup_monitor(void) {
318   if (nxpncihal_monitor != NULL) {
319     pthread_mutex_destroy(&nxpncihal_monitor->concurrency_mutex);
320     REENTRANCE_UNLOCK();
321     pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex);
322     phNxpNciHal_releaseall_cb_data();
323     listDestroy(&nxpncihal_monitor->sem_list);
324   }
325 
326   free(nxpncihal_monitor);
327   nxpncihal_monitor = NULL;
328 
329   return;
330 }
331 
332 /*******************************************************************************
333 **
334 ** Function         phNxpNciHal_get_monitor
335 **
336 ** Description      Get monitor
337 **
338 ** Returns          Pointer to monitor
339 **
340 *******************************************************************************/
phNxpNciHal_get_monitor(void)341 phNxpNciHal_Monitor_t* phNxpNciHal_get_monitor(void) {
342   if (nxpncihal_monitor == NULL) {
343     NXPLOG_NCIHAL_E("nxpncihal_monitor is null");
344   }
345   return nxpncihal_monitor;
346 }
347 
348 /* Initialize the callback data */
phNxpNciHal_init_cb_data(phNxpNciHal_Sem_t * pCallbackData,void * pContext)349 NFCSTATUS phNxpNciHal_init_cb_data(phNxpNciHal_Sem_t* pCallbackData,
350                                    void* pContext) {
351   /* Create semaphore */
352   if (sem_init(&pCallbackData->sem, 0, 0) == -1) {
353     NXPLOG_NCIHAL_E("Semaphore creation failed (errno=0x%08x)", errno);
354     return NFCSTATUS_FAILED;
355   }
356 
357   /* Set default status value */
358   pCallbackData->status = NFCSTATUS_FAILED;
359 
360   /* Copy the context */
361   pCallbackData->pContext = pContext;
362 
363   /* Add to active semaphore list */
364   if (listAdd(&phNxpNciHal_get_monitor()->sem_list, pCallbackData) != 1) {
365     NXPLOG_NCIHAL_E("Failed to add the semaphore to the list");
366   }
367 
368   return NFCSTATUS_SUCCESS;
369 }
370 
371 /*******************************************************************************
372 **
373 ** Function         phNxpNciHal_cleanup_cb_data
374 **
375 ** Description      Clean up callback data
376 **
377 ** Returns          None
378 **
379 *******************************************************************************/
phNxpNciHal_cleanup_cb_data(phNxpNciHal_Sem_t * pCallbackData)380 void phNxpNciHal_cleanup_cb_data(phNxpNciHal_Sem_t* pCallbackData) {
381   /* Destroy semaphore */
382   if (sem_destroy(&pCallbackData->sem)) {
383     NXPLOG_NCIHAL_E(
384         "phNxpNciHal_cleanup_cb_data: Failed to destroy semaphore "
385         "(errno=0x%08x)",
386         errno);
387   }
388 
389   /* Remove from active semaphore list */
390   if (listRemove(&phNxpNciHal_get_monitor()->sem_list, pCallbackData) != 1) {
391     NXPLOG_NCIHAL_E(
392         "phNxpNciHal_cleanup_cb_data: Failed to remove semaphore from the "
393         "list");
394   }
395 
396   return;
397 }
398 
399 /*******************************************************************************
400 **
401 ** Function         phNxpNciHal_releaseall_cb_data
402 **
403 ** Description      Release all callback data
404 **
405 ** Returns          None
406 **
407 *******************************************************************************/
phNxpNciHal_releaseall_cb_data(void)408 void phNxpNciHal_releaseall_cb_data(void) {
409   phNxpNciHal_Sem_t* pCallbackData;
410 
411   while (listGetAndRemoveNext(&phNxpNciHal_get_monitor()->sem_list,
412                               (void**)&pCallbackData)) {
413     pCallbackData->status = NFCSTATUS_FAILED;
414     sem_post(&pCallbackData->sem);
415   }
416 
417   return;
418 }
419 
420 /* END Semaphore and mutex helper functions */
421 
422 /**************************** Other functions *********************************/
423 
424 /*******************************************************************************
425 **
426 ** Function         phNxpNciHal_print_packet
427 **
428 ** Description      Print packet
429 **
430 ** Returns          None
431 **
432 *******************************************************************************/
phNxpNciHal_print_packet(const char * pString,const uint8_t * p_data,uint16_t len)433 void phNxpNciHal_print_packet(const char* pString, const uint8_t* p_data,
434                               uint16_t len) {
435   tNFC_printType printType = getPrintType(pString);
436   if (printType == PRINT_UNKNOWN) return;  // logging is disabled
437   uint32_t i;
438   char* print_buffer = (char*)calloc((len * 3 + 1), sizeof(char));
439   if (NULL != print_buffer) {
440     for (i = 0; i < len; i++) {
441       snprintf(&print_buffer[i * 2], 3, "%02X", p_data[i]);
442     }
443     switch (printType) {
444       case PRINT_SEND:
445         NXPLOG_NCIX_I("len = %3d > %s", len, print_buffer);
446         break;
447       case PRINT_RECV:
448         NXPLOG_NCIR_I("len = %3d > %s", len, print_buffer);
449         break;
450       case PRINT_DEBUG:
451         NXPLOG_NCIHAL_D(" Debug Info > len = %3d > %s", len, print_buffer);
452         break;
453       default:
454         // Nothing to do
455         break;
456     }
457     free(print_buffer);
458   } else {
459     NXPLOG_NCIX_E("\nphNxpNciHal_print_packet:Failed to Allocate memory\n");
460   }
461   return;
462 }
463 
464 /*******************************************************************************
465 **
466 ** Function         getPrintType
467 **
468 ** Description      get Print packet type (TX or RX or Debug)
469 **
470 ** Returns          tNFC_printType enum.
471 **
472 *******************************************************************************/
getPrintType(const char * pString)473 tNFC_printType getPrintType(const char* pString) {
474   if ((0 == memcmp(pString, "SEND", 0x04)) &&
475       (nfc_debug_enabled ||
476        (gLog_level.ncix_log_level >= NXPLOG_LOG_INFO_LOGLEVEL))) {
477     return PRINT_SEND;
478   } else if ((0 == memcmp(pString, "RECV", 0x04)) &&
479              (nfc_debug_enabled ||
480               (gLog_level.ncir_log_level >= NXPLOG_LOG_INFO_LOGLEVEL))) {
481     return PRINT_RECV;
482   } else if ((0 == memcmp(pString, "DEBUG", 0x05)) &&
483              (nfc_debug_enabled ||
484               (gLog_level.hal_log_level >= NXPLOG_LOG_DEBUG_LOGLEVEL))) {
485     return PRINT_DEBUG;
486   }
487   return PRINT_UNKNOWN;
488 }
489 
490 /*******************************************************************************
491 **
492 ** Function         phNxpNciHal_emergency_recovery
493 **
494 ** Description      Abort the process in case of ESE_OVER_TEMP_ERROR, FW Assert,
495 **                  Watchdog Reset, Input Clock lost and unrecoverable error.
496 **                  Ignore the other status.
497 **
498 ** Returns          None
499 **
500 *******************************************************************************/
501 
phNxpNciHal_emergency_recovery(uint8_t status)502 void phNxpNciHal_emergency_recovery(uint8_t status) {
503   NXPLOG_NCIHAL_D("%s: %d", __func__, status);
504 
505   switch (status) {
506     case NCI2_0_CORE_RESET_TRIGGER_TYPE_OVER_TEMPERATURE:
507     case CORE_RESET_TRIGGER_TYPE_FW_ASSERT:
508     case CORE_RESET_TRIGGER_TYPE_WATCHDOG_RESET:
509     case CORE_RESET_TRIGGER_TYPE_INPUT_CLOCK_LOST:
510     case CORE_RESET_TRIGGER_TYPE_UNRECOVERABLE_ERROR: {
511       phNxpNciHal_decodeGpioStatus();
512       NXPLOG_NCIHAL_E("abort()");
513       abort();
514     }
515     case CORE_RESET_TRIGGER_TYPE_POWERED_ON: {
516       if (nxpncihal_ctrl.hal_open_status == true &&
517           nxpncihal_ctrl.power_reset_triggered == false) {
518         phNxpNciHal_decodeGpioStatus();
519         NXPLOG_NCIHAL_E("abort()");
520         abort();
521       }
522     } break;
523     default:
524       NXPLOG_NCIHAL_E("%s: Core reset with Invalid status : %d ", __func__,
525                       status);
526       break;
527   }
528 }
529