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