1 /******************************************************************************
2 * Copyright 2020-2024 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 if (errno == ENOTCONN) {
194 NXPLOG_TML_E("%s [hdr] errno : %x", __func__, errno);
195 return -ENOTCONN;
196 } else {
197 NXPLOG_TML_E("%s [hdr] errno : %x", __func__, errno);
198 NXPLOG_TML_E(" %s pBuffer[0] = %x pBuffer[1]= %x", __func__, pBuffer[0],
199 pBuffer[1]);
200 return -1;
201 }
202
203 if (bFwDnldFlag && (pBuffer[0] != 0x00)) {
204 bFwDnldFlag = false;
205 }
206
207 if (bFwDnldFlag == false) {
208 totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
209 } else {
210 totalBtyesToRead = FW_DNLD_HEADER_LEN;
211 }
212
213 if (numRead < totalBtyesToRead) {
214 ret_Read = read((int)(intptr_t)pDevHandle, (pBuffer + numRead),
215 totalBtyesToRead - numRead);
216
217 if (ret_Read != totalBtyesToRead - numRead) {
218 NXPLOG_TML_E("%s [hdr] errno : %x", __func__, errno);
219 return -1;
220 } else {
221 numRead += ret_Read;
222 }
223 }
224 if (bFwDnldFlag == true) {
225 totalBtyesToRead =
226 pBuffer[FW_DNLD_LEN_OFFSET] + FW_DNLD_HEADER_LEN + CRC_LEN;
227 } else {
228 totalBtyesToRead =
229 pBuffer[NORMAL_MODE_LEN_OFFSET] + NORMAL_MODE_HEADER_LEN;
230 }
231 if ((totalBtyesToRead - numRead) != 0) {
232 ret_Read = read((int)(intptr_t)pDevHandle, (pBuffer + numRead),
233 totalBtyesToRead - numRead);
234 if (ret_Read > 0) {
235 numRead += ret_Read;
236 } else if (ret_Read == 0) {
237 NXPLOG_TML_E("%s [pyld] EOF", __func__);
238 return -1;
239 } else {
240 if (bFwDnldFlag == false) {
241 NXPLOG_TML_D("_i2c_read() [hdr] received");
242 phNxpNciHal_print_packet("RECV", pBuffer, NORMAL_MODE_HEADER_LEN);
243 }
244 NXPLOG_TML_E("%s [pyld] errno : %x", __func__, errno);
245 return -1;
246 }
247 } else {
248 NXPLOG_TML_E("%s _>>>>> Empty packet received !!", __func__);
249 }
250 }
251 return numRead;
252 }
253
254 /*******************************************************************************
255 **
256 ** Function Write
257 **
258 ** Description Writes requested number of bytes from given buffer into
259 ** NFCC device
260 **
261 ** Parameters pDevHandle - valid device handle
262 ** pBuffer - buffer for read data
263 ** nNbBytesToWrite - number of bytes requested to be written
264 **
265 ** Returns numWrote - number of successfully written bytes
266 ** -1 - write operation failure
267 **
268 *******************************************************************************/
Write(void * pDevHandle,uint8_t * pBuffer,int nNbBytesToWrite)269 int NfccI2cTransport::Write(void* pDevHandle, uint8_t* pBuffer,
270 int nNbBytesToWrite) {
271 int ret;
272 int numWrote = 0;
273 int numBytes = nNbBytesToWrite;
274 if (NULL == pDevHandle) {
275 return -1;
276 }
277 if (fragmentation_enabled == I2C_FRAGMENATATION_DISABLED &&
278 nNbBytesToWrite > gpphTmlNfc_Context->fragment_len) {
279 NXPLOG_TML_D(
280 "%s data larger than maximum I2C size,enable I2C fragmentation",
281 __func__);
282 return -1;
283 }
284 while (numWrote < nNbBytesToWrite) {
285 if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED &&
286 nNbBytesToWrite > gpphTmlNfc_Context->fragment_len) {
287 if (nNbBytesToWrite - numWrote > gpphTmlNfc_Context->fragment_len) {
288 numBytes = numWrote + gpphTmlNfc_Context->fragment_len;
289 } else {
290 numBytes = nNbBytesToWrite;
291 }
292 }
293 ret = write((int)(intptr_t)pDevHandle, pBuffer + numWrote,
294 numBytes - numWrote);
295 if (ret > 0) {
296 numWrote += ret;
297 if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED &&
298 numWrote < nNbBytesToWrite) {
299 usleep(500);
300 }
301 } else if (ret == 0) {
302 NXPLOG_TML_D("%s EOF", __func__);
303 return -1;
304 } else {
305 NXPLOG_TML_D("%s errno : %x", __func__, errno);
306 if (errno == EINTR || errno == EAGAIN) {
307 continue;
308 }
309 return -1;
310 }
311 }
312
313 return numWrote;
314 }
315
316 /*******************************************************************************
317 **
318 ** Function Reset
319 **
320 ** Description Reset NFCC device, using VEN pin
321 **
322 ** Parameters pDevHandle - valid device handle
323 ** eType - reset level
324 **
325 ** Returns 0 - reset operation success
326 ** -1 - reset operation failure
327 **
328 *******************************************************************************/
NfccReset(void * pDevHandle,NfccResetType eType)329 int NfccI2cTransport::NfccReset(void* pDevHandle, NfccResetType eType) {
330 int ret = -1;
331 NXPLOG_TML_D("%s, VEN eType %u", __func__, eType);
332
333 if (NULL == pDevHandle) {
334 return -1;
335 }
336
337 ret = ioctl((int)(intptr_t)pDevHandle, NFC_SET_PWR, eType);
338 if (ret < 0) {
339 NXPLOG_TML_E("%s :failed errno = 0x%x", __func__, errno);
340 }
341 if ((eType != MODE_FW_DWNLD_WITH_VEN && eType != MODE_FW_DWND_HIGH) &&
342 ret == 0) {
343 bFwDnldFlag = false;
344 }
345
346 return ret;
347 }
348 /*****************************************************************************
349 **
350 ** Function UpdateReadPending
351 **
352 ** Description Set/Reset Read Pending of NFC
353 **
354 ** Parameters pDevHandle - valid device handle
355 ** eType - set or clear the flag
356 **
357 ** Returns 0 - operation success
358 ** -1 - operation failure
359 **
360 ****************************************************************************/
UpdateReadPending(void * pDevHandle,NfcReadPending eType)361 int NfccI2cTransport::UpdateReadPending(void* pDevHandle,
362 NfcReadPending eType) {
363 int ret = -1;
364 if (NULL == pDevHandle) {
365 return -1;
366 }
367 NXPLOG_TML_D("%s, %u", __func__, eType);
368 ret = ioctl((int)(intptr_t)pDevHandle, NFC_SET_RESET_READ_PENDING, eType);
369 if (ret != 0) {
370 NXPLOG_TML_E("%s: %u ret = 0x%x", __func__, eType, ret);
371 }
372 return ret;
373 }
374
375 /*****************************************************************************
376 **
377 ** Function NfcGetGpioStatus
378 **
379 ** Description Get the gpio status flag byte from kernel space
380 **
381 ** Parameters pDevHandle - valid device handle
382 **
383 **
384 ** Returns 0 - operation success
385 ** -1 - operation failure
386 **
387 ****************************************************************************/
NfcGetGpioStatus(void * pDevHandle,uint32_t * status)388 int NfccI2cTransport ::NfcGetGpioStatus(void* pDevHandle, uint32_t* status) {
389 int ret = -1;
390 if (NULL == pDevHandle) {
391 return ret;
392 }
393 ret = ioctl((int)(intptr_t)pDevHandle, NFC_GET_GPIO_STATUS, status);
394 if (ret != 0) {
395 NXPLOG_TML_E("%s: ret = 0x%x", __func__, ret);
396 }
397 NXPLOG_TML_D("%s, %d", __func__, *status);
398 return ret;
399 }
400 /*******************************************************************************
401 **
402 ** Function EseReset
403 **
404 ** Description Request NFCC to reset the eSE
405 **
406 ** Parameters pDevHandle - valid device handle
407 ** eType - EseResetType
408 **
409 ** Returns 0 - reset operation success
410 ** else - reset operation failure
411 **
412 *******************************************************************************/
EseReset(void * pDevHandle,EseResetType eType)413 int NfccI2cTransport::EseReset(void* pDevHandle, EseResetType eType) {
414 int ret = -1;
415 NXPLOG_TML_D("%s, eType %u", __func__, eType);
416
417 if (NULL == pDevHandle) {
418 return -1;
419 }
420 ret = ioctl((int)(intptr_t)pDevHandle, ESE_SET_PWR, eType);
421 if (ret < 0) {
422 NXPLOG_TML_E("%s :failed errno = 0x%x", __func__, errno);
423 }
424 return ret;
425 }
426
427 /*******************************************************************************
428 **
429 ** Function EnableFwDnldMode
430 **
431 ** Description updates the state to Download mode
432 **
433 ** Parameters True/False
434 **
435 ** Returns None
436 *******************************************************************************/
EnableFwDnldMode(bool mode)437 void NfccI2cTransport::EnableFwDnldMode(bool mode) { bFwDnldFlag = mode; }
438
439 /*******************************************************************************
440 **
441 ** Function IsFwDnldModeEnabled
442 **
443 ** Description Returns the current mode
444 **
445 ** Parameters none
446 **
447 ** Returns Current mode download/NCI
448 *******************************************************************************/
IsFwDnldModeEnabled(void)449 bool_t NfccI2cTransport::IsFwDnldModeEnabled(void) { return bFwDnldFlag; }
450