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, &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    {
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