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