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