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