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