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 "hal_config.h"
36 #include "halcore.h"
37 #include "halcore_private.h"
38
39 #define ST21NFC_MAGIC 0xEA
40
41 #define ST21NFC_GET_WAKEUP _IOR(ST21NFC_MAGIC, 0x01, unsigned int)
42 #define ST21NFC_PULSE_RESET _IOR(ST21NFC_MAGIC, 0x02, unsigned int)
43 #define ST21NFC_SET_POLARITY_RISING _IOR(ST21NFC_MAGIC, 0x03, unsigned int)
44 #define ST21NFC_SET_POLARITY_FALLING _IOR(ST21NFC_MAGIC, 0x04, unsigned int)
45 #define ST21NFC_SET_POLARITY_HIGH _IOR(ST21NFC_MAGIC, 0x05, unsigned int)
46 #define ST21NFC_SET_POLARITY_LOW _IOR(ST21NFC_MAGIC, 0x06, unsigned int)
47 #define ST21NFC_RECOVERY _IOR(ST21NFC_MAGIC, 0x08, unsigned int)
48 #define ST21NFC_CLK_ENABLE _IOR(ST21NFC_MAGIC, 0x11, unsigned int)
49 #define ST21NFC_CLK_DISABLE _IOR(ST21NFC_MAGIC, 0x12, unsigned int)
50 #define ST21NFC_CLK_STATE _IOR(ST21NFC_MAGIC, 0x13, unsigned int)
51
52 #define LINUX_DBGBUFFER_SIZE 300
53
54 static int fidI2c = 0;
55 static int cmdPipe[2] = {0, 0};
56 static int notifyResetRequest = 0;
57 static bool recovery_mode = false;
58
59 static struct pollfd event_table[3];
60 static pthread_t threadHandle = (pthread_t)NULL;
61 pthread_mutex_t i2ctransport_mtx = PTHREAD_MUTEX_INITIALIZER;
62
63 unsigned long hal_ctrl_clk = 0;
64 unsigned long hal_activerw_timer = 0;
65
66 /**************************************************************************************************
67 *
68 * Private API Declaration
69 *
70 **************************************************************************************************/
71
72 static int i2cSetPolarity(int fid, bool low, bool edge);
73 static int i2cResetPulse(int fid);
74 static int SetToRecoveryMode(int fid);
75 static int i2cRead(int fid, uint8_t* pvBuffer, int length);
76 static int i2cGetGPIOState(int fid);
77 static int i2cWrite(int fd, const uint8_t* pvBuffer, int length);
78
79 /**************************************************************************************************
80 *
81 * Public API Entry-Points
82 *
83 **************************************************************************************************/
84
85 /**
86 * Worker thread for I2C data processing.
87 * On exit of this thread, destroy the HAL thread instance.
88 * @param arg Handle of the HAL layer
89 */
I2cWorkerThread(void * arg)90 static void* I2cWorkerThread(void* arg) {
91 bool closeThread = false;
92 HALHANDLE hHAL = (HALHANDLE)arg;
93 STLOG_HAL_D("echo thread started...\n");
94 bool readOk = false;
95 int eventNum = (notifyResetRequest <= 0) ? 2 : 3;
96 bool resetting= false;
97
98 do {
99 event_table[0].fd = fidI2c;
100 event_table[0].events = POLLIN;
101 event_table[0].revents = 0;
102
103 event_table[1].fd = cmdPipe[0];
104 event_table[1].events = POLLIN;
105 event_table[1].revents = 0;
106
107 event_table[2].fd = notifyResetRequest;
108 event_table[2].events = POLLPRI;
109 event_table[2].revents = 0;
110
111 STLOG_HAL_V("echo thread go to sleep...\n");
112
113 int poll_status = poll(event_table, eventNum, -1);
114
115 if (-1 == poll_status) {
116 poll_status = errno;
117 STLOG_HAL_E("error in poll call : %d - %s\n", poll_status,
118 strerror(poll_status));
119 if ((poll_status == EINTR) || (poll_status == EAGAIN)) continue;
120
121 // other errors, we stop.
122 break;
123 }
124
125 if (event_table[0].revents & POLLIN) {
126 STLOG_HAL_V("echo thread wakeup from chip...\n");
127 uint8_t buffer[300];
128 int count = 0;
129
130 do {
131 if (recovery_mode) {
132 break;
133 }
134 // load first four bytes:
135 int bytesRead = i2cRead(fidI2c, buffer, 3);
136
137 if (bytesRead == 3) {
138 if ((buffer[0] != 0x7E) && (buffer[1] != 0x7E)) {
139 readOk = true;
140 } else {
141 if (buffer[1] != 0x7E) {
142 STLOG_HAL_W(
143 "Idle data: 2nd byte is 0x%02x\n, reading next 2 bytes",
144 buffer[1]);
145 buffer[0] = buffer[1];
146 buffer[1] = buffer[2];
147 bytesRead = i2cRead(fidI2c, buffer + 2, 1);
148 if (bytesRead == 1) {
149 readOk = true;
150 }
151 } else if (buffer[2] != 0x7E) {
152 STLOG_HAL_W("Idle data: 3rd byte is 0x%02x\n, reading next byte",
153 buffer[2]);
154 buffer[0] = buffer[2];
155 bytesRead = i2cRead(fidI2c, buffer + 1, 2);
156 if (bytesRead == 2) {
157 readOk = true;
158 }
159 } else {
160 STLOG_HAL_W("received idle data\n");
161 }
162 }
163
164 if (readOk == true) {
165 int remaining = buffer[2];
166 bytesRead = 0;
167 if (remaining != 0) {
168 // read and pass to HALCore
169 bytesRead = i2cRead(fidI2c, buffer + 3, remaining);
170 }
171 if (bytesRead == remaining) {
172 DispHal("RX DATA", buffer, 3 + bytesRead);
173 HalSendUpstream(hHAL, buffer, 3 + bytesRead);
174 } else {
175 readOk = false;
176 STLOG_HAL_E("! didn't read expected bytes from i2c\n");
177 }
178 }
179
180 } else {
181 STLOG_HAL_E("! didn't read 3 requested bytes from i2c\n");
182 }
183
184 readOk = false;
185 memset(buffer, 0xca, sizeof(buffer));
186 /* read while we have data available, up to 2 times then allow writes */
187 } while ((i2cGetGPIOState(fidI2c) == 1) && (count++ < 2));
188 }
189
190 if (event_table[1].revents & POLLIN) {
191 STLOG_HAL_V("thread received command.. \n");
192
193 char cmd = 0;
194 read(cmdPipe[0], &cmd, 1);
195
196 switch (cmd) {
197 case 'X':
198 STLOG_HAL_D("received close command\n");
199 closeThread = true;
200 break;
201
202 case 'W': {
203 size_t length;
204 uint8_t buffer[MAX_BUFFER_SIZE];
205 STLOG_HAL_V("received write command\n");
206 read(cmdPipe[0], &length, sizeof(length));
207 if (length <= MAX_BUFFER_SIZE) {
208 read(cmdPipe[0], buffer, length);
209 i2cWrite(fidI2c, buffer, length);
210 } else {
211 STLOG_HAL_E(
212 "! received bigger data than expected!! Data not transmitted "
213 "to NFCC \n");
214 size_t bytes_read = 1;
215 // Read all the data to empty but do not use it as not expected
216 while ((bytes_read > 0) && (length > 0)) {
217 bytes_read = read(cmdPipe[0], buffer, MAX_BUFFER_SIZE);
218 length = length - bytes_read;
219 }
220 }
221 } break;
222 }
223 }
224
225 if (event_table[2].revents & POLLPRI && eventNum > 2) {
226 STLOG_HAL_W("thread received reset request command.. \n");
227 char reset[10];
228 int byte;
229 reset[9] = '\0';
230 lseek(notifyResetRequest, 0, SEEK_SET);
231 byte = read(notifyResetRequest, &reset, sizeof(reset));
232 if (byte < 10) {
233 reset[byte] = '\0';
234 }
235 if (byte > 0 && reset[0] == '1' && resetting== false) {
236 STLOG_HAL_E("trigger NFCC reset.. \n");
237 resetting= true;
238 i2cResetPulse(fidI2c);
239 }
240 }
241 } while (!closeThread);
242
243 // Stop here if we got a serious error above.
244 assert(closeThread);
245
246 close(fidI2c);
247 close(cmdPipe[0]);
248 close(cmdPipe[1]);
249 if (notifyResetRequest > 0) {
250 close(notifyResetRequest);
251 }
252
253 HalDestroy(hHAL);
254 STLOG_HAL_D("thread exit\n");
255 return 0;
256 }
257
258 /**
259 * Put command into queue for worker thread to process it.
260 * @param x Command 'X' to close I2C layer or 'W' to write data down to I2C
261 * layer followed by data frame
262 * @param len Size of command or data
263 * @return
264 */
I2cWriteCmd(const uint8_t * x,size_t len)265 int I2cWriteCmd(const uint8_t* x, size_t len) {
266 return write(cmdPipe[1], x, len);
267 }
268
269 /**
270 * Initialize the I2C layer.
271 * @param dev NFC NCI device context, NFC callbacks for control/data, HAL handle
272 * @param callb HAL Core callback upon reception on I2C
273 * @param pHandle HAL context handle
274 */
I2cOpenLayer(void * dev,HAL_CALLBACK callb,HALHANDLE * pHandle)275 bool I2cOpenLayer(void* dev, HAL_CALLBACK callb, HALHANDLE* pHandle) {
276 uint32_t NoDbgFlag = HAL_FLAG_DEBUG;
277 char nfc_dev_node[64];
278 char nfc_reset_req_node[128];
279
280 /*Read device node path*/
281 if (!GetStrValue(NAME_ST_NFC_DEV_NODE, (char*)nfc_dev_node,
282 sizeof(nfc_dev_node))) {
283 STLOG_HAL_D("Open /dev/st21nfc\n");
284 strcpy(nfc_dev_node, "/dev/st21nfc");
285 }
286 /*Read nfcc reset request sysfs*/
287 if (GetStrValue(NAME_ST_NFC_RESET_REQ_SYSFS, (char*)nfc_reset_req_node,
288 sizeof(nfc_reset_req_node))) {
289 STLOG_HAL_D("Open %s\n", nfc_reset_req_node);
290 notifyResetRequest = open(nfc_reset_req_node, O_RDONLY);
291 if (notifyResetRequest < 0) {
292 STLOG_HAL_E("unable to open %s (%s) \n", nfc_reset_req_node,
293 strerror(errno));
294 }
295 }
296
297 (void)pthread_mutex_lock(&i2ctransport_mtx);
298
299 fidI2c = open(nfc_dev_node, O_RDWR);
300 if (fidI2c < 0) {
301 STLOG_HAL_W("unable to open %s (%s) \n", nfc_dev_node, strerror(errno));
302 (void)pthread_mutex_unlock(&i2ctransport_mtx);
303 return false;
304 }
305
306 GetNumValue(NAME_STNFC_CONTROL_CLK, &hal_ctrl_clk, sizeof(hal_ctrl_clk));
307 GetNumValue(NAME_STNFC_ACTIVERW_TIMER, &hal_activerw_timer,
308 sizeof(hal_activerw_timer));
309
310 if (hal_ctrl_clk) {
311 if (ioctl(fidI2c, ST21NFC_CLK_DISABLE, NULL) < 0) {
312 char msg[LINUX_DBGBUFFER_SIZE];
313 strerror_r(errno, msg, LINUX_DBGBUFFER_SIZE);
314 STLOG_HAL_E("ST21NFC_CLK_DISABLE failed errno %d(%s)", errno, msg);
315 }
316 }
317 i2cSetPolarity(fidI2c, false, false);
318 i2cResetPulse(fidI2c);
319
320 if ((pipe(cmdPipe) == -1)) {
321 STLOG_HAL_W("unable to open cmdpipe\n");
322 (void)pthread_mutex_unlock(&i2ctransport_mtx);
323 return false;
324 }
325
326 *pHandle = HalCreate(dev, callb, NoDbgFlag);
327
328 if (!*pHandle) {
329 STLOG_HAL_E("failed to create NFC HAL Core \n");
330 (void)pthread_mutex_unlock(&i2ctransport_mtx);
331 return false;
332 }
333
334 (void)pthread_mutex_unlock(&i2ctransport_mtx);
335
336 return (pthread_create(&threadHandle, NULL, I2cWorkerThread, *pHandle) == 0);
337 }
338
339 /**
340 * Terminates the I2C layer.
341 */
I2cCloseLayer()342 void I2cCloseLayer() {
343 uint8_t cmd = 'X';
344 int ret;
345 ALOGD("%s: enter\n", __func__);
346
347 (void)pthread_mutex_lock(&i2ctransport_mtx);
348
349 if (threadHandle == (pthread_t)NULL) {
350 (void)pthread_mutex_unlock(&i2ctransport_mtx);
351 return;
352 }
353
354 I2cWriteCmd(&cmd, sizeof(cmd));
355 /* wait for terminate */
356 ret = pthread_join(threadHandle, (void**)NULL);
357 if (ret != 0) {
358 ALOGE("%s: failed to wait for thread (%d)", __func__, ret);
359 }
360 threadHandle = (pthread_t)NULL;
361 (void)pthread_mutex_unlock(&i2ctransport_mtx);
362 }
363
364 /**
365 * Terminates the I2C layer.
366 */
I2cResetPulse()367 void I2cResetPulse() {
368 ALOGD("%s: enter\n", __func__);
369
370 (void)pthread_mutex_lock(&i2ctransport_mtx);
371
372 i2cResetPulse(fidI2c);
373 (void)pthread_mutex_unlock(&i2ctransport_mtx);
374 }
I2cRecovery()375 void I2cRecovery() {
376 ALOGD("%s: enter\n", __func__);
377
378 (void)pthread_mutex_lock(&i2ctransport_mtx);
379 recovery_mode = true;
380 SetToRecoveryMode(fidI2c);
381 recovery_mode = false;
382 (void)pthread_mutex_unlock(&i2ctransport_mtx);
383 }
384 /**************************************************************************************************
385 *
386 * Private API Definition
387 *
388 **************************************************************************************************/
389 /**
390 * Call the st21nfc driver to adjust wake-up polarity.
391 * @param fid File descriptor for NFC device
392 * @param low Polarity (HIGH or LOW)
393 * @param edge Polarity (RISING or FALLING)
394 * @return Result of IOCTL system call (0 if ok)
395 */
i2cSetPolarity(int fid,bool low,bool edge)396 static int i2cSetPolarity(int fid, bool low, bool edge) {
397 int result;
398 unsigned int io_code;
399
400 if (low) {
401 if (edge) {
402 io_code = ST21NFC_SET_POLARITY_FALLING;
403 } else {
404 io_code = ST21NFC_SET_POLARITY_LOW;
405 }
406
407 } else {
408 if (edge) {
409 io_code = ST21NFC_SET_POLARITY_RISING;
410 } else {
411 io_code = ST21NFC_SET_POLARITY_HIGH;
412 }
413 }
414
415 if (-1 == (result = ioctl(fid, io_code, NULL))) {
416 result = -1;
417 }
418
419 return result;
420 } /* i2cSetPolarity*/
421
422 /**
423 * Call the st21nfc driver to generate a 30ms pulse on RESET line.
424 * @param fid File descriptor for NFC device
425 * @return Result of IOCTL system call (0 if ok)
426 */
i2cResetPulse(int fid)427 static int i2cResetPulse(int fid) {
428 int result;
429
430 if (-1 == (result = ioctl(fid, ST21NFC_PULSE_RESET, NULL))) {
431 result = -1;
432 }
433 STLOG_HAL_D("! i2cResetPulse!!, result = %d", result);
434 return result;
435 } /* i2cResetPulse*/
436
437 /**
438 * Call the st21nfc driver to generate pulses on RESET line to get a recovery.
439 * @param fid File descriptor for NFC device
440 * @return Result of IOCTL system call (0 if ok)
441 */
SetToRecoveryMode(int fid)442 static int SetToRecoveryMode(int fid) {
443 int result;
444
445 if (-1 == (result = ioctl(fid, ST21NFC_RECOVERY, NULL))) {
446 result = -1;
447 }
448 STLOG_HAL_D("! SetToRecoveryMode!!, result = %d", result);
449 return result;
450 } /* SetToRecoveryMode*/
451
452 /**
453 * Write data to st21nfc, on failure do max 3 retries.
454 * @param fid File descriptor for NFC device
455 * @param pvBuffer Data to write
456 * @param length Data size
457 * @return 0 if bytes written, -1 if error
458 */
i2cWrite(int fid,const uint8_t * pvBuffer,int length)459 static int i2cWrite(int fid, const uint8_t* pvBuffer, int length) {
460 int retries = 0;
461 int result = 0;
462 int halfsecs = 0;
463 int clk_state = -1;
464 char msg[LINUX_DBGBUFFER_SIZE];
465
466 if ((hal_ctrl_clk || hal_activerw_timer) && length >= 4 &&
467 pvBuffer[0] == 0x20 && pvBuffer[1] == 0x09) {
468 if (hal_activerw_timer && (pvBuffer[3] == 0x01 || pvBuffer[3] == 0x03)) {
469 // screen off cases
470 hal_wrapper_set_state(HAL_WRAPPER_STATE_SET_ACTIVERW_TIMER);
471 }
472 if (hal_ctrl_clk && 0 > (clk_state = ioctl(fid, ST21NFC_CLK_STATE, NULL))) {
473 strerror_r(errno, msg, LINUX_DBGBUFFER_SIZE);
474 STLOG_HAL_E("ST21NFC_CLK_STATE failed errno %d(%s)", errno, msg);
475 clk_state = -1;
476 }
477 STLOG_HAL_D("ST21NFC_CLK_STATE = %d", clk_state);
478 if (clk_state == 1 && (pvBuffer[3] == 0x01 || pvBuffer[3] == 0x03)) {
479 // screen off cases
480 if (ioctl(fid, ST21NFC_CLK_DISABLE, NULL) < 0) {
481 strerror_r(errno, msg, LINUX_DBGBUFFER_SIZE);
482 STLOG_HAL_E("ST21NFC_CLK_DISABLE failed errno %d(%s)", errno, msg);
483 } else if (0 > (clk_state = ioctl(fid, ST21NFC_CLK_STATE, NULL))) {
484 strerror_r(errno, msg, LINUX_DBGBUFFER_SIZE);
485 STLOG_HAL_E("ST21NFC_CLK_STATE failed errno %d(%s)", errno, msg);
486 clk_state = -1;
487 }
488 if (clk_state != 0) {
489 STLOG_HAL_E("CLK_DISABLE STATE ERROR clk_state = %d", clk_state);
490 }
491 } else if (clk_state == 0 && (pvBuffer[3] == 0x02 || pvBuffer[3] == 0x00)) {
492 // screen on cases
493 if (ioctl(fid, ST21NFC_CLK_ENABLE, NULL) < 0) {
494 strerror_r(errno, msg, LINUX_DBGBUFFER_SIZE);
495 STLOG_HAL_E("ST21NFC_CLK_ENABLE failed errno %d(%s)", errno, msg);
496 } else if (0 > (clk_state = ioctl(fid, ST21NFC_CLK_STATE, NULL))) {
497 strerror_r(errno, msg, LINUX_DBGBUFFER_SIZE);
498 STLOG_HAL_E("ST21NFC_CLK_STATE failed errno %d(%s)", errno, msg);
499 clk_state = -1;
500 }
501 if (clk_state != 1) {
502 STLOG_HAL_E("CLK_ENABLE STATE ERROR clk_state = %d", clk_state);
503 }
504 }
505 }
506
507 redo:
508 while (retries < 3) {
509 result = write(fid, pvBuffer, length);
510
511 if (result < 0) {
512 strerror_r(errno, msg, LINUX_DBGBUFFER_SIZE);
513 STLOG_HAL_W("! i2cWrite!!, errno is '%s'", msg);
514 usleep(4000);
515 retries++;
516 } else if (result > 0) {
517 result = 0;
518 return result;
519 } else {
520 STLOG_HAL_W("write on i2c failed, retrying\n");
521 usleep(4000);
522 retries++;
523 }
524 }
525 /* If we're here, we failed to write to NFCC. Retry after 500ms because some
526 CPUs have shown such long unavailability sometimes */
527 if (halfsecs < 10) {
528 usleep(500000);
529 retries = 0;
530 halfsecs++;
531 goto redo;
532 }
533 /* The CLF did not recover, give up */
534 return -1;
535 } /* i2cWrite */
536
537 /**
538 * Read data from st21nfc, on failure do max 3 retries.
539 *
540 * @param fid File descriptor for NFC device
541 * @param pvBuffer Buffer where to copy read data
542 * @param length Data size to read
543 * @return Length of read data, -1 if error
544 */
i2cRead(int fid,uint8_t * pvBuffer,int length)545 static int i2cRead(int fid, uint8_t* pvBuffer, int length) {
546 int retries = 0;
547 int result = -1;
548
549 while ((retries < 3) && (result < 0)) {
550 result = read(fid, pvBuffer, length);
551
552 if (result == -1) {
553 if (errno == EAGAIN) {
554 /* File is nonblocking, and no data is available.
555 * This is not an error condition!
556 */
557 result = 0;
558 STLOG_HAL_D(
559 "## i2cRead - got EAGAIN. No data available. return 0 bytes");
560 } else {
561 /* unexpected result */
562 char msg[LINUX_DBGBUFFER_SIZE];
563 strerror_r(errno, msg, LINUX_DBGBUFFER_SIZE);
564 STLOG_HAL_W("## i2cRead returns %d errno %d (%s)", result, errno, msg);
565 }
566 }
567
568 if (result < 0 && retries < 3) {
569 /* delays are different and increasing for the three retries. */
570 static const uint8_t delayTab[] = {2, 3, 5};
571 int delay = delayTab[retries];
572
573 retries++;
574 STLOG_HAL_W("## i2cRead retry %d/3 in %d milliseconds.", retries, delay);
575 usleep(delay * 1000);
576 continue;
577 }
578 }
579 return result;
580 } /* i2cRead */
581
582 /**
583 * Get the activation status of wake-up pin from st21nfc.
584 * The decision 'active' depends on selected polarity.
585 * The decision is handled inside the driver(st21nfc).
586 * @param fid File descriptor for NFC device
587 * @return
588 * Result < 0: Error condition
589 * Result > 0: Pin active
590 * Result = 0: Pin not active
591 */
i2cGetGPIOState(int fid)592 static int i2cGetGPIOState(int fid) {
593 int result;
594
595 if (-1 == (result = ioctl(fid, ST21NFC_GET_WAKEUP, NULL))) {
596 result = -1;
597 }
598
599 return result;
600 } /* i2cGetGPIOState */
601