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   int i;
    127   UNUSED(nNbBytesToRead);
    128   if (NULL == pDevHandle) {
    129     return -1;
    130   }
    131 
    132   if (bFwDnldFlag == false) {
    133     totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
    134   } else {
    135     totalBtyesToRead = FW_DNLD_HEADER_LEN;
    136   }
    137 
    138   /* Read with 2 second timeout, so that the read thread can be aborted
    139      when the PN54X does not respond and we need to switch to FW download
    140      mode. This should be done via a control socket instead. */
    141   FD_ZERO(&rfds);
    142   FD_SET((intptr_t)pDevHandle, &rfds);
    143   tv.tv_sec = 2;
    144   tv.tv_usec = 1;
    145 
    146   ret_Select =
    147       select((int)((intptr_t)pDevHandle + (int)1), &rfds, NULL, NULL, &tv);
    148   if (ret_Select < 0) {
    149     NXPLOG_TML_E("i2c select() errno : %x", errno);
    150     return -1;
    151   } else if (ret_Select == 0) {
    152     NXPLOG_TML_E("i2c select() Timeout");
    153     return -1;
    154   } else {
    155     ret_Read = read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead - numRead);
    156     if (ret_Read > 0) {
    157       numRead += ret_Read;
    158     } else if (ret_Read == 0) {
    159       NXPLOG_TML_E("_i2c_read() [hdr]EOF");
    160       return -1;
    161     } else {
    162       NXPLOG_TML_E("_i2c_read() [hdr] errno : %x", errno);
    163       return -1;
    164     }
    165 
    166     if (bFwDnldFlag == false) {
    167       totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
    168     } else {
    169       totalBtyesToRead = FW_DNLD_HEADER_LEN;
    170     }
    171 
    172     if (numRead < totalBtyesToRead) {
    173       ret_Read =
    174           read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead - numRead);
    175       if (ret_Read != totalBtyesToRead - numRead) {
    176         NXPLOG_TML_E("_i2c_read() [hdr] errno : %x", errno);
    177         return -1;
    178       } else {
    179         numRead += ret_Read;
    180       }
    181     }
    182     if (bFwDnldFlag == true) {
    183       totalBtyesToRead =
    184           pBuffer[FW_DNLD_LEN_OFFSET] + FW_DNLD_HEADER_LEN + CRC_LEN;
    185     } else {
    186       totalBtyesToRead =
    187           pBuffer[NORMAL_MODE_LEN_OFFSET] + NORMAL_MODE_HEADER_LEN;
    188     }
    189     if ((totalBtyesToRead - numRead) != 0) {
    190       ret_Read = read((intptr_t)pDevHandle, (pBuffer + numRead),
    191                       totalBtyesToRead - numRead);
    192       if (ret_Read > 0) {
    193         numRead += ret_Read;
    194       } else if (ret_Read == 0) {
    195         NXPLOG_TML_E("_i2c_read() [pyld] EOF");
    196         return -1;
    197       } else {
    198         if (bFwDnldFlag == false) {
    199           NXPLOG_TML_E("_i2c_read() [hdr] received");
    200           phNxpNciHal_print_packet("RECV", pBuffer, NORMAL_MODE_HEADER_LEN);
    201         }
    202         NXPLOG_TML_E("_i2c_read() [pyld] errno : %x", errno);
    203         return -1;
    204       }
    205     } else {
    206       NXPLOG_TML_E("_>>>>> Empty packet recieved !!");
    207     }
    208   }
    209   return numRead;
    210 }
    211 
    212 /*******************************************************************************
    213 **
    214 ** Function         phTmlNfc_i2c_write
    215 **
    216 ** Description      Writes requested number of bytes from given buffer into
    217 **                  PN54X device
    218 **
    219 ** Parameters       pDevHandle       - valid device handle
    220 **                  pBuffer          - buffer for read data
    221 **                  nNbBytesToWrite  - number of bytes requested to be written
    222 **
    223 ** Returns          numWrote   - number of successfully written bytes
    224 **                  -1         - write operation failure
    225 **
    226 *******************************************************************************/
    227 int phTmlNfc_i2c_write(void* pDevHandle, uint8_t* pBuffer,
    228                        int nNbBytesToWrite) {
    229   int ret;
    230   int numWrote = 0;
    231   int i;
    232   int numBytes = nNbBytesToWrite;
    233   if (NULL == pDevHandle) {
    234     return -1;
    235   }
    236   if (fragmentation_enabled == I2C_FRAGMENATATION_DISABLED &&
    237       nNbBytesToWrite > FRAGMENTSIZE_MAX) {
    238     NXPLOG_TML_E(
    239         "i2c_write() data larger than maximum I2C  size,enable I2C "
    240         "fragmentation");
    241     return -1;
    242   }
    243   while (numWrote < nNbBytesToWrite) {
    244     if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED &&
    245         nNbBytesToWrite > FRAGMENTSIZE_MAX) {
    246       if (nNbBytesToWrite - numWrote > FRAGMENTSIZE_MAX) {
    247         numBytes = numWrote + FRAGMENTSIZE_MAX;
    248       } else {
    249         numBytes = nNbBytesToWrite;
    250       }
    251     }
    252     ret = write((intptr_t)pDevHandle, pBuffer + numWrote, numBytes - numWrote);
    253     if (ret > 0) {
    254       numWrote += ret;
    255       if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED &&
    256           numWrote < nNbBytesToWrite) {
    257         usleep(500);
    258       }
    259     } else if (ret == 0) {
    260       NXPLOG_TML_E("_i2c_write() EOF");
    261       return -1;
    262     } else {
    263       NXPLOG_TML_E("_i2c_write() errno : %x", errno);
    264       if (errno == EINTR || errno == EAGAIN) {
    265         continue;
    266       }
    267       return -1;
    268     }
    269   }
    270 
    271   return numWrote;
    272 }
    273 
    274 /*******************************************************************************
    275 **
    276 ** Function         phTmlNfc_i2c_reset
    277 **
    278 ** Description      Reset PN54X device, using VEN pin
    279 **
    280 ** Parameters       pDevHandle     - valid device handle
    281 **                  level          - reset level
    282 **
    283 ** Returns           0   - reset operation success
    284 **                  -1   - reset operation failure
    285 **
    286 *******************************************************************************/
    287 #define PN544_SET_PWR _IOW(0xe9, 0x01, unsigned int)
    288 int phTmlNfc_i2c_reset(void* pDevHandle, long level) {
    289   int ret;
    290   NXPLOG_TML_D("phTmlNfc_i2c_reset(), VEN level %ld", level);
    291 
    292   if (NULL == pDevHandle) {
    293     return -1;
    294   }
    295 
    296   ret = ioctl((intptr_t)pDevHandle, PN544_SET_PWR, level);
    297   if (level == 2 && ret == 0) {
    298     bFwDnldFlag = true;
    299   } else {
    300     bFwDnldFlag = false;
    301   }
    302   return ret;
    303 }
    304 
    305 /*******************************************************************************
    306 **
    307 ** Function         getDownloadFlag
    308 **
    309 ** Description      Returns the current mode
    310 **
    311 ** Parameters       none
    312 **
    313 ** Returns           Current mode download/NCI
    314 *******************************************************************************/
    315 bool_t getDownloadFlag(void) { return bFwDnldFlag; }
    316