Home | History | Annotate | Download | only in Linux_x86
      1 /*
      2  * Copyright (C) 2010 NXP Semiconductors
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 /**
     18  * \file phDalNfc_i2c.c
     19  * \brief DAL I2C port implementation for linux
     20  *
     21  * Project: Trusted NFC Linux
     22  *
     23  */
     24 
     25 #define LOG_TAG "NFC_i2c"
     26 #include <cutils/log.h>
     27 #include <hardware/nfc.h>
     28 #include <stdlib.h>
     29 #include <unistd.h>
     30 #include <fcntl.h>
     31 #include <termios.h>
     32 #include <sys/ioctl.h>
     33 #include <sys/select.h>
     34 #include <errno.h>
     35 
     36 #include <phDal4Nfc_debug.h>
     37 #include <phDal4Nfc_i2c.h>
     38 #include <phOsalNfc.h>
     39 #include <phNfcStatus.h>
     40 #if defined(ANDROID)
     41 #include <string.h>
     42 #endif
     43 
     44 typedef struct
     45 {
     46    int  nHandle;
     47    char nOpened;
     48 
     49 } phDal4Nfc_I2cPortContext_t;
     50 
     51 
     52 /*-----------------------------------------------------------------------------------
     53                                       VARIABLES
     54 ------------------------------------------------------------------------------------*/
     55 static phDal4Nfc_I2cPortContext_t gI2cPortContext;
     56 
     57 
     58 
     59 /*-----------------------------------------------------------------------------
     60 
     61 FUNCTION: phDal4Nfc_i2c_set_open_from_handle
     62 
     63 PURPOSE:  Initialize internal variables
     64 
     65 -----------------------------------------------------------------------------*/
     66 
     67 void phDal4Nfc_i2c_initialize(void)
     68 {
     69    memset(&gI2cPortContext, 0, sizeof(phDal4Nfc_I2cPortContext_t));
     70 }
     71 
     72 
     73 /*-----------------------------------------------------------------------------
     74 
     75 FUNCTION: phDal4Nfc_i2c_set_open_from_handle
     76 
     77 PURPOSE:  The application could have opened the link itself. So we just need
     78           to get the handle and consider that the open operation has already
     79           been done.
     80 
     81 -----------------------------------------------------------------------------*/
     82 
     83 void phDal4Nfc_i2c_set_open_from_handle(phHal_sHwReference_t * pDalHwContext)
     84 {
     85    gI2cPortContext.nHandle = (int)(intptr_t) pDalHwContext->p_board_driver;
     86    DAL_ASSERT_STR(gI2cPortContext.nHandle >= 0, "Bad passed com port handle");
     87    gI2cPortContext.nOpened = 1;
     88 }
     89 
     90 /*-----------------------------------------------------------------------------
     91 
     92 FUNCTION: phDal4Nfc_i2c_is_opened
     93 
     94 PURPOSE:  Returns if the link is opened or not. (0 = not opened; 1 = opened)
     95 
     96 -----------------------------------------------------------------------------*/
     97 
     98 int phDal4Nfc_i2c_is_opened(void)
     99 {
    100    return gI2cPortContext.nOpened;
    101 }
    102 
    103 /*-----------------------------------------------------------------------------
    104 
    105 FUNCTION: phDal4Nfc_i2c_flush
    106 
    107 PURPOSE:  Flushes the link ; clears the link buffers
    108 
    109 -----------------------------------------------------------------------------*/
    110 
    111 void phDal4Nfc_i2c_flush(void)
    112 {
    113    /* Nothing to do (driver has no internal buffers) */
    114 }
    115 
    116 /*-----------------------------------------------------------------------------
    117 
    118 FUNCTION: phDal4Nfc_i2c_close
    119 
    120 PURPOSE:  Closes the link
    121 
    122 -----------------------------------------------------------------------------*/
    123 
    124 void phDal4Nfc_i2c_close(void)
    125 {
    126    DAL_PRINT("Closing port\n");
    127    if (gI2cPortContext.nOpened == 1)
    128    {
    129       close(gI2cPortContext.nHandle);
    130       gI2cPortContext.nHandle = 0;
    131       gI2cPortContext.nOpened = 0;
    132    }
    133 }
    134 
    135 /*-----------------------------------------------------------------------------
    136 
    137 FUNCTION: phDal4Nfc_i2c_open_and_configure
    138 
    139 PURPOSE:  Closes the link
    140 
    141 -----------------------------------------------------------------------------*/
    142 
    143 NFCSTATUS phDal4Nfc_i2c_open_and_configure(pphDal4Nfc_sConfig_t pConfig, void ** pLinkHandle)
    144 {
    145    DAL_ASSERT_STR(gI2cPortContext.nOpened==0, "Trying to open but already done!");
    146 
    147    DAL_DEBUG("Opening port=%s\n", pConfig->deviceNode);
    148 
    149    /* open port */
    150    gI2cPortContext.nHandle = open(pConfig->deviceNode, O_RDWR | O_NOCTTY);
    151    if (gI2cPortContext.nHandle < 0)
    152    {
    153        DAL_DEBUG("Open failed: open() returned %d\n", gI2cPortContext.nHandle);
    154       *pLinkHandle = NULL;
    155       return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE);
    156    }
    157 
    158    gI2cPortContext.nOpened = 1;
    159    *pLinkHandle = (void*)(intptr_t)gI2cPortContext.nHandle;
    160 
    161    DAL_PRINT("Open succeed\n");
    162 
    163    return NFCSTATUS_SUCCESS;
    164 }
    165 
    166 
    167 /*-----------------------------------------------------------------------------
    168 
    169 FUNCTION: phDal4Nfc_i2c_read
    170 
    171 PURPOSE:  Reads nNbBytesToRead bytes and writes them in pBuffer.
    172           Returns the number of bytes really read or -1 in case of error.
    173 
    174 -----------------------------------------------------------------------------*/
    175 
    176 int phDal4Nfc_i2c_read(uint8_t * pBuffer, int nNbBytesToRead)
    177 {
    178     int ret;
    179     int numRead = 0;
    180     struct timeval tv;
    181     fd_set rfds;
    182 
    183     DAL_ASSERT_STR(gI2cPortContext.nOpened == 1, "read called but not opened!");
    184     DAL_DEBUG("_i2c_read() called to read %d bytes", nNbBytesToRead);
    185 
    186     // Read with 2 second timeout, so that the read thread can be aborted
    187     // when the pn544 does not respond and we need to switch to FW download
    188     // mode. This should be done via a control socket instead.
    189     while (numRead < nNbBytesToRead) {
    190         FD_ZERO(&rfds);
    191         FD_SET(gI2cPortContext.nHandle, &rfds);
    192         tv.tv_sec = 2;
    193         tv.tv_usec = 0;
    194         ret = select(gI2cPortContext.nHandle + 1, &rfds, NULL, NULL, &tv);
    195         if (ret < 0) {
    196             DAL_DEBUG("select() errno=%d", errno);
    197             if (errno == EINTR || errno == EAGAIN) {
    198                 continue;
    199             }
    200             return -1;
    201         } else if (ret == 0) {
    202             DAL_PRINT("timeout!");
    203             return -1;
    204         }
    205         ret = read(gI2cPortContext.nHandle, pBuffer + numRead, nNbBytesToRead - numRead);
    206         if (ret > 0) {
    207             DAL_DEBUG("read %d bytes", ret);
    208             numRead += ret;
    209         } else if (ret == 0) {
    210             DAL_PRINT("_i2c_read() EOF");
    211             return -1;
    212         } else {
    213             DAL_DEBUG("_i2c_read() errno=%d", errno);
    214             if (errno == EINTR || errno == EAGAIN) {
    215                 continue;
    216             }
    217             return -1;
    218         }
    219     }
    220     return numRead;
    221 }
    222 
    223 /*-----------------------------------------------------------------------------
    224 
    225 FUNCTION: phDal4Nfc_i2c_write
    226 
    227 PURPOSE:  Writes nNbBytesToWrite bytes from pBuffer to the link
    228           Returns the number of bytes that have been wrote to the interface or -1 in case of error.
    229 
    230 -----------------------------------------------------------------------------*/
    231 
    232 int phDal4Nfc_i2c_write(uint8_t * pBuffer, int nNbBytesToWrite)
    233 {
    234     int ret;
    235     int numWrote = 0;
    236 
    237     DAL_ASSERT_STR(gI2cPortContext.nOpened == 1, "write called but not opened!");
    238     DAL_DEBUG("_i2c_write() called to write %d bytes\n", nNbBytesToWrite);
    239 
    240     while (numWrote < nNbBytesToWrite) {
    241         ret = write(gI2cPortContext.nHandle, pBuffer + numWrote, nNbBytesToWrite - numWrote);
    242         if (ret > 0) {
    243             DAL_DEBUG("wrote %d bytes", ret);
    244             numWrote += ret;
    245         } else if (ret == 0) {
    246             DAL_PRINT("_i2c_write() EOF");
    247             return -1;
    248         } else {
    249             DAL_DEBUG("_i2c_write() errno=%d", errno);
    250             if (errno == EINTR || errno == EAGAIN) {
    251                 continue;
    252             }
    253             return -1;
    254         }
    255     }
    256 
    257     return numWrote;
    258 }
    259 
    260 /*-----------------------------------------------------------------------------
    261 
    262 FUNCTION: phDal4Nfc_i2c_reset
    263 
    264 PURPOSE:  Reset the PN544, using the VEN pin
    265 
    266 -----------------------------------------------------------------------------*/
    267 #define PN544_SET_PWR _IOW(0xe9, 0x01, unsigned int)
    268 int phDal4Nfc_i2c_reset(long level)
    269 {
    270     DAL_DEBUG("phDal4Nfc_i2c_reset, VEN level = %ld", level);
    271 
    272     return ioctl(gI2cPortContext.nHandle, PN544_SET_PWR, level);
    273 }
    274