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 *******************************************************************************/
phTmlNfc_i2c_close(void * pDevHandle)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 *******************************************************************************/
phTmlNfc_i2c_open_and_configure(pphTmlNfc_Config_t pConfig,void ** pLinkHandle)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 *******************************************************************************/
phTmlNfc_i2c_read(void * pDevHandle,uint8_t * pBuffer,int nNbBytesToRead)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 *******************************************************************************/
phTmlNfc_i2c_write(void * pDevHandle,uint8_t * pBuffer,int nNbBytesToWrite)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)
phTmlNfc_i2c_reset(void * pDevHandle,long level)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 *******************************************************************************/
getDownloadFlag(void)358 bool_t getDownloadFlag(void)
359 {
360
361 return bFwDnldFlag;
362 }
363