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: bt_hci_bdroid.c 22 * 23 * Description: Bluedroid Bluetooth Host/Controller interface library 24 * implementation 25 * 26 ******************************************************************************/ 27 28 #define LOG_TAG "bt_hci_bdroid" 29 30 #include <assert.h> 31 #include <utils/Log.h> 32 33 #include "btsnoop.h" 34 #include "bt_hci_bdroid.h" 35 #include "bt_utils.h" 36 #include "bt_vendor_lib.h" 37 #include "hci.h" 38 #include "osi.h" 39 #include "thread.h" 40 #include "userial.h" 41 #include "utils.h" 42 #include "vendor.h" 43 44 #ifndef BTHC_DBG 45 #define BTHC_DBG FALSE 46 #endif 47 48 #if (BTHC_DBG == TRUE) 49 #define BTHCDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);} 50 #else 51 #define BTHCDBG(param, ...) {} 52 #endif 53 54 /* Vendor epilog process timeout period */ 55 static const uint32_t EPILOG_TIMEOUT_MS = 3000; 56 57 /****************************************************************************** 58 ** Externs 59 ******************************************************************************/ 60 61 extern int num_hci_cmd_pkts; 62 void lpm_init(void); 63 void lpm_cleanup(void); 64 void lpm_enable(uint8_t turn_on); 65 void lpm_wake_deassert(void); 66 void lpm_allow_bt_device_sleep(void); 67 void lpm_wake_assert(void); 68 void init_vnd_if(unsigned char *local_bdaddr); 69 70 /****************************************************************************** 71 ** Variables 72 ******************************************************************************/ 73 74 bt_hc_callbacks_t *bt_hc_cbacks = NULL; 75 tHCI_IF *p_hci_if; 76 volatile bool fwcfg_acked; 77 // Cleanup state indication. 78 volatile bool has_cleaned_up = false; 79 80 /****************************************************************************** 81 ** Local type definitions 82 ******************************************************************************/ 83 84 /* Host/Controller lib thread control block */ 85 typedef struct 86 { 87 thread_t *worker_thread; 88 pthread_mutex_t worker_thread_lock; 89 bool epilog_timer_created; 90 timer_t epilog_timer_id; 91 } bt_hc_cb_t; 92 93 /****************************************************************************** 94 ** Static Variables 95 ******************************************************************************/ 96 97 static bt_hc_cb_t hc_cb; 98 static bool tx_cmd_pkts_pending = false; 99 static BUFFER_Q tx_q; 100 101 /****************************************************************************** 102 ** Functions 103 ******************************************************************************/ 104 105 static void event_preload(UNUSED_ATTR void *context) { 106 userial_open(USERIAL_PORT_1); 107 vendor_send_command(BT_VND_OP_FW_CFG, NULL); 108 } 109 110 static void event_postload(UNUSED_ATTR void *context) { 111 /* Start from SCO related H/W configuration, if SCO configuration 112 * is required. Then, follow with reading requests of getting 113 * ACL data length for both BR/EDR and LE. 114 */ 115 int result = vendor_send_command(BT_VND_OP_SCO_CFG, NULL); 116 if (result == -1) 117 p_hci_if->get_acl_max_len(); 118 } 119 120 static void event_tx(UNUSED_ATTR void *context) { 121 /* 122 * We will go through every packets in the tx queue. 123 * Fine to clear tx_cmd_pkts_pending. 124 */ 125 tx_cmd_pkts_pending = false; 126 HC_BT_HDR *sending_msg_que[64]; 127 size_t sending_msg_count = 0; 128 int sending_hci_cmd_pkts_count = 0; 129 utils_lock(); 130 HC_BT_HDR *p_next_msg = tx_q.p_first; 131 while (p_next_msg && sending_msg_count < ARRAY_SIZE(sending_msg_que)) 132 { 133 if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD) 134 { 135 /* 136 * if we have used up controller's outstanding HCI command 137 * credits (normally is 1), skip all HCI command packets in 138 * the queue. 139 * The pending command packets will be sent once controller 140 * gives back us credits through CommandCompleteEvent or 141 * CommandStatusEvent. 142 */ 143 if (tx_cmd_pkts_pending || 144 (sending_hci_cmd_pkts_count >= num_hci_cmd_pkts)) 145 { 146 tx_cmd_pkts_pending = true; 147 p_next_msg = utils_getnext(p_next_msg); 148 continue; 149 } 150 sending_hci_cmd_pkts_count++; 151 } 152 153 HC_BT_HDR *p_msg = p_next_msg; 154 p_next_msg = utils_getnext(p_msg); 155 utils_remove_from_queue_unlocked(&tx_q, p_msg); 156 sending_msg_que[sending_msg_count++] = p_msg; 157 } 158 utils_unlock(); 159 for(size_t i = 0; i < sending_msg_count; i++) 160 p_hci_if->send(sending_msg_que[i]); 161 if (tx_cmd_pkts_pending) 162 BTHCDBG("Used up Tx Cmd credits"); 163 } 164 165 static void event_rx(UNUSED_ATTR void *context) { 166 #ifndef HCI_USE_MCT 167 p_hci_if->rcv(); 168 169 if (tx_cmd_pkts_pending && num_hci_cmd_pkts > 0) { 170 // Got HCI Cmd credits from controller. Send whatever data 171 // we have in our tx queue. We can call |event_tx| directly 172 // here since we're already on the worker thread. 173 event_tx(NULL); 174 } 175 #endif 176 } 177 178 static void event_lpm_enable(UNUSED_ATTR void *context) { 179 lpm_enable(true); 180 } 181 182 static void event_lpm_disable(UNUSED_ATTR void *context) { 183 lpm_enable(false); 184 } 185 186 static void event_lpm_wake_device(UNUSED_ATTR void *context) { 187 lpm_wake_assert(); 188 } 189 190 static void event_lpm_allow_sleep(UNUSED_ATTR void *context) { 191 lpm_allow_bt_device_sleep(); 192 } 193 194 static void event_lpm_idle_timeout(UNUSED_ATTR void *context) { 195 lpm_wake_deassert(); 196 } 197 198 static void event_epilog(UNUSED_ATTR void *context) { 199 vendor_send_command(BT_VND_OP_EPILOG, NULL); 200 } 201 202 static void event_tx_cmd(void *msg) { 203 HC_BT_HDR *p_msg = (HC_BT_HDR *)msg; 204 205 BTHCDBG("%s: p_msg: %p, event: 0x%x", __func__, p_msg, p_msg->event); 206 207 int event = p_msg->event & MSG_EVT_MASK; 208 int sub_event = p_msg->event & MSG_SUB_EVT_MASK; 209 if (event == MSG_CTRL_TO_HC_CMD && sub_event == BT_HC_AUDIO_STATE) { 210 vendor_send_command(BT_VND_OP_SET_AUDIO_STATE, p_msg->data); 211 } else { 212 ALOGW("%s (event: 0x%x, sub_event: 0x%x) not supported", __func__, event, sub_event); 213 } 214 215 bt_hc_cbacks->dealloc(msg); 216 } 217 218 void bthc_rx_ready(void) { 219 pthread_mutex_lock(&hc_cb.worker_thread_lock); 220 221 if (hc_cb.worker_thread) 222 thread_post(hc_cb.worker_thread, event_rx, NULL); 223 224 pthread_mutex_unlock(&hc_cb.worker_thread_lock); 225 } 226 227 void bthc_tx(HC_BT_HDR *buf) { 228 pthread_mutex_lock(&hc_cb.worker_thread_lock); 229 230 if (hc_cb.worker_thread) { 231 if (buf) 232 utils_enqueue(&tx_q, buf); 233 thread_post(hc_cb.worker_thread, event_tx, NULL); 234 } 235 236 pthread_mutex_unlock(&hc_cb.worker_thread_lock); 237 } 238 239 void bthc_idle_timeout(void) { 240 pthread_mutex_lock(&hc_cb.worker_thread_lock); 241 242 if (hc_cb.worker_thread) 243 thread_post(hc_cb.worker_thread, event_lpm_idle_timeout, NULL); 244 245 pthread_mutex_unlock(&hc_cb.worker_thread_lock); 246 } 247 248 /******************************************************************************* 249 ** 250 ** Function epilog_wait_timeout 251 ** 252 ** Description Timeout thread of epilog watchdog timer 253 ** 254 ** Returns None 255 ** 256 *******************************************************************************/ 257 static void epilog_wait_timeout(UNUSED_ATTR union sigval arg) 258 { 259 ALOGI("...epilog_wait_timeout..."); 260 261 thread_free(hc_cb.worker_thread); 262 263 pthread_mutex_lock(&hc_cb.worker_thread_lock); 264 hc_cb.worker_thread = NULL; 265 pthread_mutex_unlock(&hc_cb.worker_thread_lock); 266 } 267 268 /******************************************************************************* 269 ** 270 ** Function epilog_wait_timer 271 ** 272 ** Description Launch epilog watchdog timer 273 ** 274 ** Returns None 275 ** 276 *******************************************************************************/ 277 static void epilog_wait_timer(void) 278 { 279 int status; 280 struct itimerspec ts; 281 struct sigevent se; 282 uint32_t timeout_ms = EPILOG_TIMEOUT_MS; 283 284 se.sigev_notify = SIGEV_THREAD; 285 se.sigev_value.sival_ptr = &hc_cb.epilog_timer_id; 286 se.sigev_notify_function = epilog_wait_timeout; 287 se.sigev_notify_attributes = NULL; 288 289 status = timer_create(CLOCK_MONOTONIC, &se, &hc_cb.epilog_timer_id); 290 291 if (status == 0) 292 { 293 hc_cb.epilog_timer_created = true; 294 ts.it_value.tv_sec = timeout_ms/1000; 295 ts.it_value.tv_nsec = 1000000*(timeout_ms%1000); 296 ts.it_interval.tv_sec = 0; 297 ts.it_interval.tv_nsec = 0; 298 299 status = timer_settime(hc_cb.epilog_timer_id, 0, &ts, 0); 300 if (status == -1) 301 ALOGE("Failed to fire epilog watchdog timer"); 302 } 303 else 304 { 305 ALOGE("Failed to create epilog watchdog timer"); 306 hc_cb.epilog_timer_created = false; 307 } 308 } 309 310 /***************************************************************************** 311 ** 312 ** BLUETOOTH HOST/CONTROLLER INTERFACE LIBRARY FUNCTIONS 313 ** 314 *****************************************************************************/ 315 316 static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr) 317 { 318 int result; 319 320 ALOGI("init"); 321 322 if (p_cb == NULL) 323 { 324 ALOGE("init failed with no user callbacks!"); 325 return BT_HC_STATUS_FAIL; 326 } 327 328 hc_cb.epilog_timer_created = false; 329 fwcfg_acked = false; 330 has_cleaned_up = false; 331 332 pthread_mutex_init(&hc_cb.worker_thread_lock, NULL); 333 334 /* store reference to user callbacks */ 335 bt_hc_cbacks = (bt_hc_callbacks_t *) p_cb; 336 337 vendor_open(local_bdaddr); 338 339 utils_init(); 340 #ifdef HCI_USE_MCT 341 extern tHCI_IF hci_mct_func_table; 342 p_hci_if = &hci_mct_func_table; 343 #else 344 extern tHCI_IF hci_h4_func_table; 345 p_hci_if = &hci_h4_func_table; 346 #endif 347 348 p_hci_if->init(); 349 350 userial_init(); 351 lpm_init(); 352 353 utils_queue_init(&tx_q); 354 355 if (hc_cb.worker_thread) 356 { 357 ALOGW("init has been called repeatedly without calling cleanup ?"); 358 } 359 360 // Set prio here and let hci worker thread inherit prio 361 // remove once new thread api (thread_set_priority() ?) 362 // can switch prio 363 raise_priority_a2dp(TASK_HIGH_HCI_WORKER); 364 365 hc_cb.worker_thread = thread_new("bt_hc_worker"); 366 if (!hc_cb.worker_thread) { 367 ALOGE("%s unable to create worker thread.", __func__); 368 return BT_HC_STATUS_FAIL; 369 } 370 371 return BT_HC_STATUS_SUCCESS; 372 } 373 374 375 /** Chip power control */ 376 static void set_power(bt_hc_chip_power_state_t state) 377 { 378 int pwr_state; 379 380 BTHCDBG("set_power %d", state); 381 382 /* Calling vendor-specific part */ 383 pwr_state = (state == BT_HC_CHIP_PWR_ON) ? BT_VND_PWR_ON : BT_VND_PWR_OFF; 384 385 vendor_send_command(BT_VND_OP_POWER_CTRL, &pwr_state); 386 } 387 388 389 /** Configure low power mode wake state */ 390 static int lpm(bt_hc_low_power_event_t event) 391 { 392 switch (event) 393 { 394 case BT_HC_LPM_DISABLE: 395 thread_post(hc_cb.worker_thread, event_lpm_disable, NULL); 396 break; 397 398 case BT_HC_LPM_ENABLE: 399 thread_post(hc_cb.worker_thread, event_lpm_enable, NULL); 400 break; 401 402 case BT_HC_LPM_WAKE_ASSERT: 403 thread_post(hc_cb.worker_thread, event_lpm_wake_device, NULL); 404 break; 405 406 case BT_HC_LPM_WAKE_DEASSERT: 407 thread_post(hc_cb.worker_thread, event_lpm_allow_sleep, NULL); 408 break; 409 } 410 return BT_HC_STATUS_SUCCESS; 411 } 412 413 414 /** Called prior to stack initialization */ 415 static void preload(UNUSED_ATTR TRANSAC transac) { 416 BTHCDBG("preload"); 417 thread_post(hc_cb.worker_thread, event_preload, NULL); 418 } 419 420 /** Called post stack initialization */ 421 static void postload(UNUSED_ATTR TRANSAC transac) { 422 BTHCDBG("postload"); 423 thread_post(hc_cb.worker_thread, event_postload, NULL); 424 } 425 426 /** Transmit frame */ 427 static int transmit_buf(TRANSAC transac, UNUSED_ATTR char *p_buf, UNUSED_ATTR int len) { 428 bthc_tx((HC_BT_HDR *)transac); 429 return BT_HC_STATUS_SUCCESS; 430 } 431 432 /** Controls HCI logging on/off */ 433 static int logging(bt_hc_logging_state_t state, char *p_path, bool save_existing) { 434 BTHCDBG("logging %d", state); 435 436 if (state != BT_HC_LOGGING_ON) 437 btsnoop_close(); 438 else if (p_path != NULL) 439 btsnoop_open(p_path, save_existing); 440 441 return BT_HC_STATUS_SUCCESS; 442 } 443 444 /** sends command HC controller to configure platform specific behaviour */ 445 static int tx_hc_cmd(TRANSAC transac, char *p_buf, int len) { 446 BTHCDBG("tx_hc_cmd: transac %p", transac); 447 448 if (!transac) 449 return BT_HC_STATUS_FAIL; 450 451 thread_post(hc_cb.worker_thread, event_tx_cmd, transac); 452 return BT_HC_STATUS_SUCCESS; 453 } 454 455 // Closes the interface. 456 // This routine is not thread safe. 457 static void cleanup(void) 458 { 459 if (has_cleaned_up) { 460 ALOGW("%s Already cleaned up for this session\n", __func__); 461 return; 462 } 463 464 BTHCDBG("cleanup"); 465 466 if (hc_cb.worker_thread) 467 { 468 if (fwcfg_acked) 469 { 470 epilog_wait_timer(); 471 // Stop reading thread 472 userial_close_reader(); 473 474 thread_post(hc_cb.worker_thread, event_epilog, NULL); 475 } 476 thread_free(hc_cb.worker_thread); 477 478 pthread_mutex_lock(&hc_cb.worker_thread_lock); 479 hc_cb.worker_thread = NULL; 480 pthread_mutex_unlock(&hc_cb.worker_thread_lock); 481 482 if (hc_cb.epilog_timer_created) 483 { 484 timer_delete(hc_cb.epilog_timer_id); 485 hc_cb.epilog_timer_created = false; 486 } 487 } 488 BTHCDBG("%s Finalizing cleanup\n", __func__); 489 490 lpm_cleanup(); 491 userial_close(); 492 p_hci_if->cleanup(); 493 utils_cleanup(); 494 495 set_power(BT_VND_PWR_OFF); 496 vendor_close(); 497 498 pthread_mutex_destroy(&hc_cb.worker_thread_lock); 499 500 fwcfg_acked = false; 501 bt_hc_cbacks = NULL; 502 has_cleaned_up = true; 503 } 504 505 static const bt_hc_interface_t bluetoothHCLibInterface = { 506 sizeof(bt_hc_interface_t), 507 init, 508 set_power, 509 lpm, 510 preload, 511 postload, 512 transmit_buf, 513 logging, 514 cleanup, 515 tx_hc_cmd, 516 }; 517 518 /******************************************************************************* 519 ** 520 ** Function bt_hc_get_interface 521 ** 522 ** Description Caller calls this function to get API instance 523 ** 524 ** Returns API table 525 ** 526 *******************************************************************************/ 527 const bt_hc_interface_t *bt_hc_get_interface(void) 528 { 529 return &bluetoothHCLibInterface; 530 } 531