1 /******************************************************************************
2 * Copyright 2020-2023 NXP
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 /*
19 * DAL I2C port implementation for linux
20 *
21 * Project: Trusted NFC Linux
22 *
23 */
24 #include <errno.h>
25 #include <fcntl.h>
26 #include <hardware/nfc.h>
27 #include <stdlib.h>
28 #include <sys/ioctl.h>
29 #include <sys/select.h>
30 #include <termios.h>
31 #include <unistd.h>
32
33 #include <NfccI2cTransport.h>
34 #include <phNfcStatus.h>
35 #include <phNxpLog.h>
36 #include <string.h>
37 #include "phNxpNciHal_utils.h"
38
39 #define CRC_LEN 2
40 #define NORMAL_MODE_HEADER_LEN 3
41 #define FW_DNLD_HEADER_LEN 2
42 #define FW_DNLD_LEN_OFFSET 1
43 #define NORMAL_MODE_LEN_OFFSET 2
44 #define FLUSH_BUFFER_SIZE 0xFF
45 extern phTmlNfc_i2cfragmentation_t fragmentation_enabled;
46 extern phTmlNfc_Context_t* gpphTmlNfc_Context;
47 /*******************************************************************************
48 **
49 ** Function Close
50 **
51 ** Description Closes NFCC device
52 **
53 ** Parameters pDevHandle - device handle
54 **
55 ** Returns None
56 **
57 *******************************************************************************/
Close(void * pDevHandle)58 void NfccI2cTransport::Close(void* pDevHandle) {
59 if (NULL != pDevHandle) {
60 close((int)(intptr_t)pDevHandle);
61 }
62 sem_destroy(&mTxRxSemaphore);
63 return;
64 }
65
66 /*******************************************************************************
67 **
68 ** Function OpenAndConfigure
69 **
70 ** Description Open and configure NFCC 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 *******************************************************************************/
OpenAndConfigure(pphTmlNfc_Config_t pConfig,void ** pLinkHandle)80 NFCSTATUS NfccI2cTransport::OpenAndConfigure(pphTmlNfc_Config_t pConfig,
81 void** pLinkHandle) {
82 int nHandle;
83 NFCSTATUS status = NFCSTATUS_SUCCESS;
84 NXPLOG_TML_D("%s Opening port=%s\n", __func__, 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 status = NFCSTATUS_INVALID_DEVICE;
91 } else {
92 *pLinkHandle = (void*)((intptr_t)nHandle);
93 if (0 != sem_init(&mTxRxSemaphore, 0, 1)) {
94 NXPLOG_TML_E("%s Failed: reason sem_init : retval %x", __func__, nHandle);
95 status = NFCSTATUS_FAILED;
96 }
97 }
98 return status;
99 }
100
101 /*******************************************************************************
102 **
103 ** Function Flushdata
104 **
105 ** Description Reads payload of FW rsp from NFCC device into given buffer
106 **
107 ** Parameters pConfig - hardware information
108 **
109 ** Returns True(Success)/False(Fail)
110 **
111 *******************************************************************************/
Flushdata(pphTmlNfc_Config_t pConfig)112 bool NfccI2cTransport::Flushdata(pphTmlNfc_Config_t pConfig) {
113 int retRead = 0;
114 int nHandle;
115 uint8_t pBuffer[FLUSH_BUFFER_SIZE];
116 NXPLOG_TML_D("%s: Enter", __func__);
117 nHandle = open((const char*)pConfig->pDevName, O_RDWR | O_NONBLOCK);
118 if (nHandle < 0) {
119 NXPLOG_TML_E("%s: _i2c_open() Failed: retval %x", __func__, nHandle);
120 return false;
121 }
122 do {
123 retRead = read(nHandle, pBuffer, sizeof(pBuffer));
124 if (retRead > 0) {
125 phNxpNciHal_print_packet("RECV", pBuffer, retRead);
126 usleep(2 * 1000);
127 }
128 } while (retRead > 0);
129 close(nHandle);
130 NXPLOG_TML_D("%s: Exit", __func__);
131 return true;
132 }
133
134 /*******************************************************************************
135 **
136 ** Function Read
137 **
138 ** Description Reads requested number of bytes from NFCC device into given
139 ** buffer
140 **
141 ** Parameters pDevHandle - valid device handle
142 ** pBuffer - buffer for read data
143 ** nNbBytesToRead - number of bytes requested to be read
144 **
145 ** Returns numRead - number of successfully read bytes
146 ** -1 - read operation failure
147 **
148 *******************************************************************************/
Read(void * pDevHandle,uint8_t * pBuffer,int nNbBytesToRead)149 int NfccI2cTransport::Read(void* pDevHandle, uint8_t* pBuffer,
150 int nNbBytesToRead) {
151 int ret_Read;
152 int ret_Select;
153 int numRead = 0;
154 struct timeval tv;
155 fd_set rfds;
156 uint16_t totalBtyesToRead = 0;
157
158 UNUSED_PROP(nNbBytesToRead);
159 if (NULL == pDevHandle) {
160 return -1;
161 }
162
163 if (bFwDnldFlag == false) {
164 totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
165 } else {
166 totalBtyesToRead = FW_DNLD_HEADER_LEN;
167 }
168
169 /* Read with 2 second timeout, so that the read thread can be aborted
170 when the NFCC does not respond and we need to switch to FW download
171 mode. This should be done via a control socket instead. */
172 FD_ZERO(&rfds);
173 FD_SET((int)(intptr_t)pDevHandle, &rfds);
174 tv.tv_sec = 2;
175 tv.tv_usec = 1;
176
177 ret_Select =
178 select((int)((intptr_t)pDevHandle + (int)1), &rfds, NULL, NULL, &tv);
179 if (ret_Select < 0) {
180 NXPLOG_TML_D("%s errno : %x", __func__, errno);
181 return -1;
182 } else if (ret_Select == 0) {
183 NXPLOG_TML_D("%s Timeout", __func__);
184 return -1;
185 } else {
186 ret_Read =
187 read((int)(intptr_t)pDevHandle, pBuffer, totalBtyesToRead - numRead);
188 if (ret_Read > 0 && !(pBuffer[0] == 0xFF && pBuffer[1] == 0xFF)) {
189 numRead += ret_Read;
190 } else if (ret_Read == 0) {
191 NXPLOG_TML_E("%s [hdr]EOF", __func__);
192 return -1;
193 } else {
194 NXPLOG_TML_E("%s [hdr] errno : %x", __func__, errno);
195 NXPLOG_TML_E(" %s pBuffer[0] = %x pBuffer[1]= %x", __func__, pBuffer[0],
196 pBuffer[1]);
197 return -1;
198 }
199
200 if (bFwDnldFlag && (pBuffer[0] != 0x00)) {
201 bFwDnldFlag = false;
202 }
203
204 if (bFwDnldFlag == false) {
205 totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
206 } else {
207 totalBtyesToRead = FW_DNLD_HEADER_LEN;
208 }
209
210 if (numRead < totalBtyesToRead) {
211 ret_Read = read((int)(intptr_t)pDevHandle, (pBuffer + numRead),
212 totalBtyesToRead - numRead);
213
214 if (ret_Read != totalBtyesToRead - numRead) {
215 NXPLOG_TML_E("%s [hdr] errno : %x", __func__, errno);
216 return -1;
217 } else {
218 numRead += ret_Read;
219 }
220 }
221 if (bFwDnldFlag == true) {
222 totalBtyesToRead =
223 pBuffer[FW_DNLD_LEN_OFFSET] + FW_DNLD_HEADER_LEN + CRC_LEN;
224 } else {
225 totalBtyesToRead =
226 pBuffer[NORMAL_MODE_LEN_OFFSET] + NORMAL_MODE_HEADER_LEN;
227 }
228 if ((totalBtyesToRead - numRead) != 0) {
229 ret_Read = read((int)(intptr_t)pDevHandle, (pBuffer + numRead),
230 totalBtyesToRead - numRead);
231 if (ret_Read > 0) {
232 numRead += ret_Read;
233 } else if (ret_Read == 0) {
234 NXPLOG_TML_E("%s [pyld] EOF", __func__);
235 return -1;
236 } else {
237 if (bFwDnldFlag == false) {
238 NXPLOG_TML_D("_i2c_read() [hdr] received");
239 phNxpNciHal_print_packet("RECV", pBuffer, NORMAL_MODE_HEADER_LEN);
240 }
241 NXPLOG_TML_E("%s [pyld] errno : %x", __func__, errno);
242 return -1;
243 }
244 } else {
245 NXPLOG_TML_E("%s _>>>>> Empty packet received !!", __func__);
246 }
247 }
248 return numRead;
249 }
250
251 /*******************************************************************************
252 **
253 ** Function Write
254 **
255 ** Description Writes requested number of bytes from given buffer into
256 ** NFCC device
257 **
258 ** Parameters pDevHandle - valid device handle
259 ** pBuffer - buffer for read data
260 ** nNbBytesToWrite - number of bytes requested to be written
261 **
262 ** Returns numWrote - number of successfully written bytes
263 ** -1 - write operation failure
264 **
265 *******************************************************************************/
Write(void * pDevHandle,uint8_t * pBuffer,int nNbBytesToWrite)266 int NfccI2cTransport::Write(void* pDevHandle, uint8_t* pBuffer,
267 int nNbBytesToWrite) {
268 int ret;
269 int numWrote = 0;
270 int numBytes = nNbBytesToWrite;
271 if (NULL == pDevHandle) {
272 return -1;
273 }
274 if (fragmentation_enabled == I2C_FRAGMENATATION_DISABLED &&
275 nNbBytesToWrite > gpphTmlNfc_Context->fragment_len) {
276 NXPLOG_TML_D(
277 "%s data larger than maximum I2C size,enable I2C fragmentation",
278 __func__);
279 return -1;
280 }
281 while (numWrote < nNbBytesToWrite) {
282 if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED &&
283 nNbBytesToWrite > gpphTmlNfc_Context->fragment_len) {
284 if (nNbBytesToWrite - numWrote > gpphTmlNfc_Context->fragment_len) {
285 numBytes = numWrote + gpphTmlNfc_Context->fragment_len;
286 } else {
287 numBytes = nNbBytesToWrite;
288 }
289 }
290 ret = write((int)(intptr_t)pDevHandle, pBuffer + numWrote,
291 numBytes - numWrote);
292 if (ret > 0) {
293 numWrote += ret;
294 if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED &&
295 numWrote < nNbBytesToWrite) {
296 usleep(500);
297 }
298 } else if (ret == 0) {
299 NXPLOG_TML_D("%s EOF", __func__);
300 return -1;
301 } else {
302 NXPLOG_TML_D("%s errno : %x", __func__, errno);
303 if (errno == EINTR || errno == EAGAIN) {
304 continue;
305 }
306 return -1;
307 }
308 }
309
310 return numWrote;
311 }
312
313 /*******************************************************************************
314 **
315 ** Function Reset
316 **
317 ** Description Reset NFCC device, using VEN pin
318 **
319 ** Parameters pDevHandle - valid device handle
320 ** eType - reset level
321 **
322 ** Returns 0 - reset operation success
323 ** -1 - reset operation failure
324 **
325 *******************************************************************************/
NfccReset(void * pDevHandle,NfccResetType eType)326 int NfccI2cTransport::NfccReset(void* pDevHandle, NfccResetType eType) {
327 int ret = -1;
328 NXPLOG_TML_D("%s, VEN eType %u", __func__, eType);
329
330 if (NULL == pDevHandle) {
331 return -1;
332 }
333
334 ret = ioctl((int)(intptr_t)pDevHandle, NFC_SET_PWR, eType);
335 if (ret < 0) {
336 NXPLOG_TML_E("%s :failed errno = 0x%x", __func__, errno);
337 }
338 if ((eType != MODE_FW_DWNLD_WITH_VEN && eType != MODE_FW_DWND_HIGH) &&
339 ret == 0) {
340 bFwDnldFlag = false;
341 }
342
343 return ret;
344 }
345 /*****************************************************************************
346 **
347 ** Function UpdateReadPending
348 **
349 ** Description Set/Reset Read Pending of NFC
350 **
351 ** Parameters pDevHandle - valid device handle
352 ** eType - set or clear the flag
353 **
354 ** Returns 0 - operation success
355 ** -1 - operation failure
356 **
357 ****************************************************************************/
UpdateReadPending(void * pDevHandle,NfcReadPending eType)358 int NfccI2cTransport::UpdateReadPending(void* pDevHandle,
359 NfcReadPending eType) {
360 int ret = -1;
361 if (NULL == pDevHandle) {
362 return -1;
363 }
364 NXPLOG_TML_D("%s, %u", __func__, eType);
365 ret = ioctl((int)(intptr_t)pDevHandle, NFC_SET_RESET_READ_PENDING, eType);
366 if (ret != 0) {
367 NXPLOG_TML_E("%s: %u ret = 0x%x", __func__, eType, ret);
368 }
369 return ret;
370 }
371
372 /*****************************************************************************
373 **
374 ** Function NfcGetGpioStatus
375 **
376 ** Description Get the gpio status flag byte from kernel space
377 **
378 ** Parameters pDevHandle - valid device handle
379 **
380 **
381 ** Returns 0 - operation success
382 ** -1 - operation failure
383 **
384 ****************************************************************************/
NfcGetGpioStatus(void * pDevHandle,uint32_t * status)385 int NfccI2cTransport ::NfcGetGpioStatus(void* pDevHandle, uint32_t* status) {
386 int ret = -1;
387 if (NULL == pDevHandle) {
388 return ret;
389 }
390 ret = ioctl((int)(intptr_t)pDevHandle, NFC_GET_GPIO_STATUS, status);
391 if (ret != 0) {
392 NXPLOG_TML_E("%s: ret = 0x%x", __func__, ret);
393 }
394 NXPLOG_TML_D("%s, %d", __func__, *status);
395 return ret;
396 }
397 /*******************************************************************************
398 **
399 ** Function EseReset
400 **
401 ** Description Request NFCC to reset the eSE
402 **
403 ** Parameters pDevHandle - valid device handle
404 ** eType - EseResetType
405 **
406 ** Returns 0 - reset operation success
407 ** else - reset operation failure
408 **
409 *******************************************************************************/
EseReset(void * pDevHandle,EseResetType eType)410 int NfccI2cTransport::EseReset(void* pDevHandle, EseResetType eType) {
411 int ret = -1;
412 NXPLOG_TML_D("%s, eType %u", __func__, eType);
413
414 if (NULL == pDevHandle) {
415 return -1;
416 }
417 ret = ioctl((int)(intptr_t)pDevHandle, ESE_SET_PWR, eType);
418 if (ret < 0) {
419 NXPLOG_TML_E("%s :failed errno = 0x%x", __func__, errno);
420 }
421 return ret;
422 }
423
424 /*******************************************************************************
425 **
426 ** Function EnableFwDnldMode
427 **
428 ** Description updates the state to Download mode
429 **
430 ** Parameters True/False
431 **
432 ** Returns None
433 *******************************************************************************/
EnableFwDnldMode(bool mode)434 void NfccI2cTransport::EnableFwDnldMode(bool mode) { bFwDnldFlag = mode; }
435
436 /*******************************************************************************
437 **
438 ** Function IsFwDnldModeEnabled
439 **
440 ** Description Returns the current mode
441 **
442 ** Parameters none
443 **
444 ** Returns Current mode download/NCI
445 *******************************************************************************/
IsFwDnldModeEnabled(void)446 bool_t NfccI2cTransport::IsFwDnldModeEnabled(void) { return bFwDnldFlag; }
447