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