1 /** ----------------------------------------------------------------------
2 *
3 * Copyright (C) 2013 ST Microelectronics S.A.
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
20 #include <assert.h>
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <limits.h>
24 #include <linux/input.h> /* not required for all builds */
25 #include <poll.h>
26 #include <pthread.h>
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/ioctl.h>
32 #include <unistd.h>
33
34 #include "android_logmsg.h"
35 #include "halcore.h"
36 #include "halcore_private.h"
37
38 #define ST21NFC_MAGIC 0xEA
39
40 #define ST21NFC_GET_WAKEUP _IOR(ST21NFC_MAGIC, 0x01, unsigned int)
41 #define ST21NFC_PULSE_RESET _IOR(ST21NFC_MAGIC, 0x02, unsigned int)
42 #define ST21NFC_SET_POLARITY_RISING _IOR(ST21NFC_MAGIC, 0x03, unsigned int)
43 #define ST21NFC_SET_POLARITY_FALLING _IOR(ST21NFC_MAGIC, 0x04, unsigned int)
44 #define ST21NFC_SET_POLARITY_HIGH _IOR(ST21NFC_MAGIC, 0x05, unsigned int)
45 #define ST21NFC_SET_POLARITY_LOW _IOR(ST21NFC_MAGIC, 0x06, unsigned int)
46
47 #define LINUX_DBGBUFFER_SIZE 300
48
49 static int fidI2c = 0;
50 static int cmdPipe[2] = {0, 0};
51
52 static struct pollfd event_table[2];
53 static pthread_t threadHandle = (pthread_t)NULL;
54 pthread_mutex_t i2ctransport_mtx = PTHREAD_MUTEX_INITIALIZER;
55
56 /**************************************************************************************************
57 *
58 * Private API Declaration
59 *
60 **************************************************************************************************/
61
62 static int i2cSetPolarity(int fid, bool low, bool edge);
63 static int i2cResetPulse(int fid);
64 static int i2cRead(int fid, uint8_t* pvBuffer, int length);
65 static int i2cGetGPIOState(int fid);
66 static int i2cWrite(int fd, const uint8_t* pvBuffer, int length);
67
68 /**************************************************************************************************
69 *
70 * Public API Entry-Points
71 *
72 **************************************************************************************************/
73
74 /**
75 * Worker thread for I2C data processing.
76 * On exit of this thread, destroy the HAL thread instance.
77 * @param arg Handle of the HAL layer
78 */
I2cWorkerThread(void * arg)79 static void* I2cWorkerThread(void* arg) {
80 bool closeThread = false;
81 HALHANDLE hHAL = (HALHANDLE)arg;
82 STLOG_HAL_D("echo thread started...\n");
83 bool readOk = false;
84
85 do {
86 event_table[0].fd = fidI2c;
87 event_table[0].events = POLLIN;
88 event_table[0].revents = 0;
89
90 event_table[1].fd = cmdPipe[0];
91 event_table[1].events = POLLIN;
92 event_table[1].revents = 0;
93
94 STLOG_HAL_V("echo thread go to sleep...\n");
95
96 int poll_status = poll(event_table, 2, -1);
97
98 if (-1 == poll_status) {
99 STLOG_HAL_E("error in poll call\n");
100 break;
101 }
102
103 if (event_table[0].revents & POLLIN) {
104 STLOG_HAL_V("echo thread wakeup from chip...\n");
105
106 uint8_t buffer[300];
107 int count = 0;
108
109 do {
110 // load first four bytes:
111 int bytesRead = i2cRead(fidI2c, buffer, 3);
112
113 if (bytesRead == 3) {
114 if ((buffer[0] != 0x7E) && (buffer[1] != 0x7E)) {
115 readOk = true;
116 } else {
117 if (buffer[1] != 0x7E) {
118 STLOG_HAL_W(
119 "Idle data: 2nd byte is 0x%02x\n, reading next 2 bytes",
120 buffer[1]);
121 buffer[0] = buffer[1];
122 buffer[1] = buffer[2];
123 bytesRead = i2cRead(fidI2c, buffer + 2, 1);
124 if (bytesRead == 1) {
125 readOk = true;
126 }
127 } else if (buffer[2] != 0x7E) {
128 STLOG_HAL_W("Idle data: 3rd byte is 0x%02x\n, reading next byte",
129 buffer[2]);
130 buffer[0] = buffer[2];
131 bytesRead = i2cRead(fidI2c, buffer + 1, 2);
132 if (bytesRead == 2) {
133 readOk = true;
134 }
135 } else {
136 STLOG_HAL_W("received idle data\n");
137 }
138 }
139
140 if (readOk == true) {
141 int remaining = buffer[2];
142 bytesRead = 0;
143 if (remaining != 0) {
144 // read and pass to HALCore
145 bytesRead = i2cRead(fidI2c, buffer + 3, remaining);
146 }
147 if (bytesRead == remaining) {
148 DispHal("RX DATA", buffer, 3 + bytesRead);
149 HalSendUpstream(hHAL, buffer, 3 + bytesRead);
150 } else {
151 readOk = false;
152 STLOG_HAL_E("! didn't read expected bytes from i2c\n");
153 }
154 }
155
156 } else {
157 STLOG_HAL_E("! didn't read 3 requested bytes from i2c\n");
158 }
159
160 readOk = false;
161 memset(buffer, 0xca, sizeof(buffer));
162
163 /* read while we have data available, up to 2 times then allow writes */
164 } while ((i2cGetGPIOState(fidI2c) == 1) && (count++ < 2));
165 }
166
167 if (event_table[1].revents & POLLIN) {
168 STLOG_HAL_V("thread received command.. \n");
169
170 char cmd = 0;
171 read(cmdPipe[0], &cmd, 1);
172
173 switch (cmd) {
174 case 'X':
175 STLOG_HAL_D("received close command\n");
176 closeThread = true;
177 break;
178
179 case 'W': {
180 size_t length;
181 uint8_t buffer[MAX_BUFFER_SIZE];
182 STLOG_HAL_V("received write command\n");
183 read(cmdPipe[0], &length, sizeof(length));
184 if (length <= MAX_BUFFER_SIZE) {
185 read(cmdPipe[0], buffer, length);
186 i2cWrite(fidI2c, buffer, length);
187 } else {
188 STLOG_HAL_E(
189 "! received bigger data than expected!! Data not transmitted "
190 "to NFCC \n");
191 size_t bytes_read = 1;
192 // Read all the data to empty but do not use it as not expected
193 while ((bytes_read > 0) && (length > 0)) {
194 bytes_read = read(cmdPipe[0], buffer, MAX_BUFFER_SIZE);
195 length = length - bytes_read;
196 }
197 }
198 } break;
199 }
200 }
201
202 } while (!closeThread);
203
204 close(fidI2c);
205 close(cmdPipe[0]);
206 close(cmdPipe[1]);
207
208 HalDestroy(hHAL);
209 STLOG_HAL_D("thread exit\n");
210 return 0;
211 }
212
213 /**
214 * Put command into queue for worker thread to process it.
215 * @param x Command 'X' to close I2C layer or 'W' to write data down to I2C
216 * layer followed by data frame
217 * @param len Size of command or data
218 * @return
219 */
I2cWriteCmd(const uint8_t * x,size_t len)220 int I2cWriteCmd(const uint8_t* x, size_t len) {
221 return write(cmdPipe[1], x, len);
222 }
223
224 /**
225 * Initialize the I2C layer.
226 * @param dev NFC NCI device context, NFC callbacks for control/data, HAL handle
227 * @param callb HAL Core callback upon reception on I2C
228 * @param pHandle HAL context handle
229 */
I2cOpenLayer(void * dev,HAL_CALLBACK callb,HALHANDLE * pHandle)230 bool I2cOpenLayer(void* dev, HAL_CALLBACK callb, HALHANDLE* pHandle) {
231 uint32_t NoDbgFlag = HAL_FLAG_DEBUG;
232
233 (void)pthread_mutex_lock(&i2ctransport_mtx);
234 fidI2c = open("/dev/st21nfc", O_RDWR);
235 if (fidI2c < 0) {
236 STLOG_HAL_W("unable to open /dev/st21nfc (%s) \n", strerror(errno));
237 (void)pthread_mutex_unlock(&i2ctransport_mtx);
238 return false;
239 }
240
241 i2cSetPolarity(fidI2c, false, false);
242 i2cResetPulse(fidI2c);
243
244 if ((pipe(cmdPipe) == -1)) {
245 STLOG_HAL_W("unable to open cmdpipe\n");
246 (void)pthread_mutex_unlock(&i2ctransport_mtx);
247 return false;
248 }
249
250 *pHandle = HalCreate(dev, callb, NoDbgFlag);
251
252 if (!*pHandle) {
253 STLOG_HAL_E("failed to create NFC HAL Core \n");
254 (void)pthread_mutex_unlock(&i2ctransport_mtx);
255 return false;
256 }
257
258 (void)pthread_mutex_unlock(&i2ctransport_mtx);
259
260 return (pthread_create(&threadHandle, NULL, I2cWorkerThread, *pHandle) == 0);
261 }
262
263 /**
264 * Terminates the I2C layer.
265 */
I2cCloseLayer()266 void I2cCloseLayer() {
267 uint8_t cmd = 'X';
268 int ret;
269 ALOGD("%s: enter\n", __func__);
270
271 (void)pthread_mutex_lock(&i2ctransport_mtx);
272
273 if (threadHandle == (pthread_t)NULL) {
274 (void)pthread_mutex_unlock(&i2ctransport_mtx);
275 return;
276 }
277
278 I2cWriteCmd(&cmd, sizeof(cmd));
279 /* wait for terminate */
280 ret = pthread_join(threadHandle, (void**)NULL);
281 if (ret != 0) {
282 ALOGE("%s: failed to wait for thread (%d)", __func__, ret);
283 }
284 threadHandle = (pthread_t)NULL;
285 (void)pthread_mutex_unlock(&i2ctransport_mtx);
286 }
287
288 /**
289 * Terminates the I2C layer.
290 */
I2cResetPulse()291 void I2cResetPulse() {
292 ALOGD("%s: enter\n", __func__);
293
294 (void)pthread_mutex_lock(&i2ctransport_mtx);
295
296 i2cResetPulse(fidI2c);
297 (void)pthread_mutex_unlock(&i2ctransport_mtx);
298 }
299 /**************************************************************************************************
300 *
301 * Private API Definition
302 *
303 **************************************************************************************************/
304 /**
305 * Call the st21nfc driver to adjust wake-up polarity.
306 * @param fid File descriptor for NFC device
307 * @param low Polarity (HIGH or LOW)
308 * @param edge Polarity (RISING or FALLING)
309 * @return Result of IOCTL system call (0 if ok)
310 */
i2cSetPolarity(int fid,bool low,bool edge)311 static int i2cSetPolarity(int fid, bool low, bool edge) {
312 int result;
313 unsigned int io_code;
314
315 if (low) {
316 if (edge) {
317 io_code = ST21NFC_SET_POLARITY_FALLING;
318 } else {
319 io_code = ST21NFC_SET_POLARITY_LOW;
320 }
321
322 } else {
323 if (edge) {
324 io_code = ST21NFC_SET_POLARITY_RISING;
325 } else {
326 io_code = ST21NFC_SET_POLARITY_HIGH;
327 }
328 }
329
330 if (-1 == (result = ioctl(fid, io_code, NULL))) {
331 result = -1;
332 }
333
334 return result;
335 } /* i2cSetPolarity*/
336
337 /**
338 * Call the st21nfc driver to generate a 30ms pulse on RESET line.
339 * @param fid File descriptor for NFC device
340 * @return Result of IOCTL system call (0 if ok)
341 */
i2cResetPulse(int fid)342 static int i2cResetPulse(int fid) {
343 int result;
344
345 if (-1 == (result = ioctl(fid, ST21NFC_PULSE_RESET, NULL))) {
346 result = -1;
347 }
348 STLOG_HAL_D("! i2cResetPulse!!, result = %d", result);
349 return result;
350 } /* i2cResetPulse*/
351
352 /**
353 * Write data to st21nfc, on failure do max 3 retries.
354 * @param fid File descriptor for NFC device
355 * @param pvBuffer Data to write
356 * @param length Data size
357 * @return 0 if bytes written, -1 if error
358 */
i2cWrite(int fid,const uint8_t * pvBuffer,int length)359 static int i2cWrite(int fid, const uint8_t* pvBuffer, int length) {
360 int retries = 0;
361 int result = 0;
362 int halfsecs = 0;
363
364 redo:
365 while (retries < 3) {
366 result = write(fid, pvBuffer, length);
367
368 if (result < 0) {
369 char msg[LINUX_DBGBUFFER_SIZE];
370
371 strerror_r(errno, msg, LINUX_DBGBUFFER_SIZE);
372 STLOG_HAL_W("! i2cWrite!!, errno is '%s'", msg);
373 usleep(4000);
374 retries++;
375 } else if (result > 0) {
376 result = 0;
377 return result;
378 } else {
379 STLOG_HAL_W("write on i2c failed, retrying\n");
380 usleep(4000);
381 retries++;
382 }
383 }
384 /* If we're here, we failed to write to NFCC. Retry after 500ms because some
385 CPUs have shown such long unavailability sometimes */
386 if (halfsecs < 10) {
387 usleep(500000);
388 halfsecs++;
389 goto redo;
390 }
391 /* The CLF did not recover, give up */
392 return -1;
393 } /* i2cWrite */
394
395 /**
396 * Read data from st21nfc, on failure do max 3 retries.
397 *
398 * @param fid File descriptor for NFC device
399 * @param pvBuffer Buffer where to copy read data
400 * @param length Data size to read
401 * @return Length of read data, -1 if error
402 */
i2cRead(int fid,uint8_t * pvBuffer,int length)403 static int i2cRead(int fid, uint8_t* pvBuffer, int length) {
404 int retries = 0;
405 int result = -1;
406
407 while ((retries < 3) && (result < 0)) {
408 result = read(fid, pvBuffer, length);
409
410 if (result == -1) {
411 int e = errno;
412 if (e == EAGAIN) {
413 /* File is nonblocking, and no data is available.
414 * This is not an error condition!
415 */
416 result = 0;
417 STLOG_HAL_D(
418 "## i2cRead - got EAGAIN. No data available. return 0 bytes");
419 } else {
420 /* unexpected result */
421 char msg[LINUX_DBGBUFFER_SIZE];
422 strerror_r(e, msg, LINUX_DBGBUFFER_SIZE);
423 STLOG_HAL_W("## i2cRead returns %d errno %d (%s)", result, e, msg);
424 }
425 }
426
427 if (result < 0) {
428 if (retries < 3) {
429 /* delays are different and increasing for the three retries. */
430 static const uint8_t delayTab[] = {2, 3, 5};
431 int delay = delayTab[retries];
432
433 retries++;
434 STLOG_HAL_W("## i2cRead retry %d/3 in %d milliseconds.", retries,
435 delay);
436 usleep(delay * 1000);
437 continue;
438 }
439 }
440 }
441 return result;
442 } /* i2cRead */
443
444 /**
445 * Get the activation status of wake-up pin from st21nfc.
446 * The decision 'active' depends on selected polarity.
447 * The decision is handled inside the driver(st21nfc).
448 * @param fid File descriptor for NFC device
449 * @return
450 * Result < 0: Error condition
451 * Result > 0: Pin active
452 * Result = 0: Pin not active
453 */
i2cGetGPIOState(int fid)454 static int i2cGetGPIOState(int fid) {
455 int result;
456
457 if (-1 == (result = ioctl(fid, ST21NFC_GET_WAKEUP, NULL))) {
458 result = -1;
459 }
460
461 return result;
462 } /* i2cGetGPIOState */
463