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) == -1) {
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) == -1) {
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) == -1) {
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) == -1) {
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