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_uart.c
     19  * \brief DAL com port implementation for linux
     20  *
     21  * Project: Trusted NFC Linux Lignt
     22  *
     23  * $Date: 07 aug 2009
     24  * $Author: Jonathan roux
     25  * $Revision: 1.0 $
     26  *
     27  */
     28 
     29 #include <unistd.h>
     30 #include <fcntl.h>
     31 #include <termios.h>
     32 #include <sys/ioctl.h>
     33 #include <sys/select.h>
     34 
     35 #include <phDal4Nfc_debug.h>
     36 #include <phDal4Nfc_uart.h>
     37 #include <phOsalNfc.h>
     38 #include <phNfcStatus.h>
     39 #if defined(ANDROID)
     40 #include <string.h>
     41 #endif
     42 
     43 typedef struct
     44 {
     45    int  nHandle;
     46    char nOpened;
     47    struct termios nIoConfigBackup;
     48    struct termios nIoConfig;
     49 
     50 } phDal4Nfc_ComPortContext_t;
     51 
     52 /*-----------------------------------------------------------------------------------
     53                                 COM PORT CONFIGURATION
     54 ------------------------------------------------------------------------------------*/
     55 #define DAL_BAUD_RATE  B115200
     56 
     57 
     58 
     59 /*-----------------------------------------------------------------------------------
     60                                       VARIABLES
     61 ------------------------------------------------------------------------------------*/
     62 static phDal4Nfc_ComPortContext_t gComPortContext;
     63 
     64 
     65 
     66 /*-----------------------------------------------------------------------------
     67 
     68 FUNCTION: phDal4Nfc_uart_set_open_from_handle
     69 
     70 PURPOSE:  Initialize internal variables
     71 
     72 -----------------------------------------------------------------------------*/
     73 
     74 void phDal4Nfc_uart_initialize(void)
     75 {
     76    memset(&gComPortContext, 0, sizeof(phDal4Nfc_ComPortContext_t));
     77 }
     78 
     79 
     80 /*-----------------------------------------------------------------------------
     81 
     82 FUNCTION: phDal4Nfc_uart_set_open_from_handle
     83 
     84 PURPOSE:  The application could have opened the link itself. So we just need
     85           to get the handle and consider that the open operation has already
     86           been done.
     87 
     88 -----------------------------------------------------------------------------*/
     89 
     90 void phDal4Nfc_uart_set_open_from_handle(phHal_sHwReference_t * pDalHwContext)
     91 {
     92    gComPortContext.nHandle = (int) pDalHwContext->p_board_driver;
     93    DAL_ASSERT_STR(gComPortContext.nHandle >= 0, "Bad passed com port handle");
     94    gComPortContext.nOpened = 1;
     95 }
     96 
     97 /*-----------------------------------------------------------------------------
     98 
     99 FUNCTION: phDal4Nfc_uart_is_opened
    100 
    101 PURPOSE:  Returns if the link is opened or not. (0 = not opened; 1 = opened)
    102 
    103 -----------------------------------------------------------------------------*/
    104 
    105 int phDal4Nfc_uart_is_opened(void)
    106 {
    107    return gComPortContext.nOpened;
    108 }
    109 
    110 /*-----------------------------------------------------------------------------
    111 
    112 FUNCTION: phDal4Nfc_uart_flush
    113 
    114 PURPOSE:  Flushes the link ; clears the link buffers
    115 
    116 -----------------------------------------------------------------------------*/
    117 
    118 void phDal4Nfc_uart_flush(void)
    119 {
    120    int ret;
    121    /* flushes the com port */
    122    ret = tcflush(gComPortContext.nHandle, TCIFLUSH);
    123    DAL_ASSERT_STR(ret!=-1, "tcflush failed");
    124 }
    125 
    126 /*-----------------------------------------------------------------------------
    127 
    128 FUNCTION: phDal4Nfc_uart_close
    129 
    130 PURPOSE:  Closes the link
    131 
    132 -----------------------------------------------------------------------------*/
    133 
    134 void phDal4Nfc_uart_close(void)
    135 {
    136    if (gComPortContext.nOpened == 1)
    137    {
    138       close(gComPortContext.nHandle);
    139       gComPortContext.nHandle = 0;
    140       gComPortContext.nOpened = 0;
    141    }
    142 }
    143 
    144 /*-----------------------------------------------------------------------------
    145 
    146 FUNCTION: phDal4Nfc_uart_close
    147 
    148 PURPOSE:  Closes the link
    149 
    150 -----------------------------------------------------------------------------*/
    151 
    152 NFCSTATUS phDal4Nfc_uart_open_and_configure(pphDal4Nfc_sConfig_t pConfig, void ** pLinkHandle)
    153 {
    154    char *       pComPort;
    155    int          nComStatus;
    156    NFCSTATUS    nfcret = NFCSTATUS_SUCCESS;
    157    int          ret;
    158 
    159    DAL_ASSERT_STR(gComPortContext.nOpened==0, "Trying to open but already done!");
    160 
    161    switch(pConfig->nLinkType)
    162    {
    163      case ENUM_DAL_LINK_TYPE_COM1:
    164       pComPort = "/dev/ttyS0";
    165       break;
    166      case ENUM_DAL_LINK_TYPE_COM2:
    167       pComPort = "/dev/ttyS1";
    168       break;
    169      case ENUM_DAL_LINK_TYPE_COM3:
    170       pComPort = "/dev/ttyS2";
    171       break;
    172      case ENUM_DAL_LINK_TYPE_COM4:
    173       pComPort = "/dev/ttyS3";
    174       break;
    175      case ENUM_DAL_LINK_TYPE_COM5:
    176       pComPort = "/dev/ttyS4";
    177       break;
    178      case ENUM_DAL_LINK_TYPE_COM6:
    179       pComPort = "/dev/ttyS5";
    180       break;
    181      case ENUM_DAL_LINK_TYPE_COM7:
    182       pComPort = "/dev/ttyS6";
    183       break;
    184      case ENUM_DAL_LINK_TYPE_COM8:
    185       pComPort = "/dev/ttyS7";
    186       break;
    187      case ENUM_DAL_LINK_TYPE_USB:
    188       pComPort = "/dev/ttyUSB0";
    189       break;
    190      default:
    191       return NFCSTATUS_INVALID_PARAMETER;
    192    }
    193 
    194    /* open communication port handle */
    195    gComPortContext.nHandle = open(pComPort, O_RDWR | O_NOCTTY);
    196    if (gComPortContext.nHandle < 0)
    197    {
    198       *pLinkHandle = NULL;
    199       return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE);
    200    }
    201 
    202    gComPortContext.nOpened = 1;
    203    *pLinkHandle = (void*)gComPortContext.nHandle;
    204 
    205    /*
    206     *  Now configure the com port
    207     */
    208    ret = tcgetattr(gComPortContext.nHandle, &gComPortContext.nIoConfigBackup); /* save the old io config */
    209    if (ret == -1)
    210    {
    211       /* tcgetattr failed -- it is likely that the provided port is invalid */
    212       *pLinkHandle = NULL;
    213       return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE);
    214    }
    215    ret = fcntl(gComPortContext.nHandle, F_SETFL, 0); /* Makes the read blocking (default).  */
    216    DAL_ASSERT_STR(ret != -1, "fcntl failed");
    217    /* Configures the io */
    218    memset((void *)&gComPortContext.nIoConfig, (int)0, (size_t)sizeof(struct termios));
    219    /*
    220     BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
    221     CRTSCTS : output hardware flow control (only used if the cable has
    222               all necessary lines. See sect. 7 of Serial-HOWTO)
    223     CS8     : 8n1 (8bit,no parity,1 stopbit)
    224     CLOCAL  : local connection, no modem contol
    225     CREAD   : enable receiving characters
    226    */
    227    gComPortContext.nIoConfig.c_cflag = DAL_BAUD_RATE | CS8 | CLOCAL | CREAD;  /* Control mode flags */
    228    gComPortContext.nIoConfig.c_iflag = IGNPAR;                                          /* Input   mode flags : IGNPAR  Ignore parity errors */
    229    gComPortContext.nIoConfig.c_oflag = 0;                                               /* Output  mode flags */
    230    gComPortContext.nIoConfig.c_lflag = 0;                                               /* Local   mode flags. Read mode : non canonical, no echo */
    231    gComPortContext.nIoConfig.c_cc[VTIME] = 0;                                           /* Control characters. No inter-character timer */
    232    gComPortContext.nIoConfig.c_cc[VMIN]  = 1;                                           /* Control characters. Read is blocking until X characters are read */
    233 
    234    /*
    235       TCSANOW  Make changes now without waiting for data to complete
    236       TCSADRAIN   Wait until everything has been transmitted
    237       TCSAFLUSH   Flush input and output buffers and make the change
    238    */
    239    ret = tcsetattr(gComPortContext.nHandle, TCSANOW, &gComPortContext.nIoConfig);
    240    DAL_ASSERT_STR(ret != -1, "tcsetattr failed");
    241 
    242    /*
    243       On linux the DTR signal is set by default. That causes a problem for pn544 chip
    244       because this signal is connected to "reset". So we clear it. (on windows it is cleared by default).
    245    */
    246    ret = ioctl(gComPortContext.nHandle, TIOCMGET, &nComStatus);
    247    DAL_ASSERT_STR(ret != -1, "ioctl TIOCMGET failed");
    248    nComStatus &= ~TIOCM_DTR;
    249    ret = ioctl(gComPortContext.nHandle, TIOCMSET, &nComStatus);
    250    DAL_ASSERT_STR(ret != -1, "ioctl TIOCMSET failed");
    251    DAL_DEBUG("Com port status=%d\n", nComStatus);
    252    usleep(10000); /* Mandatory sleep so that the DTR line is ready before continuing */
    253 
    254    return nfcret;
    255 }
    256 
    257 
    258 /*-----------------------------------------------------------------------------
    259 
    260 FUNCTION: phDal4Nfc_uart_read
    261 
    262 PURPOSE:  Reads nNbBytesToRead bytes and writes them in pBuffer.
    263           Returns the number of bytes really read or -1 in case of error.
    264 
    265 -----------------------------------------------------------------------------*/
    266 
    267 int phDal4Nfc_uart_read(uint8_t * pBuffer, int nNbBytesToRead)
    268 {
    269    fd_set rfds;
    270    struct timeval tv;
    271    int ret;
    272 
    273    DAL_ASSERT_STR(gComPortContext.nOpened == 1, "read called but not opened!");
    274 
    275    FD_ZERO(&rfds);
    276    FD_SET(gComPortContext.nHandle, &rfds);
    277 
    278    /* select will block for 10 sec */
    279    tv.tv_sec = 2;
    280    tv.tv_usec = 0;
    281 
    282    ret = select(gComPortContext.nHandle + 1, &rfds, NULL, NULL, &tv);
    283 
    284    if (ret == -1)
    285       return -1;
    286 
    287    if (ret)
    288       return read(gComPortContext.nHandle, pBuffer, nNbBytesToRead);
    289 
    290    return 0;
    291 }
    292 
    293 /*-----------------------------------------------------------------------------
    294 
    295 FUNCTION: phDal4Nfc_link_write
    296 
    297 PURPOSE:  Writes nNbBytesToWrite bytes from pBuffer to the link
    298           Returns the number of bytes that have been wrote to the interface or -1 in case of error.
    299 
    300 -----------------------------------------------------------------------------*/
    301 
    302 int phDal4Nfc_uart_write(uint8_t * pBuffer, int nNbBytesToWrite)
    303 {
    304    fd_set wfds;
    305    struct timeval tv;
    306    int ret;
    307 
    308    DAL_ASSERT_STR(gComPortContext.nOpened == 1, "write called but not opened!");
    309 
    310    FD_ZERO(&wfds);
    311    FD_SET(gComPortContext.nHandle, &wfds);
    312 
    313    /* select will block for 10 sec */
    314    tv.tv_sec = 2;
    315    tv.tv_usec = 0;
    316 
    317    ret = select(gComPortContext.nHandle + 1, NULL, &wfds, NULL, &tv);
    318 
    319    if (ret == -1)
    320       return -1;
    321 
    322    if (ret)
    323       return write(gComPortContext.nHandle, pBuffer, nNbBytesToWrite);
    324 
    325    return 0;
    326 }
    327 
    328 /*-----------------------------------------------------------------------------
    329 
    330 FUNCTION: phDal4Nfc_uart_reset
    331 
    332 PURPOSE:  Reset the PN544, using the VEN pin
    333 
    334 -----------------------------------------------------------------------------*/
    335 int phDal4Nfc_uart_reset()
    336 {
    337    DAL_PRINT("phDal4Nfc_uart_reset");
    338 
    339    return NFCSTATUS_FEATURE_NOT_SUPPORTED;
    340 }
    341 
    342 /*-----------------------------------------------------------------------------
    343 
    344 FUNCTION: phDal4Nfc_uart_write
    345 
    346 PURPOSE:  Put the PN544 in download mode, using the GPIO4 pin
    347 
    348 -----------------------------------------------------------------------------*/
    349 int phDal4Nfc_uart_download()
    350 {
    351    DAL_PRINT("phDal4Nfc_uart_download");
    352 
    353    return NFCSTATUS_FEATURE_NOT_SUPPORTED;
    354 }
    355 
    356