/* * 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_i2c.c * \brief DAL I2C port implementation for linux * * Project: Trusted NFC Linux * */ #define LOG_TAG "NFC_i2c" #include <utils/Log.h> #include <stdlib.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #include <sys/ioctl.h> #include <sys/select.h> #include <phDal4Nfc_debug.h> #include <phDal4Nfc_i2c.h> #include <phOsalNfc.h> #include <phNfcStatus.h> #if defined(ANDROID) #include <string.h> #endif #include <linux/pn544.h> typedef struct { int nHandle; char nOpened; } phDal4Nfc_I2cPortContext_t; /*----------------------------------------------------------------------------------- VARIABLES ------------------------------------------------------------------------------------*/ static phDal4Nfc_I2cPortContext_t gI2cPortContext; /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_i2c_set_open_from_handle PURPOSE: Initialize internal variables -----------------------------------------------------------------------------*/ void phDal4Nfc_i2c_initialize(void) { memset(&gI2cPortContext, 0, sizeof(phDal4Nfc_I2cPortContext_t)); } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_i2c_set_open_from_handle PURPOSE: The application could have opened the link itself. So we just need to get the handle and consider that the open operation has already been done. -----------------------------------------------------------------------------*/ void phDal4Nfc_i2c_set_open_from_handle(phHal_sHwReference_t * pDalHwContext) { gI2cPortContext.nHandle = (int) pDalHwContext->p_board_driver; DAL_ASSERT_STR(gI2cPortContext.nHandle >= 0, "Bad passed com port handle"); gI2cPortContext.nOpened = 1; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_i2c_is_opened PURPOSE: Returns if the link is opened or not. (0 = not opened; 1 = opened) -----------------------------------------------------------------------------*/ int phDal4Nfc_i2c_is_opened(void) { return gI2cPortContext.nOpened; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_i2c_flush PURPOSE: Flushes the link ; clears the link buffers -----------------------------------------------------------------------------*/ void phDal4Nfc_i2c_flush(void) { /* Nothing to do (driver has no internal buffers) */ } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_i2c_close PURPOSE: Closes the link -----------------------------------------------------------------------------*/ void phDal4Nfc_i2c_close(void) { DAL_PRINT("Closing port\n"); if (gI2cPortContext.nOpened == 1) { close(gI2cPortContext.nHandle); gI2cPortContext.nHandle = 0; gI2cPortContext.nOpened = 0; } } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_i2c_open_and_configure PURPOSE: Closes the link -----------------------------------------------------------------------------*/ NFCSTATUS phDal4Nfc_i2c_open_and_configure(pphDal4Nfc_sConfig_t pConfig, void ** pLinkHandle) { char * pComPort; DAL_ASSERT_STR(gI2cPortContext.nOpened==0, "Trying to open but already done!"); switch(pConfig->nLinkType) { case ENUM_DAL_LINK_TYPE_I2C: pComPort = "/dev/pn544"; break; default: DAL_DEBUG("Open failed: unknown type %d\n", pConfig->nLinkType); return NFCSTATUS_INVALID_PARAMETER; } DAL_DEBUG("Opening port=%s\n", pComPort); /* open port */ gI2cPortContext.nHandle = open(pComPort, O_RDWR | O_NOCTTY); if (gI2cPortContext.nHandle < 0) { DAL_DEBUG("Open failed: open() returned %d\n", gI2cPortContext.nHandle); *pLinkHandle = NULL; return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE); } gI2cPortContext.nOpened = 1; *pLinkHandle = (void*)gI2cPortContext.nHandle; DAL_PRINT("Open succeed\n"); return NFCSTATUS_SUCCESS; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_i2c_read PURPOSE: Reads nNbBytesToRead bytes and writes them in pBuffer. Returns the number of bytes really read or -1 in case of error. -----------------------------------------------------------------------------*/ int phDal4Nfc_i2c_read(uint8_t * pBuffer, int nNbBytesToRead) { int ret; DAL_ASSERT_STR(gI2cPortContext.nOpened == 1, "read called but not opened!"); DAL_DEBUG("Reading %d bytes\n", nNbBytesToRead); ret = read(gI2cPortContext.nHandle, pBuffer, nNbBytesToRead); if (ret < 0) { DAL_DEBUG("Read failed: read() returned %d\n", ret); } else { DAL_DEBUG("Read succeed (%d bytes)\n", ret); } return ret; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_i2c_write PURPOSE: Writes nNbBytesToWrite bytes from pBuffer to the link Returns the number of bytes that have been wrote to the interface or -1 in case of error. -----------------------------------------------------------------------------*/ int phDal4Nfc_i2c_write(uint8_t * pBuffer, int nNbBytesToWrite) { int ret; DAL_ASSERT_STR(gI2cPortContext.nOpened == 1, "write called but not opened!"); DAL_DEBUG("Writing %d bytes\n", nNbBytesToWrite); ret = write(gI2cPortContext.nHandle, pBuffer, nNbBytesToWrite); if (ret < 0) { DAL_DEBUG("Write failed: write() returned %d \n", ret); } else { DAL_DEBUG("Write succeed (%d bytes)\n", ret); } return ret; } /*----------------------------------------------------------------------------- FUNCTION: phDal4Nfc_i2c_reset PURPOSE: Reset the PN544, using the VEN pin -----------------------------------------------------------------------------*/ int phDal4Nfc_i2c_reset(long level) { int ret = NFCSTATUS_SUCCESS; DAL_DEBUG("phDal4Nfc_i2c_reset, VEN level = %ld",level); ret = ioctl(gI2cPortContext.nHandle, PN544_SET_PWR, level); /* HACK to increase reset time * TODO: move this to kernel */ if (level == 0) { LOGW("sleeping a little longer..."); usleep(50000); } else { usleep(10000); } return ret; }