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