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_uart.c
19 * \brief DAL com port implementation for linux
20 *
21 * Project: Trusted NFC Linux Lignt
22 *
23 * $Date: 07 aug 2009
24 * $Author: Jonathan roux
25 * $Revision: 1.0 $
26 *
27 */
28
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_uart.h>
37 #include <phOsalNfc.h>
38 #include <phNfcStatus.h>
39 #if defined(ANDROID)
40 #include <string.h>
41 #endif
42
43 typedef struct
44 {
45 int nHandle;
46 char nOpened;
47 struct termios nIoConfigBackup;
48 struct termios nIoConfig;
49
50 } phDal4Nfc_ComPortContext_t;
51
52 /*-----------------------------------------------------------------------------------
53 COM PORT CONFIGURATION
54 ------------------------------------------------------------------------------------*/
55 #define DAL_BAUD_RATE B115200
56
57
58
59 /*-----------------------------------------------------------------------------------
60 VARIABLES
61 ------------------------------------------------------------------------------------*/
62 static phDal4Nfc_ComPortContext_t gComPortContext;
63
64
65
66 /*-----------------------------------------------------------------------------
67
68 FUNCTION: phDal4Nfc_uart_set_open_from_handle
69
70 PURPOSE: Initialize internal variables
71
72 -----------------------------------------------------------------------------*/
73
phDal4Nfc_uart_initialize(void)74 void phDal4Nfc_uart_initialize(void)
75 {
76 memset(&gComPortContext, 0, sizeof(phDal4Nfc_ComPortContext_t));
77 }
78
79
80 /*-----------------------------------------------------------------------------
81
82 FUNCTION: phDal4Nfc_uart_set_open_from_handle
83
84 PURPOSE: The application could have opened the link itself. So we just need
85 to get the handle and consider that the open operation has already
86 been done.
87
88 -----------------------------------------------------------------------------*/
89
phDal4Nfc_uart_set_open_from_handle(phHal_sHwReference_t * pDalHwContext)90 void phDal4Nfc_uart_set_open_from_handle(phHal_sHwReference_t * pDalHwContext)
91 {
92 gComPortContext.nHandle = (int) pDalHwContext->p_board_driver;
93 DAL_ASSERT_STR(gComPortContext.nHandle >= 0, "Bad passed com port handle");
94 gComPortContext.nOpened = 1;
95 }
96
97 /*-----------------------------------------------------------------------------
98
99 FUNCTION: phDal4Nfc_uart_is_opened
100
101 PURPOSE: Returns if the link is opened or not. (0 = not opened; 1 = opened)
102
103 -----------------------------------------------------------------------------*/
104
phDal4Nfc_uart_is_opened(void)105 int phDal4Nfc_uart_is_opened(void)
106 {
107 return gComPortContext.nOpened;
108 }
109
110 /*-----------------------------------------------------------------------------
111
112 FUNCTION: phDal4Nfc_uart_flush
113
114 PURPOSE: Flushes the link ; clears the link buffers
115
116 -----------------------------------------------------------------------------*/
117
phDal4Nfc_uart_flush(void)118 void phDal4Nfc_uart_flush(void)
119 {
120 int ret;
121 /* flushes the com port */
122 ret = tcflush(gComPortContext.nHandle, TCIFLUSH);
123 DAL_ASSERT_STR(ret!=-1, "tcflush failed");
124 }
125
126 /*-----------------------------------------------------------------------------
127
128 FUNCTION: phDal4Nfc_uart_close
129
130 PURPOSE: Closes the link
131
132 -----------------------------------------------------------------------------*/
133
phDal4Nfc_uart_close(void)134 void phDal4Nfc_uart_close(void)
135 {
136 if (gComPortContext.nOpened == 1)
137 {
138 close(gComPortContext.nHandle);
139 gComPortContext.nHandle = 0;
140 gComPortContext.nOpened = 0;
141 }
142 }
143
144 /*-----------------------------------------------------------------------------
145
146 FUNCTION: phDal4Nfc_uart_close
147
148 PURPOSE: Closes the link
149
150 -----------------------------------------------------------------------------*/
151
phDal4Nfc_uart_open_and_configure(pphDal4Nfc_sConfig_t pConfig,void ** pLinkHandle)152 NFCSTATUS phDal4Nfc_uart_open_and_configure(pphDal4Nfc_sConfig_t pConfig, void ** pLinkHandle)
153 {
154 char * pComPort;
155 int nComStatus;
156 NFCSTATUS nfcret = NFCSTATUS_SUCCESS;
157 int ret;
158
159 DAL_ASSERT_STR(gComPortContext.nOpened==0, "Trying to open but already done!");
160
161 switch(pConfig->nLinkType)
162 {
163 case ENUM_DAL_LINK_TYPE_COM1:
164 pComPort = "/dev/ttyS0";
165 break;
166 case ENUM_DAL_LINK_TYPE_COM2:
167 pComPort = "/dev/ttyS1";
168 break;
169 case ENUM_DAL_LINK_TYPE_COM3:
170 pComPort = "/dev/ttyS2";
171 break;
172 case ENUM_DAL_LINK_TYPE_COM4:
173 pComPort = "/dev/ttyS3";
174 break;
175 case ENUM_DAL_LINK_TYPE_COM5:
176 pComPort = "/dev/ttyS4";
177 break;
178 case ENUM_DAL_LINK_TYPE_COM6:
179 pComPort = "/dev/ttyS5";
180 break;
181 case ENUM_DAL_LINK_TYPE_COM7:
182 pComPort = "/dev/ttyS6";
183 break;
184 case ENUM_DAL_LINK_TYPE_COM8:
185 pComPort = "/dev/ttyS7";
186 break;
187 case ENUM_DAL_LINK_TYPE_USB:
188 pComPort = "/dev/ttyUSB0";
189 break;
190 default:
191 return NFCSTATUS_INVALID_PARAMETER;
192 }
193
194 /* open communication port handle */
195 gComPortContext.nHandle = open(pComPort, O_RDWR | O_NOCTTY);
196 if (gComPortContext.nHandle < 0)
197 {
198 *pLinkHandle = NULL;
199 return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE);
200 }
201
202 gComPortContext.nOpened = 1;
203 *pLinkHandle = (void*)gComPortContext.nHandle;
204
205 /*
206 * Now configure the com port
207 */
208 ret = tcgetattr(gComPortContext.nHandle, &gComPortContext.nIoConfigBackup); /* save the old io config */
209 if (ret == -1)
210 {
211 /* tcgetattr failed -- it is likely that the provided port is invalid */
212 *pLinkHandle = NULL;
213 return PHNFCSTVAL(CID_NFC_DAL, NFCSTATUS_INVALID_DEVICE);
214 }
215 ret = fcntl(gComPortContext.nHandle, F_SETFL, 0); /* Makes the read blocking (default). */
216 DAL_ASSERT_STR(ret != -1, "fcntl failed");
217 /* Configures the io */
218 memset((void *)&gComPortContext.nIoConfig, (int)0, (size_t)sizeof(struct termios));
219 /*
220 BAUDRATE: Set bps rate. You could also use cfsetispeed and cfsetospeed.
221 CRTSCTS : output hardware flow control (only used if the cable has
222 all necessary lines. See sect. 7 of Serial-HOWTO)
223 CS8 : 8n1 (8bit,no parity,1 stopbit)
224 CLOCAL : local connection, no modem contol
225 CREAD : enable receiving characters
226 */
227 gComPortContext.nIoConfig.c_cflag = DAL_BAUD_RATE | CS8 | CLOCAL | CREAD; /* Control mode flags */
228 gComPortContext.nIoConfig.c_iflag = IGNPAR; /* Input mode flags : IGNPAR Ignore parity errors */
229 gComPortContext.nIoConfig.c_oflag = 0; /* Output mode flags */
230 gComPortContext.nIoConfig.c_lflag = 0; /* Local mode flags. Read mode : non canonical, no echo */
231 gComPortContext.nIoConfig.c_cc[VTIME] = 0; /* Control characters. No inter-character timer */
232 gComPortContext.nIoConfig.c_cc[VMIN] = 1; /* Control characters. Read is blocking until X characters are read */
233
234 /*
235 TCSANOW Make changes now without waiting for data to complete
236 TCSADRAIN Wait until everything has been transmitted
237 TCSAFLUSH Flush input and output buffers and make the change
238 */
239 ret = tcsetattr(gComPortContext.nHandle, TCSANOW, &gComPortContext.nIoConfig);
240 DAL_ASSERT_STR(ret != -1, "tcsetattr failed");
241
242 /*
243 On linux the DTR signal is set by default. That causes a problem for pn544 chip
244 because this signal is connected to "reset". So we clear it. (on windows it is cleared by default).
245 */
246 ret = ioctl(gComPortContext.nHandle, TIOCMGET, &nComStatus);
247 DAL_ASSERT_STR(ret != -1, "ioctl TIOCMGET failed");
248 nComStatus &= ~TIOCM_DTR;
249 ret = ioctl(gComPortContext.nHandle, TIOCMSET, &nComStatus);
250 DAL_ASSERT_STR(ret != -1, "ioctl TIOCMSET failed");
251 DAL_DEBUG("Com port status=%d\n", nComStatus);
252 usleep(10000); /* Mandatory sleep so that the DTR line is ready before continuing */
253
254 return nfcret;
255 }
256
257
258 /*-----------------------------------------------------------------------------
259
260 FUNCTION: phDal4Nfc_uart_read
261
262 PURPOSE: Reads nNbBytesToRead bytes and writes them in pBuffer.
263 Returns the number of bytes really read or -1 in case of error.
264
265 -----------------------------------------------------------------------------*/
266
phDal4Nfc_uart_read(uint8_t * pBuffer,int nNbBytesToRead)267 int phDal4Nfc_uart_read(uint8_t * pBuffer, int nNbBytesToRead)
268 {
269 fd_set rfds;
270 struct timeval tv;
271 int ret;
272
273 DAL_ASSERT_STR(gComPortContext.nOpened == 1, "read called but not opened!");
274
275 FD_ZERO(&rfds);
276 FD_SET(gComPortContext.nHandle, &rfds);
277
278 /* select will block for 10 sec */
279 tv.tv_sec = 2;
280 tv.tv_usec = 0;
281
282 ret = select(gComPortContext.nHandle + 1, &rfds, NULL, NULL, &tv);
283
284 if (ret == -1)
285 return -1;
286
287 if (ret)
288 return read(gComPortContext.nHandle, pBuffer, nNbBytesToRead);
289
290 return 0;
291 }
292
293 /*-----------------------------------------------------------------------------
294
295 FUNCTION: phDal4Nfc_link_write
296
297 PURPOSE: Writes nNbBytesToWrite bytes from pBuffer to the link
298 Returns the number of bytes that have been wrote to the interface or -1 in case of error.
299
300 -----------------------------------------------------------------------------*/
301
phDal4Nfc_uart_write(uint8_t * pBuffer,int nNbBytesToWrite)302 int phDal4Nfc_uart_write(uint8_t * pBuffer, int nNbBytesToWrite)
303 {
304 fd_set wfds;
305 struct timeval tv;
306 int ret;
307
308 DAL_ASSERT_STR(gComPortContext.nOpened == 1, "write called but not opened!");
309
310 FD_ZERO(&wfds);
311 FD_SET(gComPortContext.nHandle, &wfds);
312
313 /* select will block for 10 sec */
314 tv.tv_sec = 2;
315 tv.tv_usec = 0;
316
317 ret = select(gComPortContext.nHandle + 1, NULL, &wfds, NULL, &tv);
318
319 if (ret == -1)
320 return -1;
321
322 if (ret)
323 return write(gComPortContext.nHandle, pBuffer, nNbBytesToWrite);
324
325 return 0;
326 }
327
328 /*-----------------------------------------------------------------------------
329
330 FUNCTION: phDal4Nfc_uart_reset
331
332 PURPOSE: Reset the PN544, using the VEN pin
333
334 -----------------------------------------------------------------------------*/
phDal4Nfc_uart_reset()335 int phDal4Nfc_uart_reset()
336 {
337 DAL_PRINT("phDal4Nfc_uart_reset");
338
339 return NFCSTATUS_FEATURE_NOT_SUPPORTED;
340 }
341
342 /*-----------------------------------------------------------------------------
343
344 FUNCTION: phDal4Nfc_uart_write
345
346 PURPOSE: Put the PN544 in download mode, using the GPIO4 pin
347
348 -----------------------------------------------------------------------------*/
phDal4Nfc_uart_download()349 int phDal4Nfc_uart_download()
350 {
351 DAL_PRINT("phDal4Nfc_uart_download");
352
353 return NFCSTATUS_FEATURE_NOT_SUPPORTED;
354 }
355
356