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