summaryrefslogtreecommitdiffstats
path: root/hci
diff options
context:
space:
mode:
authorYK Jeffrey Chao <jechao@broadcom.com>2012-04-23 11:28:18 -0700
committerMatthew Xie <mattx@google.com>2012-07-14 11:19:20 -0700
commit32f0db60f911ed0b7f3bca0210a4568621b99074 (patch)
tree5e41addd71324439e3bbaa2a9fe5978c262311e4 /hci
parenta4b46830e5efa9b753a692b98971d1f5a9975905 (diff)
downloadexternal_bluetooth_bluedroid-32f0db60f911ed0b7f3bca0210a4568621b99074.zip
external_bluetooth_bluedroid-32f0db60f911ed0b7f3bca0210a4568621b99074.tar.gz
external_bluetooth_bluedroid-32f0db60f911ed0b7f3bca0210a4568621b99074.tar.bz2
Split and restructure the original BT vendor lib (I - external/bluetooth/bluedroid).
1. Split the original external/bluetooth/bluedroid/vendor directory to two parts: external/bluetooth/bluedroid/hci and vendor/broadcom/libbt-vendor. Each part produces a .so library (libbt-hci.so and libbt-vendor.so). 2. libbt-hci.so contains: + HCI H4 send & receive functions + Userial read & write functions + LPM common logic operations + btsnoop functions. 3. No build-time (.txt) and run-time (.conf) configuration for libbt-hci.so. 4. libbt-vendor.so contains: + firmware patch download function + SCO configuration + LPM VSC and BT_WAKE control + UART port open + upio control for BT chip power on/off. 5. libbt-vendor.so has build-time and run-time configuration support. Change-Id: I61d55c75c66d25459d80893a5f72bccce2b54770
Diffstat (limited to 'hci')
-rw-r--r--hci/Android.mk25
-rw-r--r--hci/include/bt_hci_bdroid.h182
-rw-r--r--hci/include/bt_hci_lib.h231
-rw-r--r--hci/include/bt_vendor_lib.h171
-rw-r--r--hci/include/userial.h224
-rw-r--r--hci/include/utils.h200
-rw-r--r--hci/src/bt_hci_bdroid.c521
-rw-r--r--hci/src/bt_hw.c250
-rw-r--r--hci/src/btsnoop.c717
-rw-r--r--hci/src/hci_h4.c1074
-rw-r--r--hci/src/lpm.c453
-rw-r--r--hci/src/userial.c597
-rw-r--r--hci/src/utils.c315
13 files changed, 4960 insertions, 0 deletions
diff --git a/hci/Android.mk b/hci/Android.mk
new file mode 100644
index 0000000..a500538
--- /dev/null
+++ b/hci/Android.mk
@@ -0,0 +1,25 @@
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ src/bt_hci_bdroid.c \
+ src/hci_h4.c \
+ src/userial.c \
+ src/lpm.c \
+ src/bt_hw.c \
+ src/btsnoop.c \
+ src/utils.c
+
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/include
+
+LOCAL_SHARED_LIBRARIES := \
+ libcutils \
+ libbt-vendor
+
+LOCAL_MODULE := libbt-hci
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/hci/include/bt_hci_bdroid.h b/hci/include/bt_hci_bdroid.h
new file mode 100644
index 0000000..2345e74
--- /dev/null
+++ b/hci/include/bt_hci_bdroid.h
@@ -0,0 +1,182 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: bt_hci_bdroid.h
+ *
+ * Description: A wrapper header file of bt_hci_lib.h
+ *
+ * Contains definitions specific for interfacing with Bluedroid
+ * Bluetooth stack
+ *
+ ******************************************************************************/
+
+#ifndef BT_HCI_BDROID_H
+#define BT_HCI_BDROID_H
+
+#include "bt_hci_lib.h"
+//#include "hci_buildcfg.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#ifndef TRUE
+#define TRUE (!FALSE)
+#endif
+
+#ifndef BTHC_LINUX_BASE_POLICY
+#define BTHC_LINUX_BASE_POLICY SCHED_NORMAL
+#endif
+
+#if (BTHC_LINUX_BASE_POLICY != SCHED_NORMAL)
+#ifndef BTHC_LINUX_BASE_PRIORITY
+#define BTHC_LINUX_BASE_PRIORITY 30
+#endif
+
+#ifndef BTHC_USERIAL_READ_THREAD_PRIORITY
+#define BTHC_USERIAL_READ_THREAD_PRIORITY (BTHC_LINUX_BASE_PRIORITY)
+#endif
+
+#ifndef BTHC_MAIN_THREAD_PRIORITY
+#define BTHC_MAIN_THREAD_PRIORITY (BTHC_LINUX_BASE_PRIORITY-1)
+#endif
+#endif // (BTHC_LINUX_BASE_POLICY != SCHED_NORMAL)
+
+#ifndef BTHC_USERIAL_READ_MEM_SIZE
+#define BTHC_USERIAL_READ_MEM_SIZE (1024)
+#endif
+
+#ifndef BTSNOOPDISP_INCLUDED
+#define BTSNOOPDISP_INCLUDED TRUE
+#endif
+
+/* Host/Controller lib internal event ID */
+#define HC_EVENT_PRELOAD 0x0001
+#define HC_EVENT_POSTLOAD 0x0002
+#define HC_EVENT_RX 0x0004
+#define HC_EVENT_TX 0x0008
+#define HC_EVENT_LPM_ENABLE 0x0010
+#define HC_EVENT_LPM_DISABLE 0x0020
+#define HC_EVENT_LPM_WAKE_DEVICE 0x0040
+#define HC_EVENT_LPM_ALLOW_SLEEP 0x0080
+#define HC_EVENT_LPM_IDLE_TIMEOUT 0x0100
+#define HC_EVENT_EXIT 0x0200
+
+/* Message event mask across Host/Controller lib and stack */
+#define MSG_EVT_MASK 0xFF00 /* eq. BT_EVT_MASK */
+#define MSG_SUB_EVT_MASK 0x00FF /* eq. BT_SUB_EVT_MASK */
+
+/* Message event ID passed from Host/Controller lib to stack */
+#define MSG_HC_TO_STACK_HCI_ERR 0x1300 /* eq. BT_EVT_TO_BTU_HCIT_ERR */
+#define MSG_HC_TO_STACK_HCI_ACL 0x1100 /* eq. BT_EVT_TO_BTU_HCI_ACL */
+#define MSG_HC_TO_STACK_HCI_SCO 0x1200 /* eq. BT_EVT_TO_BTU_HCI_SCO */
+#define MSG_HC_TO_STACK_HCI_EVT 0x1000 /* eq. BT_EVT_TO_BTU_HCI_EVT */
+#define MSG_HC_TO_STACK_L2C_SEG_XMIT 0x1900 /* eq. BT_EVT_TO_BTU_L2C_SEG_XMIT */
+
+/* Message event ID passed from stack to vendor lib */
+#define MSG_STACK_TO_HC_HCI_ACL 0x2100 /* eq. BT_EVT_TO_LM_HCI_ACL */
+#define MSG_STACK_TO_HC_HCI_SCO 0x2200 /* eq. BT_EVT_TO_LM_HCI_SCO */
+#define MSG_STACK_TO_HC_HCI_CMD 0x2000 /* eq. BT_EVT_TO_LM_HCI_CMD */
+
+/* Local Bluetooth Controller ID for BR/EDR */
+#define LOCAL_BR_EDR_CONTROLLER_ID 0
+
+/******************************************************************************
+** Type definitions and return values
+******************************************************************************/
+
+typedef struct
+{
+ uint16_t event;
+ uint16_t len;
+ uint16_t offset;
+ uint16_t layer_specific;
+} HC_BT_HDR;
+
+#define BT_HC_HDR_SIZE (sizeof(HC_BT_HDR))
+
+
+typedef struct _hc_buffer_hdr
+{
+ struct _hc_buffer_hdr *p_next; /* next buffer in the queue */
+ uint8_t reserved1;
+ uint8_t reserved2;
+ uint8_t reserved3;
+ uint8_t reserved4;
+} HC_BUFFER_HDR_T;
+
+#define BT_HC_BUFFER_HDR_SIZE (sizeof(HC_BUFFER_HDR_T))
+
+/******************************************************************************
+** Extern variables and functions
+******************************************************************************/
+
+extern bt_hc_callbacks_t *bt_hc_cbacks;
+
+/******************************************************************************
+** Functions
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function bthc_signal_event
+**
+** Description Perform context switch to bt_hc main thread
+**
+** Returns None
+**
+*******************************************************************************/
+extern void bthc_signal_event(uint16_t event);
+
+#endif /* BT_HCI_BDROID_H */
+
diff --git a/hci/include/bt_hci_lib.h b/hci/include/bt_hci_lib.h
new file mode 100644
index 0000000..59feeb9
--- /dev/null
+++ b/hci/include/bt_hci_lib.h
@@ -0,0 +1,231 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+#ifndef BT_HCI_LIB_H
+#define BT_HCI_LIB_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/** Struct types */
+
+
+/** Typedefs and defines */
+
+/* Generic purpose transac returned upon request complete */
+typedef void* TRANSAC;
+
+/** Bluetooth Power Control States */
+typedef enum {
+ BT_HC_CHIP_PWR_OFF,
+ BT_HC_CHIP_PWR_ON,
+} bt_hc_chip_power_state_t;
+
+/** Bluetooth Low Power Mode */
+typedef enum {
+ BT_HC_LPM_DISABLE,
+ BT_HC_LPM_ENABLE,
+ BT_HC_LPM_WAKE_ASSERT,
+ BT_HC_LPM_WAKE_DEASSERT,
+} bt_hc_low_power_event_t;
+
+/** Receive flow control */
+typedef enum {
+ BT_RXFLOW_OFF, /* add transport device fd to select set */
+ BT_RXFLOW_ON, /* remove transport device to from select set */
+} bt_rx_flow_state_t;
+
+/** HCI logging control */
+typedef enum {
+ BT_HC_LOGGING_OFF,
+ BT_HC_LOGGING_ON,
+} bt_hc_logging_state_t;
+
+/** Result of write request */
+typedef enum {
+ BT_HC_TX_SUCCESS, /* a buffer is fully processed and can be released */
+ BT_HC_TX_FAIL, /* transmit fail */
+ BT_HC_TX_FRAGMENT, /* send split ACL pkt back to stack to reprocess */
+} bt_hc_transmit_result_t;
+
+/** Result of preload initialization */
+typedef enum {
+ BT_HC_PRELOAD_SUCCESS,
+ BT_HC_PRELOAD_FAIL,
+} bt_hc_preload_result_t;
+
+/** Result of postload initialization */
+typedef enum {
+ BT_HC_POSTLOAD_SUCCESS,
+ BT_HC_POSTLOAD_FAIL,
+} bt_hc_postload_result_t;
+
+/** Result of low power enable/disable request */
+typedef enum {
+ BT_HC_LPM_DISABLED,
+ BT_HC_LPM_ENABLED,
+} bt_hc_lpm_request_result_t;
+
+/** Host/Controller Library Return Status */
+typedef enum {
+ BT_HC_STATUS_SUCCESS,
+ BT_HC_STATUS_FAIL,
+ BT_HC_STATUS_NOT_READY,
+ BT_HC_STATUS_NOMEM,
+ BT_HC_STATUS_BUSY,
+ BT_HC_STATUS_CORRUPTED_BUFFER
+} bt_hc_status_t;
+
+
+/* Section comment */
+
+/*
+ * Bluetooth Host/Controller callback structure.
+ */
+
+/* called upon bt host wake signal */
+typedef void (*hostwake_ind_cb)(bt_hc_low_power_event_t event);
+
+/* preload initialization callback */
+typedef void (*preload_result_cb)(TRANSAC transac, bt_hc_preload_result_t result);
+
+/* postload initialization callback */
+typedef void (*postload_result_cb)(TRANSAC transac, bt_hc_postload_result_t result);
+
+/* lpm enable/disable callback */
+typedef void (*lpm_result_cb)(bt_hc_lpm_request_result_t result);
+
+/* datapath buffer allocation callback (callout) */
+typedef char* (*alloc_mem_cb)(int size);
+
+/* datapath buffer deallocation callback (callout) */
+typedef int (*dealloc_mem_cb)(TRANSAC transac, char *p_buf);
+
+/* transmit result callback */
+typedef int (*tx_result_cb)(TRANSAC transac, char *p_buf, bt_hc_transmit_result_t result);
+
+/* a previously setup buffer is read and available for processing
+ buffer is deallocated in stack when processed */
+typedef int (*data_ind_cb)(TRANSAC transac, char *p_buf, int len);
+
+typedef struct {
+ /** set to sizeof(bt_hc_callbacks_t) */
+ size_t size;
+
+ /* notifies caller result of preload request */
+ preload_result_cb preload_cb;
+
+ /* notifies caller result of postload request */
+ postload_result_cb postload_cb;
+
+ /* notifies caller result of lpm enable/disable */
+ lpm_result_cb lpm_cb;
+
+ /* notifies hardware on host wake state */
+ hostwake_ind_cb hostwake_ind;
+
+ /* buffer allocation request */
+ alloc_mem_cb alloc;
+
+ /* buffer deallocation request */
+ dealloc_mem_cb dealloc;
+
+ /* notifies stack data is available */
+ data_ind_cb data_ind;
+
+ /* notifies caller when a buffer is transmitted (or failed) */
+ tx_result_cb tx_result;
+} bt_hc_callbacks_t;
+
+/*
+ * Bluetooth Host/Controller Interface
+ */
+typedef struct {
+ /** Set to sizeof(bt_hc_interface_t) */
+ size_t size;
+
+ /**
+ * Opens the interface and provides the callback routines
+ * to the implemenation of this interface.
+ */
+ int (*init)(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr);
+
+ /** Chip power control */
+ void (*set_power)(bt_hc_chip_power_state_t state);
+
+ /** Set low power mode wake */
+ int (*lpm)(bt_hc_low_power_event_t event);
+
+ /** Called prior to stack initialization */
+ void (*preload)(TRANSAC transac);
+
+ /** Called post stack initialization */
+ void (*postload)(TRANSAC transac);
+
+ /** Transmit buffer */
+ int (*transmit_buf)(TRANSAC transac, char *p_buf, int len);
+
+ /** Controls receive flow */
+ int (*set_rxflow)(bt_rx_flow_state_t state);
+
+ /** Controls HCI logging on/off */
+ int (*logging)(bt_hc_logging_state_t state, char *p_path);
+
+ /** Closes the interface */
+ void (*cleanup)( void );
+} bt_hc_interface_t;
+
+
+/*
+ * External shared lib functions
+ */
+
+extern const bt_hc_interface_t* bt_hc_get_interface(void);
+
+#endif /* BT_HCI_LIB_H */
+
diff --git a/hci/include/bt_vendor_lib.h b/hci/include/bt_vendor_lib.h
new file mode 100644
index 0000000..202acce
--- /dev/null
+++ b/hci/include/bt_vendor_lib.h
@@ -0,0 +1,171 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+#ifndef BT_VENDOR_LIB_H
+#define BT_VENDOR_LIB_H
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+#include <sys/types.h>
+
+/** Struct types */
+
+
+/** Typedefs and defines */
+
+/** Vendor operations */
+typedef enum {
+ BT_VND_OP_POWER_CTRL,
+ BT_VND_OP_FW_CFG,
+ BT_VND_OP_SCO_CFG,
+ BT_VND_OP_USERIAL_OPEN,
+ BT_VND_OP_USERIAL_CLOSE,
+ BT_VND_OP_GET_LPM_IDLE_TIMEOUT,
+ BT_VND_OP_LPM_SET_MODE,
+ BT_VND_OP_LPM_WAKE_SET_STATE,
+} bt_vendor_opcode_t;
+
+/** Power on/off control states */
+typedef enum {
+ BT_VND_PWR_OFF,
+ BT_VND_PWR_ON,
+} bt_vendor_power_state_t;
+
+/** LPM WAKE set state request */
+typedef enum {
+ BT_VND_LPM_WAKE_ASSERT,
+ BT_VND_LPM_WAKE_DEASSERT,
+} bt_vendor_lpm_wake_state_t;
+
+/** Result of vendor operations */
+typedef enum {
+ BT_VND_OP_RESULT_SUCCESS,
+ BT_VND_OP_RESULT_FAIL,
+} bt_vendor_op_result_t;
+
+/** Userial control ID */
+typedef enum {
+ BT_VND_USERIAL_SET_BAUD,
+} bt_vendor_userial_cid_t;
+
+/*
+ * Bluetooth Host/Controller Vendor callback structure.
+ */
+
+/* vendor initialization/configuration callback */
+typedef void (*cfg_result_cb)(bt_vendor_op_result_t result);
+
+/* datapath buffer allocation callback (callout) */
+typedef void* (*malloc_cb)(int size);
+
+/* datapath buffer deallocation callback (callout) */
+typedef void (*mdealloc_cb)(void *p_buf);
+
+/* define callback of the cmd_xmit_cb */
+typedef void (*tINT_CMD_CBACK)(void *p_mem);
+
+/* hci command packet transmit callback (callout) */
+typedef uint8_t (*cmd_xmit_cb)(uint16_t opcode, void *p_buf, tINT_CMD_CBACK p_cback);
+
+/* userial control callback (callout) */
+typedef void (*userial_ctrl_cb)(bt_vendor_userial_cid_t cid, void *param);
+
+typedef struct {
+ /** set to sizeof(bt_vendor_callbacks_t) */
+ size_t size;
+
+ /* notifies caller result of firmware configuration request */
+ cfg_result_cb fwcfg_cb;
+
+ /* notifies caller result of sco configuration request */
+ cfg_result_cb scocfg_cb;
+
+ /* notifies caller result of lpm enable/disable */
+ cfg_result_cb lpm_cb;
+
+ /* buffer allocation request */
+ malloc_cb alloc;
+
+ /* buffer deallocation request */
+ mdealloc_cb dealloc;
+
+ /* hci command packet transmit request */
+ cmd_xmit_cb xmit_cb;
+
+ /* userial control request */
+ userial_ctrl_cb usrl_ctrl_cb;
+} bt_vendor_callbacks_t;
+
+/*
+ * Bluetooth Host/Controller VENDOR Interface
+ */
+typedef struct {
+ /** Set to sizeof(bt_vndor_interface_t) */
+ size_t size;
+
+ /**
+ * Opens the interface and provides the callback routines
+ * to the implemenation of this interface.
+ */
+ int (*init)(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr);
+
+ /** Vendor specific operations */
+ int (*op)(bt_vendor_opcode_t opcode, void *param);
+
+ /** Closes the interface */
+ void (*cleanup)(void);
+} bt_vendor_interface_t;
+
+
+/*
+ * External shared lib functions
+ */
+
+extern const bt_vendor_interface_t* bt_vendor_get_interface(void);
+
+#endif /* BT_VENDOR_LIB_H */
+
diff --git a/hci/include/userial.h b/hci/include/userial.h
new file mode 100644
index 0000000..db3a8cf
--- /dev/null
+++ b/hci/include/userial.h
@@ -0,0 +1,224 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: userial.h
+ *
+ * Description: Contains definitions used for serial port controls
+ *
+ ******************************************************************************/
+
+#ifndef USERIAL_H
+#define USERIAL_H
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+/**** port IDs ****/
+#define USERIAL_PORT_1 0
+#define USERIAL_PORT_2 1
+#define USERIAL_PORT_3 2
+#define USERIAL_PORT_4 3
+#define USERIAL_PORT_5 4
+#define USERIAL_PORT_6 5
+#define USERIAL_PORT_7 6
+#define USERIAL_PORT_8 7
+#define USERIAL_PORT_9 8
+#define USERIAL_PORT_10 9
+#define USERIAL_PORT_11 10
+#define USERIAL_PORT_12 11
+#define USERIAL_PORT_13 12
+#define USERIAL_PORT_14 13
+#define USERIAL_PORT_15 14
+#define USERIAL_PORT_16 15
+#define USERIAL_PORT_17 16
+#define USERIAL_PORT_18 17
+
+/**** baud rates ****/
+#define USERIAL_BAUD_300 0
+#define USERIAL_BAUD_600 1
+#define USERIAL_BAUD_1200 2
+#define USERIAL_BAUD_2400 3
+#define USERIAL_BAUD_9600 4
+#define USERIAL_BAUD_19200 5
+#define USERIAL_BAUD_57600 6
+#define USERIAL_BAUD_115200 7
+#define USERIAL_BAUD_230400 8
+#define USERIAL_BAUD_460800 9
+#define USERIAL_BAUD_921600 10
+#define USERIAL_BAUD_1M 11
+#define USERIAL_BAUD_1_5M 12
+#define USERIAL_BAUD_2M 13
+#define USERIAL_BAUD_3M 14
+#define USERIAL_BAUD_4M 15
+#define USERIAL_BAUD_AUTO 16
+
+/**** Data Format ****/
+/* Stop Bits */
+#define USERIAL_STOPBITS_1 1
+#define USERIAL_STOPBITS_1_5 (1<<1)
+#define USERIAL_STOPBITS_2 (1<<2)
+
+/* Parity Bits */
+#define USERIAL_PARITY_NONE (1<<3)
+#define USERIAL_PARITY_EVEN (1<<4)
+#define USERIAL_PARITY_ODD (1<<5)
+
+/* Data Bits */
+#define USERIAL_DATABITS_5 (1<<6)
+#define USERIAL_DATABITS_6 (1<<7)
+#define USERIAL_DATABITS_7 (1<<8)
+#define USERIAL_DATABITS_8 (1<<9)
+
+typedef enum {
+ USERIAL_OP_INIT,
+ USERIAL_OP_RXFLOW_ON,
+ USERIAL_OP_RXFLOW_OFF,
+} userial_ioctl_op_t;
+
+/******************************************************************************
+** Type definitions
+******************************************************************************/
+
+/* Structure used to configure serial port during open */
+typedef struct
+{
+ uint16_t fmt; /* Data format */
+ uint8_t baud; /* Baud rate */
+} tUSERIAL_CFG;
+
+/******************************************************************************
+** Extern variables and functions
+******************************************************************************/
+
+/******************************************************************************
+** Functions
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function userial_init
+**
+** Description Initializes the userial driver
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t userial_init(void);
+
+/*******************************************************************************
+**
+** Function userial_open
+**
+** Description Open the indicated serial port with the given configuration
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t userial_open(uint8_t port, tUSERIAL_CFG *p_cfg);
+
+/*******************************************************************************
+**
+** Function userial_read
+**
+** Description Read data from the userial port
+**
+** Returns Number of bytes actually read from the userial port and
+** copied into p_data. This may be less than len.
+**
+*******************************************************************************/
+uint16_t userial_read(uint8_t *p_buffer, uint16_t len);
+
+/*******************************************************************************
+**
+** Function userial_write
+**
+** Description Write data to the userial port
+**
+** Returns Number of bytes actually written to the userial port. This
+** may be less than len.
+**
+*******************************************************************************/
+uint16_t userial_write(uint8_t *p_data, uint16_t len);
+
+/*******************************************************************************
+**
+** Function userial_close
+**
+** Description Close the userial port
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_close(void);
+
+/*******************************************************************************
+**
+** Function userial_change_baud
+**
+** Description Change baud rate of userial port
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_change_baud(uint8_t baud);
+
+/*******************************************************************************
+**
+** Function userial_ioctl
+**
+** Description ioctl inteface
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_ioctl(userial_ioctl_op_t op, void *p_data);
+
+#endif /* USERIAL_H */
+
diff --git a/hci/include/utils.h b/hci/include/utils.h
new file mode 100644
index 0000000..85800bf
--- /dev/null
+++ b/hci/include/utils.h
@@ -0,0 +1,200 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: utils.h
+ *
+ * Description: Utility functions declaration
+ *
+ ******************************************************************************/
+
+#ifndef UTILS_H
+#define UTILS_H
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+#define STREAM_TO_UINT16(u16, p) {u16 = ((uint16_t)(*(p)) + (((uint16_t)(*((p) + 1))) << 8)); (p) += 2;}
+#define UINT16_TO_STREAM(p, u16) {*(p)++ = (uint8_t)(u16); *(p)++ = (uint8_t)((u16) >> 8);}
+#define UINT32_TO_STREAM(p, u32) {*(p)++ = (uint8_t)(u32); *(p)++ = (uint8_t)((u32) >> 8); *(p)++ = (uint8_t)((u32) >> 16); *(p)++ = (uint8_t)((u32) >> 24);}
+
+/******************************************************************************
+** Type definitions
+******************************************************************************/
+
+typedef struct
+{
+ void *p_first;
+ void *p_last;
+ uint16_t count;
+} BUFFER_Q;
+
+/******************************************************************************
+** Extern variables and functions
+******************************************************************************/
+
+/******************************************************************************
+** Functions
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function utils_init
+**
+** Description Utils initialization
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_init ();
+
+/*******************************************************************************
+**
+** Function utils_cleanup
+**
+** Description Utils cleanup
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_cleanup ();
+
+/*******************************************************************************
+**
+** Function utils_queue_init
+**
+** Description Initialize the given buffer queue
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_queue_init (BUFFER_Q *p_q);
+
+/*******************************************************************************
+**
+** Function utils_enqueue
+**
+** Description Enqueue a buffer at the tail of the given queue
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_enqueue (BUFFER_Q *p_q, void *p_buf);
+
+/*******************************************************************************
+**
+** Function utils_dequeue
+**
+** Description Dequeues a buffer from the head of the given queue
+**
+** Returns NULL if queue is empty, else buffer
+**
+*******************************************************************************/
+void *utils_dequeue (BUFFER_Q *p_q);
+
+/*******************************************************************************
+**
+** Function utils_getnext
+**
+** Description Return a pointer to the next buffer linked to the given buffer
+**
+** Returns NULL if the given buffer does not point to any next buffer,
+** else next buffer address
+**
+*******************************************************************************/
+void *utils_getnext (void *p_buf);
+
+/*******************************************************************************
+**
+** Function utils_remove_from_queue
+**
+** Description Dequeue the given buffer from the middle of the given queue
+**
+** Returns NULL if the given queue is empty, else the given buffer
+**
+*******************************************************************************/
+void *utils_remove_from_queue (BUFFER_Q *p_q, void *p_buf);
+
+/*******************************************************************************
+**
+** Function utils_delay
+**
+** Description sleep unconditionally for timeout milliseconds
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_delay (uint32_t timeout);
+
+/*******************************************************************************
+**
+** Function utils_lock
+**
+** Description application calls this function before entering critical
+** section
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_lock (void);
+
+/*******************************************************************************
+**
+** Function utils_unlock
+**
+** Description application calls this function when leaving critical
+** section
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_unlock (void);
+
+#endif /* UTILS_H */
+
diff --git a/hci/src/bt_hci_bdroid.c b/hci/src/bt_hci_bdroid.c
new file mode 100644
index 0000000..7e075cb
--- /dev/null
+++ b/hci/src/bt_hci_bdroid.c
@@ -0,0 +1,521 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: bt_hci_bdroid.c
+ *
+ * Description: Bluedroid Bluetooth Host/Controller interface library
+ * implementation
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_hci_bdroid"
+
+#include <utils/Log.h>
+#include <pthread.h>
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_lib.h"
+#include "utils.h"
+#include "userial.h"
+
+#ifndef BTHC_DBG
+#define BTHC_DBG FALSE
+#endif
+
+#if (BTHC_DBG == TRUE)
+#define BTHCDBG(param, ...) {LOGD(param, ## __VA_ARGS__);}
+#else
+#define BTHCDBG(param, ...) {}
+#endif
+
+/******************************************************************************
+** Externs
+******************************************************************************/
+
+extern bt_vendor_interface_t *bt_vnd_if;
+extern int num_hci_cmd_pkts;
+void hci_h4_init(void);
+void hci_h4_cleanup(void);
+void hci_h4_send_msg(HC_BT_HDR *p_msg);
+uint16_t hci_h4_receive_msg(void);
+void hci_h4_get_acl_data_length(void);
+void lpm_init(void);
+void lpm_cleanup(void);
+void lpm_enable(uint8_t turn_on);
+void lpm_wake_deassert(void);
+void lpm_allow_bt_device_sleep(void);
+void lpm_wake_assert(void);
+void init_vnd_if(unsigned char *local_bdaddr);
+void btsnoop_open(char *p_path);
+void btsnoop_close(void);
+
+/******************************************************************************
+** Variables
+******************************************************************************/
+
+bt_hc_callbacks_t *bt_hc_cbacks = NULL;
+BUFFER_Q tx_q;
+
+/******************************************************************************
+** Local type definitions
+******************************************************************************/
+
+/* Host/Controller lib thread control block */
+typedef struct
+{
+ pthread_t worker_thread;
+ pthread_mutex_t mutex;
+ pthread_cond_t cond;
+} bt_hc_cb_t;
+
+/******************************************************************************
+** Static Variables
+******************************************************************************/
+
+static bt_hc_cb_t hc_cb;
+static volatile uint8_t lib_running = 0;
+static volatile uint16_t ready_events = 0;
+static volatile uint8_t tx_cmd_pkts_pending = FALSE;
+
+static const tUSERIAL_CFG userial_init_cfg =
+{
+ (USERIAL_DATABITS_8 | USERIAL_PARITY_NONE | USERIAL_STOPBITS_1),
+ USERIAL_BAUD_115200
+};
+
+/******************************************************************************
+** Functions
+******************************************************************************/
+
+static void *bt_hc_worker_thread(void *arg);
+
+void bthc_signal_event(uint16_t event)
+{
+ pthread_mutex_lock(&hc_cb.mutex);
+ ready_events |= event;
+ pthread_cond_signal(&hc_cb.cond);
+ pthread_mutex_unlock(&hc_cb.mutex);
+}
+
+/*****************************************************************************
+**
+** BLUETOOTH HOST/CONTROLLER INTERFACE LIBRARY FUNCTIONS
+**
+*****************************************************************************/
+
+static int init(const bt_hc_callbacks_t* p_cb, unsigned char *local_bdaddr)
+{
+ pthread_attr_t thread_attr;
+ struct sched_param param;
+ int policy, result;
+
+ LOGI("init");
+
+ if (p_cb == NULL)
+ {
+ LOGE("init failed with no user callbacks!");
+ return BT_HC_STATUS_FAIL;
+ }
+
+ /* store reference to user callbacks */
+ bt_hc_cbacks = (bt_hc_callbacks_t *) p_cb;
+
+ init_vnd_if(local_bdaddr);
+
+ utils_init();
+ hci_h4_init();
+ userial_init();
+ lpm_init();
+
+ utils_queue_init(&tx_q);
+
+ if (lib_running)
+ {
+ LOGW("init has been called repeatedly without calling cleanup ?");
+ }
+
+ lib_running = 1;
+ ready_events = 0;
+ pthread_mutex_init(&hc_cb.mutex, NULL);
+ pthread_cond_init(&hc_cb.cond, NULL);
+ pthread_attr_init(&thread_attr);
+
+ if (pthread_create(&hc_cb.worker_thread, &thread_attr, \
+ bt_hc_worker_thread, NULL) != 0)
+ {
+ LOGE("pthread_create failed!");
+ lib_running = 0;
+ return BT_HC_STATUS_FAIL;
+ }
+
+ if(pthread_getschedparam(hc_cb.worker_thread, &policy, &param)==0)
+ {
+ policy = BTHC_LINUX_BASE_POLICY;
+#if (BTHC_LINUX_BASE_POLICY!=SCHED_NORMAL)
+ param.sched_priority = BTHC_MAIN_THREAD_PRIORITY;
+#endif
+ result = pthread_setschedparam(hc_cb.worker_thread, policy, &param);
+ if (result != 0)
+ {
+ LOGW("libbt-hci init: pthread_setschedparam failed (%s)", \
+ strerror(result));
+ }
+ }
+
+ return BT_HC_STATUS_SUCCESS;
+}
+
+
+/** Chip power control */
+static void set_power(bt_hc_chip_power_state_t state)
+{
+ int pwr_state;
+
+ BTHCDBG("set_power %d", state);
+
+ /* Calling vendor-specific part */
+ pwr_state = (state == BT_HC_CHIP_PWR_ON) ? BT_VND_PWR_ON : BT_VND_PWR_OFF;
+
+ if (bt_vnd_if)
+ bt_vnd_if->op(BT_VND_OP_POWER_CTRL, &pwr_state);
+ else
+ LOGE("vendor lib is missing!");
+}
+
+
+/** Configure low power mode wake state */
+static int lpm(bt_hc_low_power_event_t event)
+{
+ uint8_t status = TRUE;
+
+ switch (event)
+ {
+ case BT_HC_LPM_DISABLE:
+ bthc_signal_event(HC_EVENT_LPM_DISABLE);
+ break;
+
+ case BT_HC_LPM_ENABLE:
+ bthc_signal_event(HC_EVENT_LPM_ENABLE);
+ break;
+
+ case BT_HC_LPM_WAKE_ASSERT:
+ bthc_signal_event(HC_EVENT_LPM_WAKE_DEVICE);
+ break;
+
+ case BT_HC_LPM_WAKE_DEASSERT:
+ bthc_signal_event(HC_EVENT_LPM_ALLOW_SLEEP);
+ break;
+ }
+
+ return(status == TRUE) ? BT_HC_STATUS_SUCCESS : BT_HC_STATUS_FAIL;
+}
+
+
+/** Called prio to stack initialization */
+static void preload(TRANSAC transac)
+{
+ BTHCDBG("preload");
+ bthc_signal_event(HC_EVENT_PRELOAD);
+}
+
+
+/** Called post stack initialization */
+static void postload(TRANSAC transac)
+{
+ BTHCDBG("postload");
+ bthc_signal_event(HC_EVENT_POSTLOAD);
+}
+
+
+/** Transmit frame */
+static int transmit_buf(TRANSAC transac, char *p_buf, int len)
+{
+ utils_enqueue(&tx_q, (void *) transac);
+
+ bthc_signal_event(HC_EVENT_TX);
+
+ return BT_HC_STATUS_SUCCESS;
+}
+
+
+/** Controls receive flow */
+static int set_rxflow(bt_rx_flow_state_t state)
+{
+ BTHCDBG("set_rxflow %d", state);
+
+ userial_ioctl(\
+ ((state == BT_RXFLOW_ON) ? USERIAL_OP_RXFLOW_ON : USERIAL_OP_RXFLOW_OFF), \
+ NULL);
+
+ return BT_HC_STATUS_SUCCESS;
+}
+
+
+/** Controls HCI logging on/off */
+static int logging(bt_hc_logging_state_t state, char *p_path)
+{
+ BTHCDBG("logging %d", state);
+
+ if (state == BT_HC_LOGGING_ON)
+ {
+ if (p_path != NULL)
+ btsnoop_open(p_path);
+ }
+ else
+ {
+ btsnoop_close();
+ }
+
+ return BT_HC_STATUS_SUCCESS;
+}
+
+
+/** Closes the interface */
+static void cleanup( void )
+{
+ BTHCDBG("cleanup");
+
+ if (lib_running)
+ {
+ lib_running = 0;
+ bthc_signal_event(HC_EVENT_EXIT);
+ pthread_join(hc_cb.worker_thread, NULL);
+ }
+
+ lpm_cleanup();
+ userial_close();
+ hci_h4_cleanup();
+ utils_cleanup();
+
+ /* Calling vendor-specific part */
+ if (bt_vnd_if)
+ bt_vnd_if->cleanup();
+
+ bt_hc_cbacks = NULL;
+}
+
+
+static const bt_hc_interface_t bluetoothHCLibInterface = {
+ sizeof(bt_hc_interface_t),
+ init,
+ set_power,
+ lpm,
+ preload,
+ postload,
+ transmit_buf,
+ set_rxflow,
+ logging,
+ cleanup
+};
+
+
+/*******************************************************************************
+**
+** Function bt_hc_worker_thread
+**
+** Description Mian worker thread
+**
+** Returns void *
+**
+*******************************************************************************/
+static void *bt_hc_worker_thread(void *arg)
+{
+ uint16_t events;
+ HC_BT_HDR *p_msg, *p_next_msg;
+
+ BTHCDBG("bt_hc_worker_thread started");
+ tx_cmd_pkts_pending = FALSE;
+
+ while (lib_running)
+ {
+ pthread_mutex_lock(&hc_cb.mutex);
+ while (ready_events == 0)
+ {
+ pthread_cond_wait(&hc_cb.cond, &hc_cb.mutex);
+ }
+ events = ready_events;
+ ready_events = 0;
+ pthread_mutex_unlock(&hc_cb.mutex);
+
+ if (events & HC_EVENT_RX)
+ {
+ hci_h4_receive_msg();
+
+ if ((tx_cmd_pkts_pending == TRUE) && (num_hci_cmd_pkts > 0))
+ {
+ /* Got HCI Cmd Credits from Controller.
+ * Prepare to send prior pending Cmd packets in the
+ * following HC_EVENT_TX session.
+ */
+ events |= HC_EVENT_TX;
+ }
+ }
+
+ if (events & HC_EVENT_PRELOAD)
+ {
+ userial_open(USERIAL_PORT_1, (tUSERIAL_CFG *) &userial_init_cfg);
+
+ /* Calling vendor-specific part */
+ if (bt_vnd_if)
+ {
+ bt_vnd_if->op(BT_VND_OP_FW_CFG, NULL);
+ }
+ else
+ {
+ if (bt_hc_cbacks)
+ bt_hc_cbacks->preload_cb(NULL, BT_HC_PRELOAD_FAIL);
+ }
+ }
+
+ if (events & HC_EVENT_POSTLOAD)
+ {
+ /* Start from SCO related H/W configuration, if SCO configuration
+ * is required. Then, follow with reading requests of getting
+ * ACL data length for both BR/EDR and LE.
+ */
+ int result = -1;
+
+ /* Calling vendor-specific part */
+ if (bt_vnd_if)
+ result = bt_vnd_if->op(BT_VND_OP_SCO_CFG, NULL);
+
+ if (result == -1)
+ hci_h4_get_acl_data_length();
+ }
+
+ if (events & HC_EVENT_TX)
+ {
+ /*
+ * We will go through every packets in the tx queue.
+ * Fine to clear tx_cmd_pkts_pending.
+ */
+ tx_cmd_pkts_pending = FALSE;
+
+ p_next_msg = tx_q.p_first;
+ while (p_next_msg)
+ {
+ if ((p_next_msg->event & MSG_EVT_MASK)==MSG_STACK_TO_HC_HCI_CMD)
+ {
+ /*
+ * if we have used up controller's outstanding HCI command
+ * credits (normally is 1), skip all HCI command packets in
+ * the queue.
+ * The pending command packets will be sent once controller
+ * gives back us credits through CommandCompleteEvent or
+ * CommandStatusEvent.
+ */
+ if ((tx_cmd_pkts_pending == TRUE) || (num_hci_cmd_pkts <= 0))
+ {
+ tx_cmd_pkts_pending = TRUE;
+ p_next_msg = utils_getnext(p_next_msg);
+ continue;
+ }
+ }
+
+ p_msg = p_next_msg;
+ p_next_msg = utils_getnext(p_msg);
+ utils_remove_from_queue(&tx_q, p_msg);
+ hci_h4_send_msg(p_msg);
+ }
+
+ if (tx_cmd_pkts_pending == TRUE)
+ BTHCDBG("Used up Tx Cmd credits");
+
+ }
+
+ if (events & HC_EVENT_LPM_ENABLE)
+ {
+ lpm_enable(TRUE);
+ }
+
+ if (events & HC_EVENT_LPM_DISABLE)
+ {
+ lpm_enable(FALSE);
+ }
+
+ if (events & HC_EVENT_LPM_IDLE_TIMEOUT)
+ {
+ lpm_wake_deassert();
+ }
+
+ if (events & HC_EVENT_LPM_ALLOW_SLEEP)
+ {
+ lpm_allow_bt_device_sleep();
+ }
+
+ if (events & HC_EVENT_LPM_WAKE_DEVICE)
+ {
+ lpm_wake_assert();
+ }
+
+ if (events & HC_EVENT_EXIT)
+ break;
+ }
+
+ BTHCDBG("bt_hc_worker_thread exiting");
+
+ pthread_exit(NULL);
+
+ return NULL; // compiler friendly
+}
+
+
+/*******************************************************************************
+**
+** Function bt_hc_get_interface
+**
+** Description Caller calls this function to get API instance
+**
+** Returns API table
+**
+*******************************************************************************/
+const bt_hc_interface_t *bt_hc_get_interface(void)
+{
+ return &bluetoothHCLibInterface;
+}
+
diff --git a/hci/src/bt_hw.c b/hci/src/bt_hw.c
new file mode 100644
index 0000000..1c4a20f
--- /dev/null
+++ b/hci/src/bt_hw.c
@@ -0,0 +1,250 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: bt_hw.c
+ *
+ * Description: Bluedroid libbt-vendor callback functions
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_hw"
+
+#include <utils/Log.h>
+#include <pthread.h>
+#include "bt_vendor_lib.h"
+#include "bt_hci_bdroid.h"
+#include "userial.h"
+
+/******************************************************************************
+** Externs
+******************************************************************************/
+
+uint8_t hci_h4_send_int_cmd(uint16_t opcode, HC_BT_HDR *p_buf, \
+ tINT_CMD_CBACK p_cback);
+void lpm_vnd_cback(uint8_t vnd_result);
+void hci_h4_get_acl_data_length(void);
+
+/******************************************************************************
+** Variables
+******************************************************************************/
+
+bt_vendor_interface_t *bt_vnd_if=NULL;
+
+/******************************************************************************
+** Functions
+******************************************************************************/
+
+/******************************************************************************
+**
+** Function fwcfg_cb
+**
+** Description HOST/CONTROLLER VENDOR LIB CALLBACK API - This function is
+** called when the libbt-vendor completed firmware
+** configuration process
+**
+** Returns None
+**
+******************************************************************************/
+static void fwcfg_cb(bt_vendor_op_result_t result)
+{
+ bt_hc_postload_result_t status = (result == BT_VND_OP_RESULT_SUCCESS) ? \
+ BT_HC_PRELOAD_SUCCESS : BT_HC_PRELOAD_FAIL;
+
+ if (bt_hc_cbacks)
+ bt_hc_cbacks->preload_cb(NULL, status);
+}
+
+/******************************************************************************
+**
+** Function scocfg_cb
+**
+** Description HOST/CONTROLLER VENDOR LIB CALLBACK API - This function is
+** called when the libbt-vendor completed vendor specific SCO
+** configuration process
+**
+** Returns None
+**
+******************************************************************************/
+static void scocfg_cb(bt_vendor_op_result_t result)
+{
+ /* Continue rest of postload process*/
+ hci_h4_get_acl_data_length();
+}
+
+/******************************************************************************
+**
+** Function lpm_vnd_cb
+**
+** Description HOST/CONTROLLER VENDOR LIB CALLBACK API - This function is
+** called back from the libbt-vendor to indicate the result of
+** previous LPM enable/disable request
+**
+** Returns None
+**
+******************************************************************************/
+static void lpm_vnd_cb(bt_vendor_op_result_t result)
+{
+ uint8_t status = (result == BT_VND_OP_RESULT_SUCCESS) ? 0 : 1;
+
+ lpm_vnd_cback(status);
+}
+
+/******************************************************************************
+**
+** Function alloc
+**
+** Description HOST/CONTROLLER VENDOR LIB CALLOUT API - This function is
+** called from the libbt-vendor to request for data buffer
+** allocation
+**
+** Returns NULL / pointer to allocated buffer
+**
+******************************************************************************/
+static void *alloc(int size)
+{
+ HC_BT_HDR *p_hdr = NULL;
+
+ if (bt_hc_cbacks)
+ p_hdr = (HC_BT_HDR *) bt_hc_cbacks->alloc(size);
+
+ return (p_hdr);
+}
+
+/******************************************************************************
+**
+** Function dealloc
+**
+** Description HOST/CONTROLLER VENDOR LIB CALLOUT API - This function is
+** called from the libbt-vendor to release the data buffer
+** allocated through the alloc call earlier
+**
+** Returns None
+**
+******************************************************************************/
+static void dealloc(void *p_buf)
+{
+ HC_BT_HDR *p_hdr = (HC_BT_HDR *) p_buf;
+
+ if (bt_hc_cbacks)
+ bt_hc_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_hdr+1));
+}
+
+/******************************************************************************
+**
+** Function xmit_cb
+**
+** Description HOST/CONTROLLER VEDNOR LIB CALLOUT API - This function is
+** called from the libbt-vendor in order to send a prepared
+** HCI command packet through HCI transport TX function.
+**
+** Returns TRUE/FALSE
+**
+******************************************************************************/
+static uint8_t xmit_cb(uint16_t opcode, void *p_buf, tINT_CMD_CBACK p_cback)
+{
+ return hci_h4_send_int_cmd(opcode, (HC_BT_HDR *)p_buf, p_cback);
+}
+
+/******************************************************************************
+**
+** Function usrl_ctrl_cb
+**
+** Description HOST/CONTROLLER VEDNOR LIB CALLOUT API - This function is
+** called from the libbt-vendor in order to configure userial
+** attributes.
+**
+** Returns None
+**
+******************************************************************************/
+static void usrl_ctrl_cb(bt_vendor_userial_cid_t cid, void *param)
+{
+ if (cid == BT_VND_USERIAL_SET_BAUD)
+ {
+ uint8_t *baud = (uint8_t *) param;
+
+ userial_change_baud(*baud);
+ }
+}
+
+/*****************************************************************************
+** The libbt-vendor Callback Functions Table
+*****************************************************************************/
+static const bt_vendor_callbacks_t vnd_callbacks = {
+ sizeof(bt_vendor_callbacks_t),
+ fwcfg_cb,
+ scocfg_cb,
+ lpm_vnd_cb,
+ alloc,
+ dealloc,
+ xmit_cb,
+ usrl_ctrl_cb
+};
+
+
+/******************************************************************************
+**
+** Function init_vnd_if
+**
+** Description Initialize vendor lib interface
+**
+** Returns None
+**
+******************************************************************************/
+void init_vnd_if(unsigned char *local_bdaddr)
+{
+ if ((bt_vnd_if=(bt_vendor_interface_t *) bt_vendor_get_interface())!=NULL)
+ {
+ bt_vnd_if->init(&vnd_callbacks, local_bdaddr);
+ }
+ else
+ {
+ LOGE("!!! Failed to get BtVendorInterface !!!");
+ }
+}
+
diff --git a/hci/src/btsnoop.c b/hci/src/btsnoop.c
new file mode 100644
index 0000000..8160963
--- /dev/null
+++ b/hci/src/btsnoop.c
@@ -0,0 +1,717 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/****************************************************************************
+ *
+ * Name: btsnoopdisp.c
+ *
+ * Function: this file contains functions to generate a BTSNOOP file
+ *
+ *
+ ****************************************************************************/
+#include <stdio.h>
+#include <dlfcn.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <string.h>
+#include <pthread.h>
+#include <sys/prctl.h>
+#include <unistd.h>
+#include <ctype.h>
+#include <fcntl.h>
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+/* for gettimeofday */
+#include <sys/time.h>
+/* for the S_* open parameters */
+#include <sys/stat.h>
+/* for write */
+#include <unistd.h>
+/* for O_* open parameters */
+#include <fcntl.h>
+/* defines the O_* open parameters */
+#include <fcntl.h>
+
+#define LOG_TAG "BTSNOOP-DISP"
+#include <cutils/log.h>
+
+#include "bt_hci_bdroid.h"
+#include "utils.h"
+
+#ifndef BTSNOOP_DBG
+#define BTSNOOP_DBG FALSE
+#endif
+
+#if (BTSNOOP_DBG == TRUE)
+#define SNOOPDBG(param, ...) {LOGD(param, ## __VA_ARGS__);}
+#else
+#define SNOOPDBG(param, ...) {}
+#endif
+
+/* file descriptor of the BT snoop file (by default, -1 means disabled) */
+int hci_btsnoop_fd = -1;
+
+/* Macro to perform a multiplication of 2 unsigned 32bit values and store the result
+ * in an unsigned 64 bit value (as two 32 bit variables):
+ * u64 = u32In1 * u32In2
+ * u32OutLow = u64[31:0]
+ * u32OutHi = u64[63:32]
+ * basically the algorithm:
+ * (hi1*2^16 + lo1)*(hi2*2^16 + lo2) = lo1*lo2 + (hi1*hi2)*2^32 + (hi1*lo2 + hi2*lo1)*2^16
+ * and the carry is propagated 16 bit by 16 bit:
+ * result[15:0] = lo1*lo2 & 0xFFFF
+ * result[31:16] = ((lo1*lo2) >> 16) + (hi1*lo2 + hi2*lo1)
+ * and so on
+ */
+#define HCIDISP_MULT_64(u32In1, u32In2, u32OutLo, u32OutHi) \
+do { \
+ uint32_t u32In1Tmp = u32In1; \
+ uint32_t u32In2Tmp = u32In2; \
+ uint32_t u32Tmp, u32Carry; \
+ u32OutLo = (u32In1Tmp & 0xFFFF) * (u32In2Tmp & 0xFFFF); /*lo1*lo2*/ \
+ u32OutHi = ((u32In1Tmp >> 16) & 0xFFFF) * ((u32In2Tmp >> 16) & 0xFFFF); /*hi1*hi2*/ \
+ u32Tmp = (u32In1Tmp & 0xFFFF) * ((u32In2Tmp >> 16) & 0xFFFF); /*lo1*hi2*/ \
+ u32Carry = (uint32_t)((u32OutLo>>16)&0xFFFF); \
+ u32Carry += (u32Tmp&0xFFFF); \
+ u32OutLo += (u32Tmp << 16) ; \
+ u32OutHi += (u32Tmp >> 16); \
+ u32Tmp = ((u32In1Tmp >> 16) & 0xFFFF) * (u32In2Tmp & 0xFFFF); \
+ u32Carry += (u32Tmp)&0xFFFF; \
+ u32Carry>>=16; \
+ u32OutLo += (u32Tmp << 16); \
+ u32OutHi += (u32Tmp >> 16); \
+ u32OutHi += u32Carry; \
+} while (0)
+
+/* Macro to make an addition of 2 64 bit values:
+ * result = (u32OutHi & u32OutLo) + (u32InHi & u32InLo)
+ * u32OutHi = result[63:32]
+ * u32OutLo = result[31:0]
+ */
+#define HCIDISP_ADD_64(u32InLo, u32InHi, u32OutLo, u32OutHi) \
+do { \
+ (u32OutLo) += (u32InLo); \
+ if ((u32OutLo) < (u32InLo)) (u32OutHi)++; \
+ (u32OutHi) += (u32InHi); \
+} while (0)
+
+/* EPOCH in microseconds since 01/01/0000 : 0x00dcddb3.0f2f8000 */
+#define BTSNOOP_EPOCH_HI 0x00dcddb3U
+#define BTSNOOP_EPOCH_LO 0x0f2f8000U
+
+/*******************************************************************************
+ **
+ ** Function tv_to_btsnoop_ts
+ **
+ ** Description This function generate a BT Snoop timestamp.
+ **
+ ** Returns void
+ **
+ ** NOTE
+ ** The return value is 64 bit as 2 32 bit variables out_lo and * out_hi.
+ ** A BT Snoop timestamp is the number of microseconds since 01/01/0000.
+ ** The timeval structure contains the number of microseconds since EPOCH
+ ** (01/01/1970) encoded as: tv.tv_sec, number of seconds since EPOCH and
+ ** tv_usec, number of microseconds in current second
+ **
+ ** Therefore the algorithm is:
+ ** result = tv.tv_sec * 1000000
+ ** result += tv.tv_usec
+ ** result += EPOCH_OFFSET
+ *******************************************************************************/
+static void tv_to_btsnoop_ts(uint32_t *out_lo, uint32_t *out_hi, struct timeval *tv)
+{
+ /* multiply the seconds by 1000000 */
+ HCIDISP_MULT_64(tv->tv_sec, 0xf4240, *out_lo, *out_hi);
+
+ /* add the microseconds */
+ HCIDISP_ADD_64((uint32_t)tv->tv_usec, 0, *out_lo, *out_hi);
+
+ /* add the epoch */
+ HCIDISP_ADD_64(BTSNOOP_EPOCH_LO, BTSNOOP_EPOCH_HI, *out_lo, *out_hi);
+}
+
+/*******************************************************************************
+ **
+ ** Function l_to_be
+ **
+ ** Description Function to convert a 32 bit value into big endian format
+ **
+ ** Returns 32 bit value in big endian format
+*******************************************************************************/
+static uint32_t l_to_be(uint32_t x)
+{
+ #if __BIG_ENDIAN != TRUE
+ x = (x >> 24) |
+ ((x >> 8) & 0xFF00) |
+ ((x << 8) & 0xFF0000) |
+ (x << 24);
+ #endif
+ return x;
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_is_open
+ **
+ ** Description Function to check if BTSNOOP is open
+ **
+ ** Returns 1 if open otherwise 0
+*******************************************************************************/
+int btsnoop_is_open(void)
+{
+#if defined(BTSNOOPDISP_INCLUDED) && (BTSNOOPDISP_INCLUDED == TRUE)
+ SNOOPDBG("btsnoop_is_open: snoop fd = %d\n", hci_btsnoop_fd);
+
+ if (hci_btsnoop_fd != -1)
+ {
+ return 1;
+ }
+ return 0;
+#else
+ return 2; /* Snoop not available */
+#endif
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_log_open
+ **
+ ** Description Function to open the BTSNOOP file
+ **
+ ** Returns None
+*******************************************************************************/
+static int btsnoop_log_open(char *btsnoop_logfile)
+{
+#if defined(BTSNOOPDISP_INCLUDED) && (BTSNOOPDISP_INCLUDED == TRUE)
+ hci_btsnoop_fd = -1;
+
+ SNOOPDBG("btsnoop_log_open: snoop log file = %s\n", btsnoop_logfile);
+
+ /* write the BT snoop header */
+ if ((btsnoop_logfile != NULL) && (strlen(btsnoop_logfile) != 0))
+ {
+ hci_btsnoop_fd = open(btsnoop_logfile, \
+ O_WRONLY|O_CREAT|O_TRUNC, \
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH);
+ if (hci_btsnoop_fd == -1)
+ {
+ perror("open");
+ SNOOPDBG("btsnoop_log_open: Unable to open snoop log file\n");
+ hci_btsnoop_fd = -1;
+ return 0;
+ }
+ write(hci_btsnoop_fd, "btsnoop\0\0\0\0\1\0\0\x3\xea", 16);
+ return 1;
+ }
+#endif
+ return 2; /* Snoop not available */
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_log_close
+ **
+ ** Description Function to close the BTSNOOP file
+ **
+ ** Returns None
+*******************************************************************************/
+static int btsnoop_log_close(void)
+{
+#if defined(BTSNOOPDISP_INCLUDED) && (BTSNOOPDISP_INCLUDED == TRUE)
+ /* write the BT snoop header */
+ if (hci_btsnoop_fd != -1)
+ {
+ SNOOPDBG("btsnoop_log_close: Closing snoop log file\n");
+ close(hci_btsnoop_fd);
+ hci_btsnoop_fd = -1;
+ return 1;
+ }
+ return 0;
+#else
+ return 2; /* Snoop not available */
+#endif
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_hci_cmd
+ **
+ ** Description Function to add a command in the BTSNOOP file
+ **
+ ** Returns None
+*******************************************************************************/
+void btsnoop_hci_cmd(uint8_t *p)
+{
+ SNOOPDBG("btsnoop_hci_cmd: fd = %d", hci_btsnoop_fd);
+
+ if (hci_btsnoop_fd != -1)
+ {
+ uint32_t value, value_hi;
+ struct timeval tv;
+
+ /* since these display functions are called from different contexts */
+ utils_lock();
+
+ /* store the length in both original and included fields */
+ value = l_to_be(p[2] + 4);
+ write(hci_btsnoop_fd, &value, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* flags: command sent from the host */
+ value = l_to_be(2);
+ write(hci_btsnoop_fd, &value, 4);
+ /* drops: none */
+ value = 0;
+ write(hci_btsnoop_fd, &value, 4);
+ /* time */
+ gettimeofday(&tv, NULL);
+ tv_to_btsnoop_ts(&value, &value_hi, &tv);
+ value_hi = l_to_be(value_hi);
+ value = l_to_be(value);
+ write(hci_btsnoop_fd, &value_hi, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* data */
+ write(hci_btsnoop_fd, "\x1", 1);
+ write(hci_btsnoop_fd, p, p[2] + 3);
+
+ /* since these display functions are called from different contexts */
+ utils_unlock();
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_hci_evt
+ **
+ ** Description Function to add a event in the BTSNOOP file
+ **
+ ** Returns None
+*******************************************************************************/
+void btsnoop_hci_evt(uint8_t *p)
+{
+ SNOOPDBG("btsnoop_hci_evt: fd = %d", hci_btsnoop_fd);
+
+ if (hci_btsnoop_fd != -1)
+ {
+ uint32_t value, value_hi;
+ struct timeval tv;
+
+ /* since these display functions are called from different contexts */
+ utils_lock();
+
+ /* store the length in both original and included fields */
+ value = l_to_be(p[1] + 3);
+ write(hci_btsnoop_fd, &value, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* flags: event received in the host */
+ value = l_to_be(3);
+ write(hci_btsnoop_fd, &value, 4);
+ /* drops: none */
+ value = 0;
+ write(hci_btsnoop_fd, &value, 4);
+ /* time */
+ gettimeofday(&tv, NULL);
+ tv_to_btsnoop_ts(&value, &value_hi, &tv);
+ value_hi = l_to_be(value_hi);
+ value = l_to_be(value);
+ write(hci_btsnoop_fd, &value_hi, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* data */
+ write(hci_btsnoop_fd, "\x4", 1);
+ write(hci_btsnoop_fd, p, p[1] + 2);
+
+ /* since these display functions are called from different contexts */
+ utils_unlock();
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_sco_data
+ **
+ ** Description Function to add a SCO data packet in the BTSNOOP file
+ **
+ ** Returns None
+*******************************************************************************/
+void btsnoop_sco_data(uint8_t *p, uint8_t is_rcvd)
+{
+ SNOOPDBG("btsnoop_sco_data: fd = %d", hci_btsnoop_fd);
+
+ if (hci_btsnoop_fd != -1)
+ {
+ uint32_t value, value_hi;
+ struct timeval tv;
+
+ /* since these display functions are called from different contexts */
+ utils_lock();
+
+ /* store the length in both original and included fields */
+ value = l_to_be(p[2] + 4);
+ write(hci_btsnoop_fd, &value, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* flags: data can be sent or received */
+ value = l_to_be(is_rcvd?1:0);
+ write(hci_btsnoop_fd, &value, 4);
+ /* drops: none */
+ value = 0;
+ write(hci_btsnoop_fd, &value, 4);
+ /* time */
+ gettimeofday(&tv, NULL);
+ tv_to_btsnoop_ts(&value, &value_hi, &tv);
+ value_hi = l_to_be(value_hi);
+ value = l_to_be(value);
+ write(hci_btsnoop_fd, &value_hi, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* data */
+ write(hci_btsnoop_fd, "\x3", 1);
+ write(hci_btsnoop_fd, p, p[2] + 3);
+
+ /* since these display functions are called from different contexts */
+ utils_unlock();
+ }
+}
+
+/*******************************************************************************
+ **
+ ** Function btsnoop_acl_data
+ **
+ ** Description Function to add an ACL data packet in the BTSNOOP file
+ **
+ ** Returns None
+*******************************************************************************/
+void btsnoop_acl_data(uint8_t *p, uint8_t is_rcvd)
+{
+ SNOOPDBG("btsnoop_acl_data: fd = %d", hci_btsnoop_fd);
+ if (hci_btsnoop_fd != -1)
+ {
+ uint32_t value, value_hi;
+ struct timeval tv;
+
+ /* since these display functions are called from different contexts */
+ utils_lock();
+
+ /* store the length in both original and included fields */
+ value = l_to_be((p[3]<<8) + p[2] + 5);
+ write(hci_btsnoop_fd, &value, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* flags: data can be sent or received */
+ value = l_to_be(is_rcvd?1:0);
+ write(hci_btsnoop_fd, &value, 4);
+ /* drops: none */
+ value = 0;
+ write(hci_btsnoop_fd, &value, 4);
+ /* time */
+ gettimeofday(&tv, NULL);
+ tv_to_btsnoop_ts(&value, &value_hi, &tv);
+ value_hi = l_to_be(value_hi);
+ value = l_to_be(value);
+ write(hci_btsnoop_fd, &value_hi, 4);
+ write(hci_btsnoop_fd, &value, 4);
+ /* data */
+ write(hci_btsnoop_fd, "\x2", 1);
+ write(hci_btsnoop_fd, p, (p[3]<<8) + p[2] + 4);
+
+ /* since these display functions are called from different contexts */
+ utils_unlock();
+ }
+}
+
+
+/********************************************************************************
+ ** API allow external realtime parsing of output using e.g hcidump
+ *********************************************************************************/
+
+#define EXT_PARSER_PORT 4330
+
+static pthread_t thread_id;
+static int s_listen = -1;
+static int ext_parser_fd = -1;
+
+static void ext_parser_detached(void);
+
+int ext_parser_accept(int port)
+{
+ socklen_t clilen;
+ struct sockaddr_in cliaddr, servaddr;
+ int s, srvlen;
+ int n = 1;
+ int size_n;
+ int result = 0;
+
+ LOGD("waiting for connection on port %d", port);
+
+ s_listen = socket(AF_INET, SOCK_STREAM, 0);
+
+ if (s_listen < 0)
+ {
+ LOGE("listener not created: listen fd %d", s_listen);
+ return -1;
+ }
+
+ bzero(&servaddr, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_addr.s_addr = htonl(INADDR_ANY);
+ servaddr.sin_port = htons(port);
+
+ srvlen = sizeof(servaddr);
+
+ /* allow reuse of sock addr upon bind */
+ result = setsockopt(s_listen, SOL_SOCKET, SO_REUSEADDR, &n, sizeof(n));
+
+ if (result<0)
+ {
+ perror("setsockopt");
+ }
+
+ result = bind(s_listen, (struct sockaddr *) &servaddr, srvlen);
+
+ if (result < 0)
+ perror("bind");
+
+ result = listen(s_listen, 1);
+
+ if (result < 0)
+ perror("listen");
+
+ clilen = sizeof(struct sockaddr_in);
+
+ s = accept(s_listen, (struct sockaddr *) &cliaddr, &clilen);
+
+ if (s < 0)
+{
+ perror("accept");
+ return -1;
+ }
+
+ LOGD("connected (%d)", s);
+
+ return s;
+}
+
+static int send_ext_parser(char *p, int len)
+{
+ int n;
+
+ /* check if io socket is connected */
+ if (ext_parser_fd == -1)
+ return 0;
+
+ SNOOPDBG("write %d to snoop socket\n", len);
+
+ n = write(ext_parser_fd, p, len);
+
+ if (n<=0)
+ {
+ ext_parser_detached();
+ }
+
+ return n;
+}
+
+static void ext_parser_detached(void)
+{
+ LOGD("ext parser detached");
+
+ if (ext_parser_fd>0)
+ close(ext_parser_fd);
+
+ if (s_listen > 0)
+ close(s_listen);
+
+ ext_parser_fd = -1;
+ s_listen = -1;
+}
+
+static void interruptFn (int sig)
+{
+ LOGD("interruptFn");
+ pthread_exit(0);
+}
+
+static void ext_parser_thread(void* param)
+{
+ int fd;
+ int sig = SIGUSR2;
+ sigset_t sigSet;
+ sigemptyset (&sigSet);
+ sigaddset (&sigSet, sig);
+
+ LOGD("ext_parser_thread");
+
+ prctl(PR_SET_NAME, (unsigned long)"BtsnoopExtParser", 0, 0, 0);
+
+ pthread_sigmask (SIG_UNBLOCK, &sigSet, NULL);
+
+ struct sigaction act;
+ act.sa_handler = interruptFn;
+ sigaction (sig, &act, NULL );
+
+ do
+ {
+ fd = ext_parser_accept(EXT_PARSER_PORT);
+
+ ext_parser_fd = fd;
+
+ LOGD("ext parser attached on fd %d\n", ext_parser_fd);
+ } while (1);
+}
+
+void btsnoop_stop_listener(void)
+{
+ LOGD("btsnoop_init");
+ ext_parser_detached();
+}
+
+void btsnoop_init(void)
+{
+ LOGD("btsnoop_init");
+
+ /* always setup ext listener port */
+ if (pthread_create(&thread_id, NULL,
+ (void*)ext_parser_thread,NULL)!=0)
+ perror("pthread_create");
+}
+
+void btsnoop_open(char *p_path)
+{
+#if defined(BTSNOOPDISP_INCLUDED) && (BTSNOOPDISP_INCLUDED == TRUE)
+ LOGD("btsnoop_open");
+ btsnoop_log_open(p_path);
+#endif // BTSNOOPDISP_INCLUDED
+}
+
+void btsnoop_close(void)
+{
+#if defined(BTSNOOPDISP_INCLUDED) && (BTSNOOPDISP_INCLUDED == TRUE)
+ LOGD("btsnoop_close");
+ btsnoop_log_close();
+#endif
+}
+
+void btsnoop_cleanup (void)
+{
+ LOGD("btsnoop_cleanup");
+ pthread_kill(thread_id, SIGUSR2);
+ pthread_join(thread_id, NULL);
+ ext_parser_detached();
+}
+
+
+#define HCIT_TYPE_COMMAND 1
+#define HCIT_TYPE_ACL_DATA 2
+#define HCIT_TYPE_SCO_DATA 3
+#define HCIT_TYPE_EVENT 4
+
+void btsnoop_capture(HC_BT_HDR *p_buf, uint8_t is_rcvd)
+{
+ uint8_t *p = (uint8_t *)(p_buf + 1) + p_buf->offset;
+
+ SNOOPDBG("btsnoop_capture: fd = %d, type %x, rcvd %d, ext %d", \
+ hci_btsnoop_fd, p_buf->event, is_rcvd, ext_parser_fd);
+
+ if (ext_parser_fd > 0)
+ {
+ uint8_t tmp = *p;
+
+ /* borrow one byte for H4 packet type indicator */
+ p--;
+
+ switch (p_buf->event & MSG_EVT_MASK)
+ {
+ case MSG_HC_TO_STACK_HCI_EVT:
+ *p = HCIT_TYPE_EVENT;
+ break;
+ case MSG_HC_TO_STACK_HCI_ACL:
+ case MSG_STACK_TO_HC_HCI_ACL:
+ *p = HCIT_TYPE_ACL_DATA;
+ break;
+ case MSG_HC_TO_STACK_HCI_SCO:
+ case MSG_STACK_TO_HC_HCI_SCO:
+ *p = HCIT_TYPE_SCO_DATA;
+ break;
+ case MSG_STACK_TO_HC_HCI_CMD:
+ *p = HCIT_TYPE_COMMAND;
+ break;
+ }
+
+ send_ext_parser((char*)p, p_buf->len+1);
+ *(++p) = tmp;
+ return;
+ }
+
+#if defined(BTSNOOPDISP_INCLUDED) && (BTSNOOPDISP_INCLUDED == TRUE)
+ if (hci_btsnoop_fd == -1)
+ return;
+
+ switch (p_buf->event & MSG_EVT_MASK)
+ {
+ case MSG_HC_TO_STACK_HCI_EVT:
+ SNOOPDBG("TYPE : EVT");
+ btsnoop_hci_evt(p);
+ break;
+ case MSG_HC_TO_STACK_HCI_ACL:
+ case MSG_STACK_TO_HC_HCI_ACL:
+ SNOOPDBG("TYPE : ACL");
+ btsnoop_acl_data(p, is_rcvd);
+ break;
+ case MSG_HC_TO_STACK_HCI_SCO:
+ case MSG_STACK_TO_HC_HCI_SCO:
+ SNOOPDBG("TYPE : SCO");
+ btsnoop_sco_data(p, is_rcvd);
+ break;
+ case MSG_STACK_TO_HC_HCI_CMD:
+ SNOOPDBG("TYPE : CMD");
+ btsnoop_hci_cmd(p);
+ break;
+ }
+#endif // BTSNOOPDISP_INCLUDED
+}
+
+
diff --git a/hci/src/hci_h4.c b/hci/src/hci_h4.c
new file mode 100644
index 0000000..e18ee6a
--- /dev/null
+++ b/hci/src/hci_h4.c
@@ -0,0 +1,1074 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: hci_h4.c
+ *
+ * Description: Contains HCI transport send/receive functions
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_h4"
+
+#include <utils/Log.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include "bt_hci_bdroid.h"
+#include "userial.h"
+#include "utils.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+#ifndef HCIH4_DBG
+#define HCIH4_DBG FALSE
+#endif
+
+#if (HCIH4_DBG == TRUE)
+#define HCIH4DBG(param, ...) {LOGD(param, ## __VA_ARGS__);}
+#else
+#define HCIH4DBG(param, ...) {}
+#endif
+
+/* Preamble length for HCI Commands:
+** 2-bytes for opcode and 1 byte for length
+*/
+#define HCI_CMD_PREAMBLE_SIZE 3
+
+/* Preamble length for HCI Events:
+** 1-byte for opcode and 1 byte for length
+*/
+#define HCI_EVT_PREAMBLE_SIZE 2
+
+/* Preamble length for SCO Data:
+** 2-byte for Handle and 1 byte for length
+*/
+#define HCI_SCO_PREAMBLE_SIZE 3
+
+/* Preamble length for ACL Data:
+** 2-byte for Handle and 2 byte for length
+*/
+#define HCI_ACL_PREAMBLE_SIZE 4
+
+/* Table of HCI preamble sizes for the different HCI message types */
+static const uint8_t hci_preamble_table[] =
+{
+ HCI_CMD_PREAMBLE_SIZE,
+ HCI_ACL_PREAMBLE_SIZE,
+ HCI_SCO_PREAMBLE_SIZE,
+ HCI_EVT_PREAMBLE_SIZE
+};
+
+/* HCI H4 message type definitions */
+#define H4_TYPE_COMMAND 1
+#define H4_TYPE_ACL_DATA 2
+#define H4_TYPE_SCO_DATA 3
+#define H4_TYPE_EVENT 4
+
+static const uint16_t msg_evt_table[] =
+{
+ MSG_HC_TO_STACK_HCI_ERR, /* H4_TYPE_COMMAND */
+ MSG_HC_TO_STACK_HCI_ACL, /* H4_TYPE_ACL_DATA */
+ MSG_HC_TO_STACK_HCI_SCO, /* H4_TYPE_SCO_DATA */
+ MSG_HC_TO_STACK_HCI_EVT /* H4_TYPE_EVENT */
+};
+
+#define ACL_RX_PKT_START 2
+#define ACL_RX_PKT_CONTINUE 1
+#define L2CAP_HEADER_SIZE 4
+
+/* Maximum numbers of allowed internal
+** outstanding command packets at any time
+*/
+#define INT_CMD_PKT_MAX_COUNT 8
+#define INT_CMD_PKT_IDX_MASK 0x07
+
+#define HCI_COMMAND_COMPLETE_EVT 0x0E
+#define HCI_COMMAND_STATUS_EVT 0x0F
+#define HCI_READ_BUFFER_SIZE 0x1005
+#define HCI_LE_READ_BUFFER_SIZE 0x2002
+
+/******************************************************************************
+** Local type definitions
+******************************************************************************/
+
+/* H4 Rx States */
+typedef enum {
+ H4_RX_MSGTYPE_ST,
+ H4_RX_LEN_ST,
+ H4_RX_DATA_ST,
+ H4_RX_IGNORE_ST
+} tHCI_H4_RCV_STATE;
+
+/* Callback function for the returned event of internal issued command */
+typedef void (*tINT_CMD_CBACK)(void *p_mem);
+
+typedef struct
+{
+ uint16_t opcode; /* OPCODE of outstanding internal commands */
+ tINT_CMD_CBACK cback; /* Callback function when return of internal
+ * command is received */
+} tINT_CMD_Q;
+
+/* Control block for HCISU_H4 */
+typedef struct
+{
+ HC_BT_HDR *p_rcv_msg; /* Buffer to hold current rx HCI message */
+ uint16_t rcv_len; /* Size of current incoming message */
+ uint8_t rcv_msg_type; /* Current incoming message type */
+ tHCI_H4_RCV_STATE rcv_state; /* Receive state of current rx message */
+ uint16_t hc_acl_data_size; /* Controller's max ACL data length */
+ uint16_t hc_ble_acl_data_size; /* Controller's max BLE ACL data length */
+ BUFFER_Q acl_rx_q; /* Queue of base buffers for fragmented ACL pkts */
+ uint8_t preload_count; /* Count numbers of preload bytes */
+ uint8_t preload_buffer[6]; /* HCI_ACL_PREAMBLE_SIZE + 2 */
+ int int_cmd_rsp_pending; /* Num of internal cmds pending for ack */
+ uint8_t int_cmd_rd_idx; /* Read index of int_cmd_opcode queue */
+ uint8_t int_cmd_wrt_idx; /* Write index of int_cmd_opcode queue */
+ tINT_CMD_Q int_cmd[INT_CMD_PKT_MAX_COUNT]; /* FIFO queue */
+} tHCI_H4_CB;
+
+/******************************************************************************
+** Externs
+******************************************************************************/
+
+extern BUFFER_Q tx_q;
+
+void btsnoop_init(void);
+void btsnoop_close(void);
+void btsnoop_cleanup (void);
+void btsnoop_capture(HC_BT_HDR *p_buf, uint8_t is_rcvd);
+uint8_t hci_h4_send_int_cmd(uint16_t opcode, HC_BT_HDR *p_buf, \
+ tINT_CMD_CBACK p_cback);
+void lpm_wake_assert(void);
+void lpm_tx_done(uint8_t is_tx_done);
+
+/******************************************************************************
+** Variables
+******************************************************************************/
+
+/* Num of allowed outstanding HCI CMD packets */
+volatile int num_hci_cmd_pkts = 1;
+
+/******************************************************************************
+** Static variables
+******************************************************************************/
+
+static tHCI_H4_CB h4_cb;
+
+/******************************************************************************
+** Static functions
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function get_acl_data_length_cback
+**
+** Description Callback function for HCI_READ_BUFFER_SIZE and
+** HCI_LE_READ_BUFFER_SIZE commands if they were sent because
+** of internal request.
+**
+** Returns None
+**
+*******************************************************************************/
+void get_acl_data_length_cback(void *p_mem)
+{
+ uint8_t *p, status;
+ uint16_t opcode, len=0;
+ HC_BT_HDR *p_buf = (HC_BT_HDR *) p_mem;
+
+ p = (uint8_t *)(p_buf + 1) + 3;
+ STREAM_TO_UINT16(opcode, p)
+ status = *p++;
+ if (status == 0) /* Success */
+ STREAM_TO_UINT16(len, p)
+
+ if (opcode == HCI_READ_BUFFER_SIZE)
+ {
+ if (status == 0)
+ h4_cb.hc_acl_data_size = len;
+
+ /* reuse the rx buffer for sending HCI_LE_READ_BUFFER_SIZE command */
+ p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = 3;
+
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_LE_READ_BUFFER_SIZE);
+ *p = 0;
+
+ if ((status = hci_h4_send_int_cmd(HCI_LE_READ_BUFFER_SIZE, p_buf, \
+ get_acl_data_length_cback)) == FALSE)
+ {
+ bt_hc_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ bt_hc_cbacks->postload_cb(NULL, BT_HC_POSTLOAD_SUCCESS);
+ }
+ }
+ else if (opcode == HCI_LE_READ_BUFFER_SIZE)
+ {
+ if (status == 0)
+ h4_cb.hc_ble_acl_data_size = (len) ? len : h4_cb.hc_acl_data_size;
+
+ if (bt_hc_cbacks)
+ {
+ bt_hc_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ LOGE("vendor lib postload completed");
+ bt_hc_cbacks->postload_cb(NULL, BT_HC_POSTLOAD_SUCCESS);
+ }
+ }
+}
+
+
+/*******************************************************************************
+**
+** Function internal_event_intercept
+**
+** Description This function is called to parse received HCI event and
+** - update the Num_HCI_Command_Packets
+** - intercept the event if it is the result of an early
+** issued internal command.
+**
+** Returns TRUE : if the event had been intercepted for internal process
+** FALSE : send this event to core stack
+**
+*******************************************************************************/
+uint8_t internal_event_intercept(void)
+{
+ uint8_t *p;
+ uint8_t event_code;
+ uint16_t opcode, len;
+ tHCI_H4_CB *p_cb = &h4_cb;
+
+ p = (uint8_t *)(p_cb->p_rcv_msg + 1);
+
+ event_code = *p++;
+ len = *p++;
+
+ if (event_code == HCI_COMMAND_COMPLETE_EVT)
+ {
+ num_hci_cmd_pkts = *p++;
+
+ if (p_cb->int_cmd_rsp_pending > 0)
+ {
+ STREAM_TO_UINT16(opcode, p)
+
+ if (opcode == p_cb->int_cmd[p_cb->int_cmd_rd_idx].opcode)
+ {
+ HCIH4DBG( \
+ "Intercept CommandCompleteEvent for internal command (0x%04X)",\
+ opcode);
+ p_cb->int_cmd[p_cb->int_cmd_rd_idx].cback(p_cb->p_rcv_msg);
+ p_cb->int_cmd_rd_idx = ((p_cb->int_cmd_rd_idx+1) & \
+ INT_CMD_PKT_IDX_MASK);
+ p_cb->int_cmd_rsp_pending--;
+ return TRUE;
+ }
+ }
+ }
+ else if (event_code == HCI_COMMAND_STATUS_EVT)
+ {
+ num_hci_cmd_pkts = *(++p);
+ }
+
+ return FALSE;
+}
+
+/*******************************************************************************
+**
+** Function acl_rx_frame_buffer_alloc
+**
+** Description This function is called from the HCI transport when the
+** first 4 or 6 bytes of an HCI ACL packet have been received:
+** - Allocate a new buffer if it is a start pakcet of L2CAP
+** message.
+** - Return the buffer address of the starting L2CAP message
+** frame if the packet is the next segment of a fragmented
+** L2CAP message.
+**
+** Returns the address of the receive buffer H4 RX should use
+** (CR419: Modified to return NULL in case of error.)
+**
+** NOTE This assumes that the L2CAP MTU size is less than the size
+** of an HCI ACL buffer, so the maximum L2CAP message will fit
+** into one buffer.
+**
+*******************************************************************************/
+static HC_BT_HDR *acl_rx_frame_buffer_alloc (void)
+{
+ uint8_t *p;
+ uint16_t handle;
+ uint16_t hci_len;
+ uint16_t total_len;
+ uint8_t pkt_type;
+ HC_BT_HDR *p_return_buf = NULL;
+ tHCI_H4_CB *p_cb = &h4_cb;
+
+
+ p = p_cb->preload_buffer;
+
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT16 (hci_len, p);
+ STREAM_TO_UINT16 (total_len, p);
+
+ pkt_type = (uint8_t)(((handle) >> 12) & 0x0003);
+ handle = (uint16_t)((handle) & 0x0FFF);
+
+ if (p_cb->acl_rx_q.count)
+ {
+ uint16_t save_handle;
+ HC_BT_HDR *p_hdr = p_cb->acl_rx_q.p_first;
+
+ while (p_hdr != NULL)
+ {
+ p = (uint8_t *)(p_hdr + 1);
+ STREAM_TO_UINT16 (save_handle, p);
+ save_handle = (uint16_t)((save_handle) & 0x0FFF);
+ if (save_handle == handle)
+ {
+ p_return_buf = p_hdr;
+ break;
+ }
+ p_hdr = utils_getnext(p_hdr);
+ }
+ }
+
+ if (pkt_type == ACL_RX_PKT_START) /*** START PACKET ***/
+ {
+ /* Might have read 2 bytes for the L2CAP payload length */
+ p_cb->rcv_len = (hci_len) ? (hci_len - 2) : 0;
+
+ /* Start of packet. If we were in the middle of receiving */
+ /* a packet on the same ACL handle, the original packet is incomplete.
+ * Drop it. */
+ if (p_return_buf)
+ {
+ LOGW("H4 - dropping incomplete ACL frame");
+
+ utils_remove_from_queue(&(p_cb->acl_rx_q), p_return_buf);
+
+ if (bt_hc_cbacks)
+ {
+ bt_hc_cbacks->dealloc((TRANSAC) p_return_buf, \
+ (char *) (p_return_buf + 1));
+ }
+ p_return_buf = NULL;
+ }
+
+ /* Allocate a buffer for message */
+ if (bt_hc_cbacks)
+ {
+ int len = total_len + HCI_ACL_PREAMBLE_SIZE + L2CAP_HEADER_SIZE + \
+ BT_HC_HDR_SIZE;
+ p_return_buf = (HC_BT_HDR *) bt_hc_cbacks->alloc(len);
+ }
+
+ if (p_return_buf)
+ {
+ /* Initialize buffer with preloaded data */
+ p_return_buf->offset = 0;
+ p_return_buf->layer_specific = 0;
+ p_return_buf->event = MSG_HC_TO_STACK_HCI_ACL;
+ p_return_buf->len = p_cb->preload_count;
+ memcpy((uint8_t *)(p_return_buf + 1), p_cb->preload_buffer, \
+ p_cb->preload_count);
+
+ if (hci_len && ((total_len + L2CAP_HEADER_SIZE) > hci_len))
+ {
+ /* Will expect to see fragmented ACL packets */
+ /* Keep the base buffer address in the watching queue */
+ utils_enqueue(&(p_cb->acl_rx_q), p_return_buf);
+ }
+ }
+ }
+ else /*** CONTINUATION PACKET ***/
+ {
+ p_cb->rcv_len = hci_len;
+
+ if (p_return_buf)
+ {
+ /* Packet continuation and found the original rx buffer */
+ uint8_t *p_f = p = (uint8_t *)(p_return_buf + 1) + 2;
+
+ STREAM_TO_UINT16 (total_len, p);
+
+ /* Update HCI header of first segment (base buffer) with new len */
+ total_len += hci_len;
+ UINT16_TO_STREAM (p_f, total_len);
+ }
+ }
+
+ return (p_return_buf);
+}
+
+/*******************************************************************************
+**
+** Function acl_rx_frame_end_chk
+**
+** Description This function is called from the HCI transport when the last
+** byte of an HCI ACL packet has been received. It checks if
+** the L2CAP message is complete, i.e. no more continuation
+** packets are expected.
+**
+** Returns TRUE if message complete, FALSE if continuation expected
+**
+*******************************************************************************/
+static uint8_t acl_rx_frame_end_chk (void)
+{
+ uint8_t *p;
+ uint16_t handle, hci_len, l2cap_len;
+ HC_BT_HDR *p_buf;
+ tHCI_H4_CB *p_cb = &h4_cb;
+ uint8_t frame_end=TRUE;
+
+ p_buf = p_cb->p_rcv_msg;
+ p = (uint8_t *)(p_buf + 1);
+
+ STREAM_TO_UINT16 (handle, p);
+ STREAM_TO_UINT16 (hci_len, p);
+ STREAM_TO_UINT16 (l2cap_len, p);
+
+ if (hci_len > 0)
+ {
+ if (l2cap_len > (p_buf->len-(HCI_ACL_PREAMBLE_SIZE+L2CAP_HEADER_SIZE)) )
+ {
+ /* If the L2CAP length has not been reached, tell H4 not to send
+ * this buffer to stack */
+ frame_end = FALSE;
+ }
+ else
+ {
+ /*
+ * The current buffer coulb be in the watching list.
+ * Remove it from the list if it is in.
+ */
+ if (p_cb->acl_rx_q.count)
+ utils_remove_from_queue(&(p_cb->acl_rx_q), p_buf);
+ }
+ }
+
+ /****
+ ** Print snoop trace
+ ****/
+ if (p_buf->offset)
+ {
+ /* CONTINUATION PACKET */
+
+ /* save original p_buf->len content */
+ uint16_t tmp_u16 = p_buf->len;
+
+ /* borrow HCI_ACL_PREAMBLE_SIZE bytes from the payload section */
+ p = (uint8_t *)(p_buf + 1) + p_buf->offset - HCI_ACL_PREAMBLE_SIZE;
+
+ /* save contents */
+ memcpy(p_cb->preload_buffer, p, HCI_ACL_PREAMBLE_SIZE);
+
+ /* Set packet boundary flags to "continuation packet" */
+ handle = (handle & 0xCFFF) | 0x1000;
+
+ /* write handl & length info */
+ UINT16_TO_STREAM (p, handle);
+ UINT16_TO_STREAM (p, (p_buf->len - p_buf->offset));
+
+ /* roll pointer back */
+ p = p - HCI_ACL_PREAMBLE_SIZE;
+
+ /* adjust `p_buf->offset` & `p_buf->len`
+ * before calling btsnoop_capture() */
+ p_buf->offset = p_buf->offset - HCI_ACL_PREAMBLE_SIZE;
+ p_buf->len = p_buf->len - p_buf->offset;
+
+ btsnoop_capture(p_buf, TRUE);
+
+ /* restore contents */
+ memcpy(p, p_cb->preload_buffer, HCI_ACL_PREAMBLE_SIZE);
+
+ /* restore p_buf->len */
+ p_buf->len = tmp_u16;
+ }
+ else
+ {
+ /* START PACKET */
+ btsnoop_capture(p_buf, TRUE);
+ }
+
+ if (frame_end == TRUE)
+ p_buf->offset = 0;
+ else
+ p_buf->offset = p_buf->len; /* save current buffer-end position */
+
+ return frame_end;
+}
+
+/*****************************************************************************
+** HCI H4 INTERFACE FUNCTIONS
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function hci_h4_init
+**
+** Description Initialize H4 module
+**
+** Returns None
+**
+*******************************************************************************/
+void hci_h4_init(void)
+{
+ HCIH4DBG("hci_h4_init");
+
+ memset(&h4_cb, 0, sizeof(tHCI_H4_CB));
+ utils_queue_init(&(h4_cb.acl_rx_q));
+
+ /* Per HCI spec., always starts with 1 */
+ num_hci_cmd_pkts = 1;
+
+ /* Give an initial values of Host Controller's ACL data packet length
+ * Will update with an internal HCI(_LE)_Read_Buffer_Size request
+ */
+ h4_cb.hc_acl_data_size = 1021;
+ h4_cb.hc_ble_acl_data_size = 27;
+
+ btsnoop_init();
+}
+
+/*******************************************************************************
+**
+** Function hci_h4_cleanup
+**
+** Description Clean H4 module
+**
+** Returns None
+**
+*******************************************************************************/
+void hci_h4_cleanup(void)
+{
+ HCIH4DBG("hci_h4_cleanup");
+
+ btsnoop_close();
+ btsnoop_cleanup();
+}
+
+/*******************************************************************************
+**
+** Function hci_h4_send_msg
+**
+** Description Determine message type, set HCI H4 packet indicator, and
+** send message through USERIAL driver
+**
+** Returns None
+**
+*******************************************************************************/
+void hci_h4_send_msg(HC_BT_HDR *p_msg)
+{
+ uint8_t type = 0;
+ uint16_t handle;
+ uint16_t bytes_to_send, lay_spec;
+ uint8_t *p = ((uint8_t *)(p_msg + 1)) + p_msg->offset;
+ uint16_t event = p_msg->event & MSG_EVT_MASK;
+ uint16_t sub_event = p_msg->event & MSG_SUB_EVT_MASK;
+ uint16_t acl_pkt_size = 0, acl_data_size = 0;
+ uint16_t bytes_sent;
+
+ /* wake up BT device if its in sleep mode */
+ lpm_wake_assert();
+
+ if (event == MSG_STACK_TO_HC_HCI_ACL)
+ type = H4_TYPE_ACL_DATA;
+ else if (event == MSG_STACK_TO_HC_HCI_SCO)
+ type = H4_TYPE_SCO_DATA;
+ else if (event == MSG_STACK_TO_HC_HCI_CMD)
+ type = H4_TYPE_COMMAND;
+
+ if (sub_event == LOCAL_BR_EDR_CONTROLLER_ID)
+ {
+ acl_data_size = h4_cb.hc_acl_data_size;
+ acl_pkt_size = h4_cb.hc_acl_data_size + HCI_ACL_PREAMBLE_SIZE;
+ }
+ else
+ {
+ acl_data_size = h4_cb.hc_ble_acl_data_size;
+ acl_pkt_size = h4_cb.hc_ble_acl_data_size + HCI_ACL_PREAMBLE_SIZE;
+ }
+
+ /* Check if sending ACL data that needs fragmenting */
+ if ((event == MSG_STACK_TO_HC_HCI_ACL) && (p_msg->len > acl_pkt_size))
+ {
+ /* Get the handle from the packet */
+ STREAM_TO_UINT16 (handle, p);
+
+ /* Set packet boundary flags to "continuation packet" */
+ handle = (handle & 0xCFFF) | 0x1000;
+
+ /* Do all the first chunks */
+ while (p_msg->len > acl_pkt_size)
+ {
+ /* remember layer_specific because uart borrow
+ one byte from layer_specific for packet type */
+ lay_spec = p_msg->layer_specific;
+
+ p = ((uint8_t *)(p_msg + 1)) + p_msg->offset - 1;
+ *p = type;
+ bytes_to_send = acl_pkt_size + 1; /* packet_size + message type */
+
+ bytes_sent = userial_write((uint8_t *) p, bytes_to_send);
+
+ /* generate snoop trace message */
+ btsnoop_capture(p_msg, FALSE);
+
+ p_msg->layer_specific = lay_spec;
+ /* Adjust offset and length for what we just sent */
+ p_msg->offset += acl_data_size;
+ p_msg->len -= acl_data_size;
+
+ p = ((uint8_t *)(p_msg + 1)) + p_msg->offset;
+
+ UINT16_TO_STREAM (p, handle);
+
+ if (p_msg->len > acl_pkt_size)
+ {
+ UINT16_TO_STREAM (p, acl_data_size);
+ }
+ else
+ {
+ UINT16_TO_STREAM (p, p_msg->len - HCI_ACL_PREAMBLE_SIZE);
+ }
+
+ /* If we were only to send partial buffer, stop when done. */
+ /* Send the buffer back to L2CAP to send the rest of it later */
+ if (p_msg->layer_specific)
+ {
+ if (--p_msg->layer_specific == 0)
+ {
+ p_msg->event = MSG_HC_TO_STACK_L2C_SEG_XMIT;
+
+ if (bt_hc_cbacks)
+ {
+ bt_hc_cbacks->tx_result((TRANSAC) p_msg, \
+ (char *) (p_msg + 1), \
+ BT_HC_TX_FRAGMENT);
+ }
+
+ return;
+ }
+ }
+ }
+ }
+
+
+ /* remember layer_specific because uart borrow
+ one byte from layer_specific for packet type */
+ lay_spec = p_msg->layer_specific;
+
+ /* Put the HCI Transport packet type 1 byte before the message */
+ p = ((uint8_t *)(p_msg + 1)) + p_msg->offset - 1;
+ *p = type;
+ bytes_to_send = p_msg->len + 1; /* message_size + message type */
+
+ bytes_sent = userial_write((uint8_t *) p, bytes_to_send);
+
+ p_msg->layer_specific = lay_spec;
+
+ if (event == MSG_STACK_TO_HC_HCI_CMD)
+ {
+ num_hci_cmd_pkts--;
+
+ /* If this is an internal Cmd packet, the layer_specific field would
+ * have stored with the opcode of HCI command.
+ * Retrieve the opcode from the Cmd packet.
+ */
+ p++;
+ STREAM_TO_UINT16(lay_spec, p);
+ }
+
+ /* generate snoop trace message */
+ btsnoop_capture(p_msg, FALSE);
+
+ if (bt_hc_cbacks)
+ {
+ if ((event == MSG_STACK_TO_HC_HCI_CMD) && \
+ (h4_cb.int_cmd_rsp_pending > 0) && \
+ (p_msg->layer_specific == lay_spec))
+ {
+ /* dealloc buffer of internal command */
+ bt_hc_cbacks->dealloc((TRANSAC) p_msg, (char *) (p_msg + 1));
+ }
+ else
+ {
+ bt_hc_cbacks->tx_result((TRANSAC) p_msg, (char *) (p_msg + 1), \
+ BT_HC_TX_SUCCESS);
+ }
+ }
+
+ lpm_tx_done(TRUE);
+
+ return;
+}
+
+
+/*******************************************************************************
+**
+** Function hci_h4_receive_msg
+**
+** Description
+**
+** Returns
+**
+*******************************************************************************/
+uint16_t hci_h4_receive_msg(void)
+{
+ uint16_t bytes_read = 0;
+ uint8_t byte;
+ uint16_t msg_len, len;
+ uint8_t msg_received;
+ tHCI_H4_CB *p_cb=&h4_cb;
+
+ while (TRUE)
+ {
+ /* Read one byte to see if there is anything waiting to be read */
+ if (userial_read(&byte, 1) == 0)
+ {
+ break;
+ }
+
+ bytes_read++;
+ msg_received = FALSE;
+
+ switch (p_cb->rcv_state)
+ {
+ case H4_RX_MSGTYPE_ST:
+ /* Start of new message */
+ if ((byte < H4_TYPE_ACL_DATA) || (byte > H4_TYPE_EVENT))
+ {
+ /* Unknown HCI message type */
+ /* Drop this byte */
+ LOGE("[h4] Unknown HCI message type drop this byte 0x%x", byte);
+ break;
+ }
+
+ /* Initialize rx parameters */
+ p_cb->rcv_msg_type = byte;
+ p_cb->rcv_len = hci_preamble_table[byte-1];
+ memset(p_cb->preload_buffer, 0 , 6);
+ p_cb->preload_count = 0;
+ // p_cb->p_rcv_msg = NULL;
+ p_cb->rcv_state = H4_RX_LEN_ST; /* Next, wait for length to come */
+ break;
+
+ case H4_RX_LEN_ST:
+ /* Receiving preamble */
+ p_cb->preload_buffer[p_cb->preload_count++] = byte;
+ p_cb->rcv_len--;
+
+ /* Check if we received entire preamble yet */
+ if (p_cb->rcv_len == 0)
+ {
+ if (p_cb->rcv_msg_type == H4_TYPE_ACL_DATA)
+ {
+ /* ACL data lengths are 16-bits */
+ msg_len = p_cb->preload_buffer[3];
+ msg_len = (msg_len << 8) + p_cb->preload_buffer[2];
+
+ if (msg_len && (p_cb->preload_count == 4))
+ {
+ /* Check if this is a start packet */
+ byte = ((p_cb->preload_buffer[1] >> 4) & 0x03);
+
+ if (byte == ACL_RX_PKT_START)
+ {
+ /*
+ * A start packet & with non-zero data payload length.
+ * We want to read 2 more bytes to get L2CAP payload
+ * length.
+ */
+ p_cb->rcv_len = 2;
+
+ break;
+ }
+ }
+
+ /*
+ * Check for segmented packets. If this is a continuation
+ * packet, then we will continue appending data to the
+ * original rcv buffer.
+ */
+ p_cb->p_rcv_msg = acl_rx_frame_buffer_alloc();
+ }
+ else
+ {
+ /* Received entire preamble.
+ * Length is in the last received byte */
+ msg_len = byte;
+ p_cb->rcv_len = msg_len;
+
+ /* Allocate a buffer for message */
+ if (bt_hc_cbacks)
+ {
+ len = msg_len + p_cb->preload_count + BT_HC_HDR_SIZE;
+ p_cb->p_rcv_msg = \
+ (HC_BT_HDR *) bt_hc_cbacks->alloc(len);
+ }
+
+ if (p_cb->p_rcv_msg)
+ {
+ /* Initialize buffer with preloaded data */
+ p_cb->p_rcv_msg->offset = 0;
+ p_cb->p_rcv_msg->layer_specific = 0;
+ p_cb->p_rcv_msg->event = \
+ msg_evt_table[p_cb->rcv_msg_type-1];
+ p_cb->p_rcv_msg->len = p_cb->preload_count;
+ memcpy((uint8_t *)(p_cb->p_rcv_msg + 1), \
+ p_cb->preload_buffer, p_cb->preload_count);
+ }
+ }
+
+ if (p_cb->p_rcv_msg == NULL)
+ {
+ /* Unable to acquire message buffer. */
+ LOGE( \
+ "H4: Unable to acquire buffer for incoming HCI message." \
+ );
+
+ if (msg_len == 0)
+ {
+ /* Wait for next message */
+ p_cb->rcv_state = H4_RX_MSGTYPE_ST;
+ }
+ else
+ {
+ /* Ignore rest of the packet */
+ p_cb->rcv_state = H4_RX_IGNORE_ST;
+ }
+
+ break;
+ }
+
+ /* Message length is valid */
+ if (msg_len)
+ {
+ /* Read rest of message */
+ p_cb->rcv_state = H4_RX_DATA_ST;
+ }
+ else
+ {
+ /* Message has no additional parameters.
+ * (Entire message has been received) */
+ if (p_cb->rcv_msg_type == H4_TYPE_ACL_DATA)
+ acl_rx_frame_end_chk(); /* to print snoop trace */
+
+ msg_received = TRUE;
+
+ /* Next, wait for next message */
+ p_cb->rcv_state = H4_RX_MSGTYPE_ST;
+ }
+ }
+ break;
+
+ case H4_RX_DATA_ST:
+ *((uint8_t *)(p_cb->p_rcv_msg + 1) + p_cb->p_rcv_msg->len++) = byte;
+ p_cb->rcv_len--;
+
+ if (p_cb->rcv_len > 0)
+ {
+ /* Read in the rest of the message */
+ len = userial_read( \
+ ((uint8_t *)(p_cb->p_rcv_msg+1) + p_cb->p_rcv_msg->len), \
+ p_cb->rcv_len);
+ p_cb->p_rcv_msg->len += len;
+ p_cb->rcv_len -= len;
+ bytes_read += len;
+ }
+
+ /* Check if we read in entire message yet */
+ if (p_cb->rcv_len == 0)
+ {
+ /* Received entire packet. */
+ /* Check for segmented l2cap packets */
+ if ((p_cb->rcv_msg_type == H4_TYPE_ACL_DATA) &&
+ !acl_rx_frame_end_chk())
+ {
+ /* Not the end of packet yet. */
+ /* Next, wait for next message */
+ p_cb->rcv_state = H4_RX_MSGTYPE_ST;
+ }
+ else
+ {
+ msg_received = TRUE;
+ /* Next, wait for next message */
+ p_cb->rcv_state = H4_RX_MSGTYPE_ST;
+ }
+ }
+ break;
+
+
+ case H4_RX_IGNORE_ST:
+ /* Ignore reset of packet */
+ p_cb->rcv_len--;
+
+ /* Check if we read in entire message yet */
+ if (p_cb->rcv_len == 0)
+ {
+ /* Next, wait for next message */
+ p_cb->rcv_state = H4_RX_MSGTYPE_ST;
+ }
+ break;
+ }
+
+
+ /* If we received entire message, then send it to the task */
+ if (msg_received)
+ {
+ uint8_t intercepted = FALSE;
+
+ /* generate snoop trace message */
+ /* ACL packet tracing had done in acl_rx_frame_end_chk() */
+ if (p_cb->p_rcv_msg->event != MSG_HC_TO_STACK_HCI_ACL)
+ btsnoop_capture(p_cb->p_rcv_msg, TRUE);
+
+ if (p_cb->p_rcv_msg->event == MSG_HC_TO_STACK_HCI_EVT)
+ intercepted = internal_event_intercept();
+
+ if ((bt_hc_cbacks) && (intercepted == FALSE))
+ {
+ bt_hc_cbacks->data_ind((TRANSAC) p_cb->p_rcv_msg, \
+ (char *) (p_cb->p_rcv_msg + 1), \
+ p_cb->p_rcv_msg->len + BT_HC_HDR_SIZE);
+ }
+ p_cb->p_rcv_msg = NULL;
+ }
+ }
+
+ return (bytes_read);
+}
+
+
+/*******************************************************************************
+**
+** Function hci_h4_send_int_cmd
+**
+** Description Place the internal commands (issued internally by vendor lib)
+** in the tx_q.
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t hci_h4_send_int_cmd(uint16_t opcode, HC_BT_HDR *p_buf, \
+ tINT_CMD_CBACK p_cback)
+{
+ if (h4_cb.int_cmd_rsp_pending > INT_CMD_PKT_MAX_COUNT)
+ {
+ LOGE( \
+ "Allow only %d outstanding internal commands at a time [Reject 0x%04X]"\
+ , INT_CMD_PKT_MAX_COUNT, opcode);
+ return FALSE;
+ }
+
+ h4_cb.int_cmd_rsp_pending++;
+ h4_cb.int_cmd[h4_cb.int_cmd_wrt_idx].opcode = opcode;
+ h4_cb.int_cmd[h4_cb.int_cmd_wrt_idx].cback = p_cback;
+ h4_cb.int_cmd_wrt_idx = ((h4_cb.int_cmd_wrt_idx+1) & INT_CMD_PKT_IDX_MASK);
+
+ /* stamp signature to indicate an internal command */
+ p_buf->layer_specific = opcode;
+
+ utils_enqueue(&tx_q, (void *) p_buf);
+ bthc_signal_event(HC_EVENT_TX);
+
+ return TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function hci_h4_get_acl_data_length
+**
+** Description Issue HCI_READ_BUFFER_SIZE command to retrieve Controller's
+** ACL data length setting
+**
+** Returns None
+**
+*******************************************************************************/
+void hci_h4_get_acl_data_length(void)
+{
+ HC_BT_HDR *p_buf = NULL;
+ uint8_t *p, ret;
+
+ if (bt_hc_cbacks)
+ {
+ p_buf = (HC_BT_HDR *) bt_hc_cbacks->alloc(BT_HC_HDR_SIZE + \
+ HCI_CMD_PREAMBLE_SIZE);
+ }
+
+ if (p_buf)
+ {
+ p_buf->event = MSG_STACK_TO_HC_HCI_CMD;
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+ p_buf->len = HCI_CMD_PREAMBLE_SIZE;
+
+ p = (uint8_t *) (p_buf + 1);
+ UINT16_TO_STREAM(p, HCI_READ_BUFFER_SIZE);
+ *p = 0;
+
+ if ((ret = hci_h4_send_int_cmd(HCI_READ_BUFFER_SIZE, p_buf, \
+ get_acl_data_length_cback)) == FALSE)
+ {
+ bt_hc_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ }
+ else
+ return;
+ }
+
+ if (bt_hc_cbacks)
+ {
+ LOGE("vendor lib postload aborted");
+ bt_hc_cbacks->postload_cb(NULL, BT_HC_POSTLOAD_FAIL);
+ }
+}
+
diff --git a/hci/src/lpm.c b/hci/src/lpm.c
new file mode 100644
index 0000000..c07b37c
--- /dev/null
+++ b/hci/src/lpm.c
@@ -0,0 +1,453 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: lpm.c
+ *
+ * Description: Contains low power mode implementation
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_lpm"
+
+#include <utils/Log.h>
+#include <signal.h>
+#include <time.h>
+#include "bt_hci_bdroid.h"
+#include "bt_vendor_lib.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+#ifndef BTLPM_DBG
+#define BTLPM_DBG FALSE
+#endif
+
+#if (BTLPM_DBG == TRUE)
+#define BTLPMDBG(param, ...) {LOGD(param, ## __VA_ARGS__);}
+#else
+#define BTLPMDBG(param, ...) {}
+#endif
+
+#ifndef DEFAULT_LPM_IDLE_TIMEOUT
+#define DEFAULT_LPM_IDLE_TIMEOUT 3000
+#endif
+
+/******************************************************************************
+** Externs
+******************************************************************************/
+
+extern bt_vendor_interface_t *bt_vnd_if;
+
+/******************************************************************************
+** Local type definitions
+******************************************************************************/
+
+/* Low power mode state */
+enum {
+ LPM_DISABLED = 0, /* initial state */
+ LPM_ENABLED,
+ LPM_ENABLING,
+ LPM_DISABLING
+};
+
+/* LPM WAKE state */
+enum {
+ LPM_WAKE_DEASSERTED = 0, /* initial state */
+ LPM_WAKE_W4_TX_DONE,
+ LPM_WAKE_W4_TIMEOUT,
+ LPM_WAKE_ASSERTED
+};
+
+/* low power mode control block */
+typedef struct
+{
+ uint8_t state; /* Low power mode state */
+ uint8_t wake_state; /* LPM WAKE state */
+ uint8_t no_tx_data;
+ uint8_t timer_created;
+ timer_t timer_id;
+ uint32_t timeout_ms;
+} bt_lpm_cb_t;
+
+
+/******************************************************************************
+** Static variables
+******************************************************************************/
+
+static bt_lpm_cb_t bt_lpm_cb;
+
+/******************************************************************************
+** LPM Static Functions
+******************************************************************************/
+
+/*******************************************************************************
+**
+** Function lpm_idle_timeout
+**
+** Description Timeout thread of transport idle timer
+**
+** Returns None
+**
+*******************************************************************************/
+static void lpm_idle_timeout(union sigval arg)
+{
+ BTLPMDBG("..lpm_idle_timeout..");
+
+ if ((bt_lpm_cb.state == LPM_ENABLED) && \
+ (bt_lpm_cb.wake_state == LPM_WAKE_W4_TIMEOUT))
+ {
+ bthc_signal_event(HC_EVENT_LPM_IDLE_TIMEOUT);
+ }
+}
+
+/*******************************************************************************
+**
+** Function lpm_start_transport_idle_timer
+**
+** Description Launch transport idle timer
+**
+** Returns None
+**
+*******************************************************************************/
+static void lpm_start_transport_idle_timer(void)
+{
+ int status;
+ struct itimerspec ts;
+ struct sigevent se;
+
+ if (bt_lpm_cb.state != LPM_ENABLED)
+ return;
+
+ if (bt_lpm_cb.timer_created == FALSE)
+ {
+ se.sigev_notify = SIGEV_THREAD;
+ se.sigev_value.sival_ptr = &bt_lpm_cb.timer_id;
+ se.sigev_notify_function = lpm_idle_timeout;
+ se.sigev_notify_attributes = NULL;
+
+ status = timer_create(CLOCK_MONOTONIC, &se, &bt_lpm_cb.timer_id);
+
+ if (status == 0)
+ bt_lpm_cb.timer_created = TRUE;
+ }
+
+ if (bt_lpm_cb.timer_created == TRUE)
+ {
+ ts.it_value.tv_sec = bt_lpm_cb.timeout_ms/1000;
+ ts.it_value.tv_nsec = 1000*(bt_lpm_cb.timeout_ms%1000);
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+
+ status = timer_settime(bt_lpm_cb.timer_id, 0, &ts, 0);
+ if (status == -1)
+ LOGE("[START] Failed to set LPM idle timeout");
+ }
+}
+
+/*******************************************************************************
+**
+** Function lpm_stop_transport_idle_timer
+**
+** Description Launch transport idle timer
+**
+** Returns None
+**
+*******************************************************************************/
+static void lpm_stop_transport_idle_timer(void)
+{
+ int status;
+ struct itimerspec ts;
+
+ if (bt_lpm_cb.timer_created == TRUE)
+ {
+ ts.it_value.tv_sec = 0;
+ ts.it_value.tv_nsec = 0;
+ ts.it_interval.tv_sec = 0;
+ ts.it_interval.tv_nsec = 0;
+
+ status = timer_settime(bt_lpm_cb.timer_id, 0, &ts, 0);
+ if (status == -1)
+ LOGE("[STOP] Failed to set LPM idle timeout");
+ }
+}
+
+/*******************************************************************************
+**
+** Function lpm_vnd_cback
+**
+** Description Callback of vendor specific result for lpm enable/disable
+** rquest
+**
+** Returns None
+**
+*******************************************************************************/
+void lpm_vnd_cback(uint8_t vnd_result)
+{
+ if (vnd_result == 0)
+ {
+ /* Status == Success */
+ bt_lpm_cb.state = (bt_lpm_cb.state == LPM_ENABLING) ? \
+ LPM_ENABLED : LPM_DISABLED;
+ }
+ else
+ {
+ bt_lpm_cb.state = (bt_lpm_cb.state == LPM_ENABLING) ? \
+ LPM_DISABLED : LPM_ENABLED;
+ }
+
+ if (bt_hc_cbacks)
+ {
+ if (bt_lpm_cb.state == LPM_ENABLED)
+ bt_hc_cbacks->lpm_cb(BT_HC_LPM_ENABLED);
+ else
+ bt_hc_cbacks->lpm_cb(BT_HC_LPM_DISABLED);
+ }
+
+ if (bt_lpm_cb.state == LPM_DISABLED)
+ {
+ if (bt_lpm_cb.timer_created == TRUE)
+ {
+ timer_delete(bt_lpm_cb.timer_id);
+ }
+
+ memset(&bt_lpm_cb, 0, sizeof(bt_lpm_cb_t));
+ }
+}
+
+
+/*****************************************************************************
+** Low Power Mode Interface Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function lpm_init
+**
+** Description Init LPM
+**
+** Returns None
+**
+*******************************************************************************/
+void lpm_init(void)
+{
+ memset(&bt_lpm_cb, 0, sizeof(bt_lpm_cb_t));
+
+ /* Calling vendor-specific part */
+ if (bt_vnd_if)
+ bt_vnd_if->op(BT_VND_OP_GET_LPM_IDLE_TIMEOUT, &(bt_lpm_cb.timeout_ms));
+ else
+ bt_lpm_cb.timeout_ms = DEFAULT_LPM_IDLE_TIMEOUT;
+}
+
+/*******************************************************************************
+**
+** Function lpm_cleanup
+**
+** Description Clean up
+**
+** Returns None
+**
+*******************************************************************************/
+void lpm_cleanup(void)
+{
+ if (bt_lpm_cb.timer_created == TRUE)
+ {
+ timer_delete(bt_lpm_cb.timer_id);
+ }
+}
+
+/*******************************************************************************
+**
+** Function lpm_enable
+**
+** Description Enalbe/Disable LPM
+**
+** Returns None
+**
+*******************************************************************************/
+void lpm_enable(uint8_t turn_on)
+{
+ if ((bt_lpm_cb.state!=LPM_DISABLED) && (bt_lpm_cb.state!=LPM_ENABLED))
+ {
+ LOGW("Still busy on processing prior LPM enable/disable request...");
+ return;
+ }
+
+ if ((turn_on == TRUE) && (bt_lpm_cb.state == LPM_ENABLED))
+ {
+ LOGI("LPM is already on!!!");
+ if (bt_hc_cbacks)
+ bt_hc_cbacks->lpm_cb(BT_HC_LPM_ENABLED);
+ }
+ else if ((turn_on == FALSE) && (bt_lpm_cb.state == LPM_DISABLED))
+ {
+ LOGI("LPM is already off!!!");
+ if (bt_hc_cbacks)
+ bt_hc_cbacks->lpm_cb(BT_HC_LPM_DISABLED);
+ }
+
+ /* Calling vendor-specific part */
+ if (bt_vnd_if)
+ {
+ bt_lpm_cb.state = (turn_on) ? LPM_ENABLING : LPM_DISABLING;
+ bt_vnd_if->op(BT_VND_OP_LPM_SET_MODE, &turn_on);
+ }
+}
+
+/*******************************************************************************
+**
+** Function lpm_tx_done
+**
+** Description This function is to inform the lpm module
+** if data is waiting in the Tx Q or not.
+**
+** IsTxDone: TRUE if All data in the Tx Q are gone
+** FALSE if any data is still in the Tx Q.
+** Typicaly this function must be called
+** before USERIAL Write and in the Tx Done routine
+**
+** Returns None
+**
+*******************************************************************************/
+void lpm_tx_done(uint8_t is_tx_done)
+{
+ bt_lpm_cb.no_tx_data = is_tx_done;
+
+ if ((bt_lpm_cb.wake_state==LPM_WAKE_W4_TX_DONE) && (is_tx_done==TRUE))
+ {
+ bt_lpm_cb.wake_state = LPM_WAKE_W4_TIMEOUT;
+ lpm_start_transport_idle_timer();
+ }
+}
+
+/*******************************************************************************
+**
+** Function lpm_wake_assert
+**
+** Description Called to wake up Bluetooth chip.
+** Normally this is called when there is data to be sent
+** over UART.
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+void lpm_wake_assert(void)
+{
+ if (bt_lpm_cb.state != LPM_DISABLED)
+ {
+ BTLPMDBG("LPM WAKE assert");
+
+ /* Calling vendor-specific part */
+ if (bt_vnd_if)
+ {
+ uint8_t state = BT_VND_LPM_WAKE_ASSERT;
+ bt_vnd_if->op(BT_VND_OP_LPM_WAKE_SET_STATE, &state);
+ }
+
+ lpm_stop_transport_idle_timer();
+
+ bt_lpm_cb.wake_state = LPM_WAKE_ASSERTED;
+ }
+
+ lpm_tx_done(FALSE);
+}
+
+/*******************************************************************************
+**
+** Function lpm_allow_bt_device_sleep
+**
+** Description Start LPM idle timer if allowed
+**
+** Returns None
+**
+*******************************************************************************/
+void lpm_allow_bt_device_sleep(void)
+{
+ if ((bt_lpm_cb.state == LPM_ENABLED) && \
+ (bt_lpm_cb.wake_state == LPM_WAKE_ASSERTED))
+ {
+ if(bt_lpm_cb.no_tx_data == TRUE)
+ {
+ bt_lpm_cb.wake_state = LPM_WAKE_W4_TIMEOUT;
+ lpm_start_transport_idle_timer();
+ }
+ else
+ {
+ bt_lpm_cb.wake_state = LPM_WAKE_W4_TX_DONE;
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function lpm_wake_deassert
+**
+** Description Deassert wake if allowed
+**
+** Returns None
+**
+*******************************************************************************/
+void lpm_wake_deassert(void)
+{
+ if ((bt_lpm_cb.state == LPM_ENABLED) && (bt_lpm_cb.no_tx_data == TRUE))
+ {
+ BTLPMDBG("LPM WAKE deassert");
+
+ /* Calling vendor-specific part */
+ if (bt_vnd_if)
+ {
+ uint8_t state = BT_VND_LPM_WAKE_DEASSERT;
+ bt_vnd_if->op(BT_VND_OP_LPM_WAKE_SET_STATE, &state);
+ }
+
+ bt_lpm_cb.wake_state = LPM_WAKE_DEASSERTED;
+ }
+}
+
diff --git a/hci/src/userial.c b/hci/src/userial.c
new file mode 100644
index 0000000..7385480
--- /dev/null
+++ b/hci/src/userial.c
@@ -0,0 +1,597 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: userial.c
+ *
+ * Description: Contains open/read/write/close functions on serial port
+ *
+ ******************************************************************************/
+
+#define LOG_TAG "bt_userial"
+
+#include <utils/Log.h>
+#include <pthread.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include "bt_hci_bdroid.h"
+#include "userial.h"
+#include "utils.h"
+#include "bt_vendor_lib.h"
+
+/******************************************************************************
+** Constants & Macros
+******************************************************************************/
+
+#ifndef USERIAL_DBG
+#define USERIAL_DBG FALSE
+#endif
+
+#if (USERIAL_DBG == TRUE)
+#define USERIALDBG(param, ...) {LOGD(param, ## __VA_ARGS__);}
+#else
+#define USERIALDBG(param, ...) {}
+#endif
+
+#define MAX_SERIAL_PORT (USERIAL_PORT_3 + 1)
+#define READ_LIMIT (BTHC_USERIAL_READ_MEM_SIZE - BT_HC_HDR_SIZE)
+
+enum {
+ USERIAL_RX_EXIT,
+ USERIAL_RX_FLOW_OFF,
+ USERIAL_RX_FLOW_ON
+};
+
+/******************************************************************************
+** Externs
+******************************************************************************/
+
+extern bt_vendor_interface_t *bt_vnd_if;
+
+/******************************************************************************
+** Local type definitions
+******************************************************************************/
+
+typedef struct
+{
+ int sock;
+ uint8_t port;
+ pthread_t read_thread;
+ tUSERIAL_CFG cfg;
+ BUFFER_Q rx_q;
+ HC_BT_HDR *p_rx_hdr;
+} tUSERIAL_CB;
+
+/******************************************************************************
+** Static variables
+******************************************************************************/
+
+static tUSERIAL_CB userial_cb;
+static volatile uint8_t userial_running = 0;
+
+/* for friendly debugging outpout string */
+static uint32_t userial_baud_tbl[] =
+{
+ 300, /* USERIAL_BAUD_300 0 */
+ 600, /* USERIAL_BAUD_600 1 */
+ 1200, /* USERIAL_BAUD_1200 2 */
+ 2400, /* USERIAL_BAUD_2400 3 */
+ 9600, /* USERIAL_BAUD_9600 4 */
+ 19200, /* USERIAL_BAUD_19200 5 */
+ 57600, /* USERIAL_BAUD_57600 6 */
+ 115200, /* USERIAL_BAUD_115200 7 */
+ 230400, /* USERIAL_BAUD_230400 8 */
+ 460800, /* USERIAL_BAUD_460800 9 */
+ 921600, /* USERIAL_BAUD_921600 10 */
+ 1000000, /* USERIAL_BAUD_1M 11 */
+ 1500000, /* USERIAL_BAUD_1_5M 12 */
+ 2000000, /* USERIAL_BAUD_2M 13 */
+ 3000000, /* USERIAL_BAUD_3M 14 */
+ 4000000 /* USERIAL_BAUD_4M 15 */
+};
+
+/******************************************************************************
+** Static functions
+******************************************************************************/
+
+/*****************************************************************************
+** Socket signal functions to wake up userial_read_thread for termination
+**
+** creating an unnamed pair of connected sockets
+** - signal_fds[0]: join fd_set in select call of userial_read_thread
+** - signal_fds[1]: trigger from userial_close
+*****************************************************************************/
+static int signal_fds[2]={0,1};
+static uint8_t rx_flow_on = TRUE;
+static inline int create_signal_fds(fd_set* set)
+{
+ if(signal_fds[0]==0 && socketpair(AF_UNIX, SOCK_STREAM, 0, signal_fds)<0)
+ {
+ LOGE("create_signal_sockets:socketpair failed, errno: %d", errno);
+ return -1;
+ }
+ FD_SET(signal_fds[0], set);
+ return signal_fds[0];
+}
+static inline int send_wakeup_signal(char sig_cmd)
+{
+ return send(signal_fds[1], &sig_cmd, sizeof(sig_cmd), 0);
+}
+static inline char reset_signal()
+{
+ char sig_recv = -1;
+ recv(signal_fds[0], &sig_recv, sizeof(sig_recv), MSG_WAITALL);
+ return sig_recv;
+}
+static inline int is_signaled(fd_set* set)
+{
+ return FD_ISSET(signal_fds[0], set);
+}
+
+/*******************************************************************************
+**
+** Function select_read
+**
+** Description check if fd is ready for reading and listen for termination
+** signal. need to use select in order to avoid collision
+** between read and close on the same fd
+**
+** Returns -1: termination
+** >=0: numbers of bytes read back from fd
+**
+*******************************************************************************/
+static int select_read(int fd, uint8_t *pbuf, int len)
+{
+ fd_set input;
+ int n = 0, ret = -1;
+ char reason = 0;
+
+ while (userial_running)
+ {
+ /* Initialize the input fd set */
+ FD_ZERO(&input);
+ if (rx_flow_on == TRUE)
+ {
+ FD_SET(fd, &input);
+ }
+ int fd_max = create_signal_fds(&input);
+ fd_max = fd_max > fd ? fd_max : fd;
+
+ /* Do the select */
+ n = select(fd_max+1, &input, NULL, NULL, NULL);
+ if(is_signaled(&input))
+ {
+ reason = reset_signal();
+ if (reason == USERIAL_RX_EXIT)
+ {
+ USERIALDBG("RX termination");
+ return -1;
+ }
+ else if (reason == USERIAL_RX_FLOW_OFF)
+ {
+ USERIALDBG("RX flow OFF");
+ rx_flow_on = FALSE;
+ }
+ else if (reason == USERIAL_RX_FLOW_ON)
+ {
+ USERIALDBG("RX flow ON");
+ rx_flow_on = TRUE;
+ }
+ }
+
+ if (n > 0)
+ {
+ /* We might have input */
+ if (FD_ISSET(fd, &input))
+ {
+ ret = read(fd, pbuf, (size_t)len);
+ if (0 == ret)
+ LOGW( "read() returned 0!" );
+
+ return ret;
+ }
+ }
+ else if (n < 0)
+ LOGW( "select() Failed");
+ else if (n == 0)
+ LOGW( "Got a select() TIMEOUT");
+
+ }
+
+ return ret;
+}
+
+/*******************************************************************************
+**
+** Function userial_read_thread
+**
+** Description
+**
+** Returns void *
+**
+*******************************************************************************/
+static void *userial_read_thread(void *arg)
+{
+ int rx_length = 0;
+ HC_BT_HDR *p_buf = NULL;
+ uint8_t *p;
+
+ USERIALDBG("Entering userial_read_thread()");
+
+ rx_flow_on = TRUE;
+ userial_running = 1;
+
+ while (userial_running)
+ {
+ if (bt_hc_cbacks)
+ {
+ p_buf = (HC_BT_HDR *) bt_hc_cbacks->alloc( \
+ BTHC_USERIAL_READ_MEM_SIZE);
+ }
+ else
+ p_buf = NULL;
+
+ if (p_buf != NULL)
+ {
+ p_buf->offset = 0;
+ p_buf->layer_specific = 0;
+
+ p = (uint8_t *) (p_buf + 1);
+ rx_length = select_read(userial_cb.sock, p, READ_LIMIT);
+ }
+ else
+ {
+ rx_length = 0;
+ utils_delay(100);
+ LOGW("userial_read_thread() failed to gain buffers");
+ continue;
+ }
+
+
+ if (rx_length > 0)
+ {
+ p_buf->len = (uint16_t)rx_length;
+ utils_enqueue(&(userial_cb.rx_q), p_buf);
+ bthc_signal_event(HC_EVENT_RX);
+ }
+ else /* either 0 or < 0 */
+ {
+ LOGW("select_read return size <=0:%d, exiting userial_read_thread",\
+ rx_length);
+ /* if we get here, we should have a buffer */
+ bt_hc_cbacks->dealloc((TRANSAC) p_buf, (char *) (p_buf + 1));
+ /* negative value means exit thread */
+ break;
+ }
+ } /* for */
+
+ userial_running = 0;
+ USERIALDBG("Leaving userial_read_thread()");
+ pthread_exit(NULL);
+
+ return NULL; // Compiler friendly
+}
+
+
+/*****************************************************************************
+** Userial API Functions
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function userial_init
+**
+** Description Initializes the userial driver
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t userial_init(void)
+{
+ USERIALDBG("userial_init");
+ memset(&userial_cb, 0, sizeof(tUSERIAL_CB));
+ userial_cb.sock = -1;
+ utils_queue_init(&(userial_cb.rx_q));
+ return TRUE;
+}
+
+
+/*******************************************************************************
+**
+** Function userial_open
+**
+** Description Open the indicated serial port with the given configuration
+**
+** Returns TRUE/FALSE
+**
+*******************************************************************************/
+uint8_t userial_open(uint8_t port, tUSERIAL_CFG *p_cfg)
+{
+ struct sched_param param;
+ int policy, result;
+ pthread_attr_t thread_attr;
+
+ USERIALDBG("userial_open(port:%d, baud:%d)", port, p_cfg->baud);
+
+ if (userial_running)
+ {
+ /* Userial is open; close it first */
+ userial_close();
+ utils_delay(50);
+ }
+
+ if (port >= MAX_SERIAL_PORT)
+ {
+ LOGE("Port > MAX_SERIAL_PORT");
+ return FALSE;
+ }
+
+ /* Calling vendor-specific part */
+ if (bt_vnd_if)
+ {
+ userial_cb.sock = bt_vnd_if->op(BT_VND_OP_USERIAL_OPEN, p_cfg);
+ }
+ else
+ {
+ LOGE("userial_open: missing vendor lib interface !!!");
+ LOGE("userial_open: unable to open UART port");
+ return FALSE;
+ }
+
+ if (userial_cb.sock == -1)
+ {
+ LOGE("userial_open: failed to open UART port");
+ return FALSE;
+ }
+
+
+ USERIALDBG( "sock = %d", userial_cb.sock);
+
+ userial_cb.port = port;
+ memcpy(&userial_cb.cfg, p_cfg, sizeof(tUSERIAL_CFG));
+
+ pthread_attr_init(&thread_attr);
+
+ if (pthread_create(&(userial_cb.read_thread), &thread_attr, \
+ userial_read_thread, NULL) != 0 )
+ {
+ LOGE("pthread_create failed!");
+ return FALSE;
+ }
+
+ if(pthread_getschedparam(userial_cb.read_thread, &policy, &param)==0)
+ {
+ policy = BTHC_LINUX_BASE_POLICY;
+#if (BTHC_LINUX_BASE_POLICY!=SCHED_NORMAL)
+ param.sched_priority = BTHC_USERIAL_READ_THREAD_PRIORITY;
+#endif
+ result = pthread_setschedparam(userial_cb.read_thread, policy, &param);
+ if (result != 0)
+ {
+ LOGW("userial_open: pthread_setschedparam failed (%s)", \
+ strerror(result));
+ }
+ }
+
+ return TRUE;
+}
+
+/*******************************************************************************
+**
+** Function userial_read
+**
+** Description Read data from the userial port
+**
+** Returns Number of bytes actually read from the userial port and
+** copied into p_data. This may be less than len.
+**
+*******************************************************************************/
+uint16_t userial_read(uint8_t *p_buffer, uint16_t len)
+{
+ uint16_t total_len = 0;
+ uint16_t copy_len = 0;
+ uint8_t *p_data = NULL;
+
+ do
+ {
+ if(userial_cb.p_rx_hdr != NULL)
+ {
+ p_data = ((uint8_t *)(userial_cb.p_rx_hdr + 1)) + \
+ (userial_cb.p_rx_hdr->offset);
+
+ if((userial_cb.p_rx_hdr->len) <= (len - total_len))
+ copy_len = userial_cb.p_rx_hdr->len;
+ else
+ copy_len = (len - total_len);
+
+ memcpy((p_buffer + total_len), p_data, copy_len);
+
+ total_len += copy_len;
+
+ userial_cb.p_rx_hdr->offset += copy_len;
+ userial_cb.p_rx_hdr->len -= copy_len;
+
+ if(userial_cb.p_rx_hdr->len == 0)
+ {
+ if (bt_hc_cbacks)
+ bt_hc_cbacks->dealloc((TRANSAC) userial_cb.p_rx_hdr, \
+ (char *) (userial_cb.p_rx_hdr+1));
+
+ userial_cb.p_rx_hdr = NULL;
+ }
+ }
+
+ if(userial_cb.p_rx_hdr == NULL)
+ {
+ userial_cb.p_rx_hdr=(HC_BT_HDR *)utils_dequeue(&(userial_cb.rx_q));
+ }
+ } while ((userial_cb.p_rx_hdr != NULL) && (total_len < len));
+
+ return total_len;
+}
+
+/*******************************************************************************
+**
+** Function userial_write
+**
+** Description Write data to the userial port
+**
+** Returns Number of bytes actually written to the userial port. This
+** may be less than len.
+**
+*******************************************************************************/
+uint16_t userial_write(uint8_t *p_data, uint16_t len)
+{
+ int ret, total = 0;
+
+ while(len != 0)
+ {
+ ret = write(userial_cb.sock, p_data+total, len);
+ total += ret;
+ len -= ret;
+ }
+
+ return ((uint16_t)total);
+}
+
+/*******************************************************************************
+**
+** Function userial_close
+**
+** Description Close the userial port
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_close(void)
+{
+ int result;
+ TRANSAC p_buf;
+
+ USERIALDBG("userial_close(sock:%d)", userial_cb.sock);
+
+ if (userial_running)
+ send_wakeup_signal(USERIAL_RX_EXIT);
+
+ if ((result=pthread_join(userial_cb.read_thread, NULL)) < 0)
+ LOGE( "pthread_join() FAILED result:%d", result);
+
+ /* Calling vendor-specific part */
+ if (bt_vnd_if)
+ bt_vnd_if->op(BT_VND_OP_USERIAL_CLOSE, NULL);
+
+ if ((result=close(userial_cb.sock)) < 0)
+ LOGE( "close(sock:%d) FAILED result:%d", userial_cb.sock, result);
+
+ userial_cb.sock = -1;
+
+ if (bt_hc_cbacks)
+ {
+ while ((p_buf = utils_dequeue (&(userial_cb.rx_q))) != NULL)
+ {
+ bt_hc_cbacks->dealloc(p_buf, (char *) ((HC_BT_HDR *)p_buf+1));
+ }
+ }
+}
+
+/*******************************************************************************
+**
+** Function userial_change_baud
+**
+** Description Change baud rate of userial port
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_change_baud(uint8_t baud)
+{
+ USERIALDBG("userial_change_baud: Closing UART Port");
+ userial_close();
+
+ utils_delay(100);
+
+ /* change baud rate in settings - leave everything else the same */
+ userial_cb.cfg.baud = baud;
+
+ LOGI("userial_change_rate: Attempting to reopen the UART Port at %i", \
+ (unsigned int)userial_baud_tbl[baud]);
+
+ userial_open(userial_cb.port, &userial_cb.cfg);
+}
+
+/*******************************************************************************
+**
+** Function userial_ioctl
+**
+** Description ioctl inteface
+**
+** Returns None
+**
+*******************************************************************************/
+void userial_ioctl(userial_ioctl_op_t op, void *p_data)
+{
+ switch(op)
+ {
+ case USERIAL_OP_RXFLOW_ON:
+ if (userial_running)
+ send_wakeup_signal(USERIAL_RX_FLOW_ON);
+ break;
+
+ case USERIAL_OP_RXFLOW_OFF:
+ if (userial_running)
+ send_wakeup_signal(USERIAL_RX_FLOW_OFF);
+ break;
+
+ case USERIAL_OP_INIT:
+ default:
+ break;
+ }
+}
+
diff --git a/hci/src/utils.c b/hci/src/utils.c
new file mode 100644
index 0000000..9c1711b
--- /dev/null
+++ b/hci/src/utils.c
@@ -0,0 +1,315 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2009-2012 Broadcom Corporation
+ *
+ * This program is the proprietary software of Broadcom Corporation and/or its
+ * licensors, and may only be used, duplicated, modified or distributed
+ * pursuant to the terms and conditions of a separate, written license
+ * agreement executed between you and Broadcom (an "Authorized License").
+ * Except as set forth in an Authorized License, Broadcom grants no license
+ * (express or implied), right to use, or waiver of any kind with respect to
+ * the Software, and Broadcom expressly reserves all rights in and to the
+ * Software and all intellectual property rights therein.
+ * IF YOU HAVE NO AUTHORIZED LICENSE, THEN YOU HAVE NO RIGHT TO USE THIS
+ * SOFTWARE IN ANY WAY, AND SHOULD IMMEDIATELY NOTIFY BROADCOM AND DISCONTINUE
+ * ALL USE OF THE SOFTWARE.
+ *
+ * Except as expressly set forth in the Authorized License,
+ *
+ * 1. This program, including its structure, sequence and organization,
+ * constitutes the valuable trade secrets of Broadcom, and you shall
+ * use all reasonable efforts to protect the confidentiality thereof,
+ * and to use this information only in connection with your use of
+ * Broadcom integrated circuit products.
+ *
+ * 2. TO THE MAXIMUM EXTENT PERMITTED BY LAW, THE SOFTWARE IS PROVIDED
+ * "AS IS" AND WITH ALL FAULTS AND BROADCOM MAKES NO PROMISES,
+ * REPRESENTATIONS OR WARRANTIES, EITHER EXPRESS, IMPLIED, STATUTORY,
+ * OR OTHERWISE, WITH RESPECT TO THE SOFTWARE. BROADCOM SPECIFICALLY
+ * DISCLAIMS ANY AND ALL IMPLIED WARRANTIES OF TITLE, MERCHANTABILITY,
+ * NONINFRINGEMENT, FITNESS FOR A PARTICULAR PURPOSE, LACK OF VIRUSES,
+ * ACCURACY OR COMPLETENESS, QUIET ENJOYMENT, QUIET POSSESSION OR
+ * CORRESPONDENCE TO DESCRIPTION. YOU ASSUME THE ENTIRE RISK ARISING OUT
+ * OF USE OR PERFORMANCE OF THE SOFTWARE.
+ *
+ * 3. TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL BROADCOM OR
+ * ITS LICENSORS BE LIABLE FOR
+ * (i) CONSEQUENTIAL, INCIDENTAL, SPECIAL, INDIRECT, OR EXEMPLARY
+ * DAMAGES WHATSOEVER ARISING OUT OF OR IN ANY WAY RELATING TO
+ * YOUR USE OF OR INABILITY TO USE THE SOFTWARE EVEN IF BROADCOM
+ * HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES; OR
+ * (ii) ANY AMOUNT IN EXCESS OF THE AMOUNT ACTUALLY PAID FOR THE
+ * SOFTWARE ITSELF OR U.S. $1, WHICHEVER IS GREATER. THESE
+ * LIMITATIONS SHALL APPLY NOTWITHSTANDING ANY FAILURE OF
+ * ESSENTIAL PURPOSE OF ANY LIMITED REMEDY.
+ *
+ ******************************************************************************/
+
+/******************************************************************************
+ *
+ * Filename: utils.c
+ *
+ * Description: Contains helper functions
+ *
+ ******************************************************************************/
+
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+#include "bt_hci_bdroid.h"
+#include "utils.h"
+
+/******************************************************************************
+** Static variables
+******************************************************************************/
+
+static pthread_mutex_t utils_mutex;
+
+/*****************************************************************************
+** UTILS INTERFACE FUNCTIONS
+*****************************************************************************/
+
+/*******************************************************************************
+**
+** Function utils_init
+**
+** Description Utils initialization
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_init (void)
+{
+ pthread_mutex_init(&utils_mutex, NULL);
+}
+
+/*******************************************************************************
+**
+** Function utils_cleanup
+**
+** Description Utils cleanup
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_cleanup (void)
+{
+}
+
+/*******************************************************************************
+**
+** Function utils_queue_init
+**
+** Description Initialize the given buffer queue
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_queue_init (BUFFER_Q *p_q)
+{
+ p_q->p_first = p_q->p_last = NULL;
+ p_q->count = 0;
+}
+
+/*******************************************************************************
+**
+** Function utils_enqueue
+**
+** Description Enqueue a buffer at the tail of the given queue
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_enqueue (BUFFER_Q *p_q, void *p_buf)
+{
+ HC_BUFFER_HDR_T *p_hdr;
+
+ p_hdr = (HC_BUFFER_HDR_T *) ((uint8_t *) p_buf - BT_HC_BUFFER_HDR_SIZE);
+
+ pthread_mutex_lock(&utils_mutex);
+
+ if (p_q->p_last)
+ {
+ HC_BUFFER_HDR_T *p_last_hdr = \
+ (HC_BUFFER_HDR_T *)((uint8_t *)p_q->p_last - BT_HC_BUFFER_HDR_SIZE);
+
+ p_last_hdr->p_next = p_hdr;
+ }
+ else
+ p_q->p_first = p_buf;
+
+ p_q->p_last = p_buf;
+ p_q->count++;
+
+ p_hdr->p_next = NULL;
+
+ pthread_mutex_unlock(&utils_mutex);
+}
+
+/*******************************************************************************
+**
+** Function utils_dequeue
+**
+** Description Dequeues a buffer from the head of the given queue
+**
+** Returns NULL if queue is empty, else buffer
+**
+*******************************************************************************/
+void *utils_dequeue (BUFFER_Q *p_q)
+{
+ HC_BUFFER_HDR_T *p_hdr;
+
+ pthread_mutex_lock(&utils_mutex);
+
+ if (!p_q || !p_q->count)
+ {
+ pthread_mutex_unlock(&utils_mutex);
+ return (NULL);
+ }
+
+ p_hdr=(HC_BUFFER_HDR_T *)((uint8_t *)p_q->p_first-BT_HC_BUFFER_HDR_SIZE);
+
+ if (p_hdr->p_next)
+ p_q->p_first = ((uint8_t *)p_hdr->p_next + BT_HC_BUFFER_HDR_SIZE);
+ else
+ {
+ p_q->p_first = NULL;
+ p_q->p_last = NULL;
+ }
+
+ p_q->count--;
+
+ p_hdr->p_next = NULL;
+
+ pthread_mutex_unlock(&utils_mutex);
+
+ return ((uint8_t *)p_hdr + BT_HC_BUFFER_HDR_SIZE);
+}
+
+/*******************************************************************************
+**
+** Function utils_getnext
+**
+** Description Return a pointer to the next buffer linked to the given
+** buffer
+**
+** Returns NULL if the given buffer does not point to any next buffer,
+** else next buffer address
+**
+*******************************************************************************/
+void *utils_getnext (void *p_buf)
+{
+ HC_BUFFER_HDR_T *p_hdr;
+
+ p_hdr = (HC_BUFFER_HDR_T *) ((uint8_t *) p_buf - BT_HC_BUFFER_HDR_SIZE);
+
+ if (p_hdr->p_next)
+ return ((uint8_t *)p_hdr->p_next + BT_HC_BUFFER_HDR_SIZE);
+ else
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function utils_remove_from_queue
+**
+** Description Dequeue the given buffer from the middle of the given queue
+**
+** Returns NULL if the given queue is empty, else the given buffer
+**
+*******************************************************************************/
+void *utils_remove_from_queue (BUFFER_Q *p_q, void *p_buf)
+{
+ HC_BUFFER_HDR_T *p_prev;
+ HC_BUFFER_HDR_T *p_buf_hdr;
+
+ pthread_mutex_lock(&utils_mutex);
+
+ if (p_buf == p_q->p_first)
+ {
+ pthread_mutex_unlock(&utils_mutex);
+ return (utils_dequeue (p_q));
+ }
+
+ p_buf_hdr = (HC_BUFFER_HDR_T *)((uint8_t *)p_buf - BT_HC_BUFFER_HDR_SIZE);
+ p_prev=(HC_BUFFER_HDR_T *)((uint8_t *)p_q->p_first-BT_HC_BUFFER_HDR_SIZE);
+
+ for ( ; p_prev; p_prev = p_prev->p_next)
+ {
+ /* If the previous points to this one, move the pointers around */
+ if (p_prev->p_next == p_buf_hdr)
+ {
+ p_prev->p_next = p_buf_hdr->p_next;
+
+ /* If we are removing the last guy in the queue, update p_last */
+ if (p_buf == p_q->p_last)
+ p_q->p_last = p_prev + 1;
+
+ /* One less in the queue */
+ p_q->count--;
+
+ /* The buffer is now unlinked */
+ p_buf_hdr->p_next = NULL;
+
+ pthread_mutex_unlock(&utils_mutex);
+ return (p_buf);
+ }
+ }
+
+ pthread_mutex_unlock(&utils_mutex);
+ return (NULL);
+}
+
+/*******************************************************************************
+**
+** Function utils_delay
+**
+** Description sleep unconditionally for timeout milliseconds
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_delay (uint32_t timeout)
+{
+ struct timespec delay;
+ int err;
+
+ delay.tv_sec = timeout / 1000;
+ delay.tv_nsec = 1000 * 1000 * (timeout%1000);
+
+ /* [u]sleep can't be used because it uses SIGALRM */
+ do {
+ err = nanosleep(&delay, &delay);
+ } while (err < 0 && errno ==EINTR);
+}
+
+/*******************************************************************************
+**
+** Function utils_lock
+**
+** Description application calls this function before entering critical
+** section
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_lock (void)
+{
+ pthread_mutex_lock(&utils_mutex);
+}
+
+/*******************************************************************************
+**
+** Function utils_unlock
+**
+** Description application calls this function when leaving critical
+** section
+**
+** Returns None
+**
+*******************************************************************************/
+void utils_unlock (void)
+{
+ pthread_mutex_unlock(&utils_mutex);
+}
+