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