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