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