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 <utils/Log.h> 31#include <pthread.h> 32#include "bt_hci_bdroid.h" 33#include "bt_vendor_lib.h" 34#include "utils.h" 35#include "hci.h" 36#include "userial.h" 37#include "bt_utils.h" 38#include <sys/prctl.h> 39 40#ifndef BTHC_DBG 41#define BTHC_DBG FALSE 42#endif 43 44#if (BTHC_DBG == TRUE) 45#define BTHCDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);} 46#else 47#define BTHCDBG(param, ...) {} 48#endif 49 50/* Vendor epilog process timeout period */ 51#ifndef EPILOG_TIMEOUT_MS 52#define EPILOG_TIMEOUT_MS 3000 // 3 seconds 53#endif 54 55/****************************************************************************** 56** Externs 57******************************************************************************/ 58 59extern bt_vendor_interface_t *bt_vnd_if; 60extern int num_hci_cmd_pkts; 61void lpm_init(void); 62void lpm_cleanup(void); 63void lpm_enable(uint8_t turn_on); 64void lpm_wake_deassert(void); 65void lpm_allow_bt_device_sleep(void); 66void lpm_wake_assert(void); 67void init_vnd_if(unsigned char *local_bdaddr); 68void btsnoop_open(char *p_path); 69void btsnoop_close(void); 70 71/****************************************************************************** 72** Variables 73******************************************************************************/ 74 75bt_hc_callbacks_t *bt_hc_cbacks = NULL; 76BUFFER_Q tx_q; 77tHCI_IF *p_hci_if; 78volatile uint8_t fwcfg_acked; 79 80/****************************************************************************** 81** Local type definitions 82******************************************************************************/ 83 84/* Host/Controller lib thread control block */ 85typedef struct 86{ 87 pthread_t worker_thread; 88 pthread_mutex_t mutex; 89 pthread_cond_t cond; 90 uint8_t epilog_timer_created; 91 timer_t epilog_timer_id; 92} bt_hc_cb_t; 93 94/****************************************************************************** 95** Static Variables 96******************************************************************************/ 97 98static bt_hc_cb_t hc_cb; 99static volatile uint8_t lib_running = 0; 100static volatile uint16_t ready_events = 0; 101static volatile uint8_t tx_cmd_pkts_pending = FALSE; 102 103/****************************************************************************** 104** Functions 105******************************************************************************/ 106 107static void *bt_hc_worker_thread(void *arg); 108 109void bthc_signal_event(uint16_t event) 110{ 111 pthread_mutex_lock(&hc_cb.mutex); 112 ready_events |= event; 113 pthread_cond_signal(&hc_cb.cond); 114 pthread_mutex_unlock(&hc_cb.mutex); 115} 116 117/******************************************************************************* 118** 119** Function epilog_wait_timeout 120** 121** Description Timeout thread of epilog watchdog timer 122** 123** Returns None 124** 125*******************************************************************************/ 126static void epilog_wait_timeout(union sigval arg) 127{ 128 ALOGI("...epilog_wait_timeout..."); 129 bthc_signal_event(HC_EVENT_EXIT); 130} 131 132/******************************************************************************* 133** 134** Function epilog_wait_timer 135** 136** Description Launch epilog watchdog timer 137** 138** Returns None 139** 140*******************************************************************************/ 141static void epilog_wait_timer(void) 142{ 143 int status; 144 struct itimerspec ts; 145 struct sigevent se; 146 uint32_t timeout_ms = EPILOG_TIMEOUT_MS; 147 148 se.sigev_notify = SIGEV_THREAD; 149 se.sigev_value.sival_ptr = &hc_cb.epilog_timer_id; 150 se.sigev_notify_function = epilog_wait_timeout; 151 se.sigev_notify_attributes = NULL; 152 153 status = timer_create(CLOCK_MONOTONIC, &se, &hc_cb.epilog_timer_id); 154 155 if (status == 0) 156 { 157 hc_cb.epilog_timer_created = 1; 158 ts.it_value.tv_sec = timeout_ms/1000; 159 ts.it_value.tv_nsec = 1000000*(timeout_ms%1000); 160 ts.it_interval.tv_sec = 0; 161 ts.it_interval.tv_nsec = 0; 162 163 status = timer_settime(hc_cb.epilog_timer_id, 0, &ts, 0); 164 if (status == -1) 165 ALOGE("Failed to fire epilog watchdog timer"); 166 } 167 else 168 { 169 ALOGE("Failed to create epilog watchdog timer"); 170 hc_cb.epilog_timer_created = 0; 171 } 172} 173 174/***************************************************************************** 175** 176** BLUETOOTH HOST/CONTROLLER INTERFACE LIBRARY FUNCTIONS 177** 178*****************************************************************************/ 179 180static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr) 181{ 182 pthread_attr_t thread_attr; 183 struct sched_param param; 184 int policy, result; 185 186 ALOGI("init"); 187 188 if (p_cb == NULL) 189 { 190 ALOGE("init failed with no user callbacks!"); 191 return BT_HC_STATUS_FAIL; 192 } 193 194 hc_cb.epilog_timer_created = 0; 195 fwcfg_acked = FALSE; 196 197 /* store reference to user callbacks */ 198 bt_hc_cbacks = (bt_hc_callbacks_t *) p_cb; 199 200 init_vnd_if(local_bdaddr); 201 202 utils_init(); 203#ifdef HCI_USE_MCT 204 extern tHCI_IF hci_mct_func_table; 205 p_hci_if = &hci_mct_func_table; 206#else 207 extern tHCI_IF hci_h4_func_table; 208 p_hci_if = &hci_h4_func_table; 209#endif 210 211 p_hci_if->init(); 212 213 userial_init(); 214 lpm_init(); 215 216 utils_queue_init(&tx_q); 217 218 if (lib_running) 219 { 220 ALOGW("init has been called repeatedly without calling cleanup ?"); 221 } 222 223 lib_running = 1; 224 ready_events = 0; 225 pthread_mutex_init(&hc_cb.mutex, NULL); 226 pthread_cond_init(&hc_cb.cond, NULL); 227 pthread_attr_init(&thread_attr); 228 229 if (pthread_create(&hc_cb.worker_thread, &thread_attr, \ 230 bt_hc_worker_thread, NULL) != 0) 231 { 232 ALOGE("pthread_create failed!"); 233 lib_running = 0; 234 return BT_HC_STATUS_FAIL; 235 } 236 237 if(pthread_getschedparam(hc_cb.worker_thread, &policy, ¶m)==0) 238 { 239 policy = BTHC_LINUX_BASE_POLICY; 240#if (BTHC_LINUX_BASE_POLICY!=SCHED_NORMAL) 241 param.sched_priority = BTHC_MAIN_THREAD_PRIORITY; 242#endif 243 result = pthread_setschedparam(hc_cb.worker_thread, policy, ¶m); 244 if (result != 0) 245 { 246 ALOGW("libbt-hci init: pthread_setschedparam failed (%s)", \ 247 strerror(result)); 248 } 249 } 250 251 return BT_HC_STATUS_SUCCESS; 252} 253 254 255/** Chip power control */ 256static void set_power(bt_hc_chip_power_state_t state) 257{ 258 int pwr_state; 259 260 BTHCDBG("set_power %d", state); 261 262 /* Calling vendor-specific part */ 263 pwr_state = (state == BT_HC_CHIP_PWR_ON) ? BT_VND_PWR_ON : BT_VND_PWR_OFF; 264 265 if (bt_vnd_if) 266 bt_vnd_if->op(BT_VND_OP_POWER_CTRL, &pwr_state); 267 else 268 ALOGE("vendor lib is missing!"); 269} 270 271 272/** Configure low power mode wake state */ 273static int lpm(bt_hc_low_power_event_t event) 274{ 275 uint8_t status = TRUE; 276 277 switch (event) 278 { 279 case BT_HC_LPM_DISABLE: 280 bthc_signal_event(HC_EVENT_LPM_DISABLE); 281 break; 282 283 case BT_HC_LPM_ENABLE: 284 bthc_signal_event(HC_EVENT_LPM_ENABLE); 285 break; 286 287 case BT_HC_LPM_WAKE_ASSERT: 288 bthc_signal_event(HC_EVENT_LPM_WAKE_DEVICE); 289 break; 290 291 case BT_HC_LPM_WAKE_DEASSERT: 292 bthc_signal_event(HC_EVENT_LPM_ALLOW_SLEEP); 293 break; 294 } 295 296 return(status == TRUE) ? BT_HC_STATUS_SUCCESS : BT_HC_STATUS_FAIL; 297} 298 299 300/** Called prio to stack initialization */ 301static void preload(TRANSAC transac) 302{ 303 BTHCDBG("preload"); 304 bthc_signal_event(HC_EVENT_PRELOAD); 305} 306 307 308/** Called post stack initialization */ 309static void postload(TRANSAC transac) 310{ 311 BTHCDBG("postload"); 312 bthc_signal_event(HC_EVENT_POSTLOAD); 313} 314 315 316/** Transmit frame */ 317static int transmit_buf(TRANSAC transac, char *p_buf, int len) 318{ 319 utils_enqueue(&tx_q, (void *) transac); 320 321 bthc_signal_event(HC_EVENT_TX); 322 323 return BT_HC_STATUS_SUCCESS; 324} 325 326 327/** Controls receive flow */ 328static int set_rxflow(bt_rx_flow_state_t state) 329{ 330 BTHCDBG("set_rxflow %d", state); 331 332 userial_ioctl(\ 333 ((state == BT_RXFLOW_ON) ? USERIAL_OP_RXFLOW_ON : USERIAL_OP_RXFLOW_OFF), \ 334 NULL); 335 336 return BT_HC_STATUS_SUCCESS; 337} 338 339 340/** Controls HCI logging on/off */ 341static int logging(bt_hc_logging_state_t state, char *p_path) 342{ 343 BTHCDBG("logging %d", state); 344 345 if (state == BT_HC_LOGGING_ON) 346 { 347 if (p_path != NULL) 348 btsnoop_open(p_path); 349 } 350 else 351 { 352 btsnoop_close(); 353 } 354 355 return BT_HC_STATUS_SUCCESS; 356} 357 358 359/** Closes the interface */ 360static void cleanup( void ) 361{ 362 BTHCDBG("cleanup"); 363 364 if (lib_running) 365 { 366 if (fwcfg_acked == TRUE) 367 { 368 epilog_wait_timer(); 369 bthc_signal_event(HC_EVENT_EPILOG); 370 } 371 else 372 { 373 bthc_signal_event(HC_EVENT_EXIT); 374 } 375 376 pthread_join(hc_cb.worker_thread, NULL); 377 378 if (hc_cb.epilog_timer_created == 1) 379 { 380 timer_delete(hc_cb.epilog_timer_id); 381 hc_cb.epilog_timer_created = 0; 382 } 383 } 384 385 lib_running = 0; 386 387 lpm_cleanup(); 388 userial_close(); 389 p_hci_if->cleanup(); 390 utils_cleanup(); 391 392 /* Calling vendor-specific part */ 393 if (bt_vnd_if) 394 bt_vnd_if->cleanup(); 395 396 fwcfg_acked = FALSE; 397 bt_hc_cbacks = NULL; 398} 399 400 401static const bt_hc_interface_t bluetoothHCLibInterface = { 402 sizeof(bt_hc_interface_t), 403 init, 404 set_power, 405 lpm, 406 preload, 407 postload, 408 transmit_buf, 409 set_rxflow, 410 logging, 411 cleanup 412}; 413 414 415/******************************************************************************* 416** 417** Function bt_hc_worker_thread 418** 419** Description Mian worker thread 420** 421** Returns void * 422** 423*******************************************************************************/ 424static void *bt_hc_worker_thread(void *arg) 425{ 426 uint16_t events; 427 HC_BT_HDR *p_msg, *p_next_msg; 428 429 ALOGI("bt_hc_worker_thread started"); 430 prctl(PR_SET_NAME, (unsigned long)"bt_hc_worker", 0, 0, 0); 431 tx_cmd_pkts_pending = FALSE; 432 433 raise_priority_a2dp(TASK_HIGH_HCI_WORKER); 434 435 while (lib_running) 436 { 437 pthread_mutex_lock(&hc_cb.mutex); 438 while (ready_events == 0) 439 { 440 pthread_cond_wait(&hc_cb.cond, &hc_cb.mutex); 441 } 442 events = ready_events; 443 ready_events = 0; 444 pthread_mutex_unlock(&hc_cb.mutex); 445 446#ifndef HCI_USE_MCT 447 if (events & HC_EVENT_RX) 448 { 449 p_hci_if->rcv(); 450 451 if ((tx_cmd_pkts_pending == TRUE) && (num_hci_cmd_pkts > 0)) 452 { 453 /* Got HCI Cmd Credits from Controller. 454 * Prepare to send prior pending Cmd packets in the 455 * following HC_EVENT_TX session. 456 */ 457 events |= HC_EVENT_TX; 458 } 459 } 460#endif 461 462 if (events & HC_EVENT_PRELOAD) 463 { 464 userial_open(USERIAL_PORT_1); 465 466 /* Calling vendor-specific part */ 467 if (bt_vnd_if) 468 { 469 bt_vnd_if->op(BT_VND_OP_FW_CFG, NULL); 470 } 471 else 472 { 473 if (bt_hc_cbacks) 474 bt_hc_cbacks->preload_cb(NULL, BT_HC_PRELOAD_FAIL); 475 } 476 } 477 478 if (events & HC_EVENT_POSTLOAD) 479 { 480 /* Start from SCO related H/W configuration, if SCO configuration 481 * is required. Then, follow with reading requests of getting 482 * ACL data length for both BR/EDR and LE. 483 */ 484 int result = -1; 485 486 /* Calling vendor-specific part */ 487 if (bt_vnd_if) 488 result = bt_vnd_if->op(BT_VND_OP_SCO_CFG, NULL); 489 490 if (result == -1) 491 p_hci_if->get_acl_max_len(); 492 } 493 494 if (events & HC_EVENT_TX) 495 { 496 /* 497 * We will go through every packets in the tx queue. 498 * Fine to clear tx_cmd_pkts_pending. 499 */ 500 tx_cmd_pkts_pending = FALSE; 501 HC_BT_HDR * sending_msg_que[64]; 502 int sending_msg_count = 0; 503 int sending_hci_cmd_pkts_count = 0; 504 utils_lock(); 505 p_next_msg = tx_q.p_first; 506 while (p_next_msg && sending_msg_count < 507 (int)sizeof(sending_msg_que)/sizeof(sending_msg_que[0])) 508 { 509 if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD) 510 { 511 /* 512 * if we have used up controller's outstanding HCI command 513 * credits (normally is 1), skip all HCI command packets in 514 * the queue. 515 * The pending command packets will be sent once controller 516 * gives back us credits through CommandCompleteEvent or 517 * CommandStatusEvent. 518 */ 519 if ((tx_cmd_pkts_pending == TRUE) || 520 (sending_hci_cmd_pkts_count >= num_hci_cmd_pkts)) 521 { 522 tx_cmd_pkts_pending = TRUE; 523 p_next_msg = utils_getnext(p_next_msg); 524 continue; 525 } 526 sending_hci_cmd_pkts_count++; 527 } 528 529 p_msg = p_next_msg; 530 p_next_msg = utils_getnext(p_msg); 531 utils_remove_from_queue_unlocked(&tx_q, p_msg); 532 sending_msg_que[sending_msg_count++] = p_msg; 533 } 534 utils_unlock(); 535 int i; 536 for(i = 0; i < sending_msg_count; i++) 537 p_hci_if->send(sending_msg_que[i]); 538 if (tx_cmd_pkts_pending == TRUE) 539 BTHCDBG("Used up Tx Cmd credits"); 540 541 } 542 543 if (events & HC_EVENT_LPM_ENABLE) 544 { 545 lpm_enable(TRUE); 546 } 547 548 if (events & HC_EVENT_LPM_DISABLE) 549 { 550 lpm_enable(FALSE); 551 } 552 553 if (events & HC_EVENT_LPM_IDLE_TIMEOUT) 554 { 555 lpm_wake_deassert(); 556 } 557 558 if (events & HC_EVENT_LPM_ALLOW_SLEEP) 559 { 560 lpm_allow_bt_device_sleep(); 561 } 562 563 if (events & HC_EVENT_LPM_WAKE_DEVICE) 564 { 565 lpm_wake_assert(); 566 } 567 568 if (events & HC_EVENT_EPILOG) 569 { 570 /* Calling vendor-specific part */ 571 if (bt_vnd_if) 572 bt_vnd_if->op(BT_VND_OP_EPILOG, NULL); 573 else 574 break; // equivalent to HC_EVENT_EXIT 575 } 576 577 if (events & HC_EVENT_EXIT) 578 break; 579 } 580 581 ALOGI("bt_hc_worker_thread exiting"); 582 lib_running = 0; 583 584 pthread_exit(NULL); 585 586 return NULL; // compiler friendly 587} 588 589 590/******************************************************************************* 591** 592** Function bt_hc_get_interface 593** 594** Description Caller calls this function to get API instance 595** 596** Returns API table 597** 598*******************************************************************************/ 599const bt_hc_interface_t *bt_hc_get_interface(void) 600{ 601 return &bluetoothHCLibInterface; 602} 603 604