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