1 /******************************************************************************
2 * Copyright 2020-2021 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 FRAGMENTSIZE_MAX PHNFC_I2C_FRAGMENT_SIZE
45 extern phTmlNfc_i2cfragmentation_t fragmentation_enabled;
46 extern phTmlNfc_Context_t* gpphTmlNfc_Context;
47 /*******************************************************************************
48 **
49 ** Function Close
50 **
51 ** Description Closes PN54X 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((intptr_t)pDevHandle);
61 }
62 sem_destroy(&mTxRxSemaphore);
63 return;
64 }
65
66 /*******************************************************************************
67 **
68 ** Function OpenAndConfigure
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 *******************************************************************************/
OpenAndConfigure(pphTmlNfc_Config_t pConfig,void ** pLinkHandle)80 NFCSTATUS NfccI2cTransport::OpenAndConfigure(pphTmlNfc_Config_t pConfig,
81 void** pLinkHandle) {
82 int nHandle;
83
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 return NFCSTATUS_INVALID_DEVICE;
91 }
92
93 *pLinkHandle = (void*)((intptr_t)nHandle);
94 if (0 != sem_init(&mTxRxSemaphore, 0, 1)) {
95 NXPLOG_TML_E("%s Failed: reason sem_init : retval %x", __func__, nHandle);
96 }
97 return NFCSTATUS_SUCCESS;
98 }
99
100 /*******************************************************************************
101 **
102 ** Function Flushdata
103 **
104 ** Description Reads payload of FW rsp from PN54X device into given buffer
105 **
106 ** Parameters pDevHandle - valid device handle
107 ** pBuffer - buffer for read data
108 ** numRead - number of bytes read by calling function
109 **
110 ** Returns always returns -1
111 **
112 *******************************************************************************/
Flushdata(void * pDevHandle,uint8_t * pBuffer,int numRead)113 int NfccI2cTransport::Flushdata(void* pDevHandle, uint8_t* pBuffer,
114 int numRead) {
115 int retRead = 0;
116 uint16_t totalBtyesToRead =
117 pBuffer[FW_DNLD_LEN_OFFSET] + FW_DNLD_HEADER_LEN + CRC_LEN;
118 /* we shall read totalBtyesToRead-1 as one byte is already read by calling
119 * function*/
120 retRead = read((intptr_t)pDevHandle, pBuffer + numRead, totalBtyesToRead - 1);
121 if (retRead > 0) {
122 numRead += retRead;
123 phNxpNciHal_print_packet("RECV", pBuffer, numRead);
124 } else if (retRead == 0) {
125 NXPLOG_TML_E("%s _i2c_read() [pyld] EOF", __func__);
126 } else {
127 if (bFwDnldFlag == false) {
128 NXPLOG_TML_D("%s _i2c_read() [hdr] received", __func__);
129 phNxpNciHal_print_packet("RECV", pBuffer - numRead,
130 NORMAL_MODE_HEADER_LEN);
131 }
132 NXPLOG_TML_E("%s _i2c_read() [pyld] errno : %x", __func__, errno);
133 }
134 SemPost();
135 return -1;
136 }
137
138 /*******************************************************************************
139 **
140 ** Function Read
141 **
142 ** Description Reads requested number of bytes from PN54X device into given
143 ** buffer
144 **
145 ** Parameters pDevHandle - valid device handle
146 ** pBuffer - buffer for read data
147 ** nNbBytesToRead - number of bytes requested to be read
148 **
149 ** Returns numRead - number of successfully read bytes
150 ** -1 - read operation failure
151 **
152 *******************************************************************************/
Read(void * pDevHandle,uint8_t * pBuffer,int nNbBytesToRead)153 int NfccI2cTransport::Read(void* pDevHandle, uint8_t* pBuffer,
154 int nNbBytesToRead) {
155 int ret_Read;
156 int ret_Select;
157 int numRead = 0;
158 struct timeval tv;
159 fd_set rfds;
160 uint16_t totalBtyesToRead = 0;
161
162 UNUSED_PROP(nNbBytesToRead);
163 if (NULL == pDevHandle) {
164 return -1;
165 }
166
167 if (bFwDnldFlag == false) {
168 totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
169 } else {
170 totalBtyesToRead = FW_DNLD_HEADER_LEN;
171 }
172
173 /* Read with 2 second timeout, so that the read thread can be aborted
174 when the PN54X does not respond and we need to switch to FW download
175 mode. This should be done via a control socket instead. */
176 FD_ZERO(&rfds);
177 FD_SET((intptr_t)pDevHandle, &rfds);
178 tv.tv_sec = 2;
179 tv.tv_usec = 1;
180
181 ret_Select =
182 select((int)((intptr_t)pDevHandle + (int)1), &rfds, NULL, NULL, &tv);
183 if (ret_Select < 0) {
184 NXPLOG_TML_D("%s errno : %x", __func__, errno);
185 return -1;
186 } else if (ret_Select == 0) {
187 NXPLOG_TML_D("%s Timeout", __func__);
188 return -1;
189 } else {
190 ret_Read = read((intptr_t)pDevHandle, pBuffer, totalBtyesToRead - numRead);
191 if (ret_Read > 0 && !(pBuffer[0] == 0xFF && pBuffer[1] == 0xFF)) {
192 SemTimedWait();
193 numRead += ret_Read;
194 } else if (ret_Read == 0) {
195 NXPLOG_TML_E("%s [hdr]EOF", __func__);
196 return -1;
197 } else {
198 NXPLOG_TML_E("%s [hdr] errno : %x", __func__, errno);
199 NXPLOG_TML_E(" %s pBuffer[0] = %x pBuffer[1]= %x", __func__, pBuffer[0],
200 pBuffer[1]);
201 return -1;
202 }
203
204 if (bFwDnldFlag == false) {
205 totalBtyesToRead = NORMAL_MODE_HEADER_LEN;
206 #if (NXP_EXTNS == TRUE)
207 if (gpphTmlNfc_Context->tReadInfo.pContext != NULL &&
208 !memcmp(gpphTmlNfc_Context->tReadInfo.pContext, "MinOpen", 0x07) &&
209 !pBuffer[0] && pBuffer[1]) {
210 return Flushdata(pDevHandle, pBuffer, numRead);
211 }
212 #endif
213 } else {
214 totalBtyesToRead = FW_DNLD_HEADER_LEN;
215 }
216
217 if (numRead < totalBtyesToRead) {
218 ret_Read = read((intptr_t)pDevHandle, (pBuffer + numRead),
219 totalBtyesToRead - numRead);
220
221 if (ret_Read != totalBtyesToRead - numRead) {
222 SemPost();
223 NXPLOG_TML_E("%s [hdr] errno : %x", __func__, errno);
224 return -1;
225 } else {
226 numRead += ret_Read;
227 }
228 }
229 if (bFwDnldFlag == true) {
230 totalBtyesToRead =
231 pBuffer[FW_DNLD_LEN_OFFSET] + FW_DNLD_HEADER_LEN + CRC_LEN;
232 } else {
233 totalBtyesToRead =
234 pBuffer[NORMAL_MODE_LEN_OFFSET] + NORMAL_MODE_HEADER_LEN;
235 }
236 if ((totalBtyesToRead - numRead) != 0) {
237 ret_Read = read((intptr_t)pDevHandle, (pBuffer + numRead),
238 totalBtyesToRead - numRead);
239 if (ret_Read > 0) {
240 numRead += ret_Read;
241 } else if (ret_Read == 0) {
242 SemPost();
243 NXPLOG_TML_E("%s [pyld] EOF", __func__);
244 return -1;
245 } else {
246 if (bFwDnldFlag == false) {
247 NXPLOG_TML_D("_i2c_read() [hdr] received");
248 phNxpNciHal_print_packet("RECV", pBuffer, NORMAL_MODE_HEADER_LEN);
249 }
250 SemPost();
251 NXPLOG_TML_E("%s [pyld] errno : %x", __func__, errno);
252 return -1;
253 }
254 } else {
255 NXPLOG_TML_E("%s _>>>>> Empty packet received !!", __func__);
256 }
257 }
258 SemPost();
259 return numRead;
260 }
261
262 /*******************************************************************************
263 **
264 ** Function Write
265 **
266 ** Description Writes requested number of bytes from given buffer into
267 ** PN54X device
268 **
269 ** Parameters pDevHandle - valid device handle
270 ** pBuffer - buffer for read data
271 ** nNbBytesToWrite - number of bytes requested to be written
272 **
273 ** Returns numWrote - number of successfully written bytes
274 ** -1 - write operation failure
275 **
276 *******************************************************************************/
Write(void * pDevHandle,uint8_t * pBuffer,int nNbBytesToWrite)277 int NfccI2cTransport::Write(void* pDevHandle, uint8_t* pBuffer,
278 int nNbBytesToWrite) {
279 int ret;
280 int numWrote = 0;
281 int numBytes = nNbBytesToWrite;
282 if (NULL == pDevHandle) {
283 return -1;
284 }
285 if (fragmentation_enabled == I2C_FRAGMENATATION_DISABLED &&
286 nNbBytesToWrite > FRAGMENTSIZE_MAX) {
287 NXPLOG_TML_D(
288 "%s data larger than maximum I2C size,enable I2C fragmentation",
289 __func__);
290 return -1;
291 }
292 while (numWrote < nNbBytesToWrite) {
293 if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED &&
294 nNbBytesToWrite > FRAGMENTSIZE_MAX) {
295 if (nNbBytesToWrite - numWrote > FRAGMENTSIZE_MAX) {
296 numBytes = numWrote + FRAGMENTSIZE_MAX;
297 } else {
298 numBytes = nNbBytesToWrite;
299 }
300 }
301 SemTimedWait();
302 ret = write((intptr_t)pDevHandle, pBuffer + numWrote, numBytes - numWrote);
303 SemPost();
304 if (ret > 0) {
305 numWrote += ret;
306 if (fragmentation_enabled == I2C_FRAGMENTATION_ENABLED &&
307 numWrote < nNbBytesToWrite) {
308 usleep(500);
309 }
310 } else if (ret == 0) {
311 NXPLOG_TML_D("%s EOF", __func__);
312 return -1;
313 } else {
314 NXPLOG_TML_D("%s errno : %x", __func__, errno);
315 if (errno == EINTR || errno == EAGAIN) {
316 continue;
317 }
318 return -1;
319 }
320 }
321
322 return numWrote;
323 }
324
325 /*******************************************************************************
326 **
327 ** Function Reset
328 **
329 ** Description Reset PN54X device, using VEN pin
330 **
331 ** Parameters pDevHandle - valid device handle
332 ** eType - reset level
333 **
334 ** Returns 0 - reset operation success
335 ** -1 - reset operation failure
336 **
337 *******************************************************************************/
NfccReset(void * pDevHandle,NfccResetType eType)338 int NfccI2cTransport::NfccReset(void* pDevHandle, NfccResetType eType) {
339 int ret = -1;
340 NXPLOG_TML_D("%s, VEN eType %ld", __func__, eType);
341
342 if (NULL == pDevHandle) {
343 return -1;
344 }
345
346 ret = ioctl((intptr_t)pDevHandle, PN544_SET_PWR, eType);
347 if (ret < 0) {
348 NXPLOG_TML_E("%s :failed errno = 0x%x", __func__, errno);
349 }
350 if ((eType != MODE_FW_DWNLD_WITH_VEN && eType != MODE_FW_DWND_HIGH) &&
351 ret == 0) {
352 bFwDnldFlag = false;
353 }
354
355 return ret;
356 }
357
358 /*******************************************************************************
359 **
360 ** Function EseReset
361 **
362 ** Description Request NFCC to reset the eSE
363 **
364 ** Parameters pDevHandle - valid device handle
365 ** eType - EseResetType
366 **
367 ** Returns 0 - reset operation success
368 ** else - reset operation failure
369 **
370 *******************************************************************************/
EseReset(void * pDevHandle,EseResetType eType)371 int NfccI2cTransport::EseReset(void* pDevHandle, EseResetType eType) {
372 int ret = -1;
373 NXPLOG_TML_D("%s, eType %ld", __func__, eType);
374
375 if (NULL == pDevHandle) {
376 return -1;
377 }
378 ret = ioctl((intptr_t)pDevHandle, ESE_SET_PWR, eType);
379 if (ret < 0) {
380 NXPLOG_TML_E("%s :failed errno = 0x%x", __func__, errno);
381 }
382 return ret;
383 }
384
385 /*******************************************************************************
386 **
387 ** Function EseGetPower
388 **
389 ** Description Request NFCC to reset the eSE
390 **
391 ** Parameters pDevHandle - valid device handle
392 ** level - reset level
393 **
394 ** Returns 0 - reset operation success
395 ** else - reset operation failure
396 **
397 *******************************************************************************/
EseGetPower(void * pDevHandle,long level)398 int NfccI2cTransport::EseGetPower(void* pDevHandle, long level) {
399 return ioctl((intptr_t)pDevHandle, ESE_GET_PWR, level);
400 }
401
402 /*******************************************************************************
403 **
404 ** Function GetPlatform
405 **
406 ** Description Get platform interface type (i2c or i3c) for common mw
407 **
408 ** Parameters pDevHandle - valid device handle
409 **
410 ** Returns 0 - i2c
411 ** 1 - i3c
412 **
413 *******************************************************************************/
GetPlatform(void * pDevHandle)414 int NfccI2cTransport::GetPlatform(void* pDevHandle) {
415 int ret = -1;
416 NXPLOG_TML_D("%s ", __func__);
417 if (NULL == pDevHandle) {
418 return -1;
419 }
420 ret = ioctl((intptr_t)pDevHandle, P544_GET_PLATFORM_INTERFACE);
421 NXPLOG_TML_D("%s :platform = %d", __func__, ret);
422 return ret;
423 }
424
425 /*******************************************************************************
426 **
427 ** Function GetNfcState
428 **
429 ** Description Get NFC state
430 **
431 ** Parameters pDevHandle - valid device handle
432 ** Returns 0 - unknown
433 ** 1 - FW DWL
434 ** 2 - NCI
435 **
436 *******************************************************************************/
GetNfcState(void * pDevHandle)437 int NfccI2cTransport::GetNfcState(void* pDevHandle) {
438 int ret = NFC_STATE_UNKNOWN;
439 NXPLOG_TML_D("%s ", __func__);
440 if (NULL == pDevHandle) {
441 return ret;
442 }
443 ret = ioctl((intptr_t)pDevHandle, P544_GET_NFC_STATE);
444 NXPLOG_TML_D("%s :nfc state = %d", __func__, ret);
445 return ret;
446 }
447 /*******************************************************************************
448 **
449 ** Function EnableFwDnldMode
450 **
451 ** Description updates the state to Download mode
452 **
453 ** Parameters True/False
454 **
455 ** Returns None
456 *******************************************************************************/
EnableFwDnldMode(bool mode)457 void NfccI2cTransport::EnableFwDnldMode(bool mode) { bFwDnldFlag = mode; }
458
459 /*******************************************************************************
460 **
461 ** Function IsFwDnldModeEnabled
462 **
463 ** Description Returns the current mode
464 **
465 ** Parameters none
466 **
467 ** Returns Current mode download/NCI
468 *******************************************************************************/
IsFwDnldModeEnabled(void)469 bool_t NfccI2cTransport::IsFwDnldModeEnabled(void) { return bFwDnldFlag; }
470
471 /*******************************************************************************
472 **
473 ** Function SemPost
474 **
475 ** Description sem_post 2c_read / write
476 **
477 ** Parameters none
478 **
479 ** Returns none
480 *******************************************************************************/
SemPost()481 void NfccI2cTransport::SemPost() {
482 int sem_val = 0;
483 sem_getvalue(&mTxRxSemaphore, &sem_val);
484 if (sem_val == 0) {
485 sem_post(&mTxRxSemaphore);
486 }
487 }
488
489 /*******************************************************************************
490 **
491 ** Function SemTimedWait
492 **
493 ** Description Timed sem_wait for avoiding i2c_read & write overlap
494 **
495 ** Parameters none
496 **
497 ** Returns Sem_wait return status
498 *******************************************************************************/
SemTimedWait()499 int NfccI2cTransport::SemTimedWait() {
500 NFCSTATUS status = NFCSTATUS_FAILED;
501 long sem_timedout = 500 * 1000 * 1000;
502 int s = 0;
503 struct timespec ts;
504 clock_gettime(CLOCK_REALTIME, &ts);
505 ts.tv_sec += 0;
506 ts.tv_nsec += sem_timedout;
507 while ((s = sem_timedwait(&mTxRxSemaphore, &ts)) == -1 && errno == EINTR) {
508 continue; /* Restart if interrupted by handler */
509 }
510 if (s != -1) {
511 status = NFCSTATUS_SUCCESS;
512 } else if (errno == ETIMEDOUT && s == -1) {
513 NXPLOG_TML_E("%s :timed out errno = 0x%x", __func__, errno);
514 }
515 return status;
516 }
517
518 /*******************************************************************************
519 **
520 ** Function GetIrqState
521 **
522 ** Description Get state of IRQ GPIO
523 **
524 ** Parameters pDevHandle - valid device handle
525 **
526 ** Returns The state of IRQ line i.e. +ve if read is pending else Zer0.
527 ** In the case of IOCTL error, it returns -ve value.
528 **
529 *******************************************************************************/
GetIrqState(void * pDevHandle)530 int NfccI2cTransport::GetIrqState(void* pDevHandle) {
531 int ret = -1;
532
533 NXPLOG_TML_D("%s Enter", __func__);
534 if (NULL != pDevHandle) {
535 ret = ioctl((intptr_t)pDevHandle, PN544_GET_IRQ_STATE, 0x00);
536 }
537 NXPLOG_TML_D("%s exit: state = %d", __func__, ret);
538 return ret;
539 }
540