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