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_i2c.c 19 * \brief DAL I2C port implementation for linux 20 * 21 * Project: Trusted NFC Linux 22 * 23 */ 24 25 #define LOG_TAG "NFC_i2c" 26 #include <cutils/log.h> 27 #include <hardware/nfc.h> 28 #include <stdlib.h> 29 #include <unistd.h> 30 #include <fcntl.h> 31 #include <termios.h> 32 #include <sys/ioctl.h> 33 #include <sys/select.h> 34 #include <errno.h> 35 36 #include <phDal4Nfc_debug.h> 37 #include <phDal4Nfc_i2c.h> 38 #include <phOsalNfc.h> 39 #include <phNfcStatus.h> 40 #if defined(ANDROID) 41 #include <string.h> 42 #endif 43 44 #include <linux/pn544.h> 45 46 typedef struct 47 { 48 int nHandle; 49 char nOpened; 50 51 } phDal4Nfc_I2cPortContext_t; 52 53 54 /*----------------------------------------------------------------------------------- 55 VARIABLES 56 ------------------------------------------------------------------------------------*/ 57 static phDal4Nfc_I2cPortContext_t gI2cPortContext; 58 59 60 61 /*----------------------------------------------------------------------------- 62 63 FUNCTION: phDal4Nfc_i2c_set_open_from_handle 64 65 PURPOSE: Initialize internal variables 66 67 -----------------------------------------------------------------------------*/ 68 69 void phDal4Nfc_i2c_initialize(void) 70 { 71 memset(&gI2cPortContext, 0, sizeof(phDal4Nfc_I2cPortContext_t)); 72 } 73 74 75 /*----------------------------------------------------------------------------- 76 77 FUNCTION: phDal4Nfc_i2c_set_open_from_handle 78 79 PURPOSE: The application could have opened the link itself. So we just need 80 to get the handle and consider that the open operation has already 81 been done. 82 83 -----------------------------------------------------------------------------*/ 84 85 void phDal4Nfc_i2c_set_open_from_handle(phHal_sHwReference_t * pDalHwContext) 86 { 87 gI2cPortContext.nHandle = (int) pDalHwContext->p_board_driver; 88 DAL_ASSERT_STR(gI2cPortContext.nHandle >= 0, "Bad passed com port handle"); 89 gI2cPortContext.nOpened = 1; 90 } 91 92 /*----------------------------------------------------------------------------- 93 94 FUNCTION: phDal4Nfc_i2c_is_opened 95 96 PURPOSE: Returns if the link is opened or not. (0 = not opened; 1 = opened) 97 98 -----------------------------------------------------------------------------*/ 99 100 int phDal4Nfc_i2c_is_opened(void) 101 { 102 return gI2cPortContext.nOpened; 103 } 104 105 /*----------------------------------------------------------------------------- 106 107 FUNCTION: phDal4Nfc_i2c_flush 108 109 PURPOSE: Flushes the link ; clears the link buffers 110 111 -----------------------------------------------------------------------------*/ 112 113 void phDal4Nfc_i2c_flush(void) 114 { 115 /* Nothing to do (driver has no internal buffers) */ 116 } 117 118 /*----------------------------------------------------------------------------- 119 120 FUNCTION: phDal4Nfc_i2c_close 121 122 PURPOSE: Closes the link 123 124 -----------------------------------------------------------------------------*/ 125 126 void phDal4Nfc_i2c_close(void) 127 { 128 DAL_PRINT("Closing port\n"); 129 if (gI2cPortContext.nOpened == 1) 130 { 131 close(gI2cPortContext.nHandle); 132 gI2cPortContext.nHandle = 0; 133 gI2cPortContext.nOpened = 0; 134 } 135 } 136 137 /*----------------------------------------------------------------------------- 138 139 FUNCTION: phDal4Nfc_i2c_open_and_configure 140 141 PURPOSE: Closes the link 142 143 -----------------------------------------------------------------------------*/ 144 145 NFCSTATUS phDal4Nfc_i2c_open_and_configure(pphDal4Nfc_sConfig_t pConfig, void ** pLinkHandle) 146 { 147 DAL_ASSERT_STR(gI2cPortContext.nOpened==0, "Trying to open but already done!"); 148 149 DAL_DEBUG("Opening port=%s\n", pConfig->deviceNode); 150 151 /* open port */ 152 gI2cPortContext.nHandle = open(pConfig->deviceNode, O_RDWR | O_NOCTTY); 153 if (gI2cPortContext.nHandle < 0) 154 { 155 DAL_DEBUG("Open failed: open() returned %d\n", gI2cPortContext.nHandle); 156 *pLinkHandle = NULL; 157 return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE); 158 } 159 160 gI2cPortContext.nOpened = 1; 161 *pLinkHandle = (void*)gI2cPortContext.nHandle; 162 163 DAL_PRINT("Open succeed\n"); 164 165 return NFCSTATUS_SUCCESS; 166 } 167 168 169 /*----------------------------------------------------------------------------- 170 171 FUNCTION: phDal4Nfc_i2c_read 172 173 PURPOSE: Reads nNbBytesToRead bytes and writes them in pBuffer. 174 Returns the number of bytes really read or -1 in case of error. 175 176 -----------------------------------------------------------------------------*/ 177 178 int phDal4Nfc_i2c_read(uint8_t * pBuffer, int nNbBytesToRead) 179 { 180 int ret; 181 int numRead = 0; 182 struct timeval tv; 183 fd_set rfds; 184 185 DAL_ASSERT_STR(gI2cPortContext.nOpened == 1, "read called but not opened!"); 186 DAL_DEBUG("_i2c_read() called to read %d bytes", nNbBytesToRead); 187 188 // Read with 2 second timeout, so that the read thread can be aborted 189 // when the pn544 does not respond and we need to switch to FW download 190 // mode. This should be done via a control socket instead. 191 while (numRead < nNbBytesToRead) { 192 FD_ZERO(&rfds); 193 FD_SET(gI2cPortContext.nHandle, &rfds); 194 tv.tv_sec = 2; 195 tv.tv_usec = 0; 196 ret = select(gI2cPortContext.nHandle + 1, &rfds, NULL, NULL, &tv); 197 if (ret < 0) { 198 DAL_DEBUG("select() errno=%d", errno); 199 if (errno == EINTR || errno == EAGAIN) { 200 continue; 201 } 202 return -1; 203 } else if (ret == 0) { 204 DAL_PRINT("timeout!"); 205 return -1; 206 } 207 ret = read(gI2cPortContext.nHandle, pBuffer + numRead, nNbBytesToRead - numRead); 208 if (ret > 0) { 209 DAL_DEBUG("read %d bytes", ret); 210 numRead += ret; 211 } else if (ret == 0) { 212 DAL_PRINT("_i2c_read() EOF"); 213 return -1; 214 } else { 215 DAL_DEBUG("_i2c_read() errno=%d", errno); 216 if (errno == EINTR || errno == EAGAIN) { 217 continue; 218 } 219 return -1; 220 } 221 } 222 return numRead; 223 } 224 225 /*----------------------------------------------------------------------------- 226 227 FUNCTION: phDal4Nfc_i2c_write 228 229 PURPOSE: Writes nNbBytesToWrite bytes from pBuffer to the link 230 Returns the number of bytes that have been wrote to the interface or -1 in case of error. 231 232 -----------------------------------------------------------------------------*/ 233 234 int phDal4Nfc_i2c_write(uint8_t * pBuffer, int nNbBytesToWrite) 235 { 236 int ret; 237 int numWrote = 0; 238 239 DAL_ASSERT_STR(gI2cPortContext.nOpened == 1, "write called but not opened!"); 240 DAL_DEBUG("_i2c_write() called to write %d bytes\n", nNbBytesToWrite); 241 242 while (numWrote < nNbBytesToWrite) { 243 ret = write(gI2cPortContext.nHandle, pBuffer + numWrote, nNbBytesToWrite - numWrote); 244 if (ret > 0) { 245 DAL_DEBUG("wrote %d bytes", ret); 246 numWrote += ret; 247 } else if (ret == 0) { 248 DAL_PRINT("_i2c_write() EOF"); 249 return -1; 250 } else { 251 DAL_DEBUG("_i2c_write() errno=%d", errno); 252 if (errno == EINTR || errno == EAGAIN) { 253 continue; 254 } 255 return -1; 256 } 257 } 258 259 return numWrote; 260 } 261 262 /*----------------------------------------------------------------------------- 263 264 FUNCTION: phDal4Nfc_i2c_reset 265 266 PURPOSE: Reset the PN544, using the VEN pin 267 268 -----------------------------------------------------------------------------*/ 269 int phDal4Nfc_i2c_reset(long level) 270 { 271 DAL_DEBUG("phDal4Nfc_i2c_reset, VEN level = %ld", level); 272 273 return ioctl(gI2cPortContext.nHandle, PN544_SET_PWR, level); 274 } 275