1047 lines
35 KiB
C
1047 lines
35 KiB
C
/*
|
|
* Copyright (C) 2010 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.
|
|
*/
|
|
|
|
/**
|
|
* \file phDalNfc.c
|
|
* \brief DAL Implementation for linux
|
|
*
|
|
* Project: Trusted NFC Linux Lignt
|
|
*
|
|
* $Date: 07 aug 2009
|
|
* $Author: Jonathan roux
|
|
* $Revision: 1.0 $
|
|
*
|
|
*/
|
|
|
|
#define _DAL_4_NFC_C
|
|
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
#include <stdlib.h>
|
|
#ifdef ANDROID
|
|
#include <linux/ipc.h>
|
|
#include <cutils/log.h>
|
|
#include <cutils/properties.h> // for property_get
|
|
#else
|
|
#include <sys/msg.h>
|
|
#endif
|
|
#include <semaphore.h>
|
|
#include <phDal4Nfc.h>
|
|
#include <phOsalNfc.h>
|
|
#include <phNfcStatus.h>
|
|
#include <phDal4Nfc_DeferredCall.h>
|
|
#include <phDal4Nfc_debug.h>
|
|
#include <phDal4Nfc_uart.h>
|
|
#include <phDal4Nfc_i2c.h>
|
|
#include <phDal4Nfc_link.h>
|
|
#include <phDal4Nfc_messageQueueLib.h>
|
|
#include <hardware/hardware.h>
|
|
#include <hardware/nfc.h>
|
|
|
|
|
|
/*-----------------------------------------------------------------------------------
|
|
TYPES
|
|
------------------------------------------------------------------------------------*/
|
|
/*structure holds members related for both read and write operations*/
|
|
typedef struct Dal_RdWr_st
|
|
{
|
|
/* Read members */
|
|
pthread_t nReadThread; /* Read thread Hanlde */
|
|
uint8_t * pReadBuffer; /* Read local buffer */
|
|
int nNbOfBytesToRead; /* Number of bytes to read */
|
|
int nNbOfBytesRead; /* Number of read bytes */
|
|
char nReadBusy; /* Read state machine */
|
|
char nReadThreadAlive; /* Read state machine */
|
|
char nWaitingOnRead; /* Read state machine */
|
|
|
|
/* Read wait members */
|
|
uint8_t * pReadWaitBuffer; /* Read wait local Buffer */
|
|
int nNbOfBytesToReadWait; /* Number of bytes to read */
|
|
int nNbOfBytesReadWait; /* Number of read bytes */
|
|
char nReadWaitBusy; /* Read state machine */
|
|
char nWaitingOnReadWait; /* Read state machine */
|
|
char nCancelReadWait; /* Read state machine */
|
|
|
|
/* Write members */
|
|
pthread_t nWriteThread; /* Write thread Hanlde */
|
|
uint8_t * pWriteBuffer; /* Write local buffer */
|
|
uint8_t * pTempWriteBuffer; /* Temp Write local buffer */
|
|
int nNbOfBytesToWrite; /* Number of bytes to write */
|
|
int nNbOfBytesWritten; /* Number of bytes written */
|
|
char nWaitingOnWrite; /* Write state machine */
|
|
char nWriteThreadAlive; /* Write state machine */
|
|
char nWriteBusy; /* Write state machine */
|
|
} phDal4Nfc_RdWr_t;
|
|
|
|
typedef void (*pphDal4Nfc_DeferFuncPointer_t) (void * );
|
|
typedef void * (*pphDal4Nfc_thread_handler_t) (void * pParam);
|
|
|
|
|
|
/*-----------------------------------------------------------------------------------
|
|
VARIABLES
|
|
------------------------------------------------------------------------------------*/
|
|
static phDal4Nfc_RdWr_t gReadWriteContext;
|
|
static phDal4Nfc_SContext_t gDalContext;
|
|
static pphDal4Nfc_SContext_t pgDalContext;
|
|
static phHal_sHwReference_t * pgDalHwContext;
|
|
static sem_t nfc_read_sem;
|
|
static int low_level_traces;
|
|
#ifdef USE_MQ_MESSAGE_QUEUE
|
|
static phDal4Nfc_DeferredCall_Msg_t nDeferedMessage;
|
|
static mqd_t nDeferedCallMessageQueueId;
|
|
|
|
#else
|
|
int nDeferedCallMessageQueueId = 0;
|
|
#endif
|
|
static phDal4Nfc_link_cbk_interface_t gLinkFunc;
|
|
/*-----------------------------------------------------------------------------------
|
|
PROTOTYPES
|
|
------------------------------------------------------------------------------------*/
|
|
static void phDal4Nfc_DeferredCb (void *params);
|
|
static NFCSTATUS phDal4Nfc_StartThreads (void);
|
|
static void phDal4Nfc_FillMsg (phDal4Nfc_Message_t *pDalMsg, phOsalNfc_Message_t *pOsalMsg);
|
|
|
|
/*-----------------------------------------------------------------------------------
|
|
DAL API IMPLEMENTATION
|
|
------------------------------------------------------------------------------------*/
|
|
|
|
static void refresh_low_level_traces() {
|
|
#ifdef LOW_LEVEL_TRACES
|
|
low_level_traces = 1;
|
|
return;
|
|
#else
|
|
|
|
#ifdef ANDROID
|
|
char value[PROPERTY_VALUE_MAX];
|
|
|
|
property_get("ro.debuggable", value, "");
|
|
if (!value[0] || !atoi(value)) {
|
|
low_level_traces = 0; // user build, do not allow debug
|
|
return;
|
|
}
|
|
|
|
property_get("debug.nfc.LOW_LEVEL_TRACES", value, "0");
|
|
if (value[0]) {
|
|
low_level_traces = atoi(value);
|
|
return;
|
|
}
|
|
#endif
|
|
low_level_traces = 0;
|
|
#endif
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
FUNCTION: phDal4Nfc_Register
|
|
|
|
PURPOSE: DAL register function.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
NFCSTATUS phDal4Nfc_Register( phNfcIF_sReference_t *psRefer,
|
|
phNfcIF_sCallBack_t if_cb, void *psIFConf )
|
|
{
|
|
NFCSTATUS result = NFCSTATUS_SUCCESS;
|
|
|
|
if ((NULL != psRefer) &&
|
|
(NULL != psRefer->plower_if) &&
|
|
(NULL != if_cb.receive_complete) &&
|
|
(NULL != if_cb.send_complete)
|
|
)
|
|
{
|
|
/* Register the LLC functions to the upper layer */
|
|
psRefer->plower_if->init = phDal4Nfc_Init;
|
|
psRefer->plower_if->release = phDal4Nfc_Shutdown;
|
|
psRefer->plower_if->send = phDal4Nfc_Write;
|
|
psRefer->plower_if->receive = phDal4Nfc_Read;
|
|
psRefer->plower_if->receive_wait = phDal4Nfc_ReadWait;
|
|
psRefer->plower_if->transact_abort = phDal4Nfc_ReadWaitCancel;
|
|
psRefer->plower_if->unregister = phDal4Nfc_Unregister;
|
|
|
|
|
|
if (NULL != pgDalContext)
|
|
{
|
|
/* Copy the DAL context to the upper layer */
|
|
psRefer->plower_if->pcontext = pgDalContext;
|
|
/* Register the callback function from the upper layer */
|
|
pgDalContext->cb_if.receive_complete = if_cb.receive_complete;
|
|
pgDalContext->cb_if.send_complete = if_cb.send_complete;
|
|
pgDalContext->cb_if.notify = if_cb.notify;
|
|
/* Get the upper layer context */
|
|
pgDalContext->cb_if.pif_ctxt = if_cb.pif_ctxt;
|
|
/* Update the error state */
|
|
result = NFCSTATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_NOT_INITIALISED);
|
|
}
|
|
}
|
|
else /*Input parameters invalid*/
|
|
{
|
|
result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_PARAMETER);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
FUNCTION: phDal4Nfc_Unregister
|
|
|
|
PURPOSE: DAL unregister function.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
NFCSTATUS phDal4Nfc_Unregister(void *pContext, void *pHwRef )
|
|
{
|
|
NFCSTATUS result = NFCSTATUS_SUCCESS;
|
|
|
|
if ((NULL == pContext) && (NULL == pHwRef))
|
|
{
|
|
result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_PARAMETER);
|
|
}
|
|
else
|
|
{
|
|
if (NULL != pgDalContext)
|
|
{
|
|
/* Register the callback function from the upper layer */
|
|
pgDalContext->cb_if.receive_complete = NULL;
|
|
pgDalContext->cb_if.send_complete = NULL ;
|
|
pgDalContext->cb_if.notify = NULL ;
|
|
/* Get the upper layer context */
|
|
pgDalContext->cb_if.pif_ctxt = NULL ;
|
|
|
|
}
|
|
else
|
|
{
|
|
result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_NOT_INITIALISED);
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
FUNCTION: phDal4Nfc_Init
|
|
|
|
PURPOSE: DAL Init function.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
NFCSTATUS phDal4Nfc_Init(void *pContext, void *pHwRef )
|
|
{
|
|
NFCSTATUS result = NFCSTATUS_SUCCESS;
|
|
|
|
refresh_low_level_traces();
|
|
|
|
if ((NULL != pContext) && (NULL != pHwRef))
|
|
{
|
|
pContext = pgDalContext;
|
|
pgDalHwContext = (phHal_sHwReference_t *)pHwRef;
|
|
|
|
if ( gDalContext.hw_valid == TRUE )
|
|
{
|
|
/* The link has been opened from the application interface */
|
|
gLinkFunc.open_from_handle(pgDalHwContext);
|
|
|
|
if (!gLinkFunc.is_opened())
|
|
{
|
|
result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE);
|
|
}
|
|
else
|
|
{
|
|
/* Clear link buffers */
|
|
gLinkFunc.flush();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
static phDal4Nfc_sConfig_t hw_config;
|
|
hw_config.deviceNode = NULL;
|
|
result = phDal4Nfc_Config(&hw_config, pHwRef );
|
|
}
|
|
}
|
|
else /*Input parametrs invalid*/
|
|
{
|
|
result = NFCSTATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
FUNCTION: phDal4Nfc_Shutdown
|
|
|
|
PURPOSE: DAL Shutdown function.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
NFCSTATUS phDal4Nfc_Shutdown( void *pContext, void *pHwRef)
|
|
{
|
|
NFCSTATUS result = NFCSTATUS_SUCCESS;
|
|
void * pThreadReturn;
|
|
|
|
// if (pContext == NULL)
|
|
// return NFCSTATUS_INVALID_PARAMETER;
|
|
|
|
if (gDalContext.hw_valid == TRUE)
|
|
{
|
|
/* Flush the link */
|
|
gLinkFunc.flush();
|
|
|
|
/* Close the message queue */
|
|
#ifdef USE_MQ_MESSAGE_QUEUE
|
|
mq_close(nDeferedCallMessageQueueId);
|
|
#endif
|
|
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
NFCSTATUS phDal4Nfc_ConfigRelease(void *pHwRef)
|
|
{
|
|
|
|
NFCSTATUS result = NFCSTATUS_SUCCESS;
|
|
void * pThreadReturn;
|
|
|
|
DAL_PRINT("phDal4Nfc_ConfigRelease ");
|
|
|
|
if (gDalContext.hw_valid == TRUE)
|
|
{
|
|
/* Signal the read and write threads to exit. NOTE: there
|
|
actually is no write thread! :) */
|
|
DAL_PRINT("Stop Reader Thread");
|
|
gReadWriteContext.nReadThreadAlive = 0;
|
|
gReadWriteContext.nWriteThreadAlive = 0;
|
|
|
|
/* Wake up the read thread so it can exit */
|
|
DAL_PRINT("Release Read Semaphore");
|
|
sem_post(&nfc_read_sem);
|
|
|
|
DAL_DEBUG("phDal4Nfc_ConfigRelease - doing pthread_join(%d)",
|
|
gReadWriteContext.nReadThread);
|
|
if (pthread_join(gReadWriteContext.nReadThread, &pThreadReturn) != 0)
|
|
{
|
|
result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_FAILED);
|
|
DAL_PRINT("phDal4Nfc_ConfigRelease KO");
|
|
}
|
|
|
|
/* Close the message queue */
|
|
#ifdef USE_MQ_MESSAGE_QUEUE
|
|
mq_close(nDeferedCallMessageQueueId);
|
|
#endif
|
|
|
|
/* Shutdown NFC Chip */
|
|
phDal4Nfc_Reset(0);
|
|
|
|
/* Close the link */
|
|
gLinkFunc.close();
|
|
|
|
if (gDalContext.pDev != NULL) {
|
|
nfc_pn544_close(gDalContext.pDev);
|
|
}
|
|
/* Reset the Read Writer context to NULL */
|
|
memset((void *)&gReadWriteContext,0,sizeof(gReadWriteContext));
|
|
/* Reset the DAL context values to NULL */
|
|
memset((void *)&gDalContext,0,sizeof(gDalContext));
|
|
}
|
|
|
|
gDalContext.hw_valid = FALSE;
|
|
|
|
DAL_DEBUG("phDal4Nfc_ConfigRelease(): %04x\n", result);
|
|
|
|
|
|
return result;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
FUNCTION: phDal4Nfc_Write
|
|
|
|
PURPOSE: DAL Write function.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
NFCSTATUS phDal4Nfc_Write( void *pContext, void *pHwRef,uint8_t *pBuffer, uint16_t length)
|
|
{
|
|
NFCSTATUS result = NFCSTATUS_SUCCESS;
|
|
static int MsgType= PHDAL4NFC_WRITE_MESSAGE;
|
|
int * pmsgType=&MsgType;
|
|
phDal4Nfc_Message_t sMsg;
|
|
phOsalNfc_Message_t OsalMsg;
|
|
|
|
if ((NULL != pContext) && (NULL != pHwRef)&&
|
|
(NULL != pBuffer) && (0 != length))
|
|
{
|
|
if( gDalContext.hw_valid== TRUE)
|
|
{
|
|
if((!gReadWriteContext.nWriteBusy)&&
|
|
(!gReadWriteContext.nWaitingOnWrite))
|
|
{
|
|
DAL_PRINT("phDal4Nfc_Write() : Temporary buffer !! \n");
|
|
gReadWriteContext.pTempWriteBuffer = (uint8_t*)malloc(length * sizeof(uint8_t));
|
|
/* Make a copy of the passed arguments */
|
|
memcpy(gReadWriteContext.pTempWriteBuffer,pBuffer,length);
|
|
DAL_DEBUG("phDal4Nfc_Write(): %d\n", length);
|
|
gReadWriteContext.pWriteBuffer = gReadWriteContext.pTempWriteBuffer;
|
|
gReadWriteContext.nNbOfBytesToWrite = length;
|
|
/* Change the write state so that thread can take over the write */
|
|
gReadWriteContext.nWriteBusy = TRUE;
|
|
/* Just set variable here. This is the trigger for the Write thread */
|
|
gReadWriteContext.nWaitingOnWrite = TRUE;
|
|
/* Update the error state */
|
|
result = NFCSTATUS_PENDING;
|
|
/* Send Message and perform physical write in the DefferedCallback */
|
|
/* read completed immediately */
|
|
sMsg.eMsgType= PHDAL4NFC_WRITE_MESSAGE;
|
|
/* Update the state */
|
|
phDal4Nfc_FillMsg(&sMsg,&OsalMsg);
|
|
phDal4Nfc_DeferredCall((pphDal4Nfc_DeferFuncPointer_t)phDal4Nfc_DeferredCb,(void *)pmsgType);
|
|
memset(&sMsg,0,sizeof(phDal4Nfc_Message_t));
|
|
memset(&OsalMsg,0,sizeof(phOsalNfc_Message_t));
|
|
}
|
|
else
|
|
{
|
|
/* Driver is BUSY with previous Write */
|
|
DAL_PRINT("phDal4Nfc_Write() : Busy \n");
|
|
result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_BUSY) ;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* TBD :Additional error code : NOT_INITIALISED */
|
|
result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE);
|
|
}
|
|
|
|
}/*end if-Input parametrs valid-check*/
|
|
else
|
|
{
|
|
result = NFCSTATUS_INVALID_PARAMETER;
|
|
}
|
|
return result;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
FUNCTION: phDal4Nfc_Read
|
|
|
|
PURPOSE: DAL Read function.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
NFCSTATUS phDal4Nfc_Read( void *pContext, void *pHwRef,uint8_t *pBuffer, uint16_t length)
|
|
{
|
|
NFCSTATUS result = NFCSTATUS_SUCCESS;
|
|
|
|
if ((NULL != pContext) && (NULL != pHwRef)&&
|
|
(NULL != pBuffer) && (0 != length))
|
|
{
|
|
if ( gDalContext.hw_valid== TRUE)
|
|
{
|
|
if((!gReadWriteContext.nReadBusy)&&
|
|
(!gReadWriteContext.nWaitingOnRead))
|
|
{
|
|
DAL_DEBUG("*****DAl Read called length : %d\n", length);
|
|
|
|
/* Make a copy of the passed arguments */
|
|
gReadWriteContext.pReadBuffer = pBuffer;
|
|
gReadWriteContext.nNbOfBytesToRead = length;
|
|
/* Change the Read state so that thread can take over the read */
|
|
gReadWriteContext.nReadBusy = TRUE;
|
|
/* Just set variable here. This is the trigger for the Reader thread */
|
|
gReadWriteContext.nWaitingOnRead = TRUE;
|
|
/* Update the return state */
|
|
result = NFCSTATUS_PENDING;
|
|
/* unlock reader thread */
|
|
sem_post(&nfc_read_sem);
|
|
}
|
|
else
|
|
{
|
|
/* Driver is BUSY with prev Read */
|
|
DAL_PRINT("DAL BUSY\n");
|
|
/* Make a copy of the passed arguments */
|
|
gReadWriteContext.pReadBuffer = pBuffer;
|
|
gReadWriteContext.nNbOfBytesToRead = length;
|
|
result = NFCSTATUS_PENDING;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* TBD :Additional error code : NOT_INITIALISED */
|
|
result = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE);
|
|
}
|
|
}/*end if-Input parametrs valid-check*/
|
|
else
|
|
{
|
|
result = NFCSTATUS_INVALID_PARAMETER;
|
|
}
|
|
DAL_DEBUG("*****DAl Read called result : %x\n", result);
|
|
return result;
|
|
}
|
|
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
FUNCTION: phDal4Nfc_ReadWait
|
|
|
|
PURPOSE: DAL Read wait function.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
NFCSTATUS phDal4Nfc_ReadWait(void *pContext, void *pHwRef,uint8_t *pBuffer, uint16_t length)
|
|
{
|
|
/* not used */
|
|
DAL_PRINT("phDal4Nfc_ReadWait");
|
|
return 0;
|
|
}
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
FUNCTION: phDal4Nfc_ReadWaitCancel
|
|
|
|
PURPOSE: Cancel the Read wait function.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
|
|
NFCSTATUS phDal4Nfc_ReadWaitCancel( void *pContext, void *pHwRef)
|
|
{
|
|
DAL_PRINT("phDal4Nfc_ReadWaitCancel");
|
|
|
|
/* unlock read semaphore */
|
|
sem_post(&nfc_read_sem);
|
|
|
|
return 0;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
FUNCTION: phDal4Nfc_Config
|
|
|
|
PURPOSE: Configure the serial port.
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
NFCSTATUS phDal4Nfc_Config(pphDal4Nfc_sConfig_t config,void **phwref)
|
|
{
|
|
NFCSTATUS retstatus = NFCSTATUS_SUCCESS;
|
|
const hw_module_t* hw_module;
|
|
nfc_pn544_device_t* pn544_dev;
|
|
uint8_t num_eeprom_settings;
|
|
uint8_t* eeprom_settings;
|
|
int ret;
|
|
|
|
/* Retrieve the hw module from the Android NFC HAL */
|
|
ret = hw_get_module(NFC_HARDWARE_MODULE_ID, &hw_module);
|
|
if (ret) {
|
|
ALOGE("hw_get_module() failed");
|
|
return NFCSTATUS_FAILED;
|
|
}
|
|
ret = nfc_pn544_open(hw_module, &pn544_dev);
|
|
if (ret) {
|
|
ALOGE("Could not open pn544 hw_module");
|
|
return NFCSTATUS_FAILED;
|
|
}
|
|
config->deviceNode = pn544_dev->device_node;
|
|
if (config->deviceNode == NULL) {
|
|
ALOGE("deviceNode NULL");
|
|
return NFCSTATUS_FAILED;
|
|
}
|
|
|
|
DAL_PRINT("phDal4Nfc_Config");
|
|
|
|
if ((config == NULL) || (phwref == NULL))
|
|
return NFCSTATUS_INVALID_PARAMETER;
|
|
|
|
/* Register the link callbacks */
|
|
memset(&gLinkFunc, 0, sizeof(phDal4Nfc_link_cbk_interface_t));
|
|
switch(pn544_dev->linktype)
|
|
{
|
|
case PN544_LINK_TYPE_UART:
|
|
case PN544_LINK_TYPE_USB:
|
|
{
|
|
DAL_PRINT("UART link Config");
|
|
/* Uart link interface */
|
|
gLinkFunc.init = phDal4Nfc_uart_initialize;
|
|
gLinkFunc.open_from_handle = phDal4Nfc_uart_set_open_from_handle;
|
|
gLinkFunc.is_opened = phDal4Nfc_uart_is_opened;
|
|
gLinkFunc.flush = phDal4Nfc_uart_flush;
|
|
gLinkFunc.close = phDal4Nfc_uart_close;
|
|
gLinkFunc.open_and_configure = phDal4Nfc_uart_open_and_configure;
|
|
gLinkFunc.read = phDal4Nfc_uart_read;
|
|
gLinkFunc.write = phDal4Nfc_uart_write;
|
|
gLinkFunc.reset = phDal4Nfc_uart_reset;
|
|
}
|
|
break;
|
|
|
|
case PN544_LINK_TYPE_I2C:
|
|
{
|
|
DAL_PRINT("I2C link Config");
|
|
/* i2c link interface */
|
|
gLinkFunc.init = phDal4Nfc_i2c_initialize;
|
|
gLinkFunc.open_from_handle = phDal4Nfc_i2c_set_open_from_handle;
|
|
gLinkFunc.is_opened = phDal4Nfc_i2c_is_opened;
|
|
gLinkFunc.flush = phDal4Nfc_i2c_flush;
|
|
gLinkFunc.close = phDal4Nfc_i2c_close;
|
|
gLinkFunc.open_and_configure = phDal4Nfc_i2c_open_and_configure;
|
|
gLinkFunc.read = phDal4Nfc_i2c_read;
|
|
gLinkFunc.write = phDal4Nfc_i2c_write;
|
|
gLinkFunc.reset = phDal4Nfc_i2c_reset;
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
/* Shound not happen : Bad parameter */
|
|
return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
gLinkFunc.init(); /* So that link interface can initialize its internal state */
|
|
retstatus = gLinkFunc.open_and_configure(config, phwref);
|
|
if (retstatus != NFCSTATUS_SUCCESS)
|
|
return retstatus;
|
|
|
|
/* Iniatilize the DAL context */
|
|
(void)memset(&gDalContext,0,sizeof(phDal4Nfc_SContext_t));
|
|
pgDalContext = &gDalContext;
|
|
|
|
/* Reset the Reader Thread values to NULL */
|
|
memset((void *)&gReadWriteContext,0,sizeof(gReadWriteContext));
|
|
gReadWriteContext.nReadThreadAlive = TRUE;
|
|
gReadWriteContext.nWriteBusy = FALSE;
|
|
gReadWriteContext.nWaitingOnWrite = FALSE;
|
|
|
|
/* Prepare the message queue for the defered calls */
|
|
#ifdef USE_MQ_MESSAGE_QUEUE
|
|
nDeferedCallMessageQueueId = mq_open(MQ_NAME_IDENTIFIER, O_CREAT|O_RDWR, 0666, &MQ_QUEUE_ATTRIBUTES);
|
|
#else
|
|
nDeferedCallMessageQueueId = config->nClientId;
|
|
#endif
|
|
|
|
gDalContext.pDev = pn544_dev;
|
|
|
|
/* Start Read and Write Threads */
|
|
if(NFCSTATUS_SUCCESS != phDal4Nfc_StartThreads())
|
|
{
|
|
return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_FAILED);
|
|
}
|
|
|
|
gDalContext.hw_valid = TRUE;
|
|
phDal4Nfc_Reset(1);
|
|
phDal4Nfc_Reset(0);
|
|
phDal4Nfc_Reset(1);
|
|
|
|
return NFCSTATUS_SUCCESS;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
FUNCTION: phDal4Nfc_Reset
|
|
|
|
PURPOSE: Reset the PN544, using the VEN pin
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
NFCSTATUS phDal4Nfc_Reset(long level)
|
|
{
|
|
NFCSTATUS retstatus = NFCSTATUS_SUCCESS;
|
|
|
|
DAL_DEBUG("phDal4Nfc_Reset: VEN to %ld",level);
|
|
|
|
retstatus = gLinkFunc.reset(level);
|
|
|
|
return retstatus;
|
|
}
|
|
|
|
/*-----------------------------------------------------------------------------
|
|
|
|
FUNCTION: phDal4Nfc_Download
|
|
|
|
PURPOSE: Put the PN544 in download mode, using the GPIO4 pin
|
|
|
|
-----------------------------------------------------------------------------*/
|
|
NFCSTATUS phDal4Nfc_Download()
|
|
{
|
|
NFCSTATUS retstatus = NFCSTATUS_SUCCESS;
|
|
|
|
DAL_DEBUG("phDal4Nfc_Download: GPIO4 to %d",1);
|
|
|
|
usleep(10000);
|
|
retstatus = phDal4Nfc_Reset(2);
|
|
|
|
return retstatus;
|
|
}
|
|
|
|
|
|
|
|
/*-----------------------------------------------------------------------------------
|
|
DAL INTERNAL IMPLEMENTATION
|
|
------------------------------------------------------------------------------------*/
|
|
|
|
|
|
|
|
/**
|
|
* \ingroup grp_nfc_dal
|
|
*
|
|
* \brief DAL Reader thread handler
|
|
* This function manages the reads from the link interface. The reads are done from
|
|
* this thread to create the asynchronous mecanism. When calling the synchronous
|
|
* function phDal4Nfc_Read, the nWaitingOnRead mutex is unlocked and the read
|
|
* can be done. Then a client callback is called to send the result.
|
|
*
|
|
* \param[in] pArg A custom argument that can be passed to the thread (not used)
|
|
*
|
|
* \retval TRUE Thread exiting.
|
|
*/
|
|
|
|
int phDal4Nfc_ReaderThread(void * pArg)
|
|
{
|
|
char retvalue;
|
|
NFCSTATUS result = NFCSTATUS_SUCCESS;
|
|
uint8_t retry_cnt=0;
|
|
void * memsetRet;
|
|
|
|
static int MsgType= PHDAL4NFC_READ_MESSAGE;
|
|
int * pmsgType=&MsgType;
|
|
|
|
phDal4Nfc_Message_t sMsg;
|
|
phOsalNfc_Message_t OsalMsg ;
|
|
int i;
|
|
int i2c_error_count;
|
|
int i2c_workaround;
|
|
int i2c_device_address = 0x57;
|
|
if (gDalContext.pDev != NULL) {
|
|
i2c_workaround = gDalContext.pDev->enable_i2c_workaround;
|
|
if (gDalContext.pDev->i2c_device_address) {
|
|
i2c_device_address = gDalContext.pDev->i2c_device_address;
|
|
if (i2c_workaround && i2c_device_address < 32)
|
|
{
|
|
ALOGE("i2c_device_address not set to valid value");
|
|
return NFCSTATUS_FAILED;
|
|
}
|
|
}
|
|
} else {
|
|
ALOGE("gDalContext.pDev is not set");
|
|
return NFCSTATUS_FAILED;
|
|
}
|
|
|
|
pthread_setname_np(pthread_self(), "reader");
|
|
|
|
/* Create the overlapped event. Must be closed before exiting
|
|
to avoid a handle leak. This event is used READ API and the Reader thread*/
|
|
|
|
DAL_PRINT("RX Thread \n");
|
|
DAL_DEBUG("\nRX Thread nReadThreadAlive = %d",gReadWriteContext.nReadThreadAlive);
|
|
DAL_DEBUG("\nRX Thread nWaitingOnRead = %d",gReadWriteContext.nWaitingOnRead);
|
|
while(gReadWriteContext.nReadThreadAlive) /* Thread Loop */
|
|
{
|
|
/* Check for the read request from user */
|
|
DAL_PRINT("RX Thread Sem Lock\n");
|
|
sem_wait(&nfc_read_sem);
|
|
DAL_PRINT("RX Thread Sem UnLock\n");
|
|
|
|
if (!gReadWriteContext.nReadThreadAlive)
|
|
{
|
|
/* got the signal that we should exit. NOTE: we don't
|
|
attempt to read below, since the read may block */
|
|
break;
|
|
}
|
|
|
|
/* Issue read operation.*/
|
|
|
|
i2c_error_count = 0;
|
|
retry:
|
|
gReadWriteContext.nNbOfBytesRead=0;
|
|
DAL_DEBUG("RX Thread *New *** *****Request Length = %d",gReadWriteContext.nNbOfBytesToRead);
|
|
memsetRet=memset(gReadWriteContext.pReadBuffer,0,gReadWriteContext.nNbOfBytesToRead);
|
|
|
|
/* Wait for IRQ !!! */
|
|
gReadWriteContext.nNbOfBytesRead = gLinkFunc.read(gReadWriteContext.pReadBuffer, gReadWriteContext.nNbOfBytesToRead);
|
|
|
|
/* A read value equal to the i2c_device_address indicates a HW I2C error at I2C address i2c_device_address
|
|
* (pn544). There should not be false positives because a read of length 1
|
|
* must be a HCI length read, and a length of i2c_device_address is impossible (max is 33).
|
|
*/
|
|
if (i2c_workaround && gReadWriteContext.nNbOfBytesToRead == 1 &&
|
|
gReadWriteContext.pReadBuffer[0] == i2c_device_address)
|
|
{
|
|
i2c_error_count++;
|
|
DAL_DEBUG("RX Thread Read 0x%02x ", i2c_device_address);
|
|
DAL_DEBUG("%d times\n", i2c_error_count);
|
|
|
|
if (i2c_error_count < 5) {
|
|
usleep(2000);
|
|
goto retry;
|
|
}
|
|
DAL_PRINT("RX Thread NOTHING TO READ, RECOVER");
|
|
phOsalNfc_RaiseException(phOsalNfc_e_UnrecovFirmwareErr,1);
|
|
}
|
|
else
|
|
{
|
|
i2c_error_count = 0;
|
|
|
|
if (low_level_traces)
|
|
{
|
|
phOsalNfc_PrintData("RECV", (uint16_t)gReadWriteContext.nNbOfBytesRead,
|
|
gReadWriteContext.pReadBuffer, low_level_traces);
|
|
}
|
|
DAL_DEBUG("RX Thread Read ok. nbToRead=%d\n", gReadWriteContext.nNbOfBytesToRead);
|
|
DAL_DEBUG("RX Thread NbReallyRead=%d\n", gReadWriteContext.nNbOfBytesRead);
|
|
/* DAL_PRINT("RX Thread ReadBuff[]={ ");
|
|
for (i = 0; i < gReadWriteContext.nNbOfBytesRead; i++)
|
|
{
|
|
DAL_DEBUG("RX Thread 0x%x ", gReadWriteContext.pReadBuffer[i]);
|
|
}
|
|
DAL_PRINT("RX Thread }\n"); */
|
|
|
|
/* read completed immediately */
|
|
sMsg.eMsgType= PHDAL4NFC_READ_MESSAGE;
|
|
/* Update the state */
|
|
phDal4Nfc_FillMsg(&sMsg,&OsalMsg);
|
|
phDal4Nfc_DeferredCall((pphDal4Nfc_DeferFuncPointer_t)phDal4Nfc_DeferredCb,(void *)pmsgType);
|
|
memsetRet=memset(&sMsg,0,sizeof(phDal4Nfc_Message_t));
|
|
memsetRet=memset(&OsalMsg,0,sizeof(phOsalNfc_Message_t));
|
|
}
|
|
|
|
} /* End of thread Loop*/
|
|
|
|
DAL_PRINT("RX Thread exiting");
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* \ingroup grp_nfc_dal
|
|
*
|
|
* \brief DAL Start threads function
|
|
* This function is called from phDal4Nfc_Config and is responsible of creating the
|
|
* reader thread.
|
|
*
|
|
* \retval NFCSTATUS_SUCCESS If success.
|
|
* \retval NFCSTATUS_FAILED Can not create thread or retreive its attributes
|
|
*/
|
|
NFCSTATUS phDal4Nfc_StartThreads(void)
|
|
{
|
|
pthread_attr_t nReadThreadAttributes;
|
|
pthread_attr_t nWriteThreadAttributes;
|
|
int ret;
|
|
|
|
if(sem_init(&nfc_read_sem, 0, 0) == -1)
|
|
{
|
|
DAL_PRINT("NFC Init Semaphore creation Error");
|
|
return -1;
|
|
}
|
|
|
|
ret = pthread_create(&gReadWriteContext.nReadThread, NULL, (pphDal4Nfc_thread_handler_t)phDal4Nfc_ReaderThread, (void*) "dal_read_thread");
|
|
if(ret != 0)
|
|
return(PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_FAILED));
|
|
|
|
return NFCSTATUS_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* \ingroup grp_nfc_dal
|
|
*
|
|
* \brief DAL fill message function
|
|
* Internal messages management. This function fills message structure
|
|
* depending on message types.
|
|
*
|
|
* \param[in, out] pDalMsg DAL message to fill
|
|
* \param[in, out] pOsalMsg OSAL message to fill
|
|
*
|
|
*/
|
|
void phDal4Nfc_FillMsg(phDal4Nfc_Message_t *pDalMsg,phOsalNfc_Message_t *pOsalMsg)
|
|
{
|
|
if(NULL != pgDalHwContext)
|
|
{
|
|
if(pDalMsg->eMsgType == PHDAL4NFC_WRITE_MESSAGE)
|
|
{
|
|
pDalMsg->transactInfo.length = (uint8_t)gReadWriteContext.nNbOfBytesWritten;
|
|
pDalMsg->transactInfo.buffer = NULL;
|
|
pDalMsg->transactInfo.status = NFCSTATUS_SUCCESS;
|
|
pDalMsg->pHwRef = pgDalHwContext;
|
|
pDalMsg->writeCbPtr = pgDalContext->cb_if.send_complete;
|
|
pOsalMsg->eMsgType = PH_DAL4NFC_MESSAGE_BASE;
|
|
pOsalMsg->pMsgData = pDalMsg;
|
|
return;
|
|
}
|
|
else if(pDalMsg->eMsgType == PHDAL4NFC_READ_MESSAGE)
|
|
{
|
|
pDalMsg->transactInfo.length = (uint8_t)gReadWriteContext.nNbOfBytesRead;
|
|
pDalMsg->transactInfo.buffer = gReadWriteContext.pReadBuffer;
|
|
pDalMsg->pContext= pgDalContext->cb_if.pif_ctxt;
|
|
}
|
|
else
|
|
{
|
|
pDalMsg->transactInfo.length = (uint8_t)gReadWriteContext.nNbOfBytesReadWait;
|
|
pDalMsg->transactInfo.buffer = gReadWriteContext.pReadWaitBuffer;
|
|
pDalMsg->pContext= pgDalContext;
|
|
}
|
|
pDalMsg->transactInfo.status = NFCSTATUS_SUCCESS;
|
|
pDalMsg->pHwRef = pgDalHwContext;
|
|
pDalMsg->readCbPtr = pgDalContext->cb_if.receive_complete;
|
|
/*map to OSAL msg format*/
|
|
pOsalMsg->eMsgType = PH_DAL4NFC_MESSAGE_BASE;
|
|
pOsalMsg->pMsgData = pDalMsg;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* \ingroup grp_nfc_dal
|
|
*
|
|
* \brief DAL deferred callback function
|
|
* Generic handler function called by a client thread when reading a message from the queue.
|
|
* Will function will directly call the client function (same context). See phDal4Nfc_DeferredCall
|
|
*
|
|
* \param[in] params Parameter that will be passed to the client function.
|
|
*
|
|
*/
|
|
void phDal4Nfc_DeferredCb (void *params)
|
|
{
|
|
int* pParam=NULL;
|
|
int i;
|
|
phNfc_sTransactionInfo_t TransactionInfo;
|
|
|
|
pParam=(int*)params;
|
|
|
|
switch(*pParam)
|
|
{
|
|
case PHDAL4NFC_READ_MESSAGE:
|
|
DAL_PRINT(" Dal deferred read called \n");
|
|
TransactionInfo.buffer=gReadWriteContext.pReadBuffer;
|
|
TransactionInfo.length=(uint16_t)gReadWriteContext.nNbOfBytesRead;
|
|
if (gReadWriteContext.nNbOfBytesRead == gReadWriteContext.nNbOfBytesToRead) {
|
|
TransactionInfo.status=NFCSTATUS_SUCCESS;
|
|
} else {
|
|
TransactionInfo.status=NFCSTATUS_READ_FAILED;
|
|
}
|
|
gReadWriteContext.nReadBusy = FALSE;
|
|
|
|
|
|
/* Reset flag so that another opertion can be issued.*/
|
|
gReadWriteContext.nWaitingOnRead = FALSE;
|
|
if ((NULL != pgDalContext) && (NULL != pgDalContext->cb_if.receive_complete))
|
|
{
|
|
pgDalContext->cb_if.receive_complete(pgDalContext->cb_if.pif_ctxt,
|
|
pgDalHwContext,&TransactionInfo);
|
|
}
|
|
|
|
break;
|
|
case PHDAL4NFC_WRITE_MESSAGE:
|
|
DAL_PRINT(" Dal deferred write called \n");
|
|
|
|
if(low_level_traces)
|
|
{
|
|
phOsalNfc_PrintData("SEND", (uint16_t)gReadWriteContext.nNbOfBytesToWrite,
|
|
gReadWriteContext.pWriteBuffer, low_level_traces);
|
|
}
|
|
|
|
/* DAL_DEBUG("dalMsg->transactInfo.length : %d\n", dalMsg->transactInfo.length); */
|
|
/* Make a Physical WRITE */
|
|
/* NOTE: need to usleep(3000) here if the write is for SWP */
|
|
usleep(500); /* NXP advise 500us sleep required between I2C writes */
|
|
gReadWriteContext.nNbOfBytesWritten = gLinkFunc.write(gReadWriteContext.pWriteBuffer, gReadWriteContext.nNbOfBytesToWrite);
|
|
if (gReadWriteContext.nNbOfBytesWritten != gReadWriteContext.nNbOfBytesToWrite)
|
|
{
|
|
/* controller may be in standby. do it again! */
|
|
usleep(10000); /* wait 10 ms */
|
|
gReadWriteContext.nNbOfBytesWritten = gLinkFunc.write(gReadWriteContext.pWriteBuffer, gReadWriteContext.nNbOfBytesToWrite);
|
|
}
|
|
if (gReadWriteContext.nNbOfBytesWritten != gReadWriteContext.nNbOfBytesToWrite)
|
|
{
|
|
/* Report write failure or timeout */
|
|
DAL_PRINT(" Physical Write Error !!! \n");
|
|
TransactionInfo.length=(uint16_t)gReadWriteContext.nNbOfBytesWritten;
|
|
TransactionInfo.status = PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_BOARD_COMMUNICATION_ERROR);
|
|
}
|
|
else
|
|
{
|
|
DAL_PRINT(" Physical Write Success \n");
|
|
TransactionInfo.length=(uint16_t)gReadWriteContext.nNbOfBytesWritten;
|
|
TransactionInfo.status=NFCSTATUS_SUCCESS;
|
|
/* DAL_PRINT("WriteBuff[]={ ");
|
|
for (i = 0; i < gReadWriteContext.nNbOfBytesWritten; i++)
|
|
{
|
|
DAL_DEBUG("0x%x ", gReadWriteContext.pWriteBuffer[i]);
|
|
}
|
|
DAL_PRINT("}\n"); */
|
|
|
|
// Free TempWriteBuffer
|
|
if(gReadWriteContext.pTempWriteBuffer != NULL)
|
|
{
|
|
free(gReadWriteContext.pTempWriteBuffer);
|
|
}
|
|
}
|
|
/* Reset Write context */
|
|
gReadWriteContext.nWriteBusy = FALSE;
|
|
gReadWriteContext.nWaitingOnWrite = FALSE;
|
|
|
|
/* call LLC callback */
|
|
if ((NULL != pgDalContext) && (NULL != pgDalContext->cb_if.send_complete))
|
|
{
|
|
pgDalContext->cb_if.send_complete(pgDalContext->cb_if.pif_ctxt,
|
|
pgDalHwContext,&TransactionInfo);
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* \ingroup grp_nfc_dal
|
|
*
|
|
* \brief DAL deferred call function
|
|
* This function will enable to call the callback client asyncronously and in the client context.
|
|
* It will post a message in a queue that will be processed by a client thread.
|
|
*
|
|
* \param[in] func The function to call when message is read from the queue
|
|
* \param[in] param Parameter that will be passed to the 'func' function.
|
|
*
|
|
*/
|
|
void phDal4Nfc_DeferredCall(pphDal4Nfc_DeferFuncPointer_t func, void *param)
|
|
{
|
|
int retvalue = 0;
|
|
phDal4Nfc_Message_Wrapper_t nDeferedMessageWrapper;
|
|
phDal4Nfc_DeferredCall_Msg_t *pDeferedMessage;
|
|
static phDal4Nfc_DeferredCall_Msg_t nDeferedMessageRead;
|
|
static phDal4Nfc_DeferredCall_Msg_t nDeferedMessageWrite;
|
|
|
|
#ifdef USE_MQ_MESSAGE_QUEUE
|
|
nDeferedMessage.eMsgType = PH_DAL4NFC_MESSAGE_BASE;
|
|
nDeferedMessage.def_call = func;
|
|
nDeferedMessage.params = param;
|
|
retvalue = (int)mq_send(nDeferedCallMessageQueueId, (char *)&nDeferedMessage, sizeof(phDal4Nfc_DeferredCall_Msg_t), 0);
|
|
#else
|
|
if(PHDAL4NFC_READ_MESSAGE==(* (int*)param))
|
|
{
|
|
pDeferedMessage = &nDeferedMessageRead;
|
|
}
|
|
else
|
|
{
|
|
pDeferedMessage = &nDeferedMessageWrite;
|
|
}
|
|
nDeferedMessageWrapper.mtype = 1;
|
|
nDeferedMessageWrapper.msg.eMsgType = PH_DAL4NFC_MESSAGE_BASE;
|
|
pDeferedMessage->pCallback = func;
|
|
pDeferedMessage->pParameter = param;
|
|
nDeferedMessageWrapper.msg.pMsgData = pDeferedMessage;
|
|
nDeferedMessageWrapper.msg.Size = sizeof(phDal4Nfc_DeferredCall_Msg_t);
|
|
retvalue = phDal4Nfc_msgsnd(nDeferedCallMessageQueueId, (struct msgbuf *)&nDeferedMessageWrapper, sizeof(phLibNfc_Message_t), 0);
|
|
#endif
|
|
|
|
}
|
|
|
|
#undef _DAL_4_NFC_C
|