C++程序  |  528行  |  13.55 KB

/*
 *
 *  Copyright (C) 2013-2014 NXP Semiconductors
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 ******************************************************************************/
#include <errno.h>
#include <pthread.h>

#include <phNxpLog.h>
#include <phNxpNciHal.h>
#include <phNxpNciHal_utils.h>

#if(NFC_NXP_CHIP_TYPE == PN548C2)
extern uint8_t discovery_cmd[50];
extern uint8_t discovery_cmd_len;
extern uint8_t nfcdep_detected;
#endif

/*********************** Link list functions **********************************/

/*******************************************************************************
**
** Function         listInit
**
** Description      List initialization
**
** Returns          1, if list initialized, 0 otherwise
**
*******************************************************************************/
int listInit(struct listHead* pList)
{
    pList->pFirst = NULL;
    if (pthread_mutex_init(&pList->mutex, NULL) == -1)
    {
        NXPLOG_NCIHAL_E("Mutex creation failed (errno=0x%08x)", errno);
        return 0;
    }

    return 1;
}

/*******************************************************************************
**
** Function         listDestroy
**
** Description      List destruction
**
** Returns          1, if list destroyed, 0 if failed
**
*******************************************************************************/
int listDestroy(struct listHead* pList)
{
    int bListNotEmpty = 1;
    while (bListNotEmpty)
    {
        bListNotEmpty = listGetAndRemoveNext(pList, NULL);
    }

    if (pthread_mutex_destroy(&pList->mutex) == -1)
    {
        NXPLOG_NCIHAL_E("Mutex destruction failed (errno=0x%08x)", errno);
        return 0;
    }

    return 1;
}

/*******************************************************************************
**
** Function         listAdd
**
** Description      Add a node to the list
**
** Returns          1, if added, 0 if otherwise
**
*******************************************************************************/
int listAdd(struct listHead* pList, void* pData)
{
    struct listNode* pNode;
    struct listNode* pLastNode;
    int result;

    /* Create node */
    pNode = (struct listNode*) malloc(sizeof(struct listNode));
    if (pNode == NULL)
    {
        result = 0;
        NXPLOG_NCIHAL_E("Failed to malloc");
        goto clean_and_return;
    }
    pNode->pData = pData;
    pNode->pNext = NULL;

    pthread_mutex_lock(&pList->mutex);

    /* Add the node to the list */
    if (pList->pFirst == NULL)
    {
        /* Set the node as the head */
        pList->pFirst = pNode;
    }
    else
    {
        /* Seek to the end of the list */
        pLastNode = pList->pFirst;
        while (pLastNode->pNext != NULL)
        {
            pLastNode = pLastNode->pNext;
        }

        /* Add the node to the current list */
        pLastNode->pNext = pNode;
    }

    result = 1;

clean_and_return:
    pthread_mutex_unlock(&pList->mutex);
    return result;
}

/*******************************************************************************
**
** Function         listRemove
**
** Description      Remove node from the list
**
** Returns          1, if removed, 0 if otherwise
**
*******************************************************************************/
int listRemove(struct listHead* pList, void* pData)
{
    struct listNode* pNode;
    struct listNode* pRemovedNode;
    int result;

    pthread_mutex_lock(&pList->mutex);

    if (pList->pFirst == NULL)
    {
        /* Empty list */
        NXPLOG_NCIHAL_E("Failed to deallocate (list empty)");
        result = 0;
        goto clean_and_return;
    }

    pNode = pList->pFirst;
    if (pList->pFirst->pData == pData)
    {
        /* Get the removed node */
        pRemovedNode = pNode;

        /* Remove the first node */
        pList->pFirst = pList->pFirst->pNext;
    }
    else
    {
        while (pNode->pNext != NULL)
        {
            if (pNode->pNext->pData == pData)
            {
                /* Node found ! */
                break;
            }
            pNode = pNode->pNext;
        }

        if (pNode->pNext == NULL)
        {
            /* Node not found */
            result = 0;
            NXPLOG_NCIHAL_E("Failed to deallocate (not found %8p)", pData);
            goto clean_and_return;
        }

        /* Get the removed node */
        pRemovedNode = pNode->pNext;

        /* Remove the node from the list */
        pNode->pNext = pNode->pNext->pNext;
    }

    /* Deallocate the node */
    free(pRemovedNode);

    result = 1;

clean_and_return:
    pthread_mutex_unlock(&pList->mutex);
    return result;
}

/*******************************************************************************
**
** Function         listGetAndRemoveNext
**
** Description      Get next node on the list and remove it
**
** Returns          1, if successful, 0 if otherwise
**
*******************************************************************************/
int listGetAndRemoveNext(struct listHead* pList, void** ppData)
{
    struct listNode* pNode;
    int result;

    pthread_mutex_lock(&pList->mutex);

    if (pList->pFirst ==  NULL)
    {
        /* Empty list */
        NXPLOG_NCIHAL_D("Failed to deallocate (list empty)");
        result = 0;
        goto clean_and_return;
    }

    /* Work on the first node */
    pNode = pList->pFirst;

    /* Return the data */
    if (ppData != NULL)
    {
        *ppData = pNode->pData;
    }

    /* Remove and deallocate the node */
    pList->pFirst = pNode->pNext;
    free(pNode);

    result = 1;

clean_and_return:
    listDump(pList);
    pthread_mutex_unlock(&pList->mutex);
    return result;
}

/*******************************************************************************
**
** Function         listDump
**
** Description      Dump list information
**
** Returns          None
**
*******************************************************************************/
void listDump(struct listHead* pList)
{
    struct listNode* pNode = pList->pFirst;

    NXPLOG_NCIHAL_D("Node dump:");
    while (pNode != NULL)
    {
        NXPLOG_NCIHAL_D("- %8p (%8p)", pNode, pNode->pData);
        pNode = pNode->pNext;
    }

    return;
}

/* END Linked list source code */

/****************** Semaphore and mutex helper functions **********************/

static phNxpNciHal_Monitor_t *nxpncihal_monitor = NULL;

/*******************************************************************************
**
** Function         phNxpNciHal_init_monitor
**
** Description      Initialize the semaphore monitor
**
** Returns          Pointer to monitor, otherwise NULL if failed
**
*******************************************************************************/
phNxpNciHal_Monitor_t*
phNxpNciHal_init_monitor(void)
{
    NXPLOG_NCIHAL_D("Entering phNxpNciHal_init_monitor");

    if (nxpncihal_monitor == NULL)
    {
        nxpncihal_monitor = (phNxpNciHal_Monitor_t *) malloc(
                sizeof(phNxpNciHal_Monitor_t));
    }

    if (nxpncihal_monitor != NULL)
    {
        memset(nxpncihal_monitor, 0x00, sizeof(phNxpNciHal_Monitor_t));

        if (pthread_mutex_init(&nxpncihal_monitor->reentrance_mutex, NULL)
                == -1)
        {
            NXPLOG_NCIHAL_E("reentrance_mutex creation returned 0x%08x", errno);
            goto clean_and_return;
        }

        if (pthread_mutex_init(&nxpncihal_monitor->concurrency_mutex, NULL)
                == -1)
        {
            NXPLOG_NCIHAL_E("concurrency_mutex creation returned 0x%08x", errno);
            pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex);
            goto clean_and_return;
        }

        if (listInit(&nxpncihal_monitor->sem_list) != 1)
        {
            NXPLOG_NCIHAL_E("Semaphore List creation failed");
            pthread_mutex_destroy(&nxpncihal_monitor->concurrency_mutex);
            pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex);
            goto clean_and_return;
        }
    }
    else
    {
        NXPLOG_NCIHAL_E("nxphal_monitor creation failed");
        goto clean_and_return;
    }

    NXPLOG_NCIHAL_D("Returning with SUCCESS");

    return nxpncihal_monitor;

clean_and_return:
    NXPLOG_NCIHAL_D("Returning with FAILURE");

    if (nxpncihal_monitor != NULL)
    {
        free(nxpncihal_monitor);
        nxpncihal_monitor = NULL;
    }

    return NULL;
}

/*******************************************************************************
**
** Function         phNxpNciHal_cleanup_monitor
**
** Description      Clean up semaphore monitor
**
** Returns          None
**
*******************************************************************************/
void phNxpNciHal_cleanup_monitor(void)
{
    if (nxpncihal_monitor != NULL)
    {
        pthread_mutex_destroy(&nxpncihal_monitor->concurrency_mutex);
        REENTRANCE_UNLOCK();
        pthread_mutex_destroy(&nxpncihal_monitor->reentrance_mutex);
        phNxpNciHal_releaseall_cb_data();
        listDestroy(&nxpncihal_monitor->sem_list);
    }

    free(nxpncihal_monitor);
    nxpncihal_monitor = NULL;

    return;
}

/*******************************************************************************
**
** Function         phNxpNciHal_get_monitor
**
** Description      Get monitor
**
** Returns          Pointer to monitor
**
*******************************************************************************/
phNxpNciHal_Monitor_t*
phNxpNciHal_get_monitor(void)
{
    return nxpncihal_monitor;
}

/* Initialize the callback data */
NFCSTATUS phNxpNciHal_init_cb_data(phNxpNciHal_Sem_t *pCallbackData,
        void *pContext)
{
    /* Create semaphore */
    if (sem_init(&pCallbackData->sem, 0, 0) == -1)
    {
        NXPLOG_NCIHAL_E("Semaphore creation failed (errno=0x%08x)", errno);
        return NFCSTATUS_FAILED;
    }

    /* Set default status value */
    pCallbackData->status = NFCSTATUS_FAILED;

    /* Copy the context */
    pCallbackData->pContext = pContext;

    /* Add to active semaphore list */
    if (listAdd(&phNxpNciHal_get_monitor()->sem_list, pCallbackData) != 1)
    {
        NXPLOG_NCIHAL_E("Failed to add the semaphore to the list");
    }

    return NFCSTATUS_SUCCESS;
}

/*******************************************************************************
**
** Function         phNxpNciHal_cleanup_cb_data
**
** Description      Clean up callback data
**
** Returns          None
**
*******************************************************************************/
void phNxpNciHal_cleanup_cb_data(phNxpNciHal_Sem_t* pCallbackData)
{
    /* Destroy semaphore */
    if (sem_destroy(&pCallbackData->sem))
    {
        NXPLOG_NCIHAL_E("phNxpNciHal_cleanup_cb_data: Failed to destroy semaphore (errno=0x%08x)", errno);
    }

    /* Remove from active semaphore list */
    if (listRemove(&phNxpNciHal_get_monitor()->sem_list, pCallbackData) != 1)
    {
        NXPLOG_NCIHAL_E("phNxpNciHal_cleanup_cb_data: Failed to remove semaphore from the list");
    }

    return;
}

/*******************************************************************************
**
** Function         phNxpNciHal_releaseall_cb_data
**
** Description      Release all callback data
**
** Returns          None
**
*******************************************************************************/
void phNxpNciHal_releaseall_cb_data(void)
{
    phNxpNciHal_Sem_t* pCallbackData;

    while (listGetAndRemoveNext(&phNxpNciHal_get_monitor()->sem_list,
            (void**) &pCallbackData))
    {
        pCallbackData->status = NFCSTATUS_FAILED;
        sem_post(&pCallbackData->sem);
    }

    return;
}

/* END Semaphore and mutex helper functions */

/**************************** Other functions *********************************/

/*******************************************************************************
**
** Function         phNxpNciHal_print_packet
**
** Description      Print packet
**
** Returns          None
**
*******************************************************************************/
void phNxpNciHal_print_packet(const char *pString, const uint8_t *p_data,
        uint16_t len)
{
    uint32_t i, j;
    char print_buffer[len * 3 + 1];

    memset (print_buffer, 0, sizeof(print_buffer));
    for (i = 0; i < len; i++) {
        snprintf(&print_buffer[i * 2], 3, "%02X", p_data[i]);
    }
    if( 0 == memcmp(pString,"SEND",0x04))
    {
        NXPLOG_NCIX_D("len = %3d > %s", len, print_buffer);
    }
    else if( 0 == memcmp(pString,"RECV",0x04))
    {
        NXPLOG_NCIR_D("len = %3d > %s", len, print_buffer);
    }

    return;
}


/*******************************************************************************
**
** Function         phNxpNciHal_emergency_recovery
**
** Description      Emergency recovery in case of no other way out
**
** Returns          None
**
*******************************************************************************/

void phNxpNciHal_emergency_recovery (void)
{
#if(NFC_NXP_CHIP_TYPE == PN548C2)
    if (nfcdep_detected && discovery_cmd_len != 0)
    {
        pthread_t pthread;
        pthread_attr_t attr;
        pthread_attr_init (&attr);
        pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
        if (pthread_create (&pthread, &attr, (void *)phNxpNciHal_core_reset_recovery, NULL) == 0)
        {
            return;
        }
    }
#endif
    NXPLOG_NCIHAL_E ("%s: abort()", __FUNCTION__);
    abort ();
}