1 /*
2  *    Copyright (C) 2013 SAMSUNG S.LSI
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 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <poll.h>
22 #include <pthread.h>
23 #include <string.h>
24 #include <sys/ioctl.h>
25 #include <sys/select.h>
26 #include <sys/time.h>
27 #include <sys/types.h>
28 #include <termios.h>
29 #include <unistd.h>
30 
31 #include "device.h"
32 #include "hal.h"
33 #include "osi.h"
34 #include "sec_nfc.h"
35 #include "util.h"
36 
37 int pw_driver, tr_driver;
38 pthread_mutex_t tr_lock;
39 int tr_closer;
40 bool isSleep;
41 int wakeup_delay;
42 bool log_ptr;
43 eNFC_DEV_MODE dev_state;
44 tOSI_TASK_HANDLER read_task;
45 
46 // [Start] Workaround - i2c write fail(self wakeup)
47 bool first_wakeup;
48 // [End] Workaround - i2c write fail(self wakeup)
49 void read_thread(void);
50 void data_trace(const char* head, int len, uint8_t* p_data);
51 
device_init(int data_trace)52 int device_init(int data_trace) {
53   dev_state = NFC_DEV_MODE_OFF;
54   log_ptr = data_trace;
55 
56   read_task = OSI_task_allocate("read_task", read_thread);
57   if (!read_task) {
58     OSI_loge("Failed to allocate task for read thread!!");
59     return -1;
60   }
61 
62   pthread_mutex_init(&tr_lock, NULL);
63 
64   return 0;
65 }
66 
device_deinit()67 void device_deinit() {
68   device_close();
69   pthread_mutex_destroy(&tr_lock);
70   OSI_task_free(read_task);
71 }
72 
device_open()73 int device_open() {
74   int ret;
75   char pw_driver_name[64];
76   char tr_driver_name[64];
77 
78   ret = get_config_string(cfg_name_table[CFG_POWER_DRIVER], pw_driver_name,
79                           sizeof(pw_driver_name));
80   if (ret == 0) return -EPERM;
81 
82   ret = get_config_string(cfg_name_table[CFG_TRANS_DRIVER], tr_driver_name,
83                           sizeof(tr_driver_name));
84   if (ret == 0) return -EPERM;
85 
86   pw_driver = open(pw_driver_name, O_RDWR | O_NOCTTY);
87   if (pw_driver < 0) {
88     OSI_loge("Failed to open device driver: %s, pw_driver : 0x%x, errno = %d",
89              pw_driver_name, pw_driver, errno);
90     return pw_driver;
91   }
92 
93   tr_driver = pw_driver;
94 
95   OSI_loge("pw_driver: %d, tr_driver: %d", pw_driver, tr_driver);
96   device_set_mode(NFC_DEV_MODE_BOOTLOADER);
97 
98   if (OSI_OK != OSI_task_run(read_task)) {
99     OSI_loge("Failed to run read task!!");
100     OSI_task_stop(read_task);
101     close(tr_driver);
102     close(pw_driver);
103     return -1;
104   }
105 
106   if (!get_config_int(cfg_name_table[CFG_WAKEUP_DELAY], &wakeup_delay))
107     wakeup_delay = 10;
108 
109   return 0;
110 }
111 
device_close(void)112 void device_close(void) {
113   close(tr_driver);
114   close(pw_driver);
115 
116   pthread_mutex_lock(&tr_lock);
117   tr_driver = -1;
118   pw_driver = -1;
119   pthread_mutex_unlock(&tr_lock);
120 
121   if (tr_closer != 0) write(tr_closer, "x", 1);
122 
123   OSI_task_stop(read_task);
124 }
125 
device_set_mode(eNFC_DEV_MODE mode)126 int device_set_mode(eNFC_DEV_MODE mode) {
127   int ret;
128 
129   OSI_logt("device mode chage: %d -> %d", dev_state, mode);
130   ret = ioctl(pw_driver, SEC_NFC_SET_MODE, (int)mode);
131   if (!ret) {
132     if (mode == NFC_DEV_MODE_ON) isSleep = true;
133     dev_state = mode;
134   }
135 
136   return ret;
137 }
138 
device_sleep(void)139 int device_sleep(void) {
140   if (isSleep) return 0;
141 
142   isSleep = true;
143   OSI_logt("NFC can be going to sleep");
144   return ioctl(pw_driver, SEC_NFC_SLEEP, 0);
145 }
146 
device_wakeup(void)147 int device_wakeup(void) {
148   int ret = 0;
149   if (!isSleep) return 0;
150 
151   isSleep = false;
152   // [Start] Workaround - i2c write fail(self wakeup)
153   first_wakeup = true;
154   // [End] Workaround - i2c write fail(self wakeup)
155   ret = ioctl(pw_driver, SEC_NFC_WAKEUP, 0);
156 
157   /* START [H16031401] */
158   if (nfc_hal_info.state == HAL_STATE_SERVICE &&
159       nfc_hal_info.msg_event == HAL_EVT_READ)
160     return ret;
161   /* END [H16031401] */
162   OSI_logt("Wakeup! in %d ms", wakeup_delay);
163   /* wakeup delay */
164   OSI_delay(wakeup_delay);
165   OSI_logt("exit");
166 
167   return ret;
168 }
169 
device_write(uint8_t * data,size_t len)170 int device_write(uint8_t* data, size_t len) {
171   OSI_logt("enter");
172   int ret = 0;
173   int total = 0;
174   int retry = 1;
175 
176   while (len != 0) {
177     OSI_logt("before system call");
178     ret = write(tr_driver, data + total, len);
179     OSI_logt("after system call");
180     if (ret < 0) {
181       OSI_loge("write error ret = %d, errno = %d, retry = %d", ret, errno,
182                retry);
183       if (retry++ < 3 && (nfc_hal_info.flag & HAL_FLAG_RETRY_TRNS)) {
184         // [Start] Workaround - i2c write fail(self wakeup)
185         if ((retry == 2) && (first_wakeup == true)) {
186           ret = ioctl(pw_driver, SEC_NFC_SLEEP, 0);
187           OSI_delay(1);
188           ret = ioctl(pw_driver, SEC_NFC_WAKEUP, 0);
189 
190           OSI_delay(wakeup_delay);
191           first_wakeup = false;
192           continue;
193         }
194         // [End] Workaround - i2c write fail(self wakeup)
195         else {
196           OSI_delay(5);
197           continue;
198         }
199       }
200       break;
201     }
202     total += ret;
203     len -= ret;
204   }
205 
206   if (len == 0) data_trace("Send", total, data);
207 
208   OSI_logt("exit");
209   return total;
210 }
211 
device_read(uint8_t * buffer,size_t len)212 int device_read(uint8_t* buffer, size_t len) {
213   int ret = 0;
214   int total = 0;
215   int retry = 1;
216 
217   while (len != 0) {
218     ret = read(tr_driver, buffer + total, len);
219     if (ret <= 0) {
220       OSI_loge("Read error ret = %d, errno = %d", ret, errno);
221       if (retry++ < 3 && (nfc_hal_info.flag & HAL_FLAG_RETRY_TRNS)) continue;
222       break;
223     }
224 
225     total += ret;
226     len -= ret;
227   }
228 
229   return total;
230 }
231 
read_thread(void)232 void read_thread(void) {
233   tOSI_QUEUE_HANDLER msg_que = NULL;
234   tNFC_HAL_MSG* msg = NULL;
235   fd_set rfds;
236   uint8_t header[NCI_HDR_SIZE];
237   int close_pipe[2];
238   int max_fd;
239   struct timeval tv;
240   struct timeval* ptv = NULL;
241   int ret;
242 
243   OSI_logt("enter");
244   /* get msg que */
245   msg_que = OSI_queue_get_handler("msg_q");
246   if (!msg_que) {
247     OSI_loge("Not find %s queue!! exit read thread", "msg_q");
248     return;
249   }
250 
251   /* closer */
252   if (pipe(close_pipe) < 0) {
253     OSI_loge("pipe open error for closing read thread");
254     close_pipe[0] = 0;
255     close_pipe[1] = 0;
256     ptv = &tv;
257   }
258   tr_closer = close_pipe[1];
259   max_fd = (close_pipe[0] > tr_driver) ? close_pipe[0] : tr_driver;
260 
261   while (OSI_task_isRun(read_task) == OSI_RUN) {
262     pthread_mutex_lock(&tr_lock);
263     if (tr_driver < 0) {
264       pthread_mutex_unlock(&tr_lock);
265       break;
266     }
267     FD_ZERO(&rfds);
268     FD_SET(tr_driver, &rfds);
269     pthread_mutex_unlock(&tr_lock);
270 
271     if (close_pipe[0] > 0) {
272       FD_SET(close_pipe[0], &rfds);
273     } else {
274       tv.tv_sec = 0;
275       tv.tv_usec = 2000;
276     }
277 
278     ret = select(max_fd + 1, &rfds, NULL, NULL, ptv);
279 
280     pthread_mutex_lock(&tr_lock);
281     if (tr_driver < 0) {
282       pthread_mutex_unlock(&tr_lock);
283       break;
284     }
285     pthread_mutex_unlock(&tr_lock);
286 
287     if (ret == 0) /* timeout */
288       continue;
289     else if (ret < 0 && errno == EINTR) /* signal received */
290       continue;
291     else if (ret < 0) {
292       OSI_loge("Polling error");
293       nfc_stack_cback(HAL_NFC_ERROR_EVT, HAL_NFC_STATUS_OK);
294       break;
295     }
296 
297     /* read 3 bytes (header)*/
298     ret = device_read(header, NCI_HDR_SIZE);
299     if (ret == 0)
300       continue;
301     else if (ret != NCI_HDR_SIZE) {
302       OSI_loge("Reading NCI header failed");
303       continue;
304     }
305 
306     msg = (tNFC_HAL_MSG*)OSI_mem_get(NCI_CTRL_SIZE);
307     if (!msg) {
308       OSI_loge("Failed to allocate memory!1");
309       nfc_stack_cback(HAL_NFC_ERROR_EVT, HAL_NFC_STATUS_OK);
310       break;
311     }
312 
313     /* payload will read upper layer */
314 
315     msg->event = HAL_EVT_READ;
316     memcpy((void*)msg->param, (void*)header, NCI_HDR_SIZE);
317 
318     ret = OSI_queue_put(msg_que, (void*)msg);
319     OSI_logd("Sent message to HAL message task, remind que: %d", ret);
320   }
321 
322   close(close_pipe[0]);
323   close(close_pipe[1]);
324   tr_closer = 0;
325 
326   osi_unlock();  // TODO: why?
327 
328   OSI_logt("end;");
329 }
330 
331 #define TRACE_BUFFER_SIZE (NCI_CTRL_SIZE * 3 + 1)
data_trace(const char * head,int len,uint8_t * p_data)332 void data_trace(const char* head, int len, uint8_t* p_data) {
333   int i = 0, header;
334   char trace_buffer[TRACE_BUFFER_SIZE + 2];
335 
336   header = (dev_state == NFC_DEV_MODE_BOOTLOADER) ? 4 : 3;
337   while (len-- > 0 && i < NCI_CTRL_SIZE) {
338     if (i < header)
339       sprintf(trace_buffer + (i * 3), "%02x   ", p_data[i]);
340     else
341       sprintf(trace_buffer + (i * 3 + 2), "%02x ", p_data[i]);
342     i++;
343   }
344 
345   if (log_ptr) OSI_logd(" %s(%3d) %s", head, i, trace_buffer);
346 }
347