blob: 8e4f8ff76ddd5d66fea3ff65f8db174da31504f9 [file] [log] [blame]
The Android Open Source Project5738f832012-12-12 16:00:35 -08001/******************************************************************************
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
YK Jeffrey Chao67e40772013-05-07 16:28:52 -070050/* Vendor epilog process timeout period */
51#ifndef EPILOG_TIMEOUT_MS
52#define EPILOG_TIMEOUT_MS 3000 // 3 seconds
53#endif
54
The Android Open Source Project5738f832012-12-12 16:00:35 -080055/******************************************************************************
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;
YK Jeffrey Chao48ebe2c2013-04-24 11:38:06 -070078volatile uint8_t fwcfg_acked;
The Android Open Source Project5738f832012-12-12 16:00:35 -080079
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;
YK Jeffrey Chao67e40772013-05-07 16:28:52 -070090 uint8_t epilog_timer_created;
91 timer_t epilog_timer_id;
The Android Open Source Project5738f832012-12-12 16:00:35 -080092} 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
YK Jeffrey Chao67e40772013-05-07 16:28:52 -0700117/*******************************************************************************
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
The Android Open Source Project5738f832012-12-12 16:00:35 -0800174/*****************************************************************************
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
YK Jeffrey Chao67e40772013-05-07 16:28:52 -0700194 hc_cb.epilog_timer_created = 0;
YK Jeffrey Chao48ebe2c2013-04-24 11:38:06 -0700195 fwcfg_acked = FALSE;
YK Jeffrey Chao67e40772013-05-07 16:28:52 -0700196
The Android Open Source Project5738f832012-12-12 16:00:35 -0800197 /* 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, &param)==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, &param);
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 {
YK Jeffrey Chao48ebe2c2013-04-24 11:38:06 -0700366 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 }
YK Jeffrey Chao67e40772013-05-07 16:28:52 -0700375
The Android Open Source Project5738f832012-12-12 16:00:35 -0800376 pthread_join(hc_cb.worker_thread, NULL);
YK Jeffrey Chao67e40772013-05-07 16:28:52 -0700377
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 }
The Android Open Source Project5738f832012-12-12 16:00:35 -0800383 }
384
YK Jeffrey Chao67e40772013-05-07 16:28:52 -0700385 lib_running = 0;
386
The Android Open Source Project5738f832012-12-12 16:00:35 -0800387 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
YK Jeffrey Chao48ebe2c2013-04-24 11:38:06 -0700396 fwcfg_acked = FALSE;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800397 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;
Toshi Kikuchi6ff99442013-02-08 00:13:22 -0800503 int sending_hci_cmd_pkts_count = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800504 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 */
Toshi Kikuchi6ff99442013-02-08 00:13:22 -0800519 if ((tx_cmd_pkts_pending == TRUE) ||
520 (sending_hci_cmd_pkts_count >= num_hci_cmd_pkts))
The Android Open Source Project5738f832012-12-12 16:00:35 -0800521 {
522 tx_cmd_pkts_pending = TRUE;
523 p_next_msg = utils_getnext(p_next_msg);
524 continue;
525 }
Toshi Kikuchi6ff99442013-02-08 00:13:22 -0800526 sending_hci_cmd_pkts_count++;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800527 }
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
YK Jeffrey Chao67e40772013-05-07 16:28:52 -0700568 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
The Android Open Source Project5738f832012-12-12 16:00:35 -0800577 if (events & HC_EVENT_EXIT)
578 break;
579 }
580
581 ALOGI("bt_hc_worker_thread exiting");
YK Jeffrey Chao67e40772013-05-07 16:28:52 -0700582 lib_running = 0;
The Android Open Source Project5738f832012-12-12 16:00:35 -0800583
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