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_mct.c 22 * 23 * Description: Contains open/read/write/close functions on multi-channels 24 * 25 ******************************************************************************/ 26 27 #define LOG_TAG "bt_userial_mct" 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 "bt_utils.h" 40 41 /****************************************************************************** 42 ** Constants & Macros 43 ******************************************************************************/ 44 45 #define USERIAL_DBG TRUE 46 47 #ifndef USERIAL_DBG 48 #define USERIAL_DBG FALSE 49 #endif 50 51 #if (USERIAL_DBG == TRUE) 52 #define USERIALDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);} 53 #else 54 #define USERIALDBG(param, ...) {} 55 #endif 56 57 #define MAX_SERIAL_PORT (USERIAL_PORT_3 + 1) 58 59 enum { 60 USERIAL_RX_EXIT, 61 USERIAL_RX_FLOW_OFF, 62 USERIAL_RX_FLOW_ON 63 }; 64 65 /****************************************************************************** 66 ** Externs 67 ******************************************************************************/ 68 69 extern bt_vendor_interface_t *bt_vnd_if; 70 uint16_t hci_mct_receive_evt_msg(void); 71 uint16_t hci_mct_receive_acl_msg(void); 72 73 74 /****************************************************************************** 75 ** Local type definitions 76 ******************************************************************************/ 77 78 typedef struct 79 { 80 int fd[CH_MAX]; 81 uint8_t port; 82 pthread_t read_thread; 83 BUFFER_Q rx_q; 84 HC_BT_HDR *p_rx_hdr; 85 } tUSERIAL_CB; 86 87 /****************************************************************************** 88 ** Static variables 89 ******************************************************************************/ 90 91 static tUSERIAL_CB userial_cb; 92 static volatile uint8_t userial_running = 0; 93 94 /****************************************************************************** 95 ** Static functions 96 ******************************************************************************/ 97 98 /***************************************************************************** 99 ** Socket signal functions to wake up userial_read_thread for termination 100 ** 101 ** creating an unnamed pair of connected sockets 102 ** - signal_fds[0]: join fd_set in select call of userial_read_thread 103 ** - signal_fds[1]: trigger from userial_close 104 *****************************************************************************/ 105 static int signal_fds[2]={0,1}; 106 static uint8_t rx_flow_on = TRUE; 107 static inline int create_signal_fds(fd_set* set) 108 { 109 if(signal_fds[0]==0 && socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fds)<0) 110 { 111 ALOGE("create_signal_sockets:socketpair failed, errno: %d", errno); 112 return -1; 113 } 114 FD_SET(signal_fds[0], set); 115 return signal_fds[0]; 116 } 117 static inline int send_wakeup_signal(char sig_cmd) 118 { 119 return send(signal_fds[1], &sig_cmd, sizeof(sig_cmd), 0); 120 } 121 static inline char reset_signal() 122 { 123 char sig_recv = -1; 124 recv(signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL); 125 return sig_recv; 126 } 127 static inline int is_signaled(fd_set* set) 128 { 129 return FD_ISSET(signal_fds[0], set); 130 } 131 132 /******************************************************************************* 133 ** 134 ** Function userial_evt_read_thread 135 ** 136 ** Description The reading thread on EVT and ACL_IN channels 137 ** 138 ** Returns void * 139 ** 140 *******************************************************************************/ 141 static void *userial_read_thread(void *arg) 142 { 143 fd_set input; 144 int n; 145 char reason = 0; 146 147 USERIALDBG("Entering userial_read_thread()"); 148 149 rx_flow_on = TRUE; 150 userial_running = 1; 151 152 raise_priority_a2dp(TASK_HIGH_USERIAL_READ); 153 154 while (userial_running) 155 { 156 /* Initialize the input fd set */ 157 FD_ZERO(&input); 158 if (rx_flow_on == TRUE) 159 { 160 FD_SET(userial_cb.fd[CH_EVT], &input); 161 FD_SET(userial_cb.fd[CH_ACL_IN], &input); 162 } 163 164 int fd_max = create_signal_fds(&input); 165 fd_max = (fd_max>userial_cb.fd[CH_EVT]) ? fd_max : userial_cb.fd[CH_EVT]; 166 fd_max = (fd_max>userial_cb.fd[CH_ACL_IN]) ? fd_max : userial_cb.fd[CH_ACL_IN]; 167 168 /* Do the select */ 169 n = 0; 170 n = select(fd_max+1, &input, NULL, NULL, NULL); 171 if(is_signaled(&input)) 172 { 173 reason = reset_signal(); 174 if (reason == USERIAL_RX_EXIT) 175 { 176 ALOGI("exiting userial_read_thread"); 177 userial_running = 0; 178 break; 179 } 180 else if (reason == USERIAL_RX_FLOW_OFF) 181 { 182 USERIALDBG("RX flow OFF"); 183 rx_flow_on = FALSE; 184 } 185 else if (reason == USERIAL_RX_FLOW_ON) 186 { 187 USERIALDBG("RX flow ON"); 188 rx_flow_on = TRUE; 189 } 190 } 191 192 if (n > 0) 193 { 194 /* We might have input */ 195 if (FD_ISSET(userial_cb.fd[CH_EVT], &input)) 196 { 197 hci_mct_receive_evt_msg(); 198 } 199 200 if (FD_ISSET(userial_cb.fd[CH_ACL_IN], &input)) 201 { 202 hci_mct_receive_acl_msg(); 203 } 204 } 205 else if (n < 0) 206 ALOGW( "select() Failed"); 207 else if (n == 0) 208 ALOGW( "Got a select() TIMEOUT"); 209 } /* while */ 210 211 userial_running = 0; 212 USERIALDBG("Leaving userial_evt_read_thread()"); 213 pthread_exit(NULL); 214 215 return NULL; // Compiler friendly 216 } 217 218 219 /***************************************************************************** 220 ** Userial API Functions 221 *****************************************************************************/ 222 223 /******************************************************************************* 224 ** 225 ** Function userial_init 226 ** 227 ** Description Initializes the userial driver 228 ** 229 ** Returns TRUE/FALSE 230 ** 231 *******************************************************************************/ 232 uint8_t userial_init(void) 233 { 234 int idx; 235 236 USERIALDBG("userial_init"); 237 memset(&userial_cb, 0, sizeof(tUSERIAL_CB)); 238 for (idx=0; idx < CH_MAX; idx++) 239 userial_cb.fd[idx] = -1; 240 utils_queue_init(&(userial_cb.rx_q)); 241 return TRUE; 242 } 243 244 245 /******************************************************************************* 246 ** 247 ** Function userial_open 248 ** 249 ** Description Open Bluetooth device with the port ID 250 ** 251 ** Returns TRUE/FALSE 252 ** 253 *******************************************************************************/ 254 uint8_t userial_open(uint8_t port) 255 { 256 struct sched_param param; 257 int policy, result; 258 pthread_attr_t thread_attr; 259 260 USERIALDBG("userial_open(port:%d)", port); 261 262 if (userial_running) 263 { 264 /* Userial is open; close it first */ 265 userial_close(); 266 utils_delay(50); 267 } 268 269 if (port >= MAX_SERIAL_PORT) 270 { 271 ALOGE("Port > MAX_SERIAL_PORT"); 272 return FALSE; 273 } 274 275 /* Calling vendor-specific part */ 276 if (bt_vnd_if) 277 { 278 result = bt_vnd_if->op(BT_VND_OP_USERIAL_OPEN, &userial_cb.fd); 279 280 if ((result != 2) && (result != 4)) 281 { 282 ALOGE("userial_open: wrong numbers of open fd in vendor lib [%d]!", 283 result); 284 ALOGE("userial_open: HCI MCT expects 2 or 4 open file descriptors"); 285 bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL); 286 return FALSE; 287 } 288 } 289 else 290 { 291 ALOGE("userial_open: missing vendor lib interface !!!"); 292 ALOGE("userial_open: unable to open BT transport"); 293 return FALSE; 294 } 295 296 ALOGI("CMD=%d, EVT=%d, ACL_Out=%d, ACL_In=%d", \ 297 userial_cb.fd[CH_CMD], userial_cb.fd[CH_EVT], \ 298 userial_cb.fd[CH_ACL_OUT], userial_cb.fd[CH_ACL_IN]); 299 300 if ((userial_cb.fd[CH_CMD] == -1) || (userial_cb.fd[CH_EVT] == -1) || 301 (userial_cb.fd[CH_ACL_OUT] == -1) || (userial_cb.fd[CH_ACL_IN] == -1)) 302 { 303 ALOGE("userial_open: failed to open BT transport"); 304 bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL); 305 return FALSE; 306 } 307 308 userial_cb.port = port; 309 310 /* Start listening thread */ 311 pthread_attr_init(&thread_attr); 312 313 if (pthread_create(&(userial_cb.read_thread), &thread_attr, \ 314 userial_read_thread, NULL) != 0 ) 315 { 316 ALOGE("pthread_create failed!"); 317 bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL); 318 return FALSE; 319 } 320 321 if(pthread_getschedparam(userial_cb.read_thread, &policy, ¶m)==0) 322 { 323 policy = BTHC_LINUX_BASE_POLICY; 324 #if (BTHC_LINUX_BASE_POLICY!=SCHED_NORMAL) 325 param.sched_priority = BTHC_USERIAL_READ_THREAD_PRIORITY; 326 #endif 327 result=pthread_setschedparam(userial_cb.read_thread,policy,¶m); 328 if (result != 0) 329 { 330 ALOGW("userial_open: pthread_setschedparam failed (%s)", \ 331 strerror(result)); 332 } 333 } 334 335 return TRUE; 336 } 337 338 /******************************************************************************* 339 ** 340 ** Function userial_read 341 ** 342 ** Description Read data from the userial channel 343 ** 344 ** Returns Number of bytes actually read from the userial port and 345 ** copied into p_data. This may be less than len. 346 ** 347 *******************************************************************************/ 348 uint16_t userial_read(uint16_t msg_id, uint8_t *p_buffer, uint16_t len) 349 { 350 int ret = -1; 351 int ch_idx = (msg_id == MSG_HC_TO_STACK_HCI_EVT) ? CH_EVT : CH_ACL_IN; 352 353 ret = read(userial_cb.fd[ch_idx], p_buffer, (size_t)len); 354 if (ret <= 0) 355 ALOGW( "userial_read: read() returned %d!", ret); 356 357 return (uint16_t) ((ret >= 0) ? ret : 0); 358 } 359 360 /******************************************************************************* 361 ** 362 ** Function userial_write 363 ** 364 ** Description Write data to the userial port 365 ** 366 ** Returns Number of bytes actually written to the userial port. This 367 ** may be less than len. 368 ** 369 *******************************************************************************/ 370 uint16_t userial_write(uint16_t msg_id, uint8_t *p_data, uint16_t len) 371 { 372 int ret, total = 0; 373 int ch_idx = (msg_id == MSG_STACK_TO_HC_HCI_CMD) ? CH_CMD : CH_ACL_OUT; 374 375 while(len != 0) 376 { 377 ret = write(userial_cb.fd[ch_idx], p_data+total, len); 378 total += ret; 379 len -= ret; 380 } 381 382 return ((uint16_t)total); 383 } 384 385 /******************************************************************************* 386 ** 387 ** Function userial_close 388 ** 389 ** Description Close the userial port 390 ** 391 ** Returns None 392 ** 393 *******************************************************************************/ 394 void userial_close(void) 395 { 396 int idx, result; 397 398 USERIALDBG("userial_close"); 399 400 if (userial_running) 401 send_wakeup_signal(USERIAL_RX_EXIT); 402 403 if ((result=pthread_join(userial_cb.read_thread, NULL)) < 0) 404 ALOGE( "pthread_join() FAILED result:%d", result); 405 406 /* Calling vendor-specific part */ 407 if (bt_vnd_if) 408 bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL); 409 410 for (idx=0; idx < CH_MAX; idx++) 411 userial_cb.fd[idx] = -1; 412 } 413 414 /******************************************************************************* 415 ** 416 ** Function userial_ioctl 417 ** 418 ** Description ioctl inteface 419 ** 420 ** Returns None 421 ** 422 *******************************************************************************/ 423 void userial_ioctl(userial_ioctl_op_t op, void *p_data) 424 { 425 switch(op) 426 { 427 case USERIAL_OP_RXFLOW_ON: 428 if (userial_running) 429 send_wakeup_signal(USERIAL_RX_FLOW_ON); 430 break; 431 432 case USERIAL_OP_RXFLOW_OFF: 433 if (userial_running) 434 send_wakeup_signal(USERIAL_RX_FLOW_OFF); 435 break; 436 437 case USERIAL_OP_INIT: 438 default: 439 break; 440 } 441 } 442 443