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