From 9224c881cf3f8575194823a6c779c0d65c42258a Mon Sep 17 00:00:00 2001 From: Arian Date: Mon, 30 Sep 2019 11:10:42 +0200 Subject: shinano-common: pn54x: Import from lineage-15.1 * https://github.com/LineageOS/android_system_nfc/tree/lineage-15.1/halimpl/pn54x/common * support for pn54x has been dropped in lineage-16.0 and above Change-Id: I19f2c3a6e3066bf9aaaaf4ddcd7d7ad867de0ed8 --- pn54x/tml/phDal4Nfc_messageQueueLib.c | 234 +++++++++ pn54x/tml/phDal4Nfc_messageQueueLib.h | 34 ++ pn54x/tml/phOsalNfc_Timer.c | 444 ++++++++++++++++ pn54x/tml/phOsalNfc_Timer.h | 86 +++ pn54x/tml/phTmlNfc.c | 949 ++++++++++++++++++++++++++++++++++ pn54x/tml/phTmlNfc.h | 227 ++++++++ pn54x/tml/phTmlNfc_i2c.c | 315 +++++++++++ pn54x/tml/phTmlNfc_i2c.h | 32 ++ 8 files changed, 2321 insertions(+) create mode 100644 pn54x/tml/phDal4Nfc_messageQueueLib.c create mode 100644 pn54x/tml/phDal4Nfc_messageQueueLib.h create mode 100644 pn54x/tml/phOsalNfc_Timer.c create mode 100644 pn54x/tml/phOsalNfc_Timer.h create mode 100644 pn54x/tml/phTmlNfc.c create mode 100644 pn54x/tml/phTmlNfc.h create mode 100644 pn54x/tml/phTmlNfc_i2c.c create mode 100644 pn54x/tml/phTmlNfc_i2c.h (limited to 'pn54x/tml') diff --git a/pn54x/tml/phDal4Nfc_messageQueueLib.c b/pn54x/tml/phDal4Nfc_messageQueueLib.c new file mode 100644 index 0000000..f43774d --- /dev/null +++ b/pn54x/tml/phDal4Nfc_messageQueueLib.c @@ -0,0 +1,234 @@ +/* + * Copyright (C) 2010-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. + */ + +/* + * DAL independent message queue implementation for Android (can be used under + * Linux too) + */ + +#include +#include +#include +#include +#include +#include + +typedef struct phDal4Nfc_message_queue_item { + phLibNfc_Message_t nMsg; + struct phDal4Nfc_message_queue_item* pPrev; + struct phDal4Nfc_message_queue_item* pNext; +} phDal4Nfc_message_queue_item_t; + +typedef struct phDal4Nfc_message_queue { + phDal4Nfc_message_queue_item_t* pItems; + pthread_mutex_t nCriticalSectionMutex; + sem_t nProcessSemaphore; + +} phDal4Nfc_message_queue_t; + +/******************************************************************************* +** +** Function phDal4Nfc_msgget +** +** Description Allocates message queue +** +** Parameters Ignored, included only for Linux queue API compatibility +** +** Returns (int) value of pQueue if successful +** -1, if failed to allocate memory or to init mutex +** +*******************************************************************************/ +intptr_t phDal4Nfc_msgget(key_t key, int msgflg) { + phDal4Nfc_message_queue_t* pQueue; + UNUSED(key); + UNUSED(msgflg); + pQueue = + (phDal4Nfc_message_queue_t*)malloc(sizeof(phDal4Nfc_message_queue_t)); + if (pQueue == NULL) return -1; + memset(pQueue, 0, sizeof(phDal4Nfc_message_queue_t)); + if (pthread_mutex_init(&pQueue->nCriticalSectionMutex, NULL) == -1) { + free(pQueue); + return -1; + } + if (sem_init(&pQueue->nProcessSemaphore, 0, 0) == -1) { + free(pQueue); + return -1; + } + + return ((intptr_t)pQueue); +} + +/******************************************************************************* +** +** Function phDal4Nfc_msgrelease +** +** Description Releases message queue +** +** Parameters msqid - message queue handle +** +** Returns None +** +*******************************************************************************/ +void phDal4Nfc_msgrelease(intptr_t msqid) { + phDal4Nfc_message_queue_t* pQueue = (phDal4Nfc_message_queue_t*)msqid; + + if (pQueue != NULL) { + sem_post(&pQueue->nProcessSemaphore); + usleep(3000); + if (sem_destroy(&pQueue->nProcessSemaphore)) { + NXPLOG_TML_E("Failed to destroy semaphore (errno=0x%08x)", errno); + } + pthread_mutex_destroy(&pQueue->nCriticalSectionMutex); + + free(pQueue); + } + + return; +} + +/******************************************************************************* +** +** Function phDal4Nfc_msgctl +** +** Description Destroys message queue +** +** Parameters msqid - message queue handle +** cmd, buf - ignored, included only for Linux queue API +** compatibility +** +** Returns 0, if successful +** -1, if invalid handle is passed +** +*******************************************************************************/ +int phDal4Nfc_msgctl(intptr_t msqid, int cmd, void* buf) { + phDal4Nfc_message_queue_t* pQueue; + phDal4Nfc_message_queue_item_t* p; + UNUSED(cmd); + UNUSED(buf); + if (msqid == 0) return -1; + + pQueue = (phDal4Nfc_message_queue_t*)msqid; + pthread_mutex_lock(&pQueue->nCriticalSectionMutex); + if (pQueue->pItems != NULL) { + p = pQueue->pItems; + while (p->pNext != NULL) { + p = p->pNext; + } + while (p->pPrev != NULL) { + p = p->pPrev; + free(p->pNext); + p->pNext = NULL; + } + free(p); + } + pQueue->pItems = NULL; + pthread_mutex_unlock(&pQueue->nCriticalSectionMutex); + pthread_mutex_destroy(&pQueue->nCriticalSectionMutex); + free(pQueue); + + return 0; +} + +/******************************************************************************* +** +** Function phDal4Nfc_msgsnd +** +** Description Sends a message to the queue. The message will be added at +** the end of the queue as appropriate for FIFO policy +** +** Parameters msqid - message queue handle +** msgp - message to be sent +** msgsz - message size +** msgflg - ignored +** +** Returns 0, if successful +** -1, if invalid parameter passed or failed to allocate memory +** +*******************************************************************************/ +intptr_t phDal4Nfc_msgsnd(intptr_t msqid, phLibNfc_Message_t* msg, int msgflg) { + phDal4Nfc_message_queue_t* pQueue; + phDal4Nfc_message_queue_item_t* p; + phDal4Nfc_message_queue_item_t* pNew; + UNUSED(msgflg); + if ((msqid == 0) || (msg == NULL)) return -1; + + pQueue = (phDal4Nfc_message_queue_t*)msqid; + pNew = (phDal4Nfc_message_queue_item_t*)malloc( + sizeof(phDal4Nfc_message_queue_item_t)); + if (pNew == NULL) return -1; + memset(pNew, 0, sizeof(phDal4Nfc_message_queue_item_t)); + memcpy(&pNew->nMsg, msg, sizeof(phLibNfc_Message_t)); + pthread_mutex_lock(&pQueue->nCriticalSectionMutex); + + if (pQueue->pItems != NULL) { + p = pQueue->pItems; + while (p->pNext != NULL) { + p = p->pNext; + } + p->pNext = pNew; + pNew->pPrev = p; + } else { + pQueue->pItems = pNew; + } + pthread_mutex_unlock(&pQueue->nCriticalSectionMutex); + + sem_post(&pQueue->nProcessSemaphore); + + return 0; +} + +/******************************************************************************* +** +** Function phDal4Nfc_msgrcv +** +** Description Gets the oldest message from the queue. +** If the queue is empty the function waits (blocks on a mutex) +** until a message is posted to the queue with phDal4Nfc_msgsnd +** +** Parameters msqid - message queue handle +** msgp - message to be received +** msgsz - message size +** msgtyp - ignored +** msgflg - ignored +** +** Returns 0, if successful +** -1, if invalid parameter passed +** +*******************************************************************************/ +int phDal4Nfc_msgrcv(intptr_t msqid, phLibNfc_Message_t* msg, long msgtyp, + int msgflg) { + phDal4Nfc_message_queue_t* pQueue; + phDal4Nfc_message_queue_item_t* p; + UNUSED(msgflg); + UNUSED(msgtyp); + if ((msqid == 0) || (msg == NULL)) return -1; + + pQueue = (phDal4Nfc_message_queue_t*)msqid; + + sem_wait(&pQueue->nProcessSemaphore); + + pthread_mutex_lock(&pQueue->nCriticalSectionMutex); + + if (pQueue->pItems != NULL) { + memcpy(msg, &(pQueue->pItems)->nMsg, sizeof(phLibNfc_Message_t)); + p = pQueue->pItems->pNext; + free(pQueue->pItems); + pQueue->pItems = p; + } + pthread_mutex_unlock(&pQueue->nCriticalSectionMutex); + + return 0; +} diff --git a/pn54x/tml/phDal4Nfc_messageQueueLib.h b/pn54x/tml/phDal4Nfc_messageQueueLib.h new file mode 100644 index 0000000..1e0ede2 --- /dev/null +++ b/pn54x/tml/phDal4Nfc_messageQueueLib.h @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2010-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. + */ + +/* + * DAL independent message queue implementation for Android + */ + +#ifndef PHDAL4NFC_MESSAGEQUEUE_H +#define PHDAL4NFC_MESSAGEQUEUE_H + +#include +#include + +intptr_t phDal4Nfc_msgget(key_t key, int msgflg); +void phDal4Nfc_msgrelease(intptr_t msqid); +int phDal4Nfc_msgctl(intptr_t msqid, int cmd, void* buf); +intptr_t phDal4Nfc_msgsnd(intptr_t msqid, phLibNfc_Message_t* msg, int msgflg); +int phDal4Nfc_msgrcv(intptr_t msqid, phLibNfc_Message_t* msg, long msgtyp, + int msgflg); + +#endif /* PHDAL4NFC_MESSAGEQUEUE_H */ diff --git a/pn54x/tml/phOsalNfc_Timer.c b/pn54x/tml/phOsalNfc_Timer.c new file mode 100644 index 0000000..3f5269d --- /dev/null +++ b/pn54x/tml/phOsalNfc_Timer.c @@ -0,0 +1,444 @@ +/* + * Copyright (C) 2010-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. + */ + +/* + * OSAL Implementation for Timers. + */ + +#include +#include +#include +#include +#include +#include + +#define PH_NFC_MAX_TIMER (5U) +static phOsalNfc_TimerHandle_t apTimerInfo[PH_NFC_MAX_TIMER]; + +extern phNxpNciHal_Control_t nxpncihal_ctrl; + +/* + * Defines the base address for generating timerid. + */ +#define PH_NFC_TIMER_BASE_ADDRESS (100U) + +/* + * Defines the value for invalid timerid returned during timeSetEvent + */ +#define PH_NFC_TIMER_ID_ZERO (0x00) + +/* + * Invalid timer ID type. This ID used indicate timer creation is failed */ +#define PH_NFC_TIMER_ID_INVALID (0xFFFF) + +/* Forward declarations */ +static void phOsalNfc_PostTimerMsg(phLibNfc_Message_t* pMsg); +static void phOsalNfc_DeferredCall(void* pParams); +static void phOsalNfc_Timer_Expired(union sigval sv); + +/* + *************************** Function Definitions ****************************** + */ + +/******************************************************************************* +** +** Function phOsalNfc_Timer_Create +** +** Description Creates a timer which shall call back the specified function +** when the timer expires. Fails if OSAL module is not +** initialized or timers are already occupied +** +** Parameters None +** +** Returns TimerId +** TimerId value of PH_OSALNFC_TIMER_ID_INVALID indicates that +** timer is not created +** +*******************************************************************************/ +uint32_t phOsalNfc_Timer_Create(void) { + /* dwTimerId is also used as an index at which timer object can be stored */ + uint32_t dwTimerId = PH_OSALNFC_TIMER_ID_INVALID; + static struct sigevent se; + phOsalNfc_TimerHandle_t* pTimerHandle; + /* Timer needs to be initialized for timer usage */ + + se.sigev_notify = SIGEV_THREAD; + se.sigev_notify_function = phOsalNfc_Timer_Expired; + se.sigev_notify_attributes = NULL; + dwTimerId = phUtilNfc_CheckForAvailableTimer(); + + /* Check whether timers are available, if yes create a timer handle structure + */ + if ((PH_NFC_TIMER_ID_ZERO != dwTimerId) && (dwTimerId <= PH_NFC_MAX_TIMER)) { + pTimerHandle = (phOsalNfc_TimerHandle_t*)&apTimerInfo[dwTimerId - 1]; + /* Build the Timer Id to be returned to Caller Function */ + dwTimerId += PH_NFC_TIMER_BASE_ADDRESS; + se.sigev_value.sival_int = (int)dwTimerId; + /* Create POSIX timer */ + if (timer_create(CLOCK_REALTIME, &se, &(pTimerHandle->hTimerHandle)) == + -1) { + dwTimerId = PH_NFC_TIMER_ID_INVALID; + } else { + /* Set the state to indicate timer is ready */ + pTimerHandle->eState = eTimerIdle; + /* Store the Timer Id which shall act as flag during check for timer + * availability */ + pTimerHandle->TimerId = dwTimerId; + } + } else { + dwTimerId = PH_NFC_TIMER_ID_INVALID; + } + + /* Timer ID invalid can be due to Uninitialized state,Non availability of + * Timer */ + return dwTimerId; +} + +/******************************************************************************* +** +** Function phOsalNfc_Timer_Start +** +** Description Starts the requested, already created, timer. +** If the timer is already running, timer stops and restarts +** with the new timeout value and new callback function in case +** any ?????? +** Creates a timer which shall call back the specified function +** when the timer expires +** +** Parameters dwTimerId - valid timer ID obtained during timer creation +** dwRegTimeCnt - requested timeout in milliseconds +** pApplication_callback - application callback interface to be +** called when timer expires +** pContext - caller context, to be passed to the application +** callback function +** +** Returns NFC status: +** NFCSTATUS_SUCCESS - the operation was successful +** NFCSTATUS_NOT_INITIALISED - OSAL Module is not initialized +** NFCSTATUS_INVALID_PARAMETER - invalid parameter passed to +** the function +** PH_OSALNFC_TIMER_START_ERROR - timer could not be created +** due to system error +** +*******************************************************************************/ +NFCSTATUS phOsalNfc_Timer_Start(uint32_t dwTimerId, uint32_t dwRegTimeCnt, + pphOsalNfc_TimerCallbck_t pApplication_callback, + void* pContext) { + NFCSTATUS wStartStatus = NFCSTATUS_SUCCESS; + + struct itimerspec its; + uint32_t dwIndex; + phOsalNfc_TimerHandle_t* pTimerHandle; + /* Retrieve the index at which the timer handle structure is stored */ + dwIndex = dwTimerId - PH_NFC_TIMER_BASE_ADDRESS - 0x01; + pTimerHandle = (phOsalNfc_TimerHandle_t*)&apTimerInfo[dwIndex]; + /* OSAL Module needs to be initialized for timer usage */ + /* Check whether the handle provided by user is valid */ + if ((dwIndex < PH_NFC_MAX_TIMER) && (0x00 != pTimerHandle->TimerId) && + (NULL != pApplication_callback)) { + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value.tv_sec = dwRegTimeCnt / 1000; + its.it_value.tv_nsec = 1000000 * (dwRegTimeCnt % 1000); + if (its.it_value.tv_sec == 0 && its.it_value.tv_nsec == 0) { + /* This would inadvertently stop the timer*/ + its.it_value.tv_nsec = 1; + } + pTimerHandle->Application_callback = pApplication_callback; + pTimerHandle->pContext = pContext; + pTimerHandle->eState = eTimerRunning; + /* Arm the timer */ + if ((timer_settime(pTimerHandle->hTimerHandle, 0, &its, NULL)) == -1) { + wStartStatus = PHNFCSTVAL(CID_NFC_OSAL, PH_OSALNFC_TIMER_START_ERROR); + } + } else { + wStartStatus = PHNFCSTVAL(CID_NFC_OSAL, NFCSTATUS_INVALID_PARAMETER); + } + + return wStartStatus; +} + +/******************************************************************************* +** +** Function phOsalNfc_Timer_Stop +** +** Description Stops already started timer +** Allows to stop running timer. In case timer is stopped, +** timer callback will not be notified any more +** +** Parameters dwTimerId - valid timer ID obtained during timer creation +** +** Returns NFC status: +** NFCSTATUS_SUCCESS - the operation was successful +** NFCSTATUS_NOT_INITIALISED - OSAL Module is not initialized +** NFCSTATUS_INVALID_PARAMETER - invalid parameter passed to +** the function +** PH_OSALNFC_TIMER_STOP_ERROR - timer could not be stopped due +** to system error +** +*******************************************************************************/ +NFCSTATUS phOsalNfc_Timer_Stop(uint32_t dwTimerId) { + NFCSTATUS wStopStatus = NFCSTATUS_SUCCESS; + static struct itimerspec its = {{0, 0}, {0, 0}}; + + uint32_t dwIndex; + phOsalNfc_TimerHandle_t* pTimerHandle; + dwIndex = dwTimerId - PH_NFC_TIMER_BASE_ADDRESS - 0x01; + pTimerHandle = (phOsalNfc_TimerHandle_t*)&apTimerInfo[dwIndex]; + /* OSAL Module and Timer needs to be initialized for timer usage */ + /* Check whether the TimerId provided by user is valid */ + if ((dwIndex < PH_NFC_MAX_TIMER) && (0x00 != pTimerHandle->TimerId) && + (pTimerHandle->eState != eTimerIdle)) { + /* Stop the timer only if the callback has not been invoked */ + if (pTimerHandle->eState == eTimerRunning) { + if ((timer_settime(pTimerHandle->hTimerHandle, 0, &its, NULL)) == -1) { + wStopStatus = PHNFCSTVAL(CID_NFC_OSAL, PH_OSALNFC_TIMER_STOP_ERROR); + } else { + /* Change the state of timer to Stopped */ + pTimerHandle->eState = eTimerStopped; + } + } + } else { + wStopStatus = PHNFCSTVAL(CID_NFC_OSAL, NFCSTATUS_INVALID_PARAMETER); + } + + return wStopStatus; +} + +/******************************************************************************* +** +** Function phOsalNfc_Timer_Delete +** +** Description Deletes previously created timer +** Allows to delete previously created timer. In case timer is +** running, it is first stopped and then deleted +** +** Parameters dwTimerId - valid timer ID obtained during timer creation +** +** Returns NFC status: +** NFCSTATUS_SUCCESS - the operation was successful +** NFCSTATUS_NOT_INITIALISED - OSAL Module is not initialized +** NFCSTATUS_INVALID_PARAMETER - invalid parameter passed to +** the function +** PH_OSALNFC_TIMER_DELETE_ERROR - timer could not be stopped +** due to system error +** +*******************************************************************************/ +NFCSTATUS phOsalNfc_Timer_Delete(uint32_t dwTimerId) { + NFCSTATUS wDeleteStatus = NFCSTATUS_SUCCESS; + + uint32_t dwIndex; + phOsalNfc_TimerHandle_t* pTimerHandle; + dwIndex = dwTimerId - PH_NFC_TIMER_BASE_ADDRESS - 0x01; + pTimerHandle = (phOsalNfc_TimerHandle_t*)&apTimerInfo[dwIndex]; + /* OSAL Module and Timer needs to be initialized for timer usage */ + + /* Check whether the TimerId passed by user is valid and Deregistering of + * timer is successful */ + if ((dwIndex < PH_NFC_MAX_TIMER) && (0x00 != pTimerHandle->TimerId) && + (NFCSTATUS_SUCCESS == phOsalNfc_CheckTimerPresence(pTimerHandle))) { + /* Cancel the timer before deleting */ + if (timer_delete(pTimerHandle->hTimerHandle) == -1) { + wDeleteStatus = PHNFCSTVAL(CID_NFC_OSAL, PH_OSALNFC_TIMER_DELETE_ERROR); + } + /* Clear Timer structure used to store timer related data */ + memset(pTimerHandle, (uint8_t)0x00, sizeof(phOsalNfc_TimerHandle_t)); + } else { + wDeleteStatus = PHNFCSTVAL(CID_NFC_OSAL, NFCSTATUS_INVALID_PARAMETER); + } + return wDeleteStatus; +} + +/******************************************************************************* +** +** Function phOsalNfc_Timer_Cleanup +** +** Description Deletes all previously created timers +** Allows to delete previously created timers. In case timer is +** running, it is first stopped and then deleted +** +** Parameters None +** +** Returns None +** +*******************************************************************************/ +void phOsalNfc_Timer_Cleanup(void) { + /* Delete all timers */ + uint32_t dwIndex; + phOsalNfc_TimerHandle_t* pTimerHandle; + for (dwIndex = 0; dwIndex < PH_NFC_MAX_TIMER; dwIndex++) { + pTimerHandle = (phOsalNfc_TimerHandle_t*)&apTimerInfo[dwIndex]; + /* OSAL Module and Timer needs to be initialized for timer usage */ + + /* Check whether the TimerId passed by user is valid and Deregistering of + * timer is successful */ + if ((0x00 != pTimerHandle->TimerId) && + (NFCSTATUS_SUCCESS == phOsalNfc_CheckTimerPresence(pTimerHandle))) { + /* Cancel the timer before deleting */ + if (timer_delete(pTimerHandle->hTimerHandle) == -1) { + NXPLOG_TML_E("timer %d delete error!", dwIndex); + } + /* Clear Timer structure used to store timer related data */ + memset(pTimerHandle, (uint8_t)0x00, sizeof(phOsalNfc_TimerHandle_t)); + } + } + + return; +} + +/******************************************************************************* +** +** Function phOsalNfc_DeferredCall +** +** Description Invokes the timer callback function after timer expiration. +** Shall invoke the callback function registered by the timer +** caller function +** +** Parameters pParams - parameters indicating the ID of the timer +** +** Returns None - +** +*******************************************************************************/ +static void phOsalNfc_DeferredCall(void* pParams) { + /* Retrieve the timer id from the parameter */ + uint32_t dwIndex; + phOsalNfc_TimerHandle_t* pTimerHandle; + if (NULL != pParams) { + /* Retrieve the index at which the timer handle structure is stored */ + dwIndex = (uintptr_t)pParams - PH_NFC_TIMER_BASE_ADDRESS - 0x01; + pTimerHandle = (phOsalNfc_TimerHandle_t*)&apTimerInfo[dwIndex]; + if (pTimerHandle->Application_callback != NULL) { + /* Invoke the callback function with osal Timer ID */ + pTimerHandle->Application_callback((uintptr_t)pParams, + pTimerHandle->pContext); + } + } + + return; +} + +/******************************************************************************* +** +** Function phOsalNfc_PostTimerMsg +** +** Description Posts message on the user thread +** Shall be invoked upon expiration of a timer +** Shall post message on user thread through which timer +** callback function shall be invoked +** +** Parameters pMsg - pointer to the message structure posted on user +** thread +** +** Returns None +** +*******************************************************************************/ +static void phOsalNfc_PostTimerMsg(phLibNfc_Message_t* pMsg) { + (void)phDal4Nfc_msgsnd( + nxpncihal_ctrl.gDrvCfg + .nClientId /*gpphOsalNfc_Context->dwCallbackThreadID*/, + pMsg, 0); + + return; +} + +/******************************************************************************* +** +** Function phOsalNfc_Timer_Expired +** +** Description posts message upon expiration of timer +** Shall be invoked when any one timer is expired +** Shall post message on user thread to invoke respective +** callback function provided by the caller of Timer function +** +** Returns None +** +*******************************************************************************/ +static void phOsalNfc_Timer_Expired(union sigval sv) { + uint32_t dwIndex; + phOsalNfc_TimerHandle_t* pTimerHandle; + + dwIndex = ((uint32_t)(sv.sival_int)) - PH_NFC_TIMER_BASE_ADDRESS - 0x01; + pTimerHandle = (phOsalNfc_TimerHandle_t*)&apTimerInfo[dwIndex]; + /* Timer is stopped when callback function is invoked */ + pTimerHandle->eState = eTimerStopped; + + pTimerHandle->tDeferedCallInfo.pDeferedCall = &phOsalNfc_DeferredCall; + pTimerHandle->tDeferedCallInfo.pParam = (void*)((intptr_t)(sv.sival_int)); + + pTimerHandle->tOsalMessage.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; + pTimerHandle->tOsalMessage.pMsgData = (void*)&pTimerHandle->tDeferedCallInfo; + + /* Post a message on the queue to invoke the function */ + phOsalNfc_PostTimerMsg((phLibNfc_Message_t*)&pTimerHandle->tOsalMessage); + + return; +} + +/******************************************************************************* +** +** Function phUtilNfc_CheckForAvailableTimer +** +** Description Find an available timer id +** +** Parameters void +** +** Returns Available timer id +** +*******************************************************************************/ +uint32_t phUtilNfc_CheckForAvailableTimer(void) { + /* Variable used to store the index at which the object structure details + can be stored. Initialize it as not available. */ + uint32_t dwIndex = 0x00; + uint32_t dwRetval = 0x00; + + /* Check whether Timer object can be created */ + for (dwIndex = 0x00; ((dwIndex < PH_NFC_MAX_TIMER) && (0x00 == dwRetval)); + dwIndex++) { + if (!(apTimerInfo[dwIndex].TimerId)) { + dwRetval = (dwIndex + 0x01); + } + } + + return (dwRetval); +} + +/******************************************************************************* +** +** Function phOsalNfc_CheckTimerPresence +** +** Description Checks the requested timer is present or not +** +** Parameters pObjectHandle - timer context +** +** Returns NFCSTATUS_SUCCESS if found +** Other value if not found +** +*******************************************************************************/ +NFCSTATUS phOsalNfc_CheckTimerPresence(void* pObjectHandle) { + uint32_t dwIndex; + NFCSTATUS wRegisterStatus = NFCSTATUS_INVALID_PARAMETER; + + for (dwIndex = 0x00; + ((dwIndex < PH_NFC_MAX_TIMER) && (wRegisterStatus != NFCSTATUS_SUCCESS)); + dwIndex++) { + /* For Timer, check whether the requested handle is present or not */ + if (((&apTimerInfo[dwIndex]) == (phOsalNfc_TimerHandle_t*)pObjectHandle) && + (apTimerInfo[dwIndex].TimerId)) { + wRegisterStatus = NFCSTATUS_SUCCESS; + } + } + return wRegisterStatus; +} diff --git a/pn54x/tml/phOsalNfc_Timer.h b/pn54x/tml/phOsalNfc_Timer.h new file mode 100644 index 0000000..5315455 --- /dev/null +++ b/pn54x/tml/phOsalNfc_Timer.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2010-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. + */ + +/* + * OSAL header files related to Timer functions. + */ + +#ifndef PHOSALNFC_TIMER_H +#define PHOSALNFC_TIMER_H + +#ifdef __cplusplus +extern "C" { +#endif + +/* +************************* Include Files **************************************** +*/ + +/* + * Timer callback interface which will be called once registered timer + * time out expires. + * TimerId - Timer Id for which callback is called. + * pContext - Parameter to be passed to the callback function + */ +typedef void (*pphOsalNfc_TimerCallbck_t)(uint32_t TimerId, void* pContext); + +/* + * The Timer could not be created due to a + * system error */ +#define PH_OSALNFC_TIMER_CREATE_ERROR (0X00E0) + +/* + * The Timer could not be started due to a + * system error or invalid handle */ +#define PH_OSALNFC_TIMER_START_ERROR (0X00E1) + +/* + * The Timer could not be stopped due to a + * system error or invalid handle */ +#define PH_OSALNFC_TIMER_STOP_ERROR (0X00E2) + +/* + * The Timer could not be deleted due to a + * system error or invalid handle */ +#define PH_OSALNFC_TIMER_DELETE_ERROR (0X00E3) + +/* + * Invalid timer ID type.This ID used indicate timer creation is failed */ +#define PH_OSALNFC_TIMER_ID_INVALID (0xFFFF) + +/* + * OSAL timer message .This message type will be posted to + * calling application thread.*/ +#define PH_OSALNFC_TIMER_MSG (0x315) + +/* +***************************Globals,Structure and Enumeration ****************** +*/ + +uint32_t phOsalNfc_Timer_Create(void); +NFCSTATUS phOsalNfc_Timer_Start(uint32_t dwTimerId, uint32_t dwRegTimeCnt, + pphOsalNfc_TimerCallbck_t pApplication_callback, + void* pContext); +NFCSTATUS phOsalNfc_Timer_Stop(uint32_t dwTimerId); +NFCSTATUS phOsalNfc_Timer_Delete(uint32_t dwTimerId); +void phOsalNfc_Timer_Cleanup(void); +uint32_t phUtilNfc_CheckForAvailableTimer(void); +NFCSTATUS phOsalNfc_CheckTimerPresence(void* pObjectHandle); + +#ifdef __cplusplus +} +#endif /* C++ Compilation guard */ +#endif /* PHOSALNFC_TIMER_H */ diff --git a/pn54x/tml/phTmlNfc.c b/pn54x/tml/phTmlNfc.c new file mode 100644 index 0000000..8aad810 --- /dev/null +++ b/pn54x/tml/phTmlNfc.c @@ -0,0 +1,949 @@ +/* + * Copyright (C) 2010-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. + */ + +/* + * TML Implementation. + */ + +#include +#include +#include +#include +#include +#include + +/* + * Duration of Timer to wait after sending an Nci packet + */ +#define PHTMLNFC_MAXTIME_RETRANSMIT (200U) +#define MAX_WRITE_RETRY_COUNT 0x03 +/* Retry Count = Standby Recovery time of NFCC / Retransmission time + 1 */ +static uint8_t bCurrentRetryCount = (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1; + +/* Value to reset variables of TML */ +#define PH_TMLNFC_RESET_VALUE (0x00) + +/* Indicates a Initial or offset value */ +#define PH_TMLNFC_VALUE_ONE (0x01) + +/* Initialize Context structure pointer used to access context structure */ +phTmlNfc_Context_t* gpphTmlNfc_Context = NULL; +phTmlNfc_i2cfragmentation_t fragmentation_enabled = I2C_FRAGMENATATION_DISABLED; +/* Local Function prototypes */ +static NFCSTATUS phTmlNfc_StartThread(void); +static void phTmlNfc_CleanUp(void); +static void phTmlNfc_ReadDeferredCb(void* pParams); +static void phTmlNfc_WriteDeferredCb(void* pParams); +static void phTmlNfc_TmlThread(void* pParam); +static void phTmlNfc_TmlWriterThread(void* pParam); +static void phTmlNfc_ReTxTimerCb(uint32_t dwTimerId, void* pContext); +static NFCSTATUS phTmlNfc_InitiateTimer(void); + +/* Function definitions */ + +/******************************************************************************* +** +** Function phTmlNfc_Init +** +** Description Provides initialization of TML layer and hardware interface +** Configures given hardware interface and sends handle to the +** caller +** +** Parameters pConfig - TML configuration details as provided by the upper +** layer +** +** Returns NFC status: +** NFCSTATUS_SUCCESS - initialization successful +** NFCSTATUS_INVALID_PARAMETER - at least one parameter is +** invalid +** NFCSTATUS_FAILED - initialization failed (for example, +** unable to open hardware interface) +** NFCSTATUS_INVALID_DEVICE - device has not been opened or has +** been disconnected +** +*******************************************************************************/ +NFCSTATUS phTmlNfc_Init(pphTmlNfc_Config_t pConfig) { + NFCSTATUS wInitStatus = NFCSTATUS_SUCCESS; + + /* Check if TML layer is already Initialized */ + if (NULL != gpphTmlNfc_Context) { + /* TML initialization is already completed */ + wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_ALREADY_INITIALISED); + } + /* Validate Input parameters */ + else if ((NULL == pConfig) || + (PH_TMLNFC_RESET_VALUE == pConfig->dwGetMsgThreadId)) { + /*Parameters passed to TML init are wrong */ + wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER); + } else { + /* Allocate memory for TML context */ + gpphTmlNfc_Context = malloc(sizeof(phTmlNfc_Context_t)); + + if (NULL == gpphTmlNfc_Context) { + wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED); + } else { + /* Initialise all the internal TML variables */ + memset(gpphTmlNfc_Context, PH_TMLNFC_RESET_VALUE, + sizeof(phTmlNfc_Context_t)); + /* Make sure that the thread runs once it is created */ + gpphTmlNfc_Context->bThreadDone = 1; + + /* Open the device file to which data is read/written */ + wInitStatus = phTmlNfc_i2c_open_and_configure( + pConfig, &(gpphTmlNfc_Context->pDevHandle)); + + if (NFCSTATUS_SUCCESS != wInitStatus) { + wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_DEVICE); + gpphTmlNfc_Context->pDevHandle = NULL; + } else { + gpphTmlNfc_Context->tReadInfo.bEnable = 0; + gpphTmlNfc_Context->tWriteInfo.bEnable = 0; + gpphTmlNfc_Context->tReadInfo.bThreadBusy = false; + gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false; + + if (0 != sem_init(&gpphTmlNfc_Context->rxSemaphore, 0, 0)) { + wInitStatus = NFCSTATUS_FAILED; + } else if (0 != sem_init(&gpphTmlNfc_Context->txSemaphore, 0, 0)) { + wInitStatus = NFCSTATUS_FAILED; + } else if (0 != sem_init(&gpphTmlNfc_Context->postMsgSemaphore, 0, 0)) { + wInitStatus = NFCSTATUS_FAILED; + } else { + sem_post(&gpphTmlNfc_Context->postMsgSemaphore); + /* Start TML thread (to handle write and read operations) */ + if (NFCSTATUS_SUCCESS != phTmlNfc_StartThread()) { + wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED); + } else { + /* Create Timer used for Retransmission of NCI packets */ + gpphTmlNfc_Context->dwTimerId = phOsalNfc_Timer_Create(); + if (PH_OSALNFC_TIMER_ID_INVALID != gpphTmlNfc_Context->dwTimerId) { + /* Store the Thread Identifier to which Message is to be posted */ + gpphTmlNfc_Context->dwCallbackThreadId = + pConfig->dwGetMsgThreadId; + /* Enable retransmission of Nci packet & set retry count to + * default */ + gpphTmlNfc_Context->eConfig = phTmlNfc_e_DisableRetrans; + /* Retry Count = Standby Recovery time of NFCC / Retransmission + * time + 1 */ + gpphTmlNfc_Context->bRetryCount = + (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1; + gpphTmlNfc_Context->bWriteCbInvoked = false; + } else { + wInitStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED); + } + } + } + } + } + } + /* Clean up all the TML resources if any error */ + if (NFCSTATUS_SUCCESS != wInitStatus) { + /* Clear all handles and memory locations initialized during init */ + phTmlNfc_CleanUp(); + } + + return wInitStatus; +} + +/******************************************************************************* +** +** Function phTmlNfc_ConfigNciPktReTx +** +** Description Provides Enable/Disable Retransmission of NCI packets +** Needed in case of Timeout between Transmission and Reception +** of NCI packets. Retransmission can be enabled only if +** standby mode is enabled +** +** Parameters eConfig - values from phTmlNfc_ConfigRetrans_t +** bRetryCount - Number of times Nci packets shall be +** retransmitted (default = 3) +** +** Returns None +** +*******************************************************************************/ +void phTmlNfc_ConfigNciPktReTx(phTmlNfc_ConfigRetrans_t eConfiguration, + uint8_t bRetryCounter) { + /* Enable/Disable Retransmission */ + + gpphTmlNfc_Context->eConfig = eConfiguration; + if (phTmlNfc_e_EnableRetrans == eConfiguration) { + /* Check whether Retry counter passed is valid */ + if (0 != bRetryCounter) { + gpphTmlNfc_Context->bRetryCount = bRetryCounter; + } + /* Set retry counter to its default value */ + else { + /* Retry Count = Standby Recovery time of NFCC / Retransmission time + 1 + */ + gpphTmlNfc_Context->bRetryCount = + (2000 / PHTMLNFC_MAXTIME_RETRANSMIT) + 1; + } + } + + return; +} + +/******************************************************************************* +** +** Function phTmlNfc_StartThread +** +** Description Initializes comport, reader and writer threads +** +** Parameters None +** +** Returns NFC status: +** NFCSTATUS_SUCCESS - threads initialized successfully +** NFCSTATUS_FAILED - initialization failed due to system error +** +*******************************************************************************/ +static NFCSTATUS phTmlNfc_StartThread(void) { + NFCSTATUS wStartStatus = NFCSTATUS_SUCCESS; + void* h_threadsEvent = 0x00; + uint32_t dwEvent; + int pthread_create_status = 0; + + /* Create Reader and Writer threads */ + pthread_create_status = + pthread_create(&gpphTmlNfc_Context->readerThread, NULL, + (void*)&phTmlNfc_TmlThread, (void*)h_threadsEvent); + if (0 != pthread_create_status) { + wStartStatus = NFCSTATUS_FAILED; + } else { + /*Start Writer Thread*/ + pthread_create_status = + pthread_create(&gpphTmlNfc_Context->writerThread, NULL, + (void*)&phTmlNfc_TmlWriterThread, (void*)h_threadsEvent); + if (0 != pthread_create_status) { + wStartStatus = NFCSTATUS_FAILED; + } + } + + return wStartStatus; +} + +/******************************************************************************* +** +** Function phTmlNfc_ReTxTimerCb +** +** Description This is the timer callback function after timer expiration. +** +** Parameters dwThreadId - id of the thread posting message +** pContext - context provided by upper layer +** +** Returns None +** +*******************************************************************************/ +static void phTmlNfc_ReTxTimerCb(uint32_t dwTimerId, void* pContext) { + if ((gpphTmlNfc_Context->dwTimerId == dwTimerId) && (NULL == pContext)) { + /* If Retry Count has reached its limit,Retransmit Nci + packet */ + if (0 == bCurrentRetryCount) { + /* Since the count has reached its limit,return from timer callback + Upper layer Timeout would have happened */ + } else { + bCurrentRetryCount--; + gpphTmlNfc_Context->tWriteInfo.bThreadBusy = true; + gpphTmlNfc_Context->tWriteInfo.bEnable = 1; + } + sem_post(&gpphTmlNfc_Context->txSemaphore); + } + + return; +} + +/******************************************************************************* +** +** Function phTmlNfc_InitiateTimer +** +** Description Start a timer for Tx and Rx thread. +** +** Parameters void +** +** Returns NFC status +** +*******************************************************************************/ +static NFCSTATUS phTmlNfc_InitiateTimer(void) { + NFCSTATUS wStatus = NFCSTATUS_SUCCESS; + + /* Start Timer once Nci packet is sent */ + wStatus = phOsalNfc_Timer_Start(gpphTmlNfc_Context->dwTimerId, + (uint32_t)PHTMLNFC_MAXTIME_RETRANSMIT, + phTmlNfc_ReTxTimerCb, NULL); + + return wStatus; +} + +/******************************************************************************* +** +** Function phTmlNfc_TmlThread +** +** Description Read the data from the lower layer driver +** +** Parameters pParam - parameters for Writer thread function +** +** Returns None +** +*******************************************************************************/ +static void phTmlNfc_TmlThread(void* pParam) { + NFCSTATUS wStatus = NFCSTATUS_SUCCESS; + int32_t dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE; + uint8_t temp[260]; + /* Transaction info buffer to be passed to Callback Thread */ + static phTmlNfc_TransactInfo_t tTransactionInfo; + /* Structure containing Tml callback function and parameters to be invoked + by the callback thread */ + static phLibNfc_DeferredCall_t tDeferredInfo; + /* Initialize Message structure to post message onto Callback Thread */ + static phLibNfc_Message_t tMsg; + UNUSED(pParam); + NXPLOG_TML_D("PN54X - Tml Reader Thread Started................\n"); + + /* Writer thread loop shall be running till shutdown is invoked */ + while (gpphTmlNfc_Context->bThreadDone) { + /* If Tml write is requested */ + /* Set the variable to success initially */ + wStatus = NFCSTATUS_SUCCESS; + sem_wait(&gpphTmlNfc_Context->rxSemaphore); + + /* If Tml read is requested */ + if (1 == gpphTmlNfc_Context->tReadInfo.bEnable) { + NXPLOG_TML_D("PN54X - Read requested.....\n"); + /* Set the variable to success initially */ + wStatus = NFCSTATUS_SUCCESS; + + /* Variable to fetch the actual number of bytes read */ + dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE; + + /* Read the data from the file onto the buffer */ + if (NULL != gpphTmlNfc_Context->pDevHandle) { + NXPLOG_TML_D("PN54X - Invoking I2C Read.....\n"); + dwNoBytesWrRd = + phTmlNfc_i2c_read(gpphTmlNfc_Context->pDevHandle, temp, 260); + + if (-1 == dwNoBytesWrRd) { + NXPLOG_TML_E("PN54X - Error in I2C Read.....\n"); + sem_post(&gpphTmlNfc_Context->rxSemaphore); + } else if (dwNoBytesWrRd > 260) { + NXPLOG_TML_E("Numer of bytes read exceeds the limit 260.....\n"); + sem_post(&gpphTmlNfc_Context->rxSemaphore); + } else { + memcpy(gpphTmlNfc_Context->tReadInfo.pBuffer, temp, dwNoBytesWrRd); + + NXPLOG_TML_D("PN54X - I2C Read successful.....\n"); + /* This has to be reset only after a successful read */ + gpphTmlNfc_Context->tReadInfo.bEnable = 0; + if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) && + (0x00 != (gpphTmlNfc_Context->tReadInfo.pBuffer[0] & 0xE0))) { + NXPLOG_TML_D("PN54X - Retransmission timer stopped.....\n"); + /* Stop Timer to prevent Retransmission */ + uint32_t timerStatus = + phOsalNfc_Timer_Stop(gpphTmlNfc_Context->dwTimerId); + if (NFCSTATUS_SUCCESS != timerStatus) { + NXPLOG_TML_E("PN54X - timer stopped returned failure.....\n"); + } else { + gpphTmlNfc_Context->bWriteCbInvoked = false; + } + } + if (gpphTmlNfc_Context->tWriteInfo.bThreadBusy) { + NXPLOG_TML_D("Delay Read if write thread is busy"); + usleep(2000); /*2ms delay to give prio to write complete */ + } + /* Update the actual number of bytes read including header */ + gpphTmlNfc_Context->tReadInfo.wLength = (uint16_t)(dwNoBytesWrRd); + phNxpNciHal_print_packet("RECV", + gpphTmlNfc_Context->tReadInfo.pBuffer, + gpphTmlNfc_Context->tReadInfo.wLength); + + dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE; + + /* Fill the Transaction info structure to be passed to Callback + * Function */ + tTransactionInfo.wStatus = wStatus; + tTransactionInfo.pBuff = gpphTmlNfc_Context->tReadInfo.pBuffer; + /* Actual number of bytes read is filled in the structure */ + tTransactionInfo.wLength = gpphTmlNfc_Context->tReadInfo.wLength; + + /* Read operation completed successfully. Post a Message onto Callback + * Thread*/ + /* Prepare the message to be posted on User thread */ + tDeferredInfo.pCallback = &phTmlNfc_ReadDeferredCb; + tDeferredInfo.pParameter = &tTransactionInfo; + tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; + tMsg.pMsgData = &tDeferredInfo; + tMsg.Size = sizeof(tDeferredInfo); + NXPLOG_TML_D("PN54X - Posting read message.....\n"); + phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg); + } + } else { + NXPLOG_TML_D("PN54X -gpphTmlNfc_Context->pDevHandle is NULL"); + } + } else { + NXPLOG_TML_D("PN54X - read request NOT enabled"); + usleep(10 * 1000); + } + } /* End of While loop */ + + return; +} + +/******************************************************************************* +** +** Function phTmlNfc_TmlWriterThread +** +** Description Writes the requested data onto the lower layer driver +** +** Parameters pParam - context provided by upper layer +** +** Returns None +** +*******************************************************************************/ +static void phTmlNfc_TmlWriterThread(void* pParam) { + NFCSTATUS wStatus = NFCSTATUS_SUCCESS; + int32_t dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE; + /* Transaction info buffer to be passed to Callback Thread */ + static phTmlNfc_TransactInfo_t tTransactionInfo; + /* Structure containing Tml callback function and parameters to be invoked + by the callback thread */ + static phLibNfc_DeferredCall_t tDeferredInfo; + /* Initialize Message structure to post message onto Callback Thread */ + static phLibNfc_Message_t tMsg; + /* In case of I2C Write Retry */ + static uint16_t retry_cnt; + UNUSED(pParam); + NXPLOG_TML_D("PN54X - Tml Writer Thread Started................\n"); + + /* Writer thread loop shall be running till shutdown is invoked */ + while (gpphTmlNfc_Context->bThreadDone) { + NXPLOG_TML_D("PN54X - Tml Writer Thread Running................\n"); + sem_wait(&gpphTmlNfc_Context->txSemaphore); + /* If Tml write is requested */ + if (1 == gpphTmlNfc_Context->tWriteInfo.bEnable) { + NXPLOG_TML_D("PN54X - Write requested.....\n"); + /* Set the variable to success initially */ + wStatus = NFCSTATUS_SUCCESS; + if (NULL != gpphTmlNfc_Context->pDevHandle) { + retry: + gpphTmlNfc_Context->tWriteInfo.bEnable = 0; + /* Variable to fetch the actual number of bytes written */ + dwNoBytesWrRd = PH_TMLNFC_RESET_VALUE; + /* Write the data in the buffer onto the file */ + NXPLOG_TML_D("PN54X - Invoking I2C Write.....\n"); + dwNoBytesWrRd = + phTmlNfc_i2c_write(gpphTmlNfc_Context->pDevHandle, + gpphTmlNfc_Context->tWriteInfo.pBuffer, + gpphTmlNfc_Context->tWriteInfo.wLength); + + /* Try I2C Write Five Times, if it fails : Raju */ + if (-1 == dwNoBytesWrRd) { + if (getDownloadFlag() == true) { + if (retry_cnt++ < MAX_WRITE_RETRY_COUNT) { + NXPLOG_NCIHAL_E("PN54X - Error in I2C Write - Retry 0x%x", + retry_cnt); + // Add a 10 ms delay to ensure NFCC is not still in stand by mode. + usleep(10 * 1000); + goto retry; + } + } + NXPLOG_TML_E("PN54X - Error in I2C Write.....\n"); + wStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_FAILED); + } else { + phNxpNciHal_print_packet("SEND", + gpphTmlNfc_Context->tWriteInfo.pBuffer, + gpphTmlNfc_Context->tWriteInfo.wLength); + } + retry_cnt = 0; + if (NFCSTATUS_SUCCESS == wStatus) { + NXPLOG_TML_D("PN54X - I2C Write successful.....\n"); + dwNoBytesWrRd = PH_TMLNFC_VALUE_ONE; + } + /* Fill the Transaction info structure to be passed to Callback Function + */ + tTransactionInfo.wStatus = wStatus; + tTransactionInfo.pBuff = gpphTmlNfc_Context->tWriteInfo.pBuffer; + /* Actual number of bytes written is filled in the structure */ + tTransactionInfo.wLength = (uint16_t)dwNoBytesWrRd; + + /* Prepare the message to be posted on the User thread */ + tDeferredInfo.pCallback = &phTmlNfc_WriteDeferredCb; + tDeferredInfo.pParameter = &tTransactionInfo; + /* Write operation completed successfully. Post a Message onto Callback + * Thread*/ + tMsg.eMsgType = PH_LIBNFC_DEFERREDCALL_MSG; + tMsg.pMsgData = &tDeferredInfo; + tMsg.Size = sizeof(tDeferredInfo); + + /* Check whether Retransmission needs to be started, + * If yes, Post message only if + * case 1. Message is not posted && + * case 11. Write status is success || + * case 12. Last retry of write is also failure + */ + if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) && + (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) { + if (gpphTmlNfc_Context->bWriteCbInvoked == false) { + if ((NFCSTATUS_SUCCESS == wStatus) || (bCurrentRetryCount == 0)) { + NXPLOG_TML_D("PN54X - Posting Write message.....\n"); + phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, + &tMsg); + gpphTmlNfc_Context->bWriteCbInvoked = true; + } + } + } else { + NXPLOG_TML_D("PN54X - Posting Fresh Write message.....\n"); + phTmlNfc_DeferredCall(gpphTmlNfc_Context->dwCallbackThreadId, &tMsg); + } + } else { + NXPLOG_TML_D("PN54X - gpphTmlNfc_Context->pDevHandle is NULL"); + } + + /* If Data packet is sent, then NO retransmission */ + if ((phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) && + (0x00 != (gpphTmlNfc_Context->tWriteInfo.pBuffer[0] & 0xE0))) { + NXPLOG_TML_D("PN54X - Starting timer for Retransmission case"); + wStatus = phTmlNfc_InitiateTimer(); + if (NFCSTATUS_SUCCESS != wStatus) { + /* Reset Variables used for Retransmission */ + NXPLOG_TML_D("PN54X - Retransmission timer initiate failed"); + gpphTmlNfc_Context->tWriteInfo.bEnable = 0; + bCurrentRetryCount = 0; + } + } + } else { + NXPLOG_TML_D("PN54X - Write request NOT enabled"); + usleep(10000); + } + + } /* End of While loop */ + + return; +} + +/******************************************************************************* +** +** Function phTmlNfc_CleanUp +** +** Description Clears all handles opened during TML initialization +** +** Parameters None +** +** Returns None +** +*******************************************************************************/ +static void phTmlNfc_CleanUp(void) { + NFCSTATUS wRetval = NFCSTATUS_SUCCESS; + + if (NULL == gpphTmlNfc_Context) { + return; + } + if (NULL != gpphTmlNfc_Context->pDevHandle) { + (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0); + gpphTmlNfc_Context->bThreadDone = 0; + } + sem_destroy(&gpphTmlNfc_Context->rxSemaphore); + sem_destroy(&gpphTmlNfc_Context->txSemaphore); + sem_destroy(&gpphTmlNfc_Context->postMsgSemaphore); + phTmlNfc_i2c_close(gpphTmlNfc_Context->pDevHandle); + gpphTmlNfc_Context->pDevHandle = NULL; + /* Clear memory allocated for storing Context variables */ + free((void*)gpphTmlNfc_Context); + /* Set the pointer to NULL to indicate De-Initialization */ + gpphTmlNfc_Context = NULL; + + return; +} + +/******************************************************************************* +** +** Function phTmlNfc_Shutdown +** +** Description Uninitializes TML layer and hardware interface +** +** Parameters None +** +** Returns NFC status: +** NFCSTATUS_SUCCESS - TML configuration released successfully +** NFCSTATUS_INVALID_PARAMETER - at least one parameter is +** invalid +** NFCSTATUS_FAILED - un-initialization failed (example: unable +** to close interface) +** +*******************************************************************************/ +NFCSTATUS phTmlNfc_Shutdown(void) { + NFCSTATUS wShutdownStatus = NFCSTATUS_SUCCESS; + + /* Check whether TML is Initialized */ + if (NULL != gpphTmlNfc_Context) { + /* Reset thread variable to terminate the thread */ + gpphTmlNfc_Context->bThreadDone = 0; + usleep(1000); + /* Clear All the resources allocated during initialization */ + sem_post(&gpphTmlNfc_Context->rxSemaphore); + usleep(1000); + sem_post(&gpphTmlNfc_Context->txSemaphore); + usleep(1000); + sem_post(&gpphTmlNfc_Context->postMsgSemaphore); + usleep(1000); + sem_post(&gpphTmlNfc_Context->postMsgSemaphore); + usleep(1000); + if (0 != pthread_join(gpphTmlNfc_Context->readerThread, (void**)NULL)) { + NXPLOG_TML_E("Fail to kill reader thread!"); + } + if (0 != pthread_join(gpphTmlNfc_Context->writerThread, (void**)NULL)) { + NXPLOG_TML_E("Fail to kill writer thread!"); + } + NXPLOG_TML_D("bThreadDone == 0"); + + phTmlNfc_CleanUp(); + } else { + wShutdownStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED); + } + + return wShutdownStatus; +} + +/******************************************************************************* +** +** Function phTmlNfc_Write +** +** Description Asynchronously writes given data block to hardware +** interface/driver. Enables writer thread if there are no +** write requests pending. Returns successfully once writer +** thread completes write operation. Notifies upper layer using +** callback mechanism. +** +** NOTE: +** * it is important to post a message with id +** PH_TMLNFC_WRITE_MESSAGE to IntegrationThread after data +** has been written to PN54X +** * if CRC needs to be computed, then input buffer should be +** capable to store two more bytes apart from length of +** packet +** +** Parameters pBuffer - data to be sent +** wLength - length of data buffer +** pTmlWriteComplete - pointer to the function to be invoked +** upon completion +** pContext - context provided by upper layer +** +** Returns NFC status: +** NFCSTATUS_PENDING - command is yet to be processed +** NFCSTATUS_INVALID_PARAMETER - at least one parameter is +** invalid +** NFCSTATUS_BUSY - write request is already in progress +** +*******************************************************************************/ +NFCSTATUS phTmlNfc_Write(uint8_t* pBuffer, uint16_t wLength, + pphTmlNfc_TransactCompletionCb_t pTmlWriteComplete, + void* pContext) { + NFCSTATUS wWriteStatus; + + /* Check whether TML is Initialized */ + + if (NULL != gpphTmlNfc_Context) { + if ((NULL != gpphTmlNfc_Context->pDevHandle) && (NULL != pBuffer) && + (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlWriteComplete)) { + if (!gpphTmlNfc_Context->tWriteInfo.bThreadBusy) { + /* Setting the flag marks beginning of a Write Operation */ + gpphTmlNfc_Context->tWriteInfo.bThreadBusy = true; + /* Copy the buffer, length and Callback function, + This shall be utilized while invoking the Callback function in thread + */ + gpphTmlNfc_Context->tWriteInfo.pBuffer = pBuffer; + gpphTmlNfc_Context->tWriteInfo.wLength = wLength; + gpphTmlNfc_Context->tWriteInfo.pThread_Callback = pTmlWriteComplete; + gpphTmlNfc_Context->tWriteInfo.pContext = pContext; + + wWriteStatus = NFCSTATUS_PENDING; + // FIXME: If retry is going on. Stop the retry thread/timer + if (phTmlNfc_e_EnableRetrans == gpphTmlNfc_Context->eConfig) { + /* Set retry count to default value */ + // FIXME: If the timer expired there, and meanwhile we have created + // a new request. The expired timer will think that retry is still + // ongoing. + bCurrentRetryCount = gpphTmlNfc_Context->bRetryCount; + gpphTmlNfc_Context->bWriteCbInvoked = false; + } + /* Set event to invoke Writer Thread */ + gpphTmlNfc_Context->tWriteInfo.bEnable = 1; + sem_post(&gpphTmlNfc_Context->txSemaphore); + } else { + wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY); + } + } else { + wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER); + } + } else { + wWriteStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED); + } + + return wWriteStatus; +} + +/******************************************************************************* +** +** Function phTmlNfc_Read +** +** Description Asynchronously reads data from the driver +** Number of bytes to be read and buffer are passed by upper +** layer. +** Enables reader thread if there are no read requests pending +** Returns successfully once read operation is completed +** Notifies upper layer using callback mechanism +** +** Parameters pBuffer - location to send read data to the upper layer via +** callback +** wLength - length of read data buffer passed by upper layer +** pTmlReadComplete - pointer to the function to be invoked +** upon completion of read operation +** pContext - context provided by upper layer +** +** Returns NFC status: +** NFCSTATUS_PENDING - command is yet to be processed +** NFCSTATUS_INVALID_PARAMETER - at least one parameter is +** invalid +** NFCSTATUS_BUSY - read request is already in progress +** +*******************************************************************************/ +NFCSTATUS phTmlNfc_Read(uint8_t* pBuffer, uint16_t wLength, + pphTmlNfc_TransactCompletionCb_t pTmlReadComplete, + void* pContext) { + NFCSTATUS wReadStatus; + + /* Check whether TML is Initialized */ + if (NULL != gpphTmlNfc_Context) { + if ((gpphTmlNfc_Context->pDevHandle != NULL) && (NULL != pBuffer) && + (PH_TMLNFC_RESET_VALUE != wLength) && (NULL != pTmlReadComplete)) { + if (!gpphTmlNfc_Context->tReadInfo.bThreadBusy) { + /* Setting the flag marks beginning of a Read Operation */ + gpphTmlNfc_Context->tReadInfo.bThreadBusy = true; + /* Copy the buffer, length and Callback function, + This shall be utilized while invoking the Callback function in thread + */ + gpphTmlNfc_Context->tReadInfo.pBuffer = pBuffer; + gpphTmlNfc_Context->tReadInfo.wLength = wLength; + gpphTmlNfc_Context->tReadInfo.pThread_Callback = pTmlReadComplete; + gpphTmlNfc_Context->tReadInfo.pContext = pContext; + wReadStatus = NFCSTATUS_PENDING; + + /* Set event to invoke Reader Thread */ + gpphTmlNfc_Context->tReadInfo.bEnable = 1; + sem_post(&gpphTmlNfc_Context->rxSemaphore); + } else { + wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_BUSY); + } + } else { + wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_INVALID_PARAMETER); + } + } else { + wReadStatus = PHNFCSTVAL(CID_NFC_TML, NFCSTATUS_NOT_INITIALISED); + } + + return wReadStatus; +} + +/******************************************************************************* +** +** Function phTmlNfc_ReadAbort +** +** Description Aborts pending read request (if any) +** +** Parameters None +** +** Returns NFC status: +** NFCSTATUS_SUCCESS - ongoing read operation aborted +** NFCSTATUS_INVALID_PARAMETER - at least one parameter is +** invalid +** NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized +** NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel read +** operation +** +*******************************************************************************/ +NFCSTATUS phTmlNfc_ReadAbort(void) { + NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER; + gpphTmlNfc_Context->tReadInfo.bEnable = 0; + + /*Reset the flag to accept another Read Request */ + gpphTmlNfc_Context->tReadInfo.bThreadBusy = false; + wStatus = NFCSTATUS_SUCCESS; + + return wStatus; +} + +/******************************************************************************* +** +** Function phTmlNfc_WriteAbort +** +** Description Aborts pending write request (if any) +** +** Parameters None +** +** Returns NFC status: +** NFCSTATUS_SUCCESS - ongoing write operation aborted +** NFCSTATUS_INVALID_PARAMETER - at least one parameter is +** invalid +** NFCSTATUS_NOT_INITIALIZED - TML layer is not initialized +** NFCSTATUS_BOARD_COMMUNICATION_ERROR - unable to cancel write +** operation +** +*******************************************************************************/ +NFCSTATUS phTmlNfc_WriteAbort(void) { + NFCSTATUS wStatus = NFCSTATUS_INVALID_PARAMETER; + + gpphTmlNfc_Context->tWriteInfo.bEnable = 0; + /* Stop if any retransmission is in progress */ + bCurrentRetryCount = 0; + + /* Reset the flag to accept another Write Request */ + gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false; + wStatus = NFCSTATUS_SUCCESS; + + return wStatus; +} + +/******************************************************************************* +** +** Function phTmlNfc_IoCtl +** +** Description Resets device when insisted by upper layer +** Number of bytes to be read and buffer are passed by upper +** layer +** Enables reader thread if there are no read requests pending +** Returns successfully once read operation is completed +** Notifies upper layer using callback mechanism +** +** Parameters eControlCode - control code for a specific operation +** +** Returns NFC status: +** NFCSTATUS_SUCCESS - ioctl command completed successfully +** NFCSTATUS_FAILED - ioctl command request failed +** +*******************************************************************************/ +NFCSTATUS phTmlNfc_IoCtl(phTmlNfc_ControlCode_t eControlCode) { + NFCSTATUS wStatus = NFCSTATUS_SUCCESS; + + if (NULL == gpphTmlNfc_Context) { + wStatus = NFCSTATUS_FAILED; + } else { + switch (eControlCode) { + case phTmlNfc_e_ResetDevice: { + /*Reset PN54X*/ + phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1); + usleep(100 * 1000); + phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0); + usleep(100 * 1000); + phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1); + break; + } + case phTmlNfc_e_EnableNormalMode: { + /*Reset PN54X*/ + phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 0); + usleep(10 * 1000); + phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 1); + usleep(100 * 1000); + break; + } + case phTmlNfc_e_EnableDownloadMode: { + phTmlNfc_ConfigNciPktReTx(phTmlNfc_e_DisableRetrans, 0); + (void)phTmlNfc_i2c_reset(gpphTmlNfc_Context->pDevHandle, 2); + usleep(100 * 1000); + break; + } + default: { + wStatus = NFCSTATUS_INVALID_PARAMETER; + break; + } + } + } + + return wStatus; +} + +/******************************************************************************* +** +** Function phTmlNfc_DeferredCall +** +** Description Posts message on upper layer thread +** upon successful read or write operation +** +** Parameters dwThreadId - id of the thread posting message +** ptWorkerMsg - message to be posted +** +** Returns None +** +*******************************************************************************/ +void phTmlNfc_DeferredCall(uintptr_t dwThreadId, + phLibNfc_Message_t* ptWorkerMsg) { + intptr_t bPostStatus; + UNUSED(dwThreadId); + /* Post message on the user thread to invoke the callback function */ + sem_wait(&gpphTmlNfc_Context->postMsgSemaphore); + bPostStatus = + phDal4Nfc_msgsnd(gpphTmlNfc_Context->dwCallbackThreadId, ptWorkerMsg, 0); + sem_post(&gpphTmlNfc_Context->postMsgSemaphore); +} + +/******************************************************************************* +** +** Function phTmlNfc_ReadDeferredCb +** +** Description Read thread call back function +** +** Parameters pParams - context provided by upper layer +** +** Returns None +** +*******************************************************************************/ +static void phTmlNfc_ReadDeferredCb(void* pParams) { + /* Transaction info buffer to be passed to Callback Function */ + phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams; + + /* Reset the flag to accept another Read Request */ + gpphTmlNfc_Context->tReadInfo.bThreadBusy = false; + gpphTmlNfc_Context->tReadInfo.pThread_Callback( + gpphTmlNfc_Context->tReadInfo.pContext, pTransactionInfo); + + return; +} + +/******************************************************************************* +** +** Function phTmlNfc_WriteDeferredCb +** +** Description Write thread call back function +** +** Parameters pParams - context provided by upper layer +** +** Returns None +** +*******************************************************************************/ +static void phTmlNfc_WriteDeferredCb(void* pParams) { + /* Transaction info buffer to be passed to Callback Function */ + phTmlNfc_TransactInfo_t* pTransactionInfo = (phTmlNfc_TransactInfo_t*)pParams; + + /* Reset the flag to accept another Write Request */ + gpphTmlNfc_Context->tWriteInfo.bThreadBusy = false; + gpphTmlNfc_Context->tWriteInfo.pThread_Callback( + gpphTmlNfc_Context->tWriteInfo.pContext, pTransactionInfo); + + return; +} + +void phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t result) { + fragmentation_enabled = result; +} + +phTmlNfc_i2cfragmentation_t phTmlNfc_get_fragmentation_enabled() { + return fragmentation_enabled; +} diff --git a/pn54x/tml/phTmlNfc.h b/pn54x/tml/phTmlNfc.h new file mode 100644 index 0000000..3955354 --- /dev/null +++ b/pn54x/tml/phTmlNfc.h @@ -0,0 +1,227 @@ +/* + * Copyright (C) 2010-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. + */ + +/* + * Transport Mapping Layer header files containing APIs related to initializing, + * reading + * and writing data into files provided by the driver interface. + * + * API listed here encompasses Transport Mapping Layer interfaces required to be + * mapped + * to different Interfaces and Platforms. + * + */ + +#ifndef PHTMLNFC_H +#define PHTMLNFC_H + +#include + +/* + * Message posted by Reader thread upon + * completion of requested operation + */ +#define PH_TMLNFC_READ_MESSAGE (0xAA) + +/* + * Message posted by Writer thread upon + * completion of requested operation + */ +#define PH_TMLNFC_WRITE_MESSAGE (0x55) + +/* + * Value indicates to reset device + */ +#define PH_TMLNFC_RESETDEVICE (0x00008001) + +/* +***************************Globals,Structure and Enumeration ****************** +*/ + +/* + * Transaction (Tx/Rx) completion information structure of TML + * + * This structure holds the completion callback information of the + * transaction passed from the TML layer to the Upper layer + * along with the completion callback. + * + * The value of field wStatus can be interpreted as: + * + * - NFCSTATUS_SUCCESS Transaction performed + * successfully. + * - NFCSTATUS_FAILED Failed to wait on Read/Write + * operation. + * - NFCSTATUS_INSUFFICIENT_STORAGE Not enough memory to store data in + * case of read. + * - NFCSTATUS_BOARD_COMMUNICATION_ERROR Failure to Read/Write from the + * file or timeout. + */ + +typedef struct phTmlNfc_TransactInfo { + NFCSTATUS wStatus; /* Status of the Transaction Completion*/ + uint8_t* pBuff; /* Response Data of the Transaction*/ + uint16_t wLength; /* Data size of the Transaction*/ +} phTmlNfc_TransactInfo_t; /* Instance of Transaction structure */ + +/* + * TML transreceive completion callback to Upper Layer + * + * pContext - Context provided by upper layer + * pInfo - Transaction info. See phTmlNfc_TransactInfo + */ +typedef void (*pphTmlNfc_TransactCompletionCb_t)( + void* pContext, phTmlNfc_TransactInfo_t* pInfo); + +/* + * TML Deferred callback interface structure invoked by upper layer + * + * This could be used for read/write operations + * + * dwMsgPostedThread Message source identifier + * pParams Parameters for the deferred call processing + */ +typedef void (*pphTmlNfc_DeferFuncPointer_t)(uint32_t dwMsgPostedThread, + void* pParams); + +/* + * Enum definition contains supported ioctl control codes. + * + * phTmlNfc_IoCtl + */ +typedef enum { + phTmlNfc_e_Invalid = 0, + phTmlNfc_e_ResetDevice = PH_TMLNFC_RESETDEVICE, /* Reset the device */ + phTmlNfc_e_EnableDownloadMode, /* Do the hardware setting to enter into + download mode */ + phTmlNfc_e_EnableNormalMode /* Hardware setting for normal mode of operation + */ +} phTmlNfc_ControlCode_t; /* Control code for IOCTL call */ + +/* + * Enable / Disable Re-Transmission of Packets + * + * phTmlNfc_ConfigNciPktReTx + */ +typedef enum { + phTmlNfc_e_EnableRetrans = 0x00, /*Enable retransmission of Nci packet */ + phTmlNfc_e_DisableRetrans = 0x01 /*Disable retransmission of Nci packet */ +} phTmlNfc_ConfigRetrans_t; /* Configuration for Retransmission */ + +/* + * Structure containing details related to read and write operations + * + */ +typedef struct phTmlNfc_ReadWriteInfo { + volatile uint8_t bEnable; /*This flag shall decide whether to perform + Write/Read operation */ + uint8_t + bThreadBusy; /*Flag to indicate thread is busy on respective operation */ + /* Transaction completion Callback function */ + pphTmlNfc_TransactCompletionCb_t pThread_Callback; + void* pContext; /*Context passed while invocation of operation */ + uint8_t* pBuffer; /*Buffer passed while invocation of operation */ + uint16_t wLength; /*Length of data read/written */ + NFCSTATUS wWorkStatus; /*Status of the transaction performed */ +} phTmlNfc_ReadWriteInfo_t; + +/* + *Base Context Structure containing members required for entire session + */ +typedef struct phTmlNfc_Context { + pthread_t readerThread; /*Handle to the thread which handles write and read + operations */ + pthread_t writerThread; + volatile uint8_t + bThreadDone; /*Flag to decide whether to run or abort the thread */ + phTmlNfc_ConfigRetrans_t + eConfig; /*Retransmission of Nci Packet during timeout */ + uint8_t bRetryCount; /*Number of times retransmission shall happen */ + uint8_t bWriteCbInvoked; /* Indicates whether write callback is invoked during + retransmission */ + uint32_t dwTimerId; /* Timer used to retransmit nci packet */ + phTmlNfc_ReadWriteInfo_t tReadInfo; /*Pointer to Reader Thread Structure */ + phTmlNfc_ReadWriteInfo_t tWriteInfo; /*Pointer to Writer Thread Structure */ + void* pDevHandle; /* Pointer to Device Handle */ + uintptr_t dwCallbackThreadId; /* Thread ID to which message to be posted */ + uint8_t bEnableCrc; /*Flag to validate/not CRC for input buffer */ + sem_t rxSemaphore; + sem_t txSemaphore; /* Lock/Aquire txRx Semaphore */ + sem_t postMsgSemaphore; /* Semaphore to post message atomically by Reader & + writer thread */ +} phTmlNfc_Context_t; + +/* + * TML Configuration exposed to upper layer. + */ +typedef struct phTmlNfc_Config { + /* Port name connected to PN54X + * + * Platform specific canonical device name to which PN54X is connected. + * + * e.g. On Linux based systems this would be /dev/PN54X + */ + int8_t* pDevName; + /* Callback Thread ID + * + * This is the thread ID on which the Reader & Writer thread posts message. */ + uintptr_t dwGetMsgThreadId; + /* Communication speed between DH and PN54X + * + * This is the baudrate of the bus for communication between DH and PN54X */ + uint32_t dwBaudRate; +} phTmlNfc_Config_t, *pphTmlNfc_Config_t; /* pointer to phTmlNfc_Config_t */ + +/* + * TML Deferred Callback structure used to invoke Upper layer Callback function. + */ +typedef struct { + /* Deferred callback function to be invoked */ + pphTmlNfc_DeferFuncPointer_t pDef_call; + /* Source identifier + * + * Identifier of the source which posted the message + */ + uint32_t dwMsgPostedThread; + /** Actual Message + * + * This is passed as a parameter passed to the deferred callback function + * pDef_call. */ + void* pParams; +} phTmlNfc_DeferMsg_t; /* DeferMsg structure passed to User Thread */ + +typedef enum { + I2C_FRAGMENATATION_DISABLED, /*i2c fragmentation_disabled */ + I2C_FRAGMENTATION_ENABLED /*i2c_fragmentation_enabled */ +} phTmlNfc_i2cfragmentation_t; +/* Function declarations */ +NFCSTATUS phTmlNfc_Init(pphTmlNfc_Config_t pConfig); +NFCSTATUS phTmlNfc_Shutdown(void); +NFCSTATUS phTmlNfc_Write(uint8_t* pBuffer, uint16_t wLength, + pphTmlNfc_TransactCompletionCb_t pTmlWriteComplete, + void* pContext); +NFCSTATUS phTmlNfc_Read(uint8_t* pBuffer, uint16_t wLength, + pphTmlNfc_TransactCompletionCb_t pTmlReadComplete, + void* pContext); +NFCSTATUS phTmlNfc_WriteAbort(void); +NFCSTATUS phTmlNfc_ReadAbort(void); +NFCSTATUS phTmlNfc_IoCtl(phTmlNfc_ControlCode_t eControlCode); +void phTmlNfc_DeferredCall(uintptr_t dwThreadId, + phLibNfc_Message_t* ptWorkerMsg); +void phTmlNfc_ConfigNciPktReTx(phTmlNfc_ConfigRetrans_t eConfig, + uint8_t bRetryCount); +void phTmlNfc_set_fragmentation_enabled(phTmlNfc_i2cfragmentation_t enable); +phTmlNfc_i2cfragmentation_t phTmlNfc_get_fragmentation_enabled(); +#endif /* PHTMLNFC_H */ diff --git a/pn54x/tml/phTmlNfc_i2c.c b/pn54x/tml/phTmlNfc_i2c.c new file mode 100644 index 0000000..781f19b --- /dev/null +++ b/pn54x/tml/phTmlNfc_i2c.c @@ -0,0 +1,315 @@ +/* + * Copyright (C) 2010-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. + */ + +/* + * DAL I2C port implementation for linux + * + * Project: Trusted NFC Linux + * + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include "phNxpNciHal_utils.h" + +#define CRC_LEN 2 +#define NORMAL_MODE_HEADER_LEN 3 +#define FW_DNLD_HEADER_LEN 2 +#define FW_DNLD_LEN_OFFSET 1 +#define NORMAL_MODE_LEN_OFFSET 2 +#define FRAGMENTSIZE_MAX PHNFC_I2C_FRAGMENT_SIZE +static bool_t bFwDnldFlag = false; +extern phTmlNfc_i2cfragmentation_t fragmentation_enabled; + +/******************************************************************************* +** +** Function phTmlNfc_i2c_close +** +** Description Closes PN54X device +** +** Parameters pDevHandle - device handle +** +** Returns None +** +*******************************************************************************/ +void phTmlNfc_i2c_close(void* pDevHandle) { + if (NULL != pDevHandle) { + close((intptr_t)pDevHandle); + } + + return; +} + +/******************************************************************************* +** +** Function phTmlNfc_i2c_open_and_configure +** +** Description Open and configure PN54X device +** +** Parameters pConfig - hardware information +** pLinkHandle - device handle +** +** Returns NFC status: +** NFCSTATUS_SUCCESS - open_and_configure operation success +** NFCSTATUS_INVALID_DEVICE - device open operation failure +** +*******************************************************************************/ +NFCSTATUS phTmlNfc_i2c_open_and_configure(pphTmlNfc_Config_t pConfig, + void** pLinkHandle) { + int nHandle; + + NXPLOG_TML_D("Opening port=%s\n", pConfig->pDevName); + /* open port */ + nHandle = open((const char*)pConfig->pDevName, O_RDWR); + if (nHandle < 0) { + NXPLOG_TML_E("_i2c_open() Failed: retval %x", nHandle); + *pLinkHandle = NULL; + return NFCSTATUS_INVALID_DEVICE; + } + + *pLinkHandle = (void*)((intptr_t)nHandle); + + /*Reset PN54X*/ + phTmlNfc_i2c_reset((void*)((intptr_t)nHandle), 0); + usleep(10 * 1000); + phTmlNfc_i2c_reset((void*)((intptr_t)nHandle), 1); + + return NFCSTATUS_SUCCESS; +} + +/******************************************************************************* +** +** Function phTmlNfc_i2c_read +** +** Description Reads requested number of bytes from PN54X device into given +** buffer +** +** Parameters pDevHandle - valid device handle +** pBuffer - buffer for read data +** nNbBytesToRead - number of bytes requested to be read +** +** Returns numRead - number of successfully read bytes +** -1 - read operation failure +** +*******************************************************************************/ +int phTmlNfc_i2c_read(void* pDevHandle, uint8_t* pBuffer, int nNbBytesToRead) { + int ret_Read; + int ret_Select; + int numRead = 0; + struct timeval tv; + fd_set rfds; + uint16_t totalBtyesToRead = 0; + + int i; + UNUSED(nNbBytesToRead); + if (NULL == pDevHandle) { + return -1; + } + + if (bFwDnldFlag == false) { + totalBtyesToRead = NORMAL_MODE_HEADER_LEN; + } else { + totalBtyesToRead = FW_DNLD_HEADER_LEN; + } + + /* Read with 2 second timeout, so that the read thread can be aborted + when the PN54X does not respond and we need to switch to FW download + mode. This should be done via a control socket instead. */ + FD_ZERO(&rfds); + FD_SET((intptr_t)pDevHandle, &rfds); + tv.tv_sec = 2; + tv.tv_usec = 1; + + ret_Select = + select((int)((intptr_t)pDevHandle + (int)1), &rfds, NULL, NULL, &tv); + if (ret_Select < 0) { + NXPLOG_TML_E("i2c select() errno : %x", errno); + return -1; + } else if (ret_Select == 0) { + NXPLOG_TML_E("i2c select() Timeout"); + return -1; + } else { + ret_Read = read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead - numRead); + if (ret_Read > 0) { + numRead += ret_Read; + } else if (ret_Read == 0) { + NXPLOG_TML_E("_i2c_read() [hdr]EOF"); + return -1; + } else { + NXPLOG_TML_E("_i2c_read() [hdr] errno : %x", errno); + return -1; + } + + if (bFwDnldFlag == false) { + totalBtyesToRead = NORMAL_MODE_HEADER_LEN; + } else { + totalBtyesToRead = FW_DNLD_HEADER_LEN; + } + + if (numRead < totalBtyesToRead) { + ret_Read = + read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead - numRead); + if (ret_Read != totalBtyesToRead - numRead) { + NXPLOG_TML_E("_i2c_read() [hdr] errno : %x", errno); + return -1; + } else { + numRead += ret_Read; + } + } + if (bFwDnldFlag == true) { + totalBtyesToRead = + pBuffer[FW_DNLD_LEN_OFFSET] + FW_DNLD_HEADER_LEN + CRC_LEN; + } else { + totalBtyesToRead = + pBuffer[NORMAL_MODE_LEN_OFFSET] + NORMAL_MODE_HEADER_LEN; + } + if ((totalBtyesToRead - numRead) != 0) { + ret_Read = read((intptr_t)pDevHandle, (pBuffer + numRead), + totalBtyesToRead - numRead); + if (ret_Read > 0) { + numRead += ret_Read; + } else if (ret_Read == 0) { + NXPLOG_TML_E("_i2c_read() [pyld] EOF"); + return -1; + } else { + if (bFwDnldFlag == false) { + NXPLOG_TML_E("_i2c_read() [hdr] received"); + phNxpNciHal_print_packet("RECV", pBuffer, NORMAL_MODE_HEADER_LEN); + } + NXPLOG_TML_E("_i2c_read() [pyld] errno : %x", errno); + return -1; + } + } else { + NXPLOG_TML_E("_>>>>> Empty packet recieved !!"); + } + } + return numRead; +} + +/******************************************************************************* +** +** Function phTmlNfc_i2c_write +** +** Description Writes requested number of bytes from given buffer into +** PN54X device +** +** Parameters pDevHandle - valid device handle +** pBuffer - buffer for read data +** nNbBytesToWrite - number of bytes requested to be written +** +** Returns numWrote - number of successfully written bytes +** -1 - write operation failure +** +*******************************************************************************/ +int phTmlNfc_i2c_write(void* pDevHandle, uint8_t* pBuffer, + int nNbBytesToWrite) { + int ret; + int numWrote = 0; + int i; + int numBytes = nNbBytesToWrite; + if (NULL == pDevHandle) { + return -1; + } + if (fragmentation_enabled == I2C_FRAGMENATATION_DISABLED && + nNbBytesToWrite > FRAGMENTSIZE_MAX) { + NXPLOG_TML_E( + "i2c_write() data larger than maximum I2C size,enable I2C " + "fragmentation"); + return -1; + } + while (numWrote < nNbBytesToWrite) { + if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED && + nNbBytesToWrite > FRAGMENTSIZE_MAX) { + if (nNbBytesToWrite - numWrote > FRAGMENTSIZE_MAX) { + numBytes = numWrote + FRAGMENTSIZE_MAX; + } else { + numBytes = nNbBytesToWrite; + } + } + ret = write((intptr_t)pDevHandle, pBuffer + numWrote, numBytes - numWrote); + if (ret > 0) { + numWrote += ret; + if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED && + numWrote < nNbBytesToWrite) { + usleep(500); + } + } else if (ret == 0) { + NXPLOG_TML_E("_i2c_write() EOF"); + return -1; + } else { + NXPLOG_TML_E("_i2c_write() errno : %x", errno); + if (errno == EINTR || errno == EAGAIN) { + continue; + } + return -1; + } + } + + return numWrote; +} + +/******************************************************************************* +** +** Function phTmlNfc_i2c_reset +** +** Description Reset PN54X device, using VEN pin +** +** Parameters pDevHandle - valid device handle +** level - reset level +** +** Returns 0 - reset operation success +** -1 - reset operation failure +** +*******************************************************************************/ +#define PN544_SET_PWR _IOW(0xe9, 0x01, unsigned int) +int phTmlNfc_i2c_reset(void* pDevHandle, long level) { + int ret; + NXPLOG_TML_D("phTmlNfc_i2c_reset(), VEN level %ld", level); + + if (NULL == pDevHandle) { + return -1; + } + + ret = ioctl((intptr_t)pDevHandle, PN544_SET_PWR, level); + if (level == 2 && ret == 0) { + bFwDnldFlag = true; + } else { + bFwDnldFlag = false; + } + return ret; +} + +/******************************************************************************* +** +** Function getDownloadFlag +** +** Description Returns the current mode +** +** Parameters none +** +** Returns Current mode download/NCI +*******************************************************************************/ +bool_t getDownloadFlag(void) { return bFwDnldFlag; } diff --git a/pn54x/tml/phTmlNfc_i2c.h b/pn54x/tml/phTmlNfc_i2c.h new file mode 100644 index 0000000..0949a72 --- /dev/null +++ b/pn54x/tml/phTmlNfc_i2c.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2010-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. + */ + +/* + * TML I2C port implementation for linux + */ + +/* Basic type definitions */ +#include +#include + +/* Function declarations */ +void phTmlNfc_i2c_close(void* pDevHandle); +NFCSTATUS phTmlNfc_i2c_open_and_configure(pphTmlNfc_Config_t pConfig, + void** pLinkHandle); +int phTmlNfc_i2c_read(void* pDevHandle, uint8_t* pBuffer, int nNbBytesToRead); +int phTmlNfc_i2c_write(void* pDevHandle, uint8_t* pBuffer, int nNbBytesToWrite); +int phTmlNfc_i2c_reset(void* pDevHandle, long level); +bool_t getDownloadFlag(void); -- cgit v1.2.3