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