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