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