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, ¶m)==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, ¶m);
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