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