Home | History | Annotate | Download | only in tml
      1 /*
      2  * Copyright (C) 2010-2014 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  * DAL I2C port implementation for linux
     19  *
     20  * Project: Trusted NFC Linux
     21  *
     22  */
     23 #include <errno.h>
     24 #include <fcntl.h>
     25 #include <hardware/nfc.h>
     26 #include <stdlib.h>
     27 #include <sys/ioctl.h>
     28 #include <sys/select.h>
     29 #include <termios.h>
     30 #include <unistd.h>
     31 
     32 #include <phNfcStatus.h>
     33 #include <phNxpLog.h>
     34 #include <phTmlNfc_i2c.h>
     35 #include <string.h>
     36 #include "phNxpNciHal_utils.h"
     37 
     38 #define CRC_LEN 2
     39 #define NORMAL_MODE_HEADER_LEN 3
     40 #define FW_DNLD_HEADER_LEN 2
     41 #define FW_DNLD_LEN_OFFSET 1
     42 #define NORMAL_MODE_LEN_OFFSET 2
     43 #define FRAGMENTSIZE_MAX PHNFC_I2C_FRAGMENT_SIZE
     44 static bool_t bFwDnldFlag = false;
     45 extern phTmlNfc_i2cfragmentation_t fragmentation_enabled;
     46 
     47 /*******************************************************************************
     48 **
     49 ** Function         phTmlNfc_i2c_close
     50 **
     51 ** Description      Closes PN54X device
     52 **
     53 ** Parameters       pDevHandle - device handle
     54 **
     55 ** Returns          None
     56 **
     57 *******************************************************************************/
     58 void phTmlNfc_i2c_close(void* pDevHandle) {
     59   if (NULL != pDevHandle) {
     60     close((intptr_t)pDevHandle);
     61   }
     62 
     63   return;
     64 }
     65 
     66 /*******************************************************************************
     67 **
     68 ** Function         phTmlNfc_i2c_open_and_configure
     69 **
     70 ** Description      Open and configure PN54X device
     71 **
     72 ** Parameters       pConfig     - hardware information
     73 **                  pLinkHandle - device handle
     74 **
     75 ** Returns          NFC status:
     76 **                  NFCSTATUS_SUCCESS - open_and_configure operation success
     77 **                  NFCSTATUS_INVALID_DEVICE - device open operation failure
     78 **
     79 *******************************************************************************/
     80 NFCSTATUS phTmlNfc_i2c_open_and_configure(pphTmlNfc_Config_t pConfig,
     81                                           void** pLinkHandle) {
     82   int nHandle;
     83 
     84   NXPLOG_TML_D("Opening port=%s\n", pConfig->pDevName);
     85   /* open port */
     86   nHandle = open((const char*)pConfig->pDevName, O_RDWR);
     87   if (nHandle < 0) {
     88     NXPLOG_TML_E("_i2c_open() Failed: retval %x", nHandle);
     89     *pLinkHandle = NULL;
     90     return NFCSTATUS_INVALID_DEVICE;
     91   }
     92 
     93   *pLinkHandle = (void*)((intptr_t)nHandle);
     94 
     95   /*Reset PN54X*/
     96   phTmlNfc_i2c_reset((void*)((intptr_t)nHandle), 0);
     97   usleep(10 * 1000);
     98   phTmlNfc_i2c_reset((void*)((intptr_t)nHandle), 1);
     99 
    100   return NFCSTATUS_SUCCESS;
    101 }
    102 
    103 /*******************************************************************************
    104 **
    105 ** Function         phTmlNfc_i2c_read
    106 **
    107 ** Description      Reads requested number of bytes from PN54X device into given
    108 **                  buffer
    109 **
    110 ** Parameters       pDevHandle       - valid device handle
    111 **                  pBuffer          - buffer for read data
    112 **                  nNbBytesToRead   - number of bytes requested to be read
    113 **
    114 ** Returns          numRead   - number of successfully read bytes
    115 **                  -1        - read operation failure
    116 **
    117 *******************************************************************************/
    118 int phTmlNfc_i2c_read(void* pDevHandle, uint8_t* pBuffer, int nNbBytesToRead) {
    119   int ret_Read;
    120   int ret_Select;
    121   int numRead = 0;
    122   struct timeval tv;
    123   fd_set rfds;
    124   uint16_t totalBtyesToRead = 0;
    125 
    126   UNUSED(nNbBytesToRead);
    127   if (NULL == pDevHandle) {
    128     return -1;
    129   }
    130 
    131   if (bFwDnldFlag == false) {
    132     totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
    133   } else {
    134     totalBtyesToRead = FW_DNLD_HEADER_LEN;
    135   }
    136 
    137   /* Read with 2 second timeout, so that the read thread can be aborted
    138      when the PN54X does not respond and we need to switch to FW download
    139      mode. This should be done via a control socket instead. */
    140   FD_ZERO(&rfds);
    141   FD_SET((intptr_t)pDevHandle, &rfds);
    142   tv.tv_sec = 2;
    143   tv.tv_usec = 1;
    144 
    145   ret_Select =
    146       select((int)((intptr_t)pDevHandle + (int)1), &rfds, NULL, NULL, &tv);
    147   if (ret_Select < 0) {
    148     NXPLOG_TML_E("i2c select() errno : %x", errno);
    149     return -1;
    150   } else if (ret_Select == 0) {
    151     NXPLOG_TML_E("i2c select() Timeout");
    152     return -1;
    153   } else {
    154     ret_Read = read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead - numRead);
    155     if (ret_Read > 0) {
    156       numRead += ret_Read;
    157     } else if (ret_Read == 0) {
    158       NXPLOG_TML_E("_i2c_read() [hdr]EOF");
    159       return -1;
    160     } else {
    161       NXPLOG_TML_E("_i2c_read() [hdr] errno : %x", errno);
    162       return -1;
    163     }
    164 
    165     if (bFwDnldFlag == false) {
    166       totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
    167     } else {
    168       totalBtyesToRead = FW_DNLD_HEADER_LEN;
    169     }
    170 
    171     if (numRead < totalBtyesToRead) {
    172       ret_Read =
    173           read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead - numRead);
    174       if (ret_Read != totalBtyesToRead - numRead) {
    175         NXPLOG_TML_E("_i2c_read() [hdr] errno : %x", errno);
    176         return -1;
    177       } else {
    178         numRead += ret_Read;
    179       }
    180     }
    181     if (bFwDnldFlag == true) {
    182       totalBtyesToRead =
    183           pBuffer[FW_DNLD_LEN_OFFSET] + FW_DNLD_HEADER_LEN + CRC_LEN;
    184     } else {
    185       totalBtyesToRead =
    186           pBuffer[NORMAL_MODE_LEN_OFFSET] + NORMAL_MODE_HEADER_LEN;
    187     }
    188     if ((totalBtyesToRead - numRead) != 0) {
    189       ret_Read = read((intptr_t)pDevHandle, (pBuffer + numRead),
    190                       totalBtyesToRead - numRead);
    191       if (ret_Read > 0) {
    192         numRead += ret_Read;
    193       } else if (ret_Read == 0) {
    194         NXPLOG_TML_E("_i2c_read() [pyld] EOF");
    195         return -1;
    196       } else {
    197         if (bFwDnldFlag == false) {
    198           NXPLOG_TML_E("_i2c_read() [hdr] received");
    199           phNxpNciHal_print_packet("RECV", pBuffer, NORMAL_MODE_HEADER_LEN);
    200         }
    201         NXPLOG_TML_E("_i2c_read() [pyld] errno : %x", errno);
    202         return -1;
    203       }
    204     } else {
    205       NXPLOG_TML_E("_>>>>> Empty packet recieved !!");
    206     }
    207   }
    208   return numRead;
    209 }
    210 
    211 /*******************************************************************************
    212 **
    213 ** Function         phTmlNfc_i2c_write
    214 **
    215 ** Description      Writes requested number of bytes from given buffer into
    216 **                  PN54X device
    217 **
    218 ** Parameters       pDevHandle       - valid device handle
    219 **                  pBuffer          - buffer for read data
    220 **                  nNbBytesToWrite  - number of bytes requested to be written
    221 **
    222 ** Returns          numWrote   - number of successfully written bytes
    223 **                  -1         - write operation failure
    224 **
    225 *******************************************************************************/
    226 int phTmlNfc_i2c_write(void* pDevHandle, uint8_t* pBuffer,
    227                        int nNbBytesToWrite) {
    228   int ret;
    229   int numWrote = 0;
    230   int numBytes = nNbBytesToWrite;
    231   if (NULL == pDevHandle) {
    232     return -1;
    233   }
    234   if (fragmentation_enabled == I2C_FRAGMENATATION_DISABLED &&
    235       nNbBytesToWrite > FRAGMENTSIZE_MAX) {
    236     NXPLOG_TML_E(
    237         "i2c_write() data larger than maximum I2C  size,enable I2C "
    238         "fragmentation");
    239     return -1;
    240   }
    241   while (numWrote < nNbBytesToWrite) {
    242     if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED &&
    243         nNbBytesToWrite > FRAGMENTSIZE_MAX) {
    244       if (nNbBytesToWrite - numWrote > FRAGMENTSIZE_MAX) {
    245         numBytes = numWrote + FRAGMENTSIZE_MAX;
    246       } else {
    247         numBytes = nNbBytesToWrite;
    248       }
    249     }
    250     ret = write((intptr_t)pDevHandle, pBuffer + numWrote, numBytes - numWrote);
    251     if (ret > 0) {
    252       numWrote += ret;
    253       if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED &&
    254           numWrote < nNbBytesToWrite) {
    255         usleep(500);
    256       }
    257     } else if (ret == 0) {
    258       NXPLOG_TML_E("_i2c_write() EOF");
    259       return -1;
    260     } else {
    261       NXPLOG_TML_E("_i2c_write() errno : %x", errno);
    262       if (errno == EINTR || errno == EAGAIN) {
    263         continue;
    264       }
    265       return -1;
    266     }
    267   }
    268 
    269   return numWrote;
    270 }
    271 
    272 /*******************************************************************************
    273 **
    274 ** Function         phTmlNfc_i2c_reset
    275 **
    276 ** Description      Reset PN54X device, using VEN pin
    277 **
    278 ** Parameters       pDevHandle     - valid device handle
    279 **                  level          - reset level
    280 **
    281 ** Returns           0   - reset operation success
    282 **                  -1   - reset operation failure
    283 **
    284 *******************************************************************************/
    285 int phTmlNfc_i2c_reset(void* pDevHandle, long level) {
    286   int ret;
    287   NXPLOG_TML_D("phTmlNfc_i2c_reset(), VEN level %ld", level);
    288 
    289   if (NULL == pDevHandle) {
    290     return -1;
    291   }
    292 
    293   ret = ioctl((intptr_t)pDevHandle, PN544_SET_PWR, level);
    294   if (level == 2 && ret == 0) {
    295     bFwDnldFlag = true;
    296   } else {
    297     bFwDnldFlag = false;
    298   }
    299   return ret;
    300 }
    301 
    302 /*******************************************************************************
    303 **
    304 ** Function         getDownloadFlag
    305 **
    306 ** Description      Returns the current mode
    307 **
    308 ** Parameters       none
    309 **
    310 ** Returns           Current mode download/NCI
    311 *******************************************************************************/
    312 bool_t getDownloadFlag(void) { return bFwDnldFlag; }
    313