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