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