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