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 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 67 void device_deinit() { 68 device_close(); 69 pthread_mutex_destroy(&tr_lock); 70 OSI_task_free(read_task); 71 } 72 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 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 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 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 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 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 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 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) 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