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
event_preload(UNUSED_ATTR void * context)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
event_postload(UNUSED_ATTR void * context)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
event_tx(UNUSED_ATTR void * context)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
event_rx(UNUSED_ATTR void * context)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
event_lpm_enable(UNUSED_ATTR void * context)178 static void event_lpm_enable(UNUSED_ATTR void *context) {
179 lpm_enable(true);
180 }
181
event_lpm_disable(UNUSED_ATTR void * context)182 static void event_lpm_disable(UNUSED_ATTR void *context) {
183 lpm_enable(false);
184 }
185
event_lpm_wake_device(UNUSED_ATTR void * context)186 static void event_lpm_wake_device(UNUSED_ATTR void *context) {
187 lpm_wake_assert();
188 }
189
event_lpm_allow_sleep(UNUSED_ATTR void * context)190 static void event_lpm_allow_sleep(UNUSED_ATTR void *context) {
191 lpm_allow_bt_device_sleep();
192 }
193
event_lpm_idle_timeout(UNUSED_ATTR void * context)194 static void event_lpm_idle_timeout(UNUSED_ATTR void *context) {
195 lpm_wake_deassert();
196 }
197
event_epilog(UNUSED_ATTR void * context)198 static void event_epilog(UNUSED_ATTR void *context) {
199 vendor_send_command(BT_VND_OP_EPILOG, NULL);
200 }
201
event_tx_cmd(void * msg)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
bthc_rx_ready(void)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
bthc_tx(HC_BT_HDR * buf)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
bthc_idle_timeout(void)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 *******************************************************************************/
epilog_wait_timeout(UNUSED_ATTR union sigval arg)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 *******************************************************************************/
epilog_wait_timer(void)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
init(const bt_hc_callbacks_t * p_cb,unsigned char * local_bdaddr)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 */
set_power(bt_hc_chip_power_state_t state)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 */
lpm(bt_hc_low_power_event_t event)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 */
preload(UNUSED_ATTR TRANSAC transac)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 */
postload(UNUSED_ATTR TRANSAC transac)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 */
transmit_buf(TRANSAC transac,UNUSED_ATTR char * p_buf,UNUSED_ATTR int len)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 */
logging(bt_hc_logging_state_t state,char * p_path,bool save_existing)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 */
tx_hc_cmd(TRANSAC transac,char * p_buf,int len)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.
cleanup(void)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 *******************************************************************************/
bt_hc_get_interface(void)527 const bt_hc_interface_t *bt_hc_get_interface(void)
528 {
529 return &bluetoothHCLibInterface;
530 }
531