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