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