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