From 32f0db60f911ed0b7f3bca0210a4568621b99074 Mon Sep 17 00:00:00 2001 From: YK Jeffrey Chao Date: Mon, 23 Apr 2012 11:28:18 -0700 Subject: 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 --- hci/Android.mk | 25 + hci/include/bt_hci_bdroid.h | 182 ++++++++ hci/include/bt_hci_lib.h | 231 ++++++++++ hci/include/bt_vendor_lib.h | 171 +++++++ hci/include/userial.h | 224 +++++++++ hci/include/utils.h | 200 ++++++++ hci/src/bt_hci_bdroid.c | 521 +++++++++++++++++++++ hci/src/bt_hw.c | 250 ++++++++++ hci/src/btsnoop.c | 717 +++++++++++++++++++++++++++++ hci/src/hci_h4.c | 1074 +++++++++++++++++++++++++++++++++++++++++++ hci/src/lpm.c | 453 ++++++++++++++++++ hci/src/userial.c | 597 ++++++++++++++++++++++++ hci/src/utils.c | 315 +++++++++++++ 13 files changed, 4960 insertions(+) create mode 100644 hci/Android.mk create mode 100644 hci/include/bt_hci_bdroid.h create mode 100644 hci/include/bt_hci_lib.h create mode 100644 hci/include/bt_vendor_lib.h create mode 100644 hci/include/userial.h create mode 100644 hci/include/utils.h create mode 100644 hci/src/bt_hci_bdroid.c create mode 100644 hci/src/bt_hw.c create mode 100644 hci/src/btsnoop.c create mode 100644 hci/src/hci_h4.c create mode 100644 hci/src/lpm.c create mode 100644 hci/src/userial.c create mode 100644 hci/src/utils.c (limited to 'hci') 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 +#include +#include + +/** 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 +#include +#include + +/** 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 +#include +#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, ¶m)==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, ¶m); + 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 +#include +#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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* for gettimeofday */ +#include +/* for the S_* open parameters */ +#include +/* for write */ +#include +/* for O_* open parameters */ +#include +/* defines the O_* open parameters */ +#include + +#define LOG_TAG "BTSNOOP-DISP" +#include + +#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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#include +#include +#include +#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, ¶m)==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, ¶m); + 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 +#include +#include +#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); +} + -- cgit v1.1