You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
477 lines
13 KiB
477 lines
13 KiB
/* |
|
* |
|
* 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()", __func__); |
|
abort(); |
|
}
|
|
|