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