• 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 
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    char *       pComPort;
148 
149    DAL_ASSERT_STR(gI2cPortContext.nOpened==0, "Trying to open but already done!");
150 
151    switch(pConfig->nLinkType)
152    {
153        case ENUM_DAL_LINK_TYPE_I2C:
154           pComPort = "/dev/pn544";
155           break;
156        default:
157           DAL_DEBUG("Open failed: unknown type %d\n", pConfig->nLinkType);
158           return NFCSTATUS_INVALID_PARAMETER;
159    }
160 
161    DAL_DEBUG("Opening port=%s\n", pComPort);
162 
163    /* open port */
164    gI2cPortContext.nHandle = open(pComPort, O_RDWR | O_NOCTTY);
165    if (gI2cPortContext.nHandle < 0)
166    {
167        DAL_DEBUG("Open failed: open() returned %d\n", gI2cPortContext.nHandle);
168       *pLinkHandle = NULL;
169       return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE);
170    }
171 
172    gI2cPortContext.nOpened = 1;
173    *pLinkHandle = (void*)gI2cPortContext.nHandle;
174 
175    DAL_PRINT("Open succeed\n");
176 
177    return NFCSTATUS_SUCCESS;
178 }
179 
180 
181 /*-----------------------------------------------------------------------------
182 
183 FUNCTION: phDal4Nfc_i2c_read
184 
185 PURPOSE:  Reads nNbBytesToRead bytes and writes them in pBuffer.
186           Returns the number of bytes really read or -1 in case of error.
187 
188 -----------------------------------------------------------------------------*/
189 
phDal4Nfc_i2c_read(uint8_t * pBuffer,int nNbBytesToRead)190 int phDal4Nfc_i2c_read(uint8_t * pBuffer, int nNbBytesToRead)
191 {
192     int ret;
193     int numRead = 0;
194     struct timeval tv;
195     fd_set rfds;
196 
197     DAL_ASSERT_STR(gI2cPortContext.nOpened == 1, "read called but not opened!");
198     DAL_DEBUG("_i2c_read() called to read %d bytes", nNbBytesToRead);
199 
200     // Read with 2 second timeout, so that the read thread can be aborted
201     // when the pn544 does not respond and we need to switch to FW download
202     // mode. This should be done via a control socket instead.
203     while (numRead < nNbBytesToRead) {
204         FD_ZERO(&rfds);
205         FD_SET(gI2cPortContext.nHandle, &rfds);
206         tv.tv_sec = 2;
207         tv.tv_usec = 0;
208         ret = select(gI2cPortContext.nHandle + 1, &rfds, NULL, NULL, &tv);
209         if (ret < 0) {
210             DAL_DEBUG("select() errno=%d", errno);
211             if (errno == EINTR || errno == EAGAIN) {
212                 continue;
213             }
214             return -1;
215         } else if (ret == 0) {
216             DAL_PRINT("timeout!");
217             return -1;
218         }
219         ret = read(gI2cPortContext.nHandle, pBuffer + numRead, nNbBytesToRead - numRead);
220         if (ret > 0) {
221             DAL_DEBUG("read %d bytes", ret);
222             numRead += ret;
223         } else if (ret == 0) {
224             DAL_PRINT("_i2c_read() EOF");
225             return -1;
226         } else {
227             DAL_DEBUG("_i2c_read() errno=%d", errno);
228             if (errno == EINTR || errno == EAGAIN) {
229                 continue;
230             }
231             return -1;
232         }
233     }
234     return numRead;
235 }
236 
237 /*-----------------------------------------------------------------------------
238 
239 FUNCTION: phDal4Nfc_i2c_write
240 
241 PURPOSE:  Writes nNbBytesToWrite bytes from pBuffer to the link
242           Returns the number of bytes that have been wrote to the interface or -1 in case of error.
243 
244 -----------------------------------------------------------------------------*/
245 
phDal4Nfc_i2c_write(uint8_t * pBuffer,int nNbBytesToWrite)246 int phDal4Nfc_i2c_write(uint8_t * pBuffer, int nNbBytesToWrite)
247 {
248     int ret;
249     int numWrote = 0;
250 
251     DAL_ASSERT_STR(gI2cPortContext.nOpened == 1, "write called but not opened!");
252     DAL_DEBUG("_i2c_write() called to write %d bytes\n", nNbBytesToWrite);
253 
254     while (numWrote < nNbBytesToWrite) {
255         ret = write(gI2cPortContext.nHandle, pBuffer + numWrote, nNbBytesToWrite - numWrote);
256         if (ret > 0) {
257             DAL_DEBUG("wrote %d bytes", ret);
258             numWrote += ret;
259         } else if (ret == 0) {
260             DAL_PRINT("_i2c_write() EOF");
261             return -1;
262         } else {
263             DAL_DEBUG("_i2c_write() errno=%d", 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: phDal4Nfc_i2c_reset
277 
278 PURPOSE:  Reset the PN544, using the VEN pin
279 
280 -----------------------------------------------------------------------------*/
phDal4Nfc_i2c_reset(long level)281 int phDal4Nfc_i2c_reset(long level)
282 {
283     DAL_DEBUG("phDal4Nfc_i2c_reset, VEN level = %ld", level);
284 
285     return ioctl(gI2cPortContext.nHandle, PN544_SET_PWR, level);
286 }
287