1 /****************************************************************************** 2 * 3 * Copyright (C) 2009-2012 Broadcom Corporation 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 * 21 * Filename: userial.c 22 * 23 * Description: Contains open/read/write/close functions on serial port 24 * 25 ******************************************************************************/ 26 27 #define LOG_TAG "bt_userial" 28 29 #include <utils/Log.h> 30 #include <pthread.h> 31 #include <fcntl.h> 32 #include <errno.h> 33 #include <stdio.h> 34 #include <sys/socket.h> 35 #include "bt_hci_bdroid.h" 36 #include "userial.h" 37 #include "utils.h" 38 #include "bt_vendor_lib.h" 39 #include <sys/prctl.h> 40 #include "bt_utils.h" 41 42 /****************************************************************************** 43 ** Constants & Macros 44 ******************************************************************************/ 45 46 #ifndef USERIAL_DBG 47 #define USERIAL_DBG FALSE 48 #endif 49 50 #if (USERIAL_DBG == TRUE) 51 #define USERIALDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);} 52 #else 53 #define USERIALDBG(param, ...) {} 54 #endif 55 56 #ifndef ENABLE_USERIAL_TIMING_LOGS 57 #define ENABLE_USERIAL_TIMING_LOGS FALSE 58 #endif 59 60 #define MAX_SERIAL_PORT (USERIAL_PORT_3 + 1) 61 #define READ_LIMIT (BTHC_USERIAL_READ_MEM_SIZE - BT_HC_HDR_SIZE) 62 63 enum { 64 USERIAL_RX_EXIT, 65 USERIAL_RX_FLOW_OFF, 66 USERIAL_RX_FLOW_ON 67 }; 68 69 /****************************************************************************** 70 ** Externs 71 ******************************************************************************/ 72 73 extern bt_vendor_interface_t *bt_vnd_if; 74 75 /****************************************************************************** 76 ** Local type definitions 77 ******************************************************************************/ 78 79 typedef struct 80 { 81 int fd; 82 uint8_t port; 83 pthread_t read_thread; 84 BUFFER_Q rx_q; 85 HC_BT_HDR *p_rx_hdr; 86 } tUSERIAL_CB; 87 88 /****************************************************************************** 89 ** Static variables 90 ******************************************************************************/ 91 92 static tUSERIAL_CB userial_cb; 93 static volatile uint8_t userial_running = 0; 94 95 /****************************************************************************** 96 ** Static functions 97 ******************************************************************************/ 98 99 #if defined(ENABLE_USERIAL_TIMING_LOGS) && (ENABLE_USERIAL_TIMING_LOGS==TRUE) 100 101 static void log_userial_tx_timing(int len) 102 { 103 #define USEC_PER_SEC 1000000L 104 static struct timespec prev = {0, 0}; 105 struct timespec now, diff; 106 unsigned int diff_us = 0; 107 unsigned int now_us = 0; 108 109 clock_gettime(CLOCK_MONOTONIC, &now); 110 now_us = now.tv_sec*USEC_PER_SEC + now.tv_nsec/1000; 111 diff_us = (now.tv_sec - prev.tv_sec) * USEC_PER_SEC + (now.tv_nsec - prev.tv_nsec)/1000; 112 113 ALOGW("[userial] ts %08d diff : %08d len %d", now_us, diff_us, 114 len); 115 116 prev = now; 117 } 118 119 #endif 120 121 122 /***************************************************************************** 123 ** Socket signal functions to wake up userial_read_thread for termination 124 ** 125 ** creating an unnamed pair of connected sockets 126 ** - signal_fds[0]: join fd_set in select call of userial_read_thread 127 ** - signal_fds[1]: trigger from userial_close 128 *****************************************************************************/ 129 static int signal_fds[2]={0,1}; 130 static uint8_t rx_flow_on = TRUE; 131 static inline int create_signal_fds(fd_set* set) 132 { 133 if(signal_fds[0]==0 && socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fds)<0) 134 { 135 ALOGE("create_signal_sockets:socketpair failed, errno: %d", errno); 136 return -1; 137 } 138 FD_SET(signal_fds[0], set); 139 return signal_fds[0]; 140 } 141 static inline int send_wakeup_signal(char sig_cmd) 142 { 143 return send(signal_fds[1], &sig_cmd, sizeof(sig_cmd), 0); 144 } 145 static inline char reset_signal() 146 { 147 char sig_recv = -1; 148 recv(signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL); 149 return sig_recv; 150 } 151 static inline int is_signaled(fd_set* set) 152 { 153 return FD_ISSET(signal_fds[0], set); 154 } 155 156 157 /******************************************************************************* 158 ** 159 ** Function select_read 160 ** 161 ** Description check if fd is ready for reading and listen for termination 162 ** signal. need to use select in order to avoid collision 163 ** between read and close on the same fd 164 ** 165 ** Returns -1: termination 166 ** >=0: numbers of bytes read back from fd 167 ** 168 *******************************************************************************/ 169 static int select_read(int fd, uint8_t *pbuf, int len) 170 { 171 fd_set input; 172 int n = 0, ret = -1; 173 char reason = 0; 174 175 while (userial_running) 176 { 177 /* Initialize the input fd set */ 178 FD_ZERO(&input); 179 if (rx_flow_on == TRUE) 180 { 181 FD_SET(fd, &input); 182 } 183 int fd_max = create_signal_fds(&input); 184 fd_max = fd_max > fd ? fd_max : fd; 185 186 /* Do the select */ 187 n = select(fd_max+1, &input, NULL, NULL, NULL); 188 if(is_signaled(&input)) 189 { 190 reason = reset_signal(); 191 if (reason == USERIAL_RX_EXIT) 192 { 193 USERIALDBG("RX termination"); 194 return -1; 195 } 196 else if (reason == USERIAL_RX_FLOW_OFF) 197 { 198 USERIALDBG("RX flow OFF"); 199 rx_flow_on = FALSE; 200 } 201 else if (reason == USERIAL_RX_FLOW_ON) 202 { 203 USERIALDBG("RX flow ON"); 204 rx_flow_on = TRUE; 205 } 206 } 207 208 if (n > 0) 209 { 210 /* We might have input */ 211 if (FD_ISSET(fd, &input)) 212 { 213 ret = read(fd, pbuf, (size_t)len); 214 if (0 == ret) 215 ALOGW( "read() returned 0!" ); 216 217 return ret; 218 } 219 } 220 else if (n < 0) 221 ALOGW( "select() Failed"); 222 else if (n == 0) 223 ALOGW( "Got a select() TIMEOUT"); 224 225 } 226 227 return ret; 228 } 229 230 /******************************************************************************* 231 ** 232 ** Function userial_read_thread 233 ** 234 ** Description 235 ** 236 ** Returns void * 237 ** 238 *******************************************************************************/ 239 static void *userial_read_thread(void *arg) 240 { 241 int rx_length = 0; 242 HC_BT_HDR *p_buf = NULL; 243 uint8_t *p; 244 245 USERIALDBG("Entering userial_read_thread()"); 246 prctl(PR_SET_NAME, (unsigned long)"userial_read", 0, 0, 0); 247 248 rx_flow_on = TRUE; 249 userial_running = 1; 250 251 raise_priority_a2dp(TASK_HIGH_USERIAL_READ); 252 253 while (userial_running) 254 { 255 if (bt_hc_cbacks) 256 { 257 p_buf = (HC_BT_HDR *) bt_hc_cbacks->alloc( \ 258 BTHC_USERIAL_READ_MEM_SIZE); 259 } 260 else 261 p_buf = NULL; 262 263 if (p_buf != NULL) 264 { 265 p_buf->offset = 0; 266 p_buf->layer_specific = 0; 267 268 p = (uint8_t *) (p_buf + 1); 269 rx_length = select_read(userial_cb.fd, p, READ_LIMIT); 270 } 271 else 272 { 273 rx_length = 0; 274 utils_delay(100); 275 ALOGW("userial_read_thread() failed to gain buffers"); 276 continue; 277 } 278 279 280 if (rx_length > 0) 281 { 282 p_buf->len = (uint16_t)rx_length; 283 utils_enqueue(&(userial_cb.rx_q), p_buf); 284 bthc_signal_event(HC_EVENT_RX); 285 } 286 else /* either 0 or < 0 */ 287 { 288 ALOGW("select_read return size <=0:%d, exiting userial_read_thread",\ 289 rx_length); 290 /* if we get here, we should have a buffer */ 291 bt_hc_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1)); 292 /* negative value means exit thread */ 293 break; 294 } 295 } /* for */ 296 297 userial_running = 0; 298 USERIALDBG("Leaving userial_read_thread()"); 299 pthread_exit(NULL); 300 301 return NULL; // Compiler friendly 302 } 303 304 305 /***************************************************************************** 306 ** Userial API Functions 307 *****************************************************************************/ 308 309 /******************************************************************************* 310 ** 311 ** Function userial_init 312 ** 313 ** Description Initializes the userial driver 314 ** 315 ** Returns TRUE/FALSE 316 ** 317 *******************************************************************************/ 318 uint8_t userial_init(void) 319 { 320 USERIALDBG("userial_init"); 321 memset(&userial_cb, 0, sizeof(tUSERIAL_CB)); 322 userial_cb.fd = -1; 323 utils_queue_init(&(userial_cb.rx_q)); 324 return TRUE; 325 } 326 327 328 /******************************************************************************* 329 ** 330 ** Function userial_open 331 ** 332 ** Description Open Bluetooth device with the port ID 333 ** 334 ** Returns TRUE/FALSE 335 ** 336 *******************************************************************************/ 337 uint8_t userial_open(uint8_t port) 338 { 339 struct sched_param param; 340 int policy, result; 341 pthread_attr_t thread_attr; 342 int fd_array[CH_MAX]; 343 344 USERIALDBG("userial_open(port:%d)", port); 345 346 if (userial_running) 347 { 348 /* Userial is open; close it first */ 349 userial_close(); 350 utils_delay(50); 351 } 352 353 if (port >= MAX_SERIAL_PORT) 354 { 355 ALOGE("Port > MAX_SERIAL_PORT"); 356 return FALSE; 357 } 358 359 /* Calling vendor-specific part */ 360 if (bt_vnd_if) 361 { 362 result = bt_vnd_if->op(BT_VND_OP_USERIAL_OPEN, &fd_array); 363 364 if (result != 1) 365 { 366 ALOGE("userial_open: wrong numbers of open fd in vendor lib [%d]!", 367 result); 368 ALOGE("userial_open: HCI UART expects only one open fd"); 369 bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL); 370 return FALSE; 371 } 372 373 userial_cb.fd = fd_array[0]; 374 } 375 else 376 { 377 ALOGE("userial_open: missing vendor lib interface !!!"); 378 ALOGE("userial_open: unable to open UART port"); 379 return FALSE; 380 } 381 382 if (userial_cb.fd == -1) 383 { 384 ALOGE("userial_open: failed to open UART port"); 385 return FALSE; 386 } 387 388 USERIALDBG( "fd = %d", userial_cb.fd); 389 390 userial_cb.port = port; 391 392 pthread_attr_init(&thread_attr); 393 394 if (pthread_create(&(userial_cb.read_thread), &thread_attr, \ 395 userial_read_thread, NULL) != 0 ) 396 { 397 ALOGE("pthread_create failed!"); 398 return FALSE; 399 } 400 401 if(pthread_getschedparam(userial_cb.read_thread, &policy, ¶m)==0) 402 { 403 policy = BTHC_LINUX_BASE_POLICY; 404 #if (BTHC_LINUX_BASE_POLICY!=SCHED_NORMAL) 405 param.sched_priority = BTHC_USERIAL_READ_THREAD_PRIORITY; 406 #endif 407 result = pthread_setschedparam(userial_cb.read_thread, policy, ¶m); 408 if (result != 0) 409 { 410 ALOGW("userial_open: pthread_setschedparam failed (%s)", \ 411 strerror(result)); 412 } 413 } 414 415 return TRUE; 416 } 417 418 /******************************************************************************* 419 ** 420 ** Function userial_read 421 ** 422 ** Description Read data from the userial port 423 ** 424 ** Returns Number of bytes actually read from the userial port and 425 ** copied into p_data. This may be less than len. 426 ** 427 *******************************************************************************/ 428 uint16_t userial_read(uint16_t msg_id, uint8_t *p_buffer, uint16_t len) 429 { 430 uint16_t total_len = 0; 431 uint16_t copy_len = 0; 432 uint8_t *p_data = NULL; 433 434 do 435 { 436 if(userial_cb.p_rx_hdr != NULL) 437 { 438 p_data = ((uint8_t *)(userial_cb.p_rx_hdr + 1)) + \ 439 (userial_cb.p_rx_hdr->offset); 440 441 if((userial_cb.p_rx_hdr->len) <= (len - total_len)) 442 copy_len = userial_cb.p_rx_hdr->len; 443 else 444 copy_len = (len - total_len); 445 446 memcpy((p_buffer + total_len), p_data, copy_len); 447 448 total_len += copy_len; 449 450 userial_cb.p_rx_hdr->offset += copy_len; 451 userial_cb.p_rx_hdr->len -= copy_len; 452 453 if(userial_cb.p_rx_hdr->len == 0) 454 { 455 if (bt_hc_cbacks) 456 bt_hc_cbacks->dealloc((TRANSAC) userial_cb.p_rx_hdr, \ 457 (char *) (userial_cb.p_rx_hdr+1)); 458 459 userial_cb.p_rx_hdr = NULL; 460 } 461 } 462 463 if(userial_cb.p_rx_hdr == NULL) 464 { 465 userial_cb.p_rx_hdr=(HC_BT_HDR *)utils_dequeue(&(userial_cb.rx_q)); 466 } 467 } while ((userial_cb.p_rx_hdr != NULL) && (total_len < len)); 468 469 return total_len; 470 } 471 472 /******************************************************************************* 473 ** 474 ** Function userial_write 475 ** 476 ** Description Write data to the userial port 477 ** 478 ** Returns Number of bytes actually written to the userial port. This 479 ** may be less than len. 480 ** 481 *******************************************************************************/ 482 uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len) 483 { 484 int ret, total = 0; 485 486 while(len != 0) 487 { 488 #if defined(ENABLE_USERIAL_TIMING_LOGS) && (ENABLE_USERIAL_TIMING_LOGS==TRUE) 489 log_userial_tx_timing(len); 490 #endif 491 ret = write(userial_cb.fd, p_data+total, len); 492 total += ret; 493 len -= ret; 494 } 495 496 return ((uint16_t)total); 497 } 498 499 /******************************************************************************* 500 ** 501 ** Function userial_close 502 ** 503 ** Description Close the userial port 504 ** 505 ** Returns None 506 ** 507 *******************************************************************************/ 508 void userial_close(void) 509 { 510 int result; 511 TRANSAC p_buf; 512 513 USERIALDBG("userial_close(fd:%d)", userial_cb.fd); 514 515 if (userial_running) 516 send_wakeup_signal(USERIAL_RX_EXIT); 517 518 if ((result=pthread_join(userial_cb.read_thread, NULL)) < 0) 519 ALOGE( "pthread_join() FAILED result:%d", result); 520 521 /* Calling vendor-specific part */ 522 if (bt_vnd_if) 523 bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL); 524 525 userial_cb.fd = -1; 526 527 if (bt_hc_cbacks) 528 { 529 while ((p_buf = utils_dequeue (&(userial_cb.rx_q))) != NULL) 530 { 531 bt_hc_cbacks->dealloc(p_buf, (char *) ((HC_BT_HDR *)p_buf+1)); 532 } 533 } 534 } 535 536 /******************************************************************************* 537 ** 538 ** Function userial_ioctl 539 ** 540 ** Description ioctl inteface 541 ** 542 ** Returns None 543 ** 544 *******************************************************************************/ 545 void userial_ioctl(userial_ioctl_op_t op, void *p_data) 546 { 547 switch(op) 548 { 549 case USERIAL_OP_RXFLOW_ON: 550 if (userial_running) 551 send_wakeup_signal(USERIAL_RX_FLOW_ON); 552 break; 553 554 case USERIAL_OP_RXFLOW_OFF: 555 if (userial_running) 556 send_wakeup_signal(USERIAL_RX_FLOW_OFF); 557 break; 558 559 case USERIAL_OP_INIT: 560 default: 561 break; 562 } 563 } 564 565