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
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
phDal4Nfc_i2c_initialize(void)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
phDal4Nfc_i2c_set_open_from_handle(phHal_sHwReference_t * pDalHwContext)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
phDal4Nfc_i2c_is_opened(void)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
phDal4Nfc_i2c_flush(void)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
phDal4Nfc_i2c_close(void)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
phDal4Nfc_i2c_open_and_configure(pphDal4Nfc_sConfig_t pConfig,void ** pLinkHandle)145 NFCSTATUS phDal4Nfc_i2c_open_and_configure(pphDal4Nfc_sConfig_t pConfig, void ** pLinkHandle)
146 {
147 char * pComPort;
148
149 DAL_ASSERT_STR(gI2cPortContext.nOpened==0, "Trying to open but already done!");
150
151 switch(pConfig->nLinkType)
152 {
153 case ENUM_DAL_LINK_TYPE_I2C:
154 pComPort = "/dev/pn544";
155 break;
156 default:
157 DAL_DEBUG("Open failed: unknown type %d\n", pConfig->nLinkType);
158 return NFCSTATUS_INVALID_PARAMETER;
159 }
160
161 DAL_DEBUG("Opening port=%s\n", pComPort);
162
163 /* open port */
164 gI2cPortContext.nHandle = open(pComPort, O_RDWR | O_NOCTTY);
165 if (gI2cPortContext.nHandle < 0)
166 {
167 DAL_DEBUG("Open failed: open() returned %d\n", gI2cPortContext.nHandle);
168 *pLinkHandle = NULL;
169 return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE);
170 }
171
172 gI2cPortContext.nOpened = 1;
173 *pLinkHandle = (void*)gI2cPortContext.nHandle;
174
175 DAL_PRINT("Open succeed\n");
176
177 return NFCSTATUS_SUCCESS;
178 }
179
180
181 /*-----------------------------------------------------------------------------
182
183 FUNCTION: phDal4Nfc_i2c_read
184
185 PURPOSE: Reads nNbBytesToRead bytes and writes them in pBuffer.
186 Returns the number of bytes really read or -1 in case of error.
187
188 -----------------------------------------------------------------------------*/
189
phDal4Nfc_i2c_read(uint8_t * pBuffer,int nNbBytesToRead)190 int phDal4Nfc_i2c_read(uint8_t * pBuffer, int nNbBytesToRead)
191 {
192 int ret;
193 int numRead = 0;
194 struct timeval tv;
195 fd_set rfds;
196
197 DAL_ASSERT_STR(gI2cPortContext.nOpened == 1, "read called but not opened!");
198 DAL_DEBUG("_i2c_read() called to read %d bytes", nNbBytesToRead);
199
200 // Read with 2 second timeout, so that the read thread can be aborted
201 // when the pn544 does not respond and we need to switch to FW download
202 // mode. This should be done via a control socket instead.
203 while (numRead < nNbBytesToRead) {
204 FD_ZERO(&rfds);
205 FD_SET(gI2cPortContext.nHandle, &rfds);
206 tv.tv_sec = 2;
207 tv.tv_usec = 0;
208 ret = select(gI2cPortContext.nHandle + 1, &rfds, NULL, NULL, &tv);
209 if (ret < 0) {
210 DAL_DEBUG("select() errno=%d", errno);
211 if (errno == EINTR || errno == EAGAIN) {
212 continue;
213 }
214 return -1;
215 } else if (ret == 0) {
216 DAL_PRINT("timeout!");
217 return -1;
218 }
219 ret = read(gI2cPortContext.nHandle, pBuffer + numRead, nNbBytesToRead - numRead);
220 if (ret > 0) {
221 DAL_DEBUG("read %d bytes", ret);
222 numRead += ret;
223 } else if (ret == 0) {
224 DAL_PRINT("_i2c_read() EOF");
225 return -1;
226 } else {
227 DAL_DEBUG("_i2c_read() errno=%d", errno);
228 if (errno == EINTR || errno == EAGAIN) {
229 continue;
230 }
231 return -1;
232 }
233 }
234 return numRead;
235 }
236
237 /*-----------------------------------------------------------------------------
238
239 FUNCTION: phDal4Nfc_i2c_write
240
241 PURPOSE: Writes nNbBytesToWrite bytes from pBuffer to the link
242 Returns the number of bytes that have been wrote to the interface or -1 in case of error.
243
244 -----------------------------------------------------------------------------*/
245
phDal4Nfc_i2c_write(uint8_t * pBuffer,int nNbBytesToWrite)246 int phDal4Nfc_i2c_write(uint8_t * pBuffer, int nNbBytesToWrite)
247 {
248 int ret;
249 int numWrote = 0;
250
251 DAL_ASSERT_STR(gI2cPortContext.nOpened == 1, "write called but not opened!");
252 DAL_DEBUG("_i2c_write() called to write %d bytes\n", nNbBytesToWrite);
253
254 while (numWrote < nNbBytesToWrite) {
255 ret = write(gI2cPortContext.nHandle, pBuffer + numWrote, nNbBytesToWrite - numWrote);
256 if (ret > 0) {
257 DAL_DEBUG("wrote %d bytes", ret);
258 numWrote += ret;
259 } else if (ret == 0) {
260 DAL_PRINT("_i2c_write() EOF");
261 return -1;
262 } else {
263 DAL_DEBUG("_i2c_write() errno=%d", 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: phDal4Nfc_i2c_reset
277
278 PURPOSE: Reset the PN544, using the VEN pin
279
280 -----------------------------------------------------------------------------*/
phDal4Nfc_i2c_reset(long level)281 int phDal4Nfc_i2c_reset(long level)
282 {
283 DAL_DEBUG("phDal4Nfc_i2c_reset, VEN level = %ld", level);
284
285 return ioctl(gI2cPortContext.nHandle, PN544_SET_PWR, level);
286 }
287