• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1  /*
2   * Copyright (C) 2010 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   * \file phDalNfc_i2c.c
19   * \brief DAL I2C port implementation for linux
20   *
21   * Project: Trusted NFC Linux
22   *
23   */
24  
25  #define LOG_TAG "NFC_i2c"
26  #include <cutils/log.h>
27  #include <hardware/nfc.h>
28  #include <stdlib.h>
29  #include <unistd.h>
30  #include <fcntl.h>
31  #include <termios.h>
32  #include <sys/ioctl.h>
33  #include <sys/select.h>
34  #include <errno.h>
35  
36  #include <phDal4Nfc_debug.h>
37  #include <phDal4Nfc_i2c.h>
38  #include <phOsalNfc.h>
39  #include <phNfcStatus.h>
40  #if defined(ANDROID)
41  #include <string.h>
42  #endif
43  
44  typedef struct
45  {
46     int  nHandle;
47     char nOpened;
48  
49  } phDal4Nfc_I2cPortContext_t;
50  
51  
52  /*-----------------------------------------------------------------------------------
53                                        VARIABLES
54  ------------------------------------------------------------------------------------*/
55  static phDal4Nfc_I2cPortContext_t gI2cPortContext;
56  
57  
58  
59  /*-----------------------------------------------------------------------------
60  
61  FUNCTION: phDal4Nfc_i2c_set_open_from_handle
62  
63  PURPOSE:  Initialize internal variables
64  
65  -----------------------------------------------------------------------------*/
66  
phDal4Nfc_i2c_initialize(void)67  void phDal4Nfc_i2c_initialize(void)
68  {
69     memset(&gI2cPortContext, 0, sizeof(phDal4Nfc_I2cPortContext_t));
70  }
71  
72  
73  /*-----------------------------------------------------------------------------
74  
75  FUNCTION: phDal4Nfc_i2c_set_open_from_handle
76  
77  PURPOSE:  The application could have opened the link itself. So we just need
78            to get the handle and consider that the open operation has already
79            been done.
80  
81  -----------------------------------------------------------------------------*/
82  
phDal4Nfc_i2c_set_open_from_handle(phHal_sHwReference_t * pDalHwContext)83  void phDal4Nfc_i2c_set_open_from_handle(phHal_sHwReference_t * pDalHwContext)
84  {
85     gI2cPortContext.nHandle = (int)(intptr_t) pDalHwContext->p_board_driver;
86     DAL_ASSERT_STR(gI2cPortContext.nHandle >= 0, "Bad passed com port handle");
87     gI2cPortContext.nOpened = 1;
88  }
89  
90  /*-----------------------------------------------------------------------------
91  
92  FUNCTION: phDal4Nfc_i2c_is_opened
93  
94  PURPOSE:  Returns if the link is opened or not. (0 = not opened; 1 = opened)
95  
96  -----------------------------------------------------------------------------*/
97  
phDal4Nfc_i2c_is_opened(void)98  int phDal4Nfc_i2c_is_opened(void)
99  {
100     return gI2cPortContext.nOpened;
101  }
102  
103  /*-----------------------------------------------------------------------------
104  
105  FUNCTION: phDal4Nfc_i2c_flush
106  
107  PURPOSE:  Flushes the link ; clears the link buffers
108  
109  -----------------------------------------------------------------------------*/
110  
phDal4Nfc_i2c_flush(void)111  void phDal4Nfc_i2c_flush(void)
112  {
113     /* Nothing to do (driver has no internal buffers) */
114  }
115  
116  /*-----------------------------------------------------------------------------
117  
118  FUNCTION: phDal4Nfc_i2c_close
119  
120  PURPOSE:  Closes the link
121  
122  -----------------------------------------------------------------------------*/
123  
phDal4Nfc_i2c_close(void)124  void phDal4Nfc_i2c_close(void)
125  {
126     DAL_PRINT("Closing port\n");
127     if (gI2cPortContext.nOpened == 1)
128     {
129        close(gI2cPortContext.nHandle);
130        gI2cPortContext.nHandle = 0;
131        gI2cPortContext.nOpened = 0;
132     }
133  }
134  
135  /*-----------------------------------------------------------------------------
136  
137  FUNCTION: phDal4Nfc_i2c_open_and_configure
138  
139  PURPOSE:  Closes the link
140  
141  -----------------------------------------------------------------------------*/
142  
phDal4Nfc_i2c_open_and_configure(pphDal4Nfc_sConfig_t pConfig,void ** pLinkHandle)143  NFCSTATUS phDal4Nfc_i2c_open_and_configure(pphDal4Nfc_sConfig_t pConfig, void ** pLinkHandle)
144  {
145     DAL_ASSERT_STR(gI2cPortContext.nOpened==0, "Trying to open but already done!");
146  
147     DAL_DEBUG("Opening port=%s\n", pConfig->deviceNode);
148  
149     /* open port */
150     gI2cPortContext.nHandle = open(pConfig->deviceNode, O_RDWR | O_NOCTTY);
151     if (gI2cPortContext.nHandle < 0)
152     {
153         DAL_DEBUG("Open failed: open() returned %d\n", gI2cPortContext.nHandle);
154        *pLinkHandle = NULL;
155        return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE);
156     }
157  
158     gI2cPortContext.nOpened = 1;
159     *pLinkHandle = (void*)(intptr_t)gI2cPortContext.nHandle;
160  
161     DAL_PRINT("Open succeed\n");
162  
163     return NFCSTATUS_SUCCESS;
164  }
165  
166  
167  /*-----------------------------------------------------------------------------
168  
169  FUNCTION: phDal4Nfc_i2c_read
170  
171  PURPOSE:  Reads nNbBytesToRead bytes and writes them in pBuffer.
172            Returns the number of bytes really read or -1 in case of error.
173  
174  -----------------------------------------------------------------------------*/
175  
phDal4Nfc_i2c_read(uint8_t * pBuffer,int nNbBytesToRead)176  int phDal4Nfc_i2c_read(uint8_t * pBuffer, int nNbBytesToRead)
177  {
178      int ret;
179      int numRead = 0;
180      struct timeval tv;
181      fd_set rfds;
182  
183      DAL_ASSERT_STR(gI2cPortContext.nOpened == 1, "read called but not opened!");
184      DAL_DEBUG("_i2c_read() called to read %d bytes", nNbBytesToRead);
185  
186      // Read with 2 second timeout, so that the read thread can be aborted
187      // when the pn544 does not respond and we need to switch to FW download
188      // mode. This should be done via a control socket instead.
189      while (numRead < nNbBytesToRead) {
190          FD_ZERO(&rfds);
191          FD_SET(gI2cPortContext.nHandle, &rfds);
192          tv.tv_sec = 2;
193          tv.tv_usec = 0;
194          ret = select(gI2cPortContext.nHandle + 1, &rfds, NULL, NULL, &tv);
195          if (ret < 0) {
196              DAL_DEBUG("select() errno=%d", errno);
197              if (errno == EINTR || errno == EAGAIN) {
198                  continue;
199              }
200              return -1;
201          } else if (ret == 0) {
202              DAL_PRINT("timeout!");
203              return -1;
204          }
205          ret = read(gI2cPortContext.nHandle, pBuffer + numRead, nNbBytesToRead - numRead);
206          if (ret > 0) {
207              DAL_DEBUG("read %d bytes", ret);
208              numRead += ret;
209          } else if (ret == 0) {
210              DAL_PRINT("_i2c_read() EOF");
211              return -1;
212          } else {
213              DAL_DEBUG("_i2c_read() errno=%d", errno);
214              if (errno == EINTR || errno == EAGAIN) {
215                  continue;
216              }
217              return -1;
218          }
219      }
220      return numRead;
221  }
222  
223  /*-----------------------------------------------------------------------------
224  
225  FUNCTION: phDal4Nfc_i2c_write
226  
227  PURPOSE:  Writes nNbBytesToWrite bytes from pBuffer to the link
228            Returns the number of bytes that have been wrote to the interface or -1 in case of error.
229  
230  -----------------------------------------------------------------------------*/
231  
phDal4Nfc_i2c_write(uint8_t * pBuffer,int nNbBytesToWrite)232  int phDal4Nfc_i2c_write(uint8_t * pBuffer, int nNbBytesToWrite)
233  {
234      int ret;
235      int numWrote = 0;
236  
237      DAL_ASSERT_STR(gI2cPortContext.nOpened == 1, "write called but not opened!");
238      DAL_DEBUG("_i2c_write() called to write %d bytes\n", nNbBytesToWrite);
239  
240      while (numWrote < nNbBytesToWrite) {
241          ret = write(gI2cPortContext.nHandle, pBuffer + numWrote, nNbBytesToWrite - numWrote);
242          if (ret > 0) {
243              DAL_DEBUG("wrote %d bytes", ret);
244              numWrote += ret;
245          } else if (ret == 0) {
246              DAL_PRINT("_i2c_write() EOF");
247              return -1;
248          } else {
249              DAL_DEBUG("_i2c_write() errno=%d", errno);
250              if (errno == EINTR || errno == EAGAIN) {
251                  continue;
252              }
253              return -1;
254          }
255      }
256  
257      return numWrote;
258  }
259  
260  /*-----------------------------------------------------------------------------
261  
262  FUNCTION: phDal4Nfc_i2c_reset
263  
264  PURPOSE:  Reset the PN544, using the VEN pin
265  
266  -----------------------------------------------------------------------------*/
267  #define PN544_SET_PWR _IOW(0xe9, 0x01, unsigned int)
phDal4Nfc_i2c_reset(long level)268  int phDal4Nfc_i2c_reset(long level)
269  {
270      DAL_DEBUG("phDal4Nfc_i2c_reset, VEN level = %ld", level);
271  
272      return ioctl(gI2cPortContext.nHandle, PN544_SET_PWR, level);
273  }
274