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
44static bool_t bFwDnldFlag = false;
45extern 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*******************************************************************************/
58void 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*******************************************************************************/
80NFCSTATUS 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*******************************************************************************/
118int 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*******************************************************************************/
227int 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)
288int 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*******************************************************************************/
315bool_t getDownloadFlag(void) { return bFwDnldFlag; }
316