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