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