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 *******************************************************************************/
phTmlNfc_i2c_close(void * pDevHandle)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 *******************************************************************************/
phTmlNfc_i2c_open_and_configure(pphTmlNfc_Config_t pConfig,void ** pLinkHandle)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 *******************************************************************************/
phTmlNfc_i2c_read(void * pDevHandle,uint8_t * pBuffer,int nNbBytesToRead)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 UNUSED(nNbBytesToRead);
127 if (NULL == pDevHandle) {
128 return -1;
129 }
130
131 if (bFwDnldFlag == false) {
132 totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
133 } else {
134 totalBtyesToRead = FW_DNLD_HEADER_LEN;
135 }
136
137 /* Read with 2 second timeout, so that the read thread can be aborted
138 when the PN54X does not respond and we need to switch to FW download
139 mode. This should be done via a control socket instead. */
140 FD_ZERO(&rfds);
141 FD_SET((intptr_t)pDevHandle, &rfds);
142 tv.tv_sec = 2;
143 tv.tv_usec = 1;
144
145 ret_Select =
146 select((int)((intptr_t)pDevHandle + (int)1), &rfds, NULL, NULL, &tv);
147 if (ret_Select < 0) {
148 NXPLOG_TML_D("i2c select() errno : %x", errno);
149 return -1;
150 } else if (ret_Select == 0) {
151 NXPLOG_TML_D("i2c select() Timeout");
152 return -1;
153 } else {
154 ret_Read = read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead - numRead);
155 if (ret_Read > 0) {
156 numRead += ret_Read;
157 } else if (ret_Read == 0) {
158 NXPLOG_TML_E("_i2c_read() [hdr]EOF");
159 return -1;
160 } else {
161 NXPLOG_TML_E("_i2c_read() [hdr] errno : %x", errno);
162 return -1;
163 }
164
165 if (bFwDnldFlag == false) {
166 totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
167 } else {
168 totalBtyesToRead = FW_DNLD_HEADER_LEN;
169 }
170
171 if (numRead < totalBtyesToRead) {
172 ret_Read =
173 read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead - numRead);
174 if (ret_Read != totalBtyesToRead - numRead) {
175 NXPLOG_TML_E("_i2c_read() [hdr] errno : %x", errno);
176 return -1;
177 } else {
178 numRead += ret_Read;
179 }
180 }
181 if (bFwDnldFlag == true) {
182 totalBtyesToRead =
183 pBuffer[FW_DNLD_LEN_OFFSET] + FW_DNLD_HEADER_LEN + CRC_LEN;
184 } else {
185 totalBtyesToRead =
186 pBuffer[NORMAL_MODE_LEN_OFFSET] + NORMAL_MODE_HEADER_LEN;
187 }
188 if ((totalBtyesToRead - numRead) != 0) {
189 ret_Read = read((intptr_t)pDevHandle, (pBuffer + numRead),
190 totalBtyesToRead - numRead);
191 if (ret_Read > 0) {
192 numRead += ret_Read;
193 } else if (ret_Read == 0) {
194 NXPLOG_TML_E("_i2c_read() [pyld] EOF");
195 return -1;
196 } else {
197 if (bFwDnldFlag == false) {
198 NXPLOG_TML_D("_i2c_read() [hdr] received");
199 phNxpNciHal_print_packet("RECV", pBuffer, NORMAL_MODE_HEADER_LEN);
200 }
201 NXPLOG_TML_E("_i2c_read() [pyld] errno : %x", errno);
202 return -1;
203 }
204 } else {
205 NXPLOG_TML_E("_>>>>> Empty packet recieved !!");
206 }
207 }
208 return numRead;
209 }
210
211 /*******************************************************************************
212 **
213 ** Function phTmlNfc_i2c_write
214 **
215 ** Description Writes requested number of bytes from given buffer into
216 ** PN54X device
217 **
218 ** Parameters pDevHandle - valid device handle
219 ** pBuffer - buffer for read data
220 ** nNbBytesToWrite - number of bytes requested to be written
221 **
222 ** Returns numWrote - number of successfully written bytes
223 ** -1 - write operation failure
224 **
225 *******************************************************************************/
phTmlNfc_i2c_write(void * pDevHandle,uint8_t * pBuffer,int nNbBytesToWrite)226 int phTmlNfc_i2c_write(void* pDevHandle, uint8_t* pBuffer,
227 int nNbBytesToWrite) {
228 int ret;
229 int numWrote = 0;
230 int numBytes = nNbBytesToWrite;
231 if (NULL == pDevHandle) {
232 return -1;
233 }
234 if (fragmentation_enabled == I2C_FRAGMENATATION_DISABLED &&
235 nNbBytesToWrite > FRAGMENTSIZE_MAX) {
236 NXPLOG_TML_D(
237 "i2c_write() data larger than maximum I2C size,enable I2C "
238 "fragmentation");
239 return -1;
240 }
241 while (numWrote < nNbBytesToWrite) {
242 if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED &&
243 nNbBytesToWrite > FRAGMENTSIZE_MAX) {
244 if (nNbBytesToWrite - numWrote > FRAGMENTSIZE_MAX) {
245 numBytes = numWrote + FRAGMENTSIZE_MAX;
246 } else {
247 numBytes = nNbBytesToWrite;
248 }
249 }
250 ret = write((intptr_t)pDevHandle, pBuffer + numWrote, numBytes - numWrote);
251 if (ret > 0) {
252 numWrote += ret;
253 if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED &&
254 numWrote < nNbBytesToWrite) {
255 usleep(500);
256 }
257 } else if (ret == 0) {
258 NXPLOG_TML_D("_i2c_write() EOF");
259 return -1;
260 } else {
261 NXPLOG_TML_D("_i2c_write() errno : %x", errno);
262 if (errno == EINTR || errno == EAGAIN) {
263 continue;
264 }
265 return -1;
266 }
267 }
268
269 return numWrote;
270 }
271
272 /*******************************************************************************
273 **
274 ** Function phTmlNfc_i2c_reset
275 **
276 ** Description Reset PN54X device, using VEN pin
277 **
278 ** Parameters pDevHandle - valid device handle
279 ** level - reset level
280 **
281 ** Returns 0 - reset operation success
282 ** -1 - reset operation failure
283 **
284 *******************************************************************************/
phTmlNfc_i2c_reset(void * pDevHandle,long level)285 int phTmlNfc_i2c_reset(void* pDevHandle, long level) {
286 int ret;
287 NXPLOG_TML_D("phTmlNfc_i2c_reset(), VEN level %ld", level);
288
289 if (NULL == pDevHandle) {
290 return -1;
291 }
292
293 ret = ioctl((intptr_t)pDevHandle, PN544_SET_PWR, level);
294 if (level == 2 && ret == 0) {
295 bFwDnldFlag = true;
296 } else {
297 bFwDnldFlag = false;
298 }
299 return ret;
300 }
301
302 /*******************************************************************************
303 **
304 ** Function getDownloadFlag
305 **
306 ** Description Returns the current mode
307 **
308 ** Parameters none
309 **
310 ** Returns Current mode download/NCI
311 *******************************************************************************/
getDownloadFlag(void)312 bool_t getDownloadFlag(void) { return bFwDnldFlag; }
313