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