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