You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
315 lines
9.3 KiB
315 lines
9.3 KiB
/* |
|
* 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 <errno.h> |
|
#include <fcntl.h> |
|
#include <hardware/nfc.h> |
|
#include <stdlib.h> |
|
#include <sys/ioctl.h> |
|
#include <sys/select.h> |
|
#include <termios.h> |
|
#include <unistd.h> |
|
|
|
#include <phNfcStatus.h> |
|
#include <phNxpLog.h> |
|
#include <phTmlNfc_i2c.h> |
|
#include <string.h> |
|
#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; }
|
|
|