From 3f154f783bbe7f64d7ab455c01294a361f7ac133 Mon Sep 17 00:00:00 2001 From: Devin Kim Date: Mon, 18 May 2015 10:39:12 -0700 Subject: Bluetooth: Fix the FW loading in BCM4343 BCM4343 doesn't have the name starting with 'BCM'. So fix the name to use the dynamic FW loading for BCM4343 Bug: 21268506 Change-Id: Id43a748bf6180c2464671d35e7be3caaa6532e82 --- src/hardware.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'src') diff --git a/src/hardware.c b/src/hardware.c index 02103ca..9869ffa 100755 --- a/src/hardware.c +++ b/src/hardware.c @@ -676,6 +676,15 @@ void hw_config_cback(void *p_mem) strncpy(hw_cfg_cb.local_chip_name, p_name, \ LOCAL_NAME_BUFFER_LEN-1); } +#ifdef USE_BLUETOOTH_BCM4343 + else if ((p_name = strstr(p_tmp, "4343")) != NULL) + { + snprintf(hw_cfg_cb.local_chip_name, + LOCAL_NAME_BUFFER_LEN-1, "BCM%s", p_name); + strncpy(p_name, hw_cfg_cb.local_chip_name, + LOCAL_NAME_BUFFER_LEN-1); + } +#endif else { strncpy(hw_cfg_cb.local_chip_name, "UNKNOWN", \ -- cgit v1.2.3 From 13e0e2facd831d71fb6a2d0021c11203c1a873ff Mon Sep 17 00:00:00 2001 From: Zhao Xuewen Date: Fri, 18 Sep 2015 19:07:35 +0800 Subject: Bluetooth:config SCO seting for HFP call 1, enable SCO_USE_I2S_INTERFACE for sturgeon 2, configure audio configuration in hw_sco_config for I2S as SCO_CODEC_CVSD by default BUG=24044548 Change-Id: Id39102ee812eb2b173dfab45f4fb97fd99c5e7b8 Signed-off-by: z00184990 --- src/hardware.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 'src') diff --git a/src/hardware.c b/src/hardware.c index b97d5f1..bf59896 100755 --- a/src/hardware.c +++ b/src/hardware.c @@ -1292,8 +1292,28 @@ void hw_sco_config(void) * and FM on the same PCM pins, we defer Bluetooth audio (SCO/eSCO) * configuration till SCO/eSCO is being established; * i.e. in hw_set_audio_state() call. + * When configured as I2S only, Bluetooth audio configuration is executed + * immediately with SCO_CODEC_CVSD by default. */ + if (SCO_INTERFACE_I2S == sco_bus_interface) { + HC_BT_HDR *p_buf = NULL; + uint16_t cmd_u16 = HCI_CMD_PREAMBLE_SIZE + SCO_I2SPCM_PARAM_SIZE; + + if (bt_vendor_cbacks) + p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc(BT_HC_HDR_SIZE + cmd_u16); + + if (p_buf) { + p_buf->event = MSG_STACK_TO_HC_HCI_CMD; + p_buf->offset = 0; + p_buf->layer_specific = 0; + p_buf->len = cmd_u16; + hw_sco_i2spcm_config(p_buf, SCO_CODEC_CVSD); + } else { + ALOGE("Cannot allocate memory for p_buf in hw_sco_config sco config"); + } + } + if (bt_vendor_cbacks) { bt_vendor_cbacks->scocfg_cb(BT_VND_OP_RESULT_SUCCESS); -- cgit v1.2.3 From d51ab12cc1e7b02279b45f91c2f2f9a9b4a1404e Mon Sep 17 00:00:00 2001 From: Sridhar Vashist Date: Tue, 19 May 2015 03:32:21 -0500 Subject: A2DP Offload BRCM vendor specific implementation A2DP Offload vendor specific implementation for Broadcom chipsets. Change-Id: Ifbb432c21c3e939253188b55e344d8e00a2b9f9e Signed-off-by: Sridhar Vashist --- src/bt_vendor_brcm.c | 10 +- src/bt_vendor_brcm_a2dp.c | 744 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 753 insertions(+), 1 deletion(-) create mode 100644 src/bt_vendor_brcm_a2dp.c (limited to 'src') diff --git a/src/bt_vendor_brcm.c b/src/bt_vendor_brcm.c index 05a5bcb..12dc80b 100755 --- a/src/bt_vendor_brcm.c +++ b/src/bt_vendor_brcm.c @@ -123,6 +123,10 @@ static int init(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr) /* This is handed over from the stack */ memcpy(vnd_local_bd_addr, local_bdaddr, 6); +#if (BRCM_A2DP_OFFLOAD == TRUE) + brcm_vnd_a2dp_init(); +#endif + return 0; } @@ -130,7 +134,7 @@ static int init(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr) /** Requested operations */ static int op(bt_vendor_opcode_t opcode, void *param) { - int retval = 0; + int retval = BT_VND_OP_RESULT_SUCCESS; BTVNDDBG("op for %d", opcode); @@ -225,6 +229,10 @@ static int op(bt_vendor_opcode_t opcode, void *param) hw_epilog_process(); #endif } + + case BT_VND_OP_A2DP_OFFLOAD_START: + case BT_VND_OP_A2DP_OFFLOAD_STOP: + retval = brcm_vnd_a2dp_execute(opcode, param); break; } diff --git a/src/bt_vendor_brcm_a2dp.c b/src/bt_vendor_brcm_a2dp.c new file mode 100644 index 0000000..45d4295 --- /dev/null +++ b/src/bt_vendor_brcm_a2dp.c @@ -0,0 +1,744 @@ +/****************************************************************************** + * + * Copyright (C) 2015 Motorola Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at: + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + ******************************************************************************/ + +/****************************************************************************** + * + * This is the stream state machine for the BRCM offloaded advanced audio. + * + ******************************************************************************/ + +#define LOG_TAG "bt_vnd_a2dp" +#define LOG_NDEBUG 0 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "bt_hci_bdroid.h" +#include "bt_vendor_brcm_a2dp.h" +#include "a2d_api.h" +#include "a2d_sbc.h" + +#if (BTA2DP_DEBUG == TRUE) +#define BTA2DPDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);} +#else +#define BTA2DPDBG(param, ...) {} +#endif + +/***************************************************************************** +** Constants and types +*****************************************************************************/ + +typedef void (*hci_cback)(void *); + +typedef enum +{ + BRCM_VND_A2DP_OFFLOAD_INIT_REQ, + BRCM_VND_A2DP_OFFLOAD_START_REQ, + BRCM_VND_A2DP_OFFLOAD_STOP_REQ, + BRCM_VND_UIPC_OPEN_RSP, + BRCM_VND_L2C_SYNC_TO_LITE_RSP, + BRCM_VND_SYNC_TO_BTC_LITE_RSP, + BRCM_VND_AUDIO_CODEC_CONFIG_RSP, + BRCM_VND_AUDIO_ROUTE_CONFIG_RSP, + BRCM_VND_UIPC_CLOSE_RSP, + BRCM_VND_L2C_REMOVE_TO_LITE_RSP, + BRCM_VND_A2DP_START_RSP, + BRCM_VND_A2DP_SUSPEND_RSP, + BRCM_VND_STREAM_STOP_RSP, + BRCM_VND_A2DP_CLEANUP_RSP, + BRCM_VND_A2DP_OFFLOAD_FAILED_ABORT, +} tBRCM_VND_A2DP_EVENT; + +/* state machine states */ +typedef enum +{ + BRCM_VND_A2DP_INVALID_SST = -1, + BRCM_VND_A2DP_IDLE_SST, + BRCM_VND_A2DP_STARTING_SST, + BRCM_VND_A2DP_STREAM_SST, +} +tBRCM_VND_A2DP_SST_STATES; + +static uint8_t brcm_vnd_a2dp_offload_cleanup(); +static uint8_t brcm_vnd_a2dp_offload_suspend(); +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_enter(tBRCM_VND_A2DP_EVENT event); +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_enter(tBRCM_VND_A2DP_EVENT event); +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_enter(tBRCM_VND_A2DP_EVENT event); +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data); +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data); +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data); +static void brcm_vnd_a2dp_hci_uipc_cback(void *pmem); + +typedef struct { + uint8_t fcn; + uint32_t pad_conf; +} +tBRCM_VND_PCM_CONF; + +typedef struct { + tBRCM_VND_A2DP_SST_STATES state; + tCODEC_INFO_SBC codec_info; + tBRCM_VND_PCM_CONF pcmi2s_pinmux; + bt_vendor_op_a2dp_offload_t offload_params; +} +tBRCM_VND_A2DP_PDATA; + +typedef struct { + tBRCM_VND_A2DP_SST_STATES (*enter)(tBRCM_VND_A2DP_EVENT event); + tBRCM_VND_A2DP_SST_STATES (*process_event)(tBRCM_VND_A2DP_EVENT event, void *ev_data); +} +tBRCM_VND_A2DP_SST_STATE; + +/* state table */ +static tBRCM_VND_A2DP_SST_STATE brcm_vnd_a2dp_sst_tbl[] = +{ + {brcm_vnd_a2dp_sm_idle_enter, brcm_vnd_a2dp_sm_idle_process_ev}, + {brcm_vnd_a2dp_sm_starting_enter, brcm_vnd_a2dp_sm_starting_process_ev}, + {brcm_vnd_a2dp_sm_stream_enter, brcm_vnd_a2dp_sm_stream_process_ev}, +}; + +static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; +static tBRCM_VND_A2DP_PDATA brcm_vnd_a2dp_pdata = { .state = BRCM_VND_A2DP_INVALID_SST }; + + +/******************************************************************************* +** Local Utility Functions +*******************************************************************************/ + +static void log_bin_to_hexstr(uint8_t *bin, uint8_t binsz, const char *log_tag) +{ +#if (BTA2DP_DEBUG == TRUE) + char *str, hex_str[]= "0123456789abcdef"; + uint8_t i; + + str = (char *)malloc(binsz * 3); + if (!binsz) { + ALOGE("%s alloc failed", __FUNCTION__); + return; + } + + for (i = 0; i < binsz; i++) { + str[(i * 3) + 0] = hex_str[(bin[i] >> 4) & 0x0F]; + str[(i * 3) + 1] = hex_str[(bin[i] ) & 0x0F]; + str[(i * 3) + 2] = ' '; + } + str[(binsz * 3) - 1] = 0x00; + BTA2DPDBG("%s %s", log_tag, str); +#endif +} + +static uint8_t brcm_vnd_a2dp_send_hci_vsc(uint16_t cmd, uint8_t *payload, uint8_t len, hci_cback cback) +{ + HC_BT_HDR *p_buf; + uint8_t *p, status; + uint16_t opcode; + + // Perform Opening configure cmds. // + if (bt_vendor_cbacks) { + p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc( + BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + len); + 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 + len; + p = (uint8_t *)(p_buf + 1); + + UINT16_TO_STREAM(p, cmd); + *p++ = len; + memcpy(p, payload, len); + + //BTA2DPDBG("%s Cmd %04x UIPC Event %02x%02x UIPC Op %02x Len %d", __FUNCTION__, cmd, event, payload[1], payload[0], payload[2], len); + log_bin_to_hexstr((uint8_t *)(p_buf + 1), HCI_CMD_PREAMBLE_SIZE + len, __FUNCTION__); + + if (bt_vendor_cbacks->xmit_cb(cmd, p_buf, cback)) + { + return BT_VND_OP_RESULT_SUCCESS; + } + bt_vendor_cbacks->dealloc(p_buf); + } + } + return BT_VND_OP_RESULT_FAIL; +} + +static void brcm_vnd_map_a2d_uipc_codec_info(tCODEC_INFO_SBC *codec_info) +{ + switch(codec_info->sampling_freq) { + case A2D_SBC_IE_SAMP_FREQ_16: + codec_info->sampling_freq = CODEC_INFO_SBC_SF_16K; break; + case A2D_SBC_IE_SAMP_FREQ_32: + codec_info->sampling_freq = CODEC_INFO_SBC_SF_32K; break; + case A2D_SBC_IE_SAMP_FREQ_44: + codec_info->sampling_freq = CODEC_INFO_SBC_SF_44K; break; + case A2D_SBC_IE_SAMP_FREQ_48: + codec_info->sampling_freq = CODEC_INFO_SBC_SF_48K; break; + + } + switch(codec_info->channel_mode) { + case A2D_SBC_IE_CH_MD_MONO: + codec_info->channel_mode = CODEC_INFO_SBC_CH_MONO; break; + case A2D_SBC_IE_CH_MD_DUAL: + codec_info->channel_mode = CODEC_INFO_SBC_CH_DUAL; break; + case A2D_SBC_IE_CH_MD_STEREO: + codec_info->channel_mode = CODEC_INFO_SBC_CH_STEREO; break; + case A2D_SBC_IE_CH_MD_JOINT: + codec_info->channel_mode = CODEC_INFO_SBC_CH_JS; break; + } + switch(codec_info->block_length) { + case A2D_SBC_IE_BLOCKS_4: + codec_info->block_length = CODEC_INFO_SBC_BLOCK_4; break; + case A2D_SBC_IE_BLOCKS_8: + codec_info->block_length = CODEC_INFO_SBC_BLOCK_8; break; + case A2D_SBC_IE_BLOCKS_12: + codec_info->block_length = CODEC_INFO_SBC_BLOCK_12; break; + case A2D_SBC_IE_BLOCKS_16: + codec_info->block_length = CODEC_INFO_SBC_BLOCK_16; break; + } + switch(codec_info->alloc_method) { + case A2D_SBC_IE_ALLOC_MD_S: + codec_info->alloc_method = CODEC_INFO_SBC_ALLOC_SNR; break; + case A2D_SBC_IE_ALLOC_MD_L: + codec_info->alloc_method = CODEC_INFO_SBC_ALLOC_LOUDNESS; break; + } + switch(codec_info->num_subbands) { + case A2D_SBC_IE_SUBBAND_4: + codec_info->num_subbands = CODEC_INFO_SBC_SUBBAND_4; break; + case A2D_SBC_IE_SUBBAND_8: + codec_info->num_subbands = CODEC_INFO_SBC_SUBBAND_8; break; + } +} + +static tA2D_STATUS bcrm_vnd_a2dp_parse_codec_info(tCODEC_INFO_SBC *parsed_info, uint8_t *codec_info) +{ + tA2D_STATUS status = A2D_SUCCESS; + UINT8 losc; + UINT8 mt; + + BTA2DPDBG("%s", __FUNCTION__); + + if( parsed_info == NULL || codec_info == NULL) + status = A2D_FAIL; + else + { + losc = *codec_info++; + mt = *codec_info++; + /* If the function is called for the wrong Media Type or Media Codec Type */ + if(losc != A2D_SBC_INFO_LEN || *codec_info != A2D_MEDIA_CT_SBC) + status = A2D_WRONG_CODEC; + else + { + codec_info++; + parsed_info->sampling_freq = *codec_info & A2D_SBC_IE_SAMP_FREQ_MSK; + parsed_info->channel_mode = *codec_info & A2D_SBC_IE_CH_MD_MSK; + codec_info++; + parsed_info->block_length = *codec_info & A2D_SBC_IE_BLOCKS_MSK; + parsed_info->num_subbands = *codec_info & A2D_SBC_IE_SUBBAND_MSK; + parsed_info->alloc_method = *codec_info & A2D_SBC_IE_ALLOC_MD_MSK; + codec_info += 2; + parsed_info->bitpool_size = *codec_info; // MAX BITPOOL // + + if(MULTI_BIT_SET(parsed_info->sampling_freq)) + status = A2D_BAD_SAMP_FREQ; + if(MULTI_BIT_SET(parsed_info->channel_mode)) + status = A2D_BAD_CH_MODE; + if(MULTI_BIT_SET(parsed_info->block_length)) + status = A2D_BAD_BLOCK_LEN; + if(MULTI_BIT_SET(parsed_info->num_subbands)) + status = A2D_BAD_SUBBANDS; + if(MULTI_BIT_SET(parsed_info->alloc_method)) + status = A2D_BAD_ALLOC_MTHD; + if(parsed_info->bitpool_size < A2D_SBC_IE_MIN_BITPOOL || parsed_info->bitpool_size > A2D_SBC_IE_MAX_BITPOOL ) + status = A2D_BAD_MIN_BITPOOL; + + if(status == A2D_SUCCESS) + brcm_vnd_map_a2d_uipc_codec_info(parsed_info); + + BTA2DPDBG("%s STATUS %d parsed info : SampF %02x, ChnMode %02x, BlockL %02x, NSubB %02x, alloc %02x, bitpool %02x", + __FUNCTION__, status, parsed_info->sampling_freq, parsed_info->channel_mode, parsed_info->block_length, + parsed_info->num_subbands, parsed_info->alloc_method, parsed_info->bitpool_size); + + } + } + return status; +} + +/******************************************************************************* +** State Machine Functions +*******************************************************************************/ + +/******************************************************************************* +** +** Function brcm_vnd_a2dp_ssm_execute +** +** Description Stream state machine event handling function for AV +** +** +** Returns void +** +*******************************************************************************/ +int brcm_vnd_a2dp_ssm_execute(tBRCM_VND_A2DP_EVENT event, void *ev_data) +{ + tBRCM_VND_A2DP_SST_STATE *state_table; + tBRCM_VND_A2DP_SST_STATES next_state; + + BTA2DPDBG("%s ev %d state %d", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state); + + pthread_mutex_lock(&g_mutex); + + if (brcm_vnd_a2dp_pdata.state != BRCM_VND_A2DP_INVALID_SST) { + state_table = &brcm_vnd_a2dp_sst_tbl[brcm_vnd_a2dp_pdata.state]; + /* process event */ + next_state = state_table->process_event(event, ev_data); + } else if (BRCM_VND_A2DP_OFFLOAD_INIT_REQ == event) { + next_state = BRCM_VND_A2DP_IDLE_SST; + } + else { + pthread_mutex_unlock(&g_mutex); + return BT_VND_OP_RESULT_FAIL; + } + + /* transition stae */ + while (next_state != brcm_vnd_a2dp_pdata.state) { + brcm_vnd_a2dp_pdata.state = next_state; + state_table = &brcm_vnd_a2dp_sst_tbl[next_state]; + if (state_table->enter) + next_state = state_table->enter(event); + } + + pthread_mutex_unlock(&g_mutex); + return BT_VND_OP_RESULT_SUCCESS; +} + +/* state machine actions */ + +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_enter(tBRCM_VND_A2DP_EVENT event) +{ + UNUSED(event); + BTA2DPDBG("%s", __FUNCTION__); + brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn = PCM_PIN_FCN_INVALID; + return brcm_vnd_a2dp_pdata.state; +} + +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_enter(tBRCM_VND_A2DP_EVENT event) +{ + UNUSED(event); + uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; + BTA2DPDBG("%s", __FUNCTION__); + + p = msg_req; + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_READ_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_FCN); + UINT32_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_PADCNF); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_MGMT_EVT); + UINT8_TO_STREAM(p, UIPC_OPEN_REQ); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_L2C_EVT); + UINT8_TO_STREAM(p, L2C_SYNC_TO_LITE_REQ); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.acl_data_size); + UINT16_TO_STREAM(p, !(brcm_vnd_a2dp_pdata.offload_params.is_flushable)); + UINT8_TO_STREAM(p, 0x02); //multi_av_data_cong_start + UINT8_TO_STREAM(p, 0x00); //multi_av_data_cong_end + UINT8_TO_STREAM(p, 0x04); //multi_av_data_cong_discard + UINT8_TO_STREAM(p, 1); //num_stream + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.remote_cid); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.lm_handle); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.is_flushable); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_AVDT_EVT); + UINT8_TO_STREAM(p, AVDT_SYNC_TO_BTC_LITE_REQ); + UINT8_TO_STREAM(p, 1); //num_stream + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); + UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_source); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); + UINT8_TO_STREAM(p, AUDIO_ROUTE_CONFIG_REQ); + UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC); + UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF); + UINT8_TO_STREAM(p, AUDIO_ROUTE_OUT_BTA2DP); + UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF); + UINT8_TO_STREAM(p, AUDIO_ROUTE_SF_NA); + UINT8_TO_STREAM(p, AUDIO_ROUTE_EQ_BYPASS); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); + UINT8_TO_STREAM(p, AUDIO_CODEC_CONFIG_REQ); + UINT16_TO_STREAM(p, AUDIO_CODEC_SBC_ENC); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.sampling_freq); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.channel_mode); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.block_length); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.num_subbands); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.alloc_method); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.bitpool_size); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); + UINT8_TO_STREAM(p, A2DP_START_REQ); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + return brcm_vnd_a2dp_pdata.state; +} + + +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_enter(tBRCM_VND_A2DP_EVENT event) +{ + UNUSED(event); + ALOGV("%s", __FUNCTION__); + + return brcm_vnd_a2dp_pdata.state; +} + +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data) +{ + tBRCM_VND_A2DP_SST_STATES next_state = brcm_vnd_a2dp_pdata.state; + + switch (event) { + case BRCM_VND_A2DP_OFFLOAD_START_REQ: + brcm_vnd_a2dp_pdata.offload_params = *(bt_vendor_op_a2dp_offload_t*)ev_data; + if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( &brcm_vnd_a2dp_pdata.codec_info, + (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) { + ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__); + } + + next_state = BRCM_VND_A2DP_STARTING_SST; + break; + + default: + ALOGV("%s Unexpected Event %d in State %d, IGNORE", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state); + break; + } + return next_state; +} + +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data) +{ + tBRCM_VND_A2DP_SST_STATES next_state = brcm_vnd_a2dp_pdata.state; + uint8_t status, *p; + switch (event) { + case BRCM_VND_A2DP_OFFLOAD_START_REQ: + brcm_vnd_a2dp_offload_cleanup(); + brcm_vnd_a2dp_pdata.offload_params = *(bt_vendor_op_a2dp_offload_t*)ev_data; + if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( + &brcm_vnd_a2dp_pdata.codec_info, (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) { + ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__); + } + + next_state = BRCM_VND_A2DP_STARTING_SST; + break; + + + case BRCM_VND_A2DP_OFFLOAD_STOP_REQ: + brcm_vnd_a2dp_offload_cleanup(); + next_state = BRCM_VND_A2DP_IDLE_SST; + break; + + case BRCM_VND_UIPC_OPEN_RSP: { + uint8_t num_streams; + uint16_t maj_ver, min_ver; + p = (uint8_t*)ev_data + offsetof(tUIPC_OPEN_RSP, status); + STREAM_TO_UINT8(status,p); + STREAM_TO_UINT16(maj_ver,p); + STREAM_TO_UINT16(min_ver,p); + STREAM_TO_UINT8(num_streams,p); + // TODO Verify Params // + if (status) { + ALOGE("%s BRCM_VND_UIPC_OPEN_RSP %02x FAILED", __FUNCTION__, status); + brcm_vnd_a2dp_offload_cleanup(); + bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, + brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); + next_state = BRCM_VND_A2DP_IDLE_SST; + } + } + break; + + case BRCM_VND_L2C_SYNC_TO_LITE_RSP: + status = *((uint8_t*)ev_data + offsetof(tL2C_SYNC_TO_LITE_RESP, stream.status)); + if (status) { + ALOGE("%s L2C_SYNC_TO_LITE_RESP %02x FAILED", __FUNCTION__, status); + brcm_vnd_a2dp_offload_cleanup(); + bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, + brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); + next_state = BRCM_VND_A2DP_IDLE_SST; + } + break; + + case BRCM_VND_SYNC_TO_BTC_LITE_RSP: + status = *((uint8_t*)ev_data + offsetof(tAVDT_SYNC_TO_BTC_LITE_RESP, status)); + if (status) { + ALOGE("%s AVDT_SYNC_TO_BTC_LITE_RESP %02x FAILED", __FUNCTION__, status); + brcm_vnd_a2dp_offload_cleanup(); + bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, + brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); + next_state = BRCM_VND_A2DP_IDLE_SST; + } + break; + + case BRCM_VND_AUDIO_ROUTE_CONFIG_RSP: + status = *((uint8_t*)ev_data + offsetof(tAUDIO_ROUTE_CONFIG_RESP, status)); + if (status) { + ALOGE("%s AUDIO_ROUTE_CONFIG_RESP %02x FAILED", __FUNCTION__, status); + brcm_vnd_a2dp_offload_cleanup(); + bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, + brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); + next_state = BRCM_VND_A2DP_IDLE_SST; + } + break; + + case BRCM_VND_AUDIO_CODEC_CONFIG_RSP: + status = *((uint8_t*)ev_data + offsetof(tAUDIO_CODEC_CONFIG_RESP, status)); + if (status) { + ALOGE("%s BRCM_VND_AUDIO_CODEC_CONFIG_RSP %02x FAILED", __FUNCTION__, status); + brcm_vnd_a2dp_offload_cleanup(); + bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, + brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); + next_state = BRCM_VND_A2DP_IDLE_SST; + } + break; + + case BRCM_VND_A2DP_START_RSP: + /* status = *((uint8_t*)ev_data + offsetof(tA2DP_GENERIC_RESP, status)); */ + bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_SUCCESS, BT_VND_OP_A2DP_OFFLOAD_START, + brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); + next_state = BRCM_VND_A2DP_STREAM_SST; + break; + + case BRCM_VND_A2DP_OFFLOAD_FAILED_ABORT: + ALOGE("%s BRCM_VND_A2DP_OFFLOAD_FAILED_ABORT", __FUNCTION__); + brcm_vnd_a2dp_offload_cleanup(); + bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, + brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); + next_state = BRCM_VND_A2DP_IDLE_SST; + break; + + default: + ALOGE("%s Unexpected Event %d in State %d, IGNORE", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state); + break; + } + return next_state; +} + +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data) +{ + tBRCM_VND_A2DP_SST_STATES next_state = brcm_vnd_a2dp_pdata.state; + switch (event) { + case BRCM_VND_A2DP_OFFLOAD_START_REQ: + brcm_vnd_a2dp_offload_cleanup(); + brcm_vnd_a2dp_pdata.offload_params = *(bt_vendor_op_a2dp_offload_t*)ev_data; + if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( + &brcm_vnd_a2dp_pdata.codec_info, (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) { + ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__); + } + next_state = BRCM_VND_A2DP_STARTING_SST; + break; + + case BRCM_VND_A2DP_OFFLOAD_STOP_REQ: + case BRCM_VND_A2DP_OFFLOAD_FAILED_ABORT: + ALOGE("%s BRCM_VND_A2DP_OFFLOAD_STOP ABORT %d.", __FUNCTION__, + (event == BRCM_VND_A2DP_OFFLOAD_FAILED_ABORT)); + brcm_vnd_a2dp_offload_cleanup(); + next_state = BRCM_VND_A2DP_IDLE_SST; + break; + + default: + ALOGE("%s Unexpected Event %d in State %d, IGNORE", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state); + break; + } + return next_state; +} + +static uint8_t brcm_vnd_a2dp_offload_cleanup() +{ + uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; + + BTA2DPDBG("%s", __FUNCTION__); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); + UINT8_TO_STREAM(p, A2DP_CLEANUP_REQ); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_L2C_EVT); + UINT8_TO_STREAM(p, L2C_REMOVE_TO_LITE_REQ); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); + UINT8_TO_STREAM(p, 1); //num_stream + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_MGMT_EVT); + UINT8_TO_STREAM(p, UIPC_CLOSE_REQ); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + if (PCM_PIN_FCN_INVALID != brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn) { + p = msg_req; + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn); + UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.pcmi2s_pinmux.pad_conf); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + } + + return 0; +} + +static uint8_t brcm_vnd_a2dp_offload_suspend() +{ + uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; + + BTA2DPDBG("%s", __FUNCTION__); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); + UINT8_TO_STREAM(p, A2DP_SUSPEND_REQ); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + return 0; +} + +void brcm_vnd_a2dp_hci_uipc_cback(void *pmem) +{ + HC_BT_HDR *p_evt_buf = (HC_BT_HDR *)pmem; + uint8_t *p, len, vsc_result, uipc_opcode; + uint16_t vsc_opcode, uipc_event; + HC_BT_HDR *p_buf = NULL; + bt_vendor_op_result_t status = BT_VND_OP_RESULT_SUCCESS; + tBRCM_VND_A2DP_EVENT ssm_event; + + p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_LEN; + len = *p; + p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_VSC; + STREAM_TO_UINT16(vsc_opcode,p); + vsc_result = *p++; + + log_bin_to_hexstr(((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_VSC), len-1, __FUNCTION__); + + if (vsc_result != 0) { + ALOGE("%s Failed VSC Op %04x", __FUNCTION__, vsc_opcode); + status = BT_VND_OP_RESULT_FAIL; + } + else if (vsc_opcode == HCI_VSC_UIPC_OVER_HCI) { + STREAM_TO_UINT16(uipc_event,p); + uipc_opcode = *p; + BTA2DPDBG("%s UIPC Event %04x UIPC Op %02x", __FUNCTION__, uipc_event, uipc_opcode); + + switch (uipc_event) { + case BT_EVT_BTU_IPC_MGMT_EVT : + switch (uipc_opcode) { + case UIPC_OPEN_RSP : ssm_event = BRCM_VND_UIPC_OPEN_RSP; break; + case UIPC_CLOSE_RSP : ssm_event = BRCM_VND_UIPC_CLOSE_RSP; break; + default: status = BT_VND_OP_RESULT_FAIL; + } + break; + + case BT_EVT_BTU_IPC_BTM_EVT : + switch (uipc_opcode) { + case A2DP_START_RESP: ssm_event = BRCM_VND_A2DP_START_RSP; break; + case A2DP_SUSPEND_RESP: ssm_event = BRCM_VND_A2DP_SUSPEND_RSP; break; + case A2DP_CLEANUP_RESP: ssm_event = BRCM_VND_A2DP_CLEANUP_RSP; break; + case AUDIO_CODEC_CONFIG_RESP: ssm_event = BRCM_VND_AUDIO_CODEC_CONFIG_RSP; break; + case AUDIO_ROUTE_CONFIG_RESP: ssm_event = BRCM_VND_AUDIO_ROUTE_CONFIG_RSP; break; + default: status = BT_VND_OP_RESULT_FAIL; + } + break; + + case BT_EVT_BTU_IPC_L2C_EVT : + switch (uipc_opcode) { + case L2C_REMOVE_TO_LITE_RESP: ssm_event = BRCM_VND_L2C_REMOVE_TO_LITE_RSP; break; + case L2C_SYNC_TO_LITE_RESP: ssm_event = BRCM_VND_L2C_SYNC_TO_LITE_RSP; break; + default: status = BT_VND_OP_RESULT_FAIL; + } + break; + + case BT_EVT_BTU_IPC_AVDT_EVT : + if (uipc_opcode == AVDT_SYNC_TO_BTC_LITE_RESP) { + ssm_event = BRCM_VND_SYNC_TO_BTC_LITE_RSP; + break; + } + + default: + status = BT_VND_OP_RESULT_FAIL; + break; + } + if (status == BT_VND_OP_RESULT_SUCCESS) + brcm_vnd_a2dp_ssm_execute(ssm_event, p); + } + else if (vsc_opcode == HCI_VSC_READ_PCM_PINS) { + STREAM_TO_UINT8(brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn, p); + STREAM_TO_UINT32(brcm_vnd_a2dp_pdata.pcmi2s_pinmux.pad_conf, p); + BTA2DPDBG("%s HCI_VSC_READ_PCM_PINS %02x %08x", __FUNCTION__, + brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn, brcm_vnd_a2dp_pdata.pcmi2s_pinmux.pad_conf); + } + + if (status != BT_VND_OP_RESULT_SUCCESS) + brcm_vnd_a2dp_ssm_execute(BRCM_VND_A2DP_OFFLOAD_FAILED_ABORT, NULL); + + /* Free the RX event buffer */ + bt_vendor_cbacks->dealloc(p_evt_buf); +} + +void brcm_vnd_a2dp_init() +{ + if (!bt_vendor_cbacks) + return; + + ALOGD("%s ", __FUNCTION__); + brcm_vnd_a2dp_ssm_execute(BRCM_VND_A2DP_OFFLOAD_INIT_REQ, NULL); +} + +int brcm_vnd_a2dp_execute(bt_vendor_opcode_t opcode, void *ev_data) +{ + tBRCM_VND_A2DP_EVENT ssm_event = (opcode == BT_VND_OP_A2DP_OFFLOAD_START)? + BRCM_VND_A2DP_OFFLOAD_START_REQ:BRCM_VND_A2DP_OFFLOAD_STOP_REQ; + + ALOGD("%s opcode %d ", __FUNCTION__, opcode); + + return brcm_vnd_a2dp_ssm_execute(ssm_event, ev_data); +} + + -- cgit v1.2.3 From 6708688fef36253ffe63bbca37db40d96a9748fd Mon Sep 17 00:00:00 2001 From: Sridhar Vashist Date: Tue, 25 Aug 2015 17:36:01 -0500 Subject: Fix A2DP Offload lockup when RE-STARTING The A2DP Offload vendor lib can cause a lockup in the corner case when a START event is received while already in STARTING state resulting in a mediaserver crash. - Refactor state machine code. - Move offload session configuration to a helper func. Change-Id: I93dc2ebd3910c8302c3d0d5b1ee912cb7244b98b Signed-off-by: Sridhar Vashist --- src/bt_vendor_brcm_a2dp.c | 215 ++++++++++++++++++++++------------------------ 1 file changed, 104 insertions(+), 111 deletions(-) (limited to 'src') diff --git a/src/bt_vendor_brcm_a2dp.c b/src/bt_vendor_brcm_a2dp.c index 45d4295..0526196 100644 --- a/src/bt_vendor_brcm_a2dp.c +++ b/src/bt_vendor_brcm_a2dp.c @@ -84,18 +84,16 @@ typedef enum } tBRCM_VND_A2DP_SST_STATES; +static uint8_t brcm_vnd_a2dp_offload_configure(); static uint8_t brcm_vnd_a2dp_offload_cleanup(); static uint8_t brcm_vnd_a2dp_offload_suspend(); -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_enter(tBRCM_VND_A2DP_EVENT event); -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_enter(tBRCM_VND_A2DP_EVENT event); -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_enter(tBRCM_VND_A2DP_EVENT event); static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data); static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data); static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data); static void brcm_vnd_a2dp_hci_uipc_cback(void *pmem); typedef struct { - uint8_t fcn; + uint8_t fcn; uint32_t pad_conf; } tBRCM_VND_PCM_CONF; @@ -117,9 +115,9 @@ tBRCM_VND_A2DP_SST_STATE; /* state table */ static tBRCM_VND_A2DP_SST_STATE brcm_vnd_a2dp_sst_tbl[] = { - {brcm_vnd_a2dp_sm_idle_enter, brcm_vnd_a2dp_sm_idle_process_ev}, - {brcm_vnd_a2dp_sm_starting_enter, brcm_vnd_a2dp_sm_starting_process_ev}, - {brcm_vnd_a2dp_sm_stream_enter, brcm_vnd_a2dp_sm_stream_process_ev}, + {NULL, brcm_vnd_a2dp_sm_idle_process_ev}, + {NULL, brcm_vnd_a2dp_sm_starting_process_ev}, + {NULL, brcm_vnd_a2dp_sm_stream_process_ev}, }; static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -307,10 +305,10 @@ int brcm_vnd_a2dp_ssm_execute(tBRCM_VND_A2DP_EVENT event, void *ev_data) tBRCM_VND_A2DP_SST_STATE *state_table; tBRCM_VND_A2DP_SST_STATES next_state; - BTA2DPDBG("%s ev %d state %d", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state); - pthread_mutex_lock(&g_mutex); + BTA2DPDBG("%s ev %d state %d", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state); + if (brcm_vnd_a2dp_pdata.state != BRCM_VND_A2DP_INVALID_SST) { state_table = &brcm_vnd_a2dp_sst_tbl[brcm_vnd_a2dp_pdata.state]; /* process event */ @@ -337,101 +335,6 @@ int brcm_vnd_a2dp_ssm_execute(tBRCM_VND_A2DP_EVENT event, void *ev_data) /* state machine actions */ -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_enter(tBRCM_VND_A2DP_EVENT event) -{ - UNUSED(event); - BTA2DPDBG("%s", __FUNCTION__); - brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn = PCM_PIN_FCN_INVALID; - return brcm_vnd_a2dp_pdata.state; -} - -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_enter(tBRCM_VND_A2DP_EVENT event) -{ - UNUSED(event); - uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; - BTA2DPDBG("%s", __FUNCTION__); - - p = msg_req; - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_READ_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_FCN); - UINT32_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_PADCNF); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_MGMT_EVT); - UINT8_TO_STREAM(p, UIPC_OPEN_REQ); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_L2C_EVT); - UINT8_TO_STREAM(p, L2C_SYNC_TO_LITE_REQ); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.acl_data_size); - UINT16_TO_STREAM(p, !(brcm_vnd_a2dp_pdata.offload_params.is_flushable)); - UINT8_TO_STREAM(p, 0x02); //multi_av_data_cong_start - UINT8_TO_STREAM(p, 0x00); //multi_av_data_cong_end - UINT8_TO_STREAM(p, 0x04); //multi_av_data_cong_discard - UINT8_TO_STREAM(p, 1); //num_stream - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.remote_cid); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.lm_handle); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.is_flushable); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_AVDT_EVT); - UINT8_TO_STREAM(p, AVDT_SYNC_TO_BTC_LITE_REQ); - UINT8_TO_STREAM(p, 1); //num_stream - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); - UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_source); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); - UINT8_TO_STREAM(p, AUDIO_ROUTE_CONFIG_REQ); - UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC); - UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF); - UINT8_TO_STREAM(p, AUDIO_ROUTE_OUT_BTA2DP); - UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF); - UINT8_TO_STREAM(p, AUDIO_ROUTE_SF_NA); - UINT8_TO_STREAM(p, AUDIO_ROUTE_EQ_BYPASS); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); - UINT8_TO_STREAM(p, AUDIO_CODEC_CONFIG_REQ); - UINT16_TO_STREAM(p, AUDIO_CODEC_SBC_ENC); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.sampling_freq); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.channel_mode); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.block_length); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.num_subbands); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.alloc_method); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.bitpool_size); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); - UINT8_TO_STREAM(p, A2DP_START_REQ); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - return brcm_vnd_a2dp_pdata.state; -} - - -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_enter(tBRCM_VND_A2DP_EVENT event) -{ - UNUSED(event); - ALOGV("%s", __FUNCTION__); - - return brcm_vnd_a2dp_pdata.state; -} - static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data) { tBRCM_VND_A2DP_SST_STATES next_state = brcm_vnd_a2dp_pdata.state; @@ -442,9 +345,12 @@ static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_process_ev(tBRCM_VND_A2DP if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( &brcm_vnd_a2dp_pdata.codec_info, (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) { ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__); + bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, + brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); + } else { + brcm_vnd_a2dp_offload_configure(); + next_state = BRCM_VND_A2DP_STARTING_SST; } - - next_state = BRCM_VND_A2DP_STARTING_SST; break; default: @@ -458,6 +364,7 @@ static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_process_ev(tBRCM_VND_ { tBRCM_VND_A2DP_SST_STATES next_state = brcm_vnd_a2dp_pdata.state; uint8_t status, *p; + switch (event) { case BRCM_VND_A2DP_OFFLOAD_START_REQ: brcm_vnd_a2dp_offload_cleanup(); @@ -465,12 +372,14 @@ static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_process_ev(tBRCM_VND_ if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( &brcm_vnd_a2dp_pdata.codec_info, (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) { ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__); + bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, + brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); + next_state = BRCM_VND_A2DP_IDLE_SST; + } else { + brcm_vnd_a2dp_offload_configure(); } - - next_state = BRCM_VND_A2DP_STARTING_SST; break; - case BRCM_VND_A2DP_OFFLOAD_STOP_REQ: brcm_vnd_a2dp_offload_cleanup(); next_state = BRCM_VND_A2DP_IDLE_SST; @@ -571,8 +480,13 @@ static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_process_ev(tBRCM_VND_A2 if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( &brcm_vnd_a2dp_pdata.codec_info, (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) { ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__); + bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, + brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); + next_state = BRCM_VND_A2DP_IDLE_SST; + } else { + brcm_vnd_a2dp_offload_configure(); + next_state = BRCM_VND_A2DP_STARTING_SST; } - next_state = BRCM_VND_A2DP_STARTING_SST; break; case BRCM_VND_A2DP_OFFLOAD_STOP_REQ: @@ -590,6 +504,84 @@ static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_process_ev(tBRCM_VND_A2 return next_state; } +static uint8_t brcm_vnd_a2dp_offload_configure() +{ + uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; + + BTA2DPDBG("%s", __FUNCTION__); + + p = msg_req; + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_READ_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_FCN); + UINT32_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_PADCNF); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_MGMT_EVT); + UINT8_TO_STREAM(p, UIPC_OPEN_REQ); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_L2C_EVT); + UINT8_TO_STREAM(p, L2C_SYNC_TO_LITE_REQ); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.acl_data_size); + UINT16_TO_STREAM(p, !(brcm_vnd_a2dp_pdata.offload_params.is_flushable)); + UINT8_TO_STREAM(p, 0x02); //multi_av_data_cong_start + UINT8_TO_STREAM(p, 0x00); //multi_av_data_cong_end + UINT8_TO_STREAM(p, 0x04); //multi_av_data_cong_discard + UINT8_TO_STREAM(p, 1); //num_stream + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.remote_cid); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.lm_handle); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.is_flushable); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_AVDT_EVT); + UINT8_TO_STREAM(p, AVDT_SYNC_TO_BTC_LITE_REQ); + UINT8_TO_STREAM(p, 1); //num_stream + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); + UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_source); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); + UINT8_TO_STREAM(p, AUDIO_ROUTE_CONFIG_REQ); + UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC); + UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF); + UINT8_TO_STREAM(p, AUDIO_ROUTE_OUT_BTA2DP); + UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF); + UINT8_TO_STREAM(p, AUDIO_ROUTE_SF_NA); + UINT8_TO_STREAM(p, AUDIO_ROUTE_EQ_BYPASS); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); + UINT8_TO_STREAM(p, AUDIO_CODEC_CONFIG_REQ); + UINT16_TO_STREAM(p, AUDIO_CODEC_SBC_ENC); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.sampling_freq); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.channel_mode); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.block_length); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.num_subbands); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.alloc_method); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.bitpool_size); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); + UINT8_TO_STREAM(p, A2DP_START_REQ); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + return 0; +} + static uint8_t brcm_vnd_a2dp_offload_cleanup() { uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; @@ -621,6 +613,7 @@ static uint8_t brcm_vnd_a2dp_offload_cleanup() UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn); UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.pcmi2s_pinmux.pad_conf); brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn = PCM_PIN_FCN_INVALID; } return 0; @@ -736,7 +729,7 @@ int brcm_vnd_a2dp_execute(bt_vendor_opcode_t opcode, void *ev_data) tBRCM_VND_A2DP_EVENT ssm_event = (opcode == BT_VND_OP_A2DP_OFFLOAD_START)? BRCM_VND_A2DP_OFFLOAD_START_REQ:BRCM_VND_A2DP_OFFLOAD_STOP_REQ; - ALOGD("%s opcode %d ", __FUNCTION__, opcode); + ALOGD("%s opcode %d , state %d", __FUNCTION__, opcode, brcm_vnd_a2dp_pdata.state); return brcm_vnd_a2dp_ssm_execute(ssm_event, ev_data); } -- cgit v1.2.3 From 49b5e6f5dfdddd0f875d120f5aebc39d7d9415a5 Mon Sep 17 00:00:00 2001 From: Sridhar Vashist Date: Tue, 25 Aug 2015 17:36:01 -0500 Subject: Make A2DP Offload max bitpool configurable by device. Set default a2dp offload bitpool for 44.1kHz hi-quality stream. Avoid bt fw from using excessively high bitpools even if supported. Change-Id: Iae3d5e16a77a09c81ad12573fc66f1181fae836c Signed-off-by: Sridhar Vashist --- src/bt_vendor_brcm_a2dp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/bt_vendor_brcm_a2dp.c b/src/bt_vendor_brcm_a2dp.c index 0526196..b5df5fb 100644 --- a/src/bt_vendor_brcm_a2dp.c +++ b/src/bt_vendor_brcm_a2dp.c @@ -258,8 +258,9 @@ static tA2D_STATUS bcrm_vnd_a2dp_parse_codec_info(tCODEC_INFO_SBC *parsed_info, parsed_info->block_length = *codec_info & A2D_SBC_IE_BLOCKS_MSK; parsed_info->num_subbands = *codec_info & A2D_SBC_IE_SUBBAND_MSK; parsed_info->alloc_method = *codec_info & A2D_SBC_IE_ALLOC_MD_MSK; - codec_info += 2; - parsed_info->bitpool_size = *codec_info; // MAX BITPOOL // + codec_info += 2; /* MAX Bitpool */ + parsed_info->bitpool_size = (*codec_info > BRCM_A2DP_OFFLOAD_MAX_BITPOOL) ? + BRCM_A2DP_OFFLOAD_MAX_BITPOOL : (*codec_info); if(MULTI_BIT_SET(parsed_info->sampling_freq)) status = A2D_BAD_SAMP_FREQ; -- cgit v1.2.3 From 3e1fc82009b434a496f920a29023426e4d16fd4f Mon Sep 17 00:00:00 2001 From: Chris Elliott Date: Tue, 1 Dec 2015 14:47:15 -0800 Subject: Fix build breakage by removing ad2p impl. Change-Id: Id8d172a407c679a8f2000d17f47aa45a571b291a --- src/bt_vendor_brcm.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) (limited to 'src') diff --git a/src/bt_vendor_brcm.c b/src/bt_vendor_brcm.c index 12dc80b..05a5bcb 100755 --- a/src/bt_vendor_brcm.c +++ b/src/bt_vendor_brcm.c @@ -123,10 +123,6 @@ static int init(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr) /* This is handed over from the stack */ memcpy(vnd_local_bd_addr, local_bdaddr, 6); -#if (BRCM_A2DP_OFFLOAD == TRUE) - brcm_vnd_a2dp_init(); -#endif - return 0; } @@ -134,7 +130,7 @@ static int init(const bt_vendor_callbacks_t* p_cb, unsigned char *local_bdaddr) /** Requested operations */ static int op(bt_vendor_opcode_t opcode, void *param) { - int retval = BT_VND_OP_RESULT_SUCCESS; + int retval = 0; BTVNDDBG("op for %d", opcode); @@ -229,10 +225,6 @@ static int op(bt_vendor_opcode_t opcode, void *param) hw_epilog_process(); #endif } - - case BT_VND_OP_A2DP_OFFLOAD_START: - case BT_VND_OP_A2DP_OFFLOAD_STOP: - retval = brcm_vnd_a2dp_execute(opcode, param); break; } -- cgit v1.2.3 From 4fecb323b78600ddf92abab191bf9f909054fb20 Mon Sep 17 00:00:00 2001 From: Chris Elliott Date: Wed, 2 Dec 2015 12:38:18 -0800 Subject: DO NOT MERGE Revert "Fix A2DP Offload lockup when RE-STARTING" This reverts commit 6708688fef36253ffe63bbca37db40d96a9748fd. --- src/bt_vendor_brcm_a2dp.c | 215 ++++++++++++++++++++++++---------------------- 1 file changed, 111 insertions(+), 104 deletions(-) (limited to 'src') diff --git a/src/bt_vendor_brcm_a2dp.c b/src/bt_vendor_brcm_a2dp.c index b5df5fb..d12979b 100644 --- a/src/bt_vendor_brcm_a2dp.c +++ b/src/bt_vendor_brcm_a2dp.c @@ -84,16 +84,18 @@ typedef enum } tBRCM_VND_A2DP_SST_STATES; -static uint8_t brcm_vnd_a2dp_offload_configure(); static uint8_t brcm_vnd_a2dp_offload_cleanup(); static uint8_t brcm_vnd_a2dp_offload_suspend(); +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_enter(tBRCM_VND_A2DP_EVENT event); +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_enter(tBRCM_VND_A2DP_EVENT event); +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_enter(tBRCM_VND_A2DP_EVENT event); static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data); static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data); static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data); static void brcm_vnd_a2dp_hci_uipc_cback(void *pmem); typedef struct { - uint8_t fcn; + uint8_t fcn; uint32_t pad_conf; } tBRCM_VND_PCM_CONF; @@ -115,9 +117,9 @@ tBRCM_VND_A2DP_SST_STATE; /* state table */ static tBRCM_VND_A2DP_SST_STATE brcm_vnd_a2dp_sst_tbl[] = { - {NULL, brcm_vnd_a2dp_sm_idle_process_ev}, - {NULL, brcm_vnd_a2dp_sm_starting_process_ev}, - {NULL, brcm_vnd_a2dp_sm_stream_process_ev}, + {brcm_vnd_a2dp_sm_idle_enter, brcm_vnd_a2dp_sm_idle_process_ev}, + {brcm_vnd_a2dp_sm_starting_enter, brcm_vnd_a2dp_sm_starting_process_ev}, + {brcm_vnd_a2dp_sm_stream_enter, brcm_vnd_a2dp_sm_stream_process_ev}, }; static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; @@ -306,10 +308,10 @@ int brcm_vnd_a2dp_ssm_execute(tBRCM_VND_A2DP_EVENT event, void *ev_data) tBRCM_VND_A2DP_SST_STATE *state_table; tBRCM_VND_A2DP_SST_STATES next_state; - pthread_mutex_lock(&g_mutex); - BTA2DPDBG("%s ev %d state %d", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state); + pthread_mutex_lock(&g_mutex); + if (brcm_vnd_a2dp_pdata.state != BRCM_VND_A2DP_INVALID_SST) { state_table = &brcm_vnd_a2dp_sst_tbl[brcm_vnd_a2dp_pdata.state]; /* process event */ @@ -336,6 +338,101 @@ int brcm_vnd_a2dp_ssm_execute(tBRCM_VND_A2DP_EVENT event, void *ev_data) /* state machine actions */ +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_enter(tBRCM_VND_A2DP_EVENT event) +{ + UNUSED(event); + BTA2DPDBG("%s", __FUNCTION__); + brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn = PCM_PIN_FCN_INVALID; + return brcm_vnd_a2dp_pdata.state; +} + +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_enter(tBRCM_VND_A2DP_EVENT event) +{ + UNUSED(event); + uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; + BTA2DPDBG("%s", __FUNCTION__); + + p = msg_req; + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_READ_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_FCN); + UINT32_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_PADCNF); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_MGMT_EVT); + UINT8_TO_STREAM(p, UIPC_OPEN_REQ); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_L2C_EVT); + UINT8_TO_STREAM(p, L2C_SYNC_TO_LITE_REQ); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.acl_data_size); + UINT16_TO_STREAM(p, !(brcm_vnd_a2dp_pdata.offload_params.is_flushable)); + UINT8_TO_STREAM(p, 0x02); //multi_av_data_cong_start + UINT8_TO_STREAM(p, 0x00); //multi_av_data_cong_end + UINT8_TO_STREAM(p, 0x04); //multi_av_data_cong_discard + UINT8_TO_STREAM(p, 1); //num_stream + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.remote_cid); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.lm_handle); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.is_flushable); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_AVDT_EVT); + UINT8_TO_STREAM(p, AVDT_SYNC_TO_BTC_LITE_REQ); + UINT8_TO_STREAM(p, 1); //num_stream + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); + UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_source); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); + UINT8_TO_STREAM(p, AUDIO_ROUTE_CONFIG_REQ); + UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC); + UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF); + UINT8_TO_STREAM(p, AUDIO_ROUTE_OUT_BTA2DP); + UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF); + UINT8_TO_STREAM(p, AUDIO_ROUTE_SF_NA); + UINT8_TO_STREAM(p, AUDIO_ROUTE_EQ_BYPASS); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); + UINT8_TO_STREAM(p, AUDIO_CODEC_CONFIG_REQ); + UINT16_TO_STREAM(p, AUDIO_CODEC_SBC_ENC); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.sampling_freq); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.channel_mode); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.block_length); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.num_subbands); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.alloc_method); + UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.bitpool_size); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + p = msg_req; + UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); + UINT8_TO_STREAM(p, A2DP_START_REQ); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); + UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); + brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); + + return brcm_vnd_a2dp_pdata.state; +} + + +static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_enter(tBRCM_VND_A2DP_EVENT event) +{ + UNUSED(event); + ALOGV("%s", __FUNCTION__); + + return brcm_vnd_a2dp_pdata.state; +} + static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data) { tBRCM_VND_A2DP_SST_STATES next_state = brcm_vnd_a2dp_pdata.state; @@ -346,12 +443,9 @@ static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_process_ev(tBRCM_VND_A2DP if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( &brcm_vnd_a2dp_pdata.codec_info, (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) { ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__); - bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, - brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); - } else { - brcm_vnd_a2dp_offload_configure(); - next_state = BRCM_VND_A2DP_STARTING_SST; } + + next_state = BRCM_VND_A2DP_STARTING_SST; break; default: @@ -365,7 +459,6 @@ static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_process_ev(tBRCM_VND_ { tBRCM_VND_A2DP_SST_STATES next_state = brcm_vnd_a2dp_pdata.state; uint8_t status, *p; - switch (event) { case BRCM_VND_A2DP_OFFLOAD_START_REQ: brcm_vnd_a2dp_offload_cleanup(); @@ -373,14 +466,12 @@ static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_process_ev(tBRCM_VND_ if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( &brcm_vnd_a2dp_pdata.codec_info, (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) { ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__); - bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, - brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); - next_state = BRCM_VND_A2DP_IDLE_SST; - } else { - brcm_vnd_a2dp_offload_configure(); } + + next_state = BRCM_VND_A2DP_STARTING_SST; break; + case BRCM_VND_A2DP_OFFLOAD_STOP_REQ: brcm_vnd_a2dp_offload_cleanup(); next_state = BRCM_VND_A2DP_IDLE_SST; @@ -481,13 +572,8 @@ static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_process_ev(tBRCM_VND_A2 if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( &brcm_vnd_a2dp_pdata.codec_info, (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) { ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__); - bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, - brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); - next_state = BRCM_VND_A2DP_IDLE_SST; - } else { - brcm_vnd_a2dp_offload_configure(); - next_state = BRCM_VND_A2DP_STARTING_SST; } + next_state = BRCM_VND_A2DP_STARTING_SST; break; case BRCM_VND_A2DP_OFFLOAD_STOP_REQ: @@ -505,84 +591,6 @@ static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_process_ev(tBRCM_VND_A2 return next_state; } -static uint8_t brcm_vnd_a2dp_offload_configure() -{ - uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; - - BTA2DPDBG("%s", __FUNCTION__); - - p = msg_req; - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_READ_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_FCN); - UINT32_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_PADCNF); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_MGMT_EVT); - UINT8_TO_STREAM(p, UIPC_OPEN_REQ); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_L2C_EVT); - UINT8_TO_STREAM(p, L2C_SYNC_TO_LITE_REQ); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.acl_data_size); - UINT16_TO_STREAM(p, !(brcm_vnd_a2dp_pdata.offload_params.is_flushable)); - UINT8_TO_STREAM(p, 0x02); //multi_av_data_cong_start - UINT8_TO_STREAM(p, 0x00); //multi_av_data_cong_end - UINT8_TO_STREAM(p, 0x04); //multi_av_data_cong_discard - UINT8_TO_STREAM(p, 1); //num_stream - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.remote_cid); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.lm_handle); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.is_flushable); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_AVDT_EVT); - UINT8_TO_STREAM(p, AVDT_SYNC_TO_BTC_LITE_REQ); - UINT8_TO_STREAM(p, 1); //num_stream - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); - UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_source); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); - UINT8_TO_STREAM(p, AUDIO_ROUTE_CONFIG_REQ); - UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC); - UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF); - UINT8_TO_STREAM(p, AUDIO_ROUTE_OUT_BTA2DP); - UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF); - UINT8_TO_STREAM(p, AUDIO_ROUTE_SF_NA); - UINT8_TO_STREAM(p, AUDIO_ROUTE_EQ_BYPASS); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); - UINT8_TO_STREAM(p, AUDIO_CODEC_CONFIG_REQ); - UINT16_TO_STREAM(p, AUDIO_CODEC_SBC_ENC); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.sampling_freq); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.channel_mode); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.block_length); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.num_subbands); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.alloc_method); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.bitpool_size); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); - UINT8_TO_STREAM(p, A2DP_START_REQ); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - return 0; -} - static uint8_t brcm_vnd_a2dp_offload_cleanup() { uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; @@ -614,7 +622,6 @@ static uint8_t brcm_vnd_a2dp_offload_cleanup() UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn); UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.pcmi2s_pinmux.pad_conf); brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn = PCM_PIN_FCN_INVALID; } return 0; @@ -730,7 +737,7 @@ int brcm_vnd_a2dp_execute(bt_vendor_opcode_t opcode, void *ev_data) tBRCM_VND_A2DP_EVENT ssm_event = (opcode == BT_VND_OP_A2DP_OFFLOAD_START)? BRCM_VND_A2DP_OFFLOAD_START_REQ:BRCM_VND_A2DP_OFFLOAD_STOP_REQ; - ALOGD("%s opcode %d , state %d", __FUNCTION__, opcode, brcm_vnd_a2dp_pdata.state); + ALOGD("%s opcode %d ", __FUNCTION__, opcode); return brcm_vnd_a2dp_ssm_execute(ssm_event, ev_data); } -- cgit v1.2.3 From cda874fab03f78efebddb8fb81f9ea7aeee87eb2 Mon Sep 17 00:00:00 2001 From: Chris Elliott Date: Wed, 2 Dec 2015 13:37:04 -0800 Subject: DO NOT MERGE Final Revert "Make A2DP Offload max bitpool configurable by device." This reverts commit 49b5e6f5dfdddd0f875d120f5aebc39d7d9415a5. --- src/bt_vendor_brcm_a2dp.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/bt_vendor_brcm_a2dp.c b/src/bt_vendor_brcm_a2dp.c index b5df5fb..0526196 100644 --- a/src/bt_vendor_brcm_a2dp.c +++ b/src/bt_vendor_brcm_a2dp.c @@ -258,9 +258,8 @@ static tA2D_STATUS bcrm_vnd_a2dp_parse_codec_info(tCODEC_INFO_SBC *parsed_info, parsed_info->block_length = *codec_info & A2D_SBC_IE_BLOCKS_MSK; parsed_info->num_subbands = *codec_info & A2D_SBC_IE_SUBBAND_MSK; parsed_info->alloc_method = *codec_info & A2D_SBC_IE_ALLOC_MD_MSK; - codec_info += 2; /* MAX Bitpool */ - parsed_info->bitpool_size = (*codec_info > BRCM_A2DP_OFFLOAD_MAX_BITPOOL) ? - BRCM_A2DP_OFFLOAD_MAX_BITPOOL : (*codec_info); + codec_info += 2; + parsed_info->bitpool_size = *codec_info; // MAX BITPOOL // if(MULTI_BIT_SET(parsed_info->sampling_freq)) status = A2D_BAD_SAMP_FREQ; -- cgit v1.2.3 From 8a1508699619f12a0847faa4e98e51601b283a73 Mon Sep 17 00:00:00 2001 From: Chris Elliott Date: Wed, 2 Dec 2015 13:48:50 -0800 Subject: DO NOT MERGE Final Revert "A2DP Offload BRCM vendor specific implementation" This reverts commit d51ab12cc1e7b02279b45f91c2f2f9a9b4a1404e. --- src/bt_vendor_brcm_a2dp.c | 744 ---------------------------------------------- 1 file changed, 744 deletions(-) delete mode 100644 src/bt_vendor_brcm_a2dp.c (limited to 'src') diff --git a/src/bt_vendor_brcm_a2dp.c b/src/bt_vendor_brcm_a2dp.c deleted file mode 100644 index 45d4295..0000000 --- a/src/bt_vendor_brcm_a2dp.c +++ /dev/null @@ -1,744 +0,0 @@ -/****************************************************************************** - * - * Copyright (C) 2015 Motorola Corporation - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - ******************************************************************************/ - -/****************************************************************************** - * - * This is the stream state machine for the BRCM offloaded advanced audio. - * - ******************************************************************************/ - -#define LOG_TAG "bt_vnd_a2dp" -#define LOG_NDEBUG 0 - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "bt_hci_bdroid.h" -#include "bt_vendor_brcm_a2dp.h" -#include "a2d_api.h" -#include "a2d_sbc.h" - -#if (BTA2DP_DEBUG == TRUE) -#define BTA2DPDBG(param, ...) {ALOGD(param, ## __VA_ARGS__);} -#else -#define BTA2DPDBG(param, ...) {} -#endif - -/***************************************************************************** -** Constants and types -*****************************************************************************/ - -typedef void (*hci_cback)(void *); - -typedef enum -{ - BRCM_VND_A2DP_OFFLOAD_INIT_REQ, - BRCM_VND_A2DP_OFFLOAD_START_REQ, - BRCM_VND_A2DP_OFFLOAD_STOP_REQ, - BRCM_VND_UIPC_OPEN_RSP, - BRCM_VND_L2C_SYNC_TO_LITE_RSP, - BRCM_VND_SYNC_TO_BTC_LITE_RSP, - BRCM_VND_AUDIO_CODEC_CONFIG_RSP, - BRCM_VND_AUDIO_ROUTE_CONFIG_RSP, - BRCM_VND_UIPC_CLOSE_RSP, - BRCM_VND_L2C_REMOVE_TO_LITE_RSP, - BRCM_VND_A2DP_START_RSP, - BRCM_VND_A2DP_SUSPEND_RSP, - BRCM_VND_STREAM_STOP_RSP, - BRCM_VND_A2DP_CLEANUP_RSP, - BRCM_VND_A2DP_OFFLOAD_FAILED_ABORT, -} tBRCM_VND_A2DP_EVENT; - -/* state machine states */ -typedef enum -{ - BRCM_VND_A2DP_INVALID_SST = -1, - BRCM_VND_A2DP_IDLE_SST, - BRCM_VND_A2DP_STARTING_SST, - BRCM_VND_A2DP_STREAM_SST, -} -tBRCM_VND_A2DP_SST_STATES; - -static uint8_t brcm_vnd_a2dp_offload_cleanup(); -static uint8_t brcm_vnd_a2dp_offload_suspend(); -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_enter(tBRCM_VND_A2DP_EVENT event); -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_enter(tBRCM_VND_A2DP_EVENT event); -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_enter(tBRCM_VND_A2DP_EVENT event); -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data); -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data); -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data); -static void brcm_vnd_a2dp_hci_uipc_cback(void *pmem); - -typedef struct { - uint8_t fcn; - uint32_t pad_conf; -} -tBRCM_VND_PCM_CONF; - -typedef struct { - tBRCM_VND_A2DP_SST_STATES state; - tCODEC_INFO_SBC codec_info; - tBRCM_VND_PCM_CONF pcmi2s_pinmux; - bt_vendor_op_a2dp_offload_t offload_params; -} -tBRCM_VND_A2DP_PDATA; - -typedef struct { - tBRCM_VND_A2DP_SST_STATES (*enter)(tBRCM_VND_A2DP_EVENT event); - tBRCM_VND_A2DP_SST_STATES (*process_event)(tBRCM_VND_A2DP_EVENT event, void *ev_data); -} -tBRCM_VND_A2DP_SST_STATE; - -/* state table */ -static tBRCM_VND_A2DP_SST_STATE brcm_vnd_a2dp_sst_tbl[] = -{ - {brcm_vnd_a2dp_sm_idle_enter, brcm_vnd_a2dp_sm_idle_process_ev}, - {brcm_vnd_a2dp_sm_starting_enter, brcm_vnd_a2dp_sm_starting_process_ev}, - {brcm_vnd_a2dp_sm_stream_enter, brcm_vnd_a2dp_sm_stream_process_ev}, -}; - -static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER; -static tBRCM_VND_A2DP_PDATA brcm_vnd_a2dp_pdata = { .state = BRCM_VND_A2DP_INVALID_SST }; - - -/******************************************************************************* -** Local Utility Functions -*******************************************************************************/ - -static void log_bin_to_hexstr(uint8_t *bin, uint8_t binsz, const char *log_tag) -{ -#if (BTA2DP_DEBUG == TRUE) - char *str, hex_str[]= "0123456789abcdef"; - uint8_t i; - - str = (char *)malloc(binsz * 3); - if (!binsz) { - ALOGE("%s alloc failed", __FUNCTION__); - return; - } - - for (i = 0; i < binsz; i++) { - str[(i * 3) + 0] = hex_str[(bin[i] >> 4) & 0x0F]; - str[(i * 3) + 1] = hex_str[(bin[i] ) & 0x0F]; - str[(i * 3) + 2] = ' '; - } - str[(binsz * 3) - 1] = 0x00; - BTA2DPDBG("%s %s", log_tag, str); -#endif -} - -static uint8_t brcm_vnd_a2dp_send_hci_vsc(uint16_t cmd, uint8_t *payload, uint8_t len, hci_cback cback) -{ - HC_BT_HDR *p_buf; - uint8_t *p, status; - uint16_t opcode; - - // Perform Opening configure cmds. // - if (bt_vendor_cbacks) { - p_buf = (HC_BT_HDR *)bt_vendor_cbacks->alloc( - BT_HC_HDR_SIZE + HCI_CMD_PREAMBLE_SIZE + len); - 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 + len; - p = (uint8_t *)(p_buf + 1); - - UINT16_TO_STREAM(p, cmd); - *p++ = len; - memcpy(p, payload, len); - - //BTA2DPDBG("%s Cmd %04x UIPC Event %02x%02x UIPC Op %02x Len %d", __FUNCTION__, cmd, event, payload[1], payload[0], payload[2], len); - log_bin_to_hexstr((uint8_t *)(p_buf + 1), HCI_CMD_PREAMBLE_SIZE + len, __FUNCTION__); - - if (bt_vendor_cbacks->xmit_cb(cmd, p_buf, cback)) - { - return BT_VND_OP_RESULT_SUCCESS; - } - bt_vendor_cbacks->dealloc(p_buf); - } - } - return BT_VND_OP_RESULT_FAIL; -} - -static void brcm_vnd_map_a2d_uipc_codec_info(tCODEC_INFO_SBC *codec_info) -{ - switch(codec_info->sampling_freq) { - case A2D_SBC_IE_SAMP_FREQ_16: - codec_info->sampling_freq = CODEC_INFO_SBC_SF_16K; break; - case A2D_SBC_IE_SAMP_FREQ_32: - codec_info->sampling_freq = CODEC_INFO_SBC_SF_32K; break; - case A2D_SBC_IE_SAMP_FREQ_44: - codec_info->sampling_freq = CODEC_INFO_SBC_SF_44K; break; - case A2D_SBC_IE_SAMP_FREQ_48: - codec_info->sampling_freq = CODEC_INFO_SBC_SF_48K; break; - - } - switch(codec_info->channel_mode) { - case A2D_SBC_IE_CH_MD_MONO: - codec_info->channel_mode = CODEC_INFO_SBC_CH_MONO; break; - case A2D_SBC_IE_CH_MD_DUAL: - codec_info->channel_mode = CODEC_INFO_SBC_CH_DUAL; break; - case A2D_SBC_IE_CH_MD_STEREO: - codec_info->channel_mode = CODEC_INFO_SBC_CH_STEREO; break; - case A2D_SBC_IE_CH_MD_JOINT: - codec_info->channel_mode = CODEC_INFO_SBC_CH_JS; break; - } - switch(codec_info->block_length) { - case A2D_SBC_IE_BLOCKS_4: - codec_info->block_length = CODEC_INFO_SBC_BLOCK_4; break; - case A2D_SBC_IE_BLOCKS_8: - codec_info->block_length = CODEC_INFO_SBC_BLOCK_8; break; - case A2D_SBC_IE_BLOCKS_12: - codec_info->block_length = CODEC_INFO_SBC_BLOCK_12; break; - case A2D_SBC_IE_BLOCKS_16: - codec_info->block_length = CODEC_INFO_SBC_BLOCK_16; break; - } - switch(codec_info->alloc_method) { - case A2D_SBC_IE_ALLOC_MD_S: - codec_info->alloc_method = CODEC_INFO_SBC_ALLOC_SNR; break; - case A2D_SBC_IE_ALLOC_MD_L: - codec_info->alloc_method = CODEC_INFO_SBC_ALLOC_LOUDNESS; break; - } - switch(codec_info->num_subbands) { - case A2D_SBC_IE_SUBBAND_4: - codec_info->num_subbands = CODEC_INFO_SBC_SUBBAND_4; break; - case A2D_SBC_IE_SUBBAND_8: - codec_info->num_subbands = CODEC_INFO_SBC_SUBBAND_8; break; - } -} - -static tA2D_STATUS bcrm_vnd_a2dp_parse_codec_info(tCODEC_INFO_SBC *parsed_info, uint8_t *codec_info) -{ - tA2D_STATUS status = A2D_SUCCESS; - UINT8 losc; - UINT8 mt; - - BTA2DPDBG("%s", __FUNCTION__); - - if( parsed_info == NULL || codec_info == NULL) - status = A2D_FAIL; - else - { - losc = *codec_info++; - mt = *codec_info++; - /* If the function is called for the wrong Media Type or Media Codec Type */ - if(losc != A2D_SBC_INFO_LEN || *codec_info != A2D_MEDIA_CT_SBC) - status = A2D_WRONG_CODEC; - else - { - codec_info++; - parsed_info->sampling_freq = *codec_info & A2D_SBC_IE_SAMP_FREQ_MSK; - parsed_info->channel_mode = *codec_info & A2D_SBC_IE_CH_MD_MSK; - codec_info++; - parsed_info->block_length = *codec_info & A2D_SBC_IE_BLOCKS_MSK; - parsed_info->num_subbands = *codec_info & A2D_SBC_IE_SUBBAND_MSK; - parsed_info->alloc_method = *codec_info & A2D_SBC_IE_ALLOC_MD_MSK; - codec_info += 2; - parsed_info->bitpool_size = *codec_info; // MAX BITPOOL // - - if(MULTI_BIT_SET(parsed_info->sampling_freq)) - status = A2D_BAD_SAMP_FREQ; - if(MULTI_BIT_SET(parsed_info->channel_mode)) - status = A2D_BAD_CH_MODE; - if(MULTI_BIT_SET(parsed_info->block_length)) - status = A2D_BAD_BLOCK_LEN; - if(MULTI_BIT_SET(parsed_info->num_subbands)) - status = A2D_BAD_SUBBANDS; - if(MULTI_BIT_SET(parsed_info->alloc_method)) - status = A2D_BAD_ALLOC_MTHD; - if(parsed_info->bitpool_size < A2D_SBC_IE_MIN_BITPOOL || parsed_info->bitpool_size > A2D_SBC_IE_MAX_BITPOOL ) - status = A2D_BAD_MIN_BITPOOL; - - if(status == A2D_SUCCESS) - brcm_vnd_map_a2d_uipc_codec_info(parsed_info); - - BTA2DPDBG("%s STATUS %d parsed info : SampF %02x, ChnMode %02x, BlockL %02x, NSubB %02x, alloc %02x, bitpool %02x", - __FUNCTION__, status, parsed_info->sampling_freq, parsed_info->channel_mode, parsed_info->block_length, - parsed_info->num_subbands, parsed_info->alloc_method, parsed_info->bitpool_size); - - } - } - return status; -} - -/******************************************************************************* -** State Machine Functions -*******************************************************************************/ - -/******************************************************************************* -** -** Function brcm_vnd_a2dp_ssm_execute -** -** Description Stream state machine event handling function for AV -** -** -** Returns void -** -*******************************************************************************/ -int brcm_vnd_a2dp_ssm_execute(tBRCM_VND_A2DP_EVENT event, void *ev_data) -{ - tBRCM_VND_A2DP_SST_STATE *state_table; - tBRCM_VND_A2DP_SST_STATES next_state; - - BTA2DPDBG("%s ev %d state %d", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state); - - pthread_mutex_lock(&g_mutex); - - if (brcm_vnd_a2dp_pdata.state != BRCM_VND_A2DP_INVALID_SST) { - state_table = &brcm_vnd_a2dp_sst_tbl[brcm_vnd_a2dp_pdata.state]; - /* process event */ - next_state = state_table->process_event(event, ev_data); - } else if (BRCM_VND_A2DP_OFFLOAD_INIT_REQ == event) { - next_state = BRCM_VND_A2DP_IDLE_SST; - } - else { - pthread_mutex_unlock(&g_mutex); - return BT_VND_OP_RESULT_FAIL; - } - - /* transition stae */ - while (next_state != brcm_vnd_a2dp_pdata.state) { - brcm_vnd_a2dp_pdata.state = next_state; - state_table = &brcm_vnd_a2dp_sst_tbl[next_state]; - if (state_table->enter) - next_state = state_table->enter(event); - } - - pthread_mutex_unlock(&g_mutex); - return BT_VND_OP_RESULT_SUCCESS; -} - -/* state machine actions */ - -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_enter(tBRCM_VND_A2DP_EVENT event) -{ - UNUSED(event); - BTA2DPDBG("%s", __FUNCTION__); - brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn = PCM_PIN_FCN_INVALID; - return brcm_vnd_a2dp_pdata.state; -} - -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_enter(tBRCM_VND_A2DP_EVENT event) -{ - UNUSED(event); - uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; - BTA2DPDBG("%s", __FUNCTION__); - - p = msg_req; - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_READ_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_FCN); - UINT32_TO_STREAM(p, BRCM_A2DP_OFFLOAD_PCM_PIN_PADCNF); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_MGMT_EVT); - UINT8_TO_STREAM(p, UIPC_OPEN_REQ); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_L2C_EVT); - UINT8_TO_STREAM(p, L2C_SYNC_TO_LITE_REQ); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.acl_data_size); - UINT16_TO_STREAM(p, !(brcm_vnd_a2dp_pdata.offload_params.is_flushable)); - UINT8_TO_STREAM(p, 0x02); //multi_av_data_cong_start - UINT8_TO_STREAM(p, 0x00); //multi_av_data_cong_end - UINT8_TO_STREAM(p, 0x04); //multi_av_data_cong_discard - UINT8_TO_STREAM(p, 1); //num_stream - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.remote_cid); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.lm_handle); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.is_flushable); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_AVDT_EVT); - UINT8_TO_STREAM(p, AVDT_SYNC_TO_BTC_LITE_REQ); - UINT8_TO_STREAM(p, 1); //num_stream - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); - UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_source); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); - UINT8_TO_STREAM(p, AUDIO_ROUTE_CONFIG_REQ); - UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC); - UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF); - UINT8_TO_STREAM(p, AUDIO_ROUTE_OUT_BTA2DP); - UINT8_TO_STREAM(p, BRCM_A2DP_OFFLOAD_SRC_SF); - UINT8_TO_STREAM(p, AUDIO_ROUTE_SF_NA); - UINT8_TO_STREAM(p, AUDIO_ROUTE_EQ_BYPASS); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); - UINT8_TO_STREAM(p, AUDIO_CODEC_CONFIG_REQ); - UINT16_TO_STREAM(p, AUDIO_CODEC_SBC_ENC); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.sampling_freq); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.channel_mode); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.block_length); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.num_subbands); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.alloc_method); - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.codec_info.bitpool_size); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); - UINT8_TO_STREAM(p, A2DP_START_REQ); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - return brcm_vnd_a2dp_pdata.state; -} - - -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_enter(tBRCM_VND_A2DP_EVENT event) -{ - UNUSED(event); - ALOGV("%s", __FUNCTION__); - - return brcm_vnd_a2dp_pdata.state; -} - -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_idle_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data) -{ - tBRCM_VND_A2DP_SST_STATES next_state = brcm_vnd_a2dp_pdata.state; - - switch (event) { - case BRCM_VND_A2DP_OFFLOAD_START_REQ: - brcm_vnd_a2dp_pdata.offload_params = *(bt_vendor_op_a2dp_offload_t*)ev_data; - if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( &brcm_vnd_a2dp_pdata.codec_info, - (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) { - ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__); - } - - next_state = BRCM_VND_A2DP_STARTING_SST; - break; - - default: - ALOGV("%s Unexpected Event %d in State %d, IGNORE", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state); - break; - } - return next_state; -} - -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_starting_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data) -{ - tBRCM_VND_A2DP_SST_STATES next_state = brcm_vnd_a2dp_pdata.state; - uint8_t status, *p; - switch (event) { - case BRCM_VND_A2DP_OFFLOAD_START_REQ: - brcm_vnd_a2dp_offload_cleanup(); - brcm_vnd_a2dp_pdata.offload_params = *(bt_vendor_op_a2dp_offload_t*)ev_data; - if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( - &brcm_vnd_a2dp_pdata.codec_info, (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) { - ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__); - } - - next_state = BRCM_VND_A2DP_STARTING_SST; - break; - - - case BRCM_VND_A2DP_OFFLOAD_STOP_REQ: - brcm_vnd_a2dp_offload_cleanup(); - next_state = BRCM_VND_A2DP_IDLE_SST; - break; - - case BRCM_VND_UIPC_OPEN_RSP: { - uint8_t num_streams; - uint16_t maj_ver, min_ver; - p = (uint8_t*)ev_data + offsetof(tUIPC_OPEN_RSP, status); - STREAM_TO_UINT8(status,p); - STREAM_TO_UINT16(maj_ver,p); - STREAM_TO_UINT16(min_ver,p); - STREAM_TO_UINT8(num_streams,p); - // TODO Verify Params // - if (status) { - ALOGE("%s BRCM_VND_UIPC_OPEN_RSP %02x FAILED", __FUNCTION__, status); - brcm_vnd_a2dp_offload_cleanup(); - bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, - brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); - next_state = BRCM_VND_A2DP_IDLE_SST; - } - } - break; - - case BRCM_VND_L2C_SYNC_TO_LITE_RSP: - status = *((uint8_t*)ev_data + offsetof(tL2C_SYNC_TO_LITE_RESP, stream.status)); - if (status) { - ALOGE("%s L2C_SYNC_TO_LITE_RESP %02x FAILED", __FUNCTION__, status); - brcm_vnd_a2dp_offload_cleanup(); - bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, - brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); - next_state = BRCM_VND_A2DP_IDLE_SST; - } - break; - - case BRCM_VND_SYNC_TO_BTC_LITE_RSP: - status = *((uint8_t*)ev_data + offsetof(tAVDT_SYNC_TO_BTC_LITE_RESP, status)); - if (status) { - ALOGE("%s AVDT_SYNC_TO_BTC_LITE_RESP %02x FAILED", __FUNCTION__, status); - brcm_vnd_a2dp_offload_cleanup(); - bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, - brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); - next_state = BRCM_VND_A2DP_IDLE_SST; - } - break; - - case BRCM_VND_AUDIO_ROUTE_CONFIG_RSP: - status = *((uint8_t*)ev_data + offsetof(tAUDIO_ROUTE_CONFIG_RESP, status)); - if (status) { - ALOGE("%s AUDIO_ROUTE_CONFIG_RESP %02x FAILED", __FUNCTION__, status); - brcm_vnd_a2dp_offload_cleanup(); - bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, - brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); - next_state = BRCM_VND_A2DP_IDLE_SST; - } - break; - - case BRCM_VND_AUDIO_CODEC_CONFIG_RSP: - status = *((uint8_t*)ev_data + offsetof(tAUDIO_CODEC_CONFIG_RESP, status)); - if (status) { - ALOGE("%s BRCM_VND_AUDIO_CODEC_CONFIG_RSP %02x FAILED", __FUNCTION__, status); - brcm_vnd_a2dp_offload_cleanup(); - bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, - brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); - next_state = BRCM_VND_A2DP_IDLE_SST; - } - break; - - case BRCM_VND_A2DP_START_RSP: - /* status = *((uint8_t*)ev_data + offsetof(tA2DP_GENERIC_RESP, status)); */ - bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_SUCCESS, BT_VND_OP_A2DP_OFFLOAD_START, - brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); - next_state = BRCM_VND_A2DP_STREAM_SST; - break; - - case BRCM_VND_A2DP_OFFLOAD_FAILED_ABORT: - ALOGE("%s BRCM_VND_A2DP_OFFLOAD_FAILED_ABORT", __FUNCTION__); - brcm_vnd_a2dp_offload_cleanup(); - bt_vendor_cbacks->a2dp_offload_cb(BT_VND_OP_RESULT_FAIL, BT_VND_OP_A2DP_OFFLOAD_START, - brcm_vnd_a2dp_pdata.offload_params.bta_av_handle); - next_state = BRCM_VND_A2DP_IDLE_SST; - break; - - default: - ALOGE("%s Unexpected Event %d in State %d, IGNORE", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state); - break; - } - return next_state; -} - -static tBRCM_VND_A2DP_SST_STATES brcm_vnd_a2dp_sm_stream_process_ev(tBRCM_VND_A2DP_EVENT event, void *ev_data) -{ - tBRCM_VND_A2DP_SST_STATES next_state = brcm_vnd_a2dp_pdata.state; - switch (event) { - case BRCM_VND_A2DP_OFFLOAD_START_REQ: - brcm_vnd_a2dp_offload_cleanup(); - brcm_vnd_a2dp_pdata.offload_params = *(bt_vendor_op_a2dp_offload_t*)ev_data; - if (A2D_SUCCESS != bcrm_vnd_a2dp_parse_codec_info( - &brcm_vnd_a2dp_pdata.codec_info, (uint8_t *)brcm_vnd_a2dp_pdata.offload_params.codec_info)) { - ALOGE("%s CodecConfig BT_VND_OP_A2DP_OFFLOAD_START FAILED", __FUNCTION__); - } - next_state = BRCM_VND_A2DP_STARTING_SST; - break; - - case BRCM_VND_A2DP_OFFLOAD_STOP_REQ: - case BRCM_VND_A2DP_OFFLOAD_FAILED_ABORT: - ALOGE("%s BRCM_VND_A2DP_OFFLOAD_STOP ABORT %d.", __FUNCTION__, - (event == BRCM_VND_A2DP_OFFLOAD_FAILED_ABORT)); - brcm_vnd_a2dp_offload_cleanup(); - next_state = BRCM_VND_A2DP_IDLE_SST; - break; - - default: - ALOGE("%s Unexpected Event %d in State %d, IGNORE", __FUNCTION__, event, brcm_vnd_a2dp_pdata.state); - break; - } - return next_state; -} - -static uint8_t brcm_vnd_a2dp_offload_cleanup() -{ - uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; - - BTA2DPDBG("%s", __FUNCTION__); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); - UINT8_TO_STREAM(p, A2DP_CLEANUP_REQ); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.stream_mtu); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_L2C_EVT); - UINT8_TO_STREAM(p, L2C_REMOVE_TO_LITE_REQ); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.xmit_quota); - UINT8_TO_STREAM(p, 1); //num_stream - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_MGMT_EVT); - UINT8_TO_STREAM(p, UIPC_CLOSE_REQ); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - if (PCM_PIN_FCN_INVALID != brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn) { - p = msg_req; - UINT8_TO_STREAM(p, brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn); - UINT32_TO_STREAM(p, brcm_vnd_a2dp_pdata.pcmi2s_pinmux.pad_conf); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_WRITE_PCM_PINS, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - } - - return 0; -} - -static uint8_t brcm_vnd_a2dp_offload_suspend() -{ - uint8_t *p, msg_req[HCI_CMD_MAX_LEN]; - - BTA2DPDBG("%s", __FUNCTION__); - - p = msg_req; - UINT16_TO_STREAM(p, BT_EVT_BTU_IPC_BTM_EVT); - UINT8_TO_STREAM(p, A2DP_SUSPEND_REQ); - UINT16_TO_STREAM(p, brcm_vnd_a2dp_pdata.offload_params.local_cid); - brcm_vnd_a2dp_send_hci_vsc(HCI_VSC_UIPC_OVER_HCI, msg_req, (uint8_t)(p - msg_req), brcm_vnd_a2dp_hci_uipc_cback); - - return 0; -} - -void brcm_vnd_a2dp_hci_uipc_cback(void *pmem) -{ - HC_BT_HDR *p_evt_buf = (HC_BT_HDR *)pmem; - uint8_t *p, len, vsc_result, uipc_opcode; - uint16_t vsc_opcode, uipc_event; - HC_BT_HDR *p_buf = NULL; - bt_vendor_op_result_t status = BT_VND_OP_RESULT_SUCCESS; - tBRCM_VND_A2DP_EVENT ssm_event; - - p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_LEN; - len = *p; - p = (uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_VSC; - STREAM_TO_UINT16(vsc_opcode,p); - vsc_result = *p++; - - log_bin_to_hexstr(((uint8_t *)(p_evt_buf + 1) + HCI_EVT_CMD_CMPL_VSC), len-1, __FUNCTION__); - - if (vsc_result != 0) { - ALOGE("%s Failed VSC Op %04x", __FUNCTION__, vsc_opcode); - status = BT_VND_OP_RESULT_FAIL; - } - else if (vsc_opcode == HCI_VSC_UIPC_OVER_HCI) { - STREAM_TO_UINT16(uipc_event,p); - uipc_opcode = *p; - BTA2DPDBG("%s UIPC Event %04x UIPC Op %02x", __FUNCTION__, uipc_event, uipc_opcode); - - switch (uipc_event) { - case BT_EVT_BTU_IPC_MGMT_EVT : - switch (uipc_opcode) { - case UIPC_OPEN_RSP : ssm_event = BRCM_VND_UIPC_OPEN_RSP; break; - case UIPC_CLOSE_RSP : ssm_event = BRCM_VND_UIPC_CLOSE_RSP; break; - default: status = BT_VND_OP_RESULT_FAIL; - } - break; - - case BT_EVT_BTU_IPC_BTM_EVT : - switch (uipc_opcode) { - case A2DP_START_RESP: ssm_event = BRCM_VND_A2DP_START_RSP; break; - case A2DP_SUSPEND_RESP: ssm_event = BRCM_VND_A2DP_SUSPEND_RSP; break; - case A2DP_CLEANUP_RESP: ssm_event = BRCM_VND_A2DP_CLEANUP_RSP; break; - case AUDIO_CODEC_CONFIG_RESP: ssm_event = BRCM_VND_AUDIO_CODEC_CONFIG_RSP; break; - case AUDIO_ROUTE_CONFIG_RESP: ssm_event = BRCM_VND_AUDIO_ROUTE_CONFIG_RSP; break; - default: status = BT_VND_OP_RESULT_FAIL; - } - break; - - case BT_EVT_BTU_IPC_L2C_EVT : - switch (uipc_opcode) { - case L2C_REMOVE_TO_LITE_RESP: ssm_event = BRCM_VND_L2C_REMOVE_TO_LITE_RSP; break; - case L2C_SYNC_TO_LITE_RESP: ssm_event = BRCM_VND_L2C_SYNC_TO_LITE_RSP; break; - default: status = BT_VND_OP_RESULT_FAIL; - } - break; - - case BT_EVT_BTU_IPC_AVDT_EVT : - if (uipc_opcode == AVDT_SYNC_TO_BTC_LITE_RESP) { - ssm_event = BRCM_VND_SYNC_TO_BTC_LITE_RSP; - break; - } - - default: - status = BT_VND_OP_RESULT_FAIL; - break; - } - if (status == BT_VND_OP_RESULT_SUCCESS) - brcm_vnd_a2dp_ssm_execute(ssm_event, p); - } - else if (vsc_opcode == HCI_VSC_READ_PCM_PINS) { - STREAM_TO_UINT8(brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn, p); - STREAM_TO_UINT32(brcm_vnd_a2dp_pdata.pcmi2s_pinmux.pad_conf, p); - BTA2DPDBG("%s HCI_VSC_READ_PCM_PINS %02x %08x", __FUNCTION__, - brcm_vnd_a2dp_pdata.pcmi2s_pinmux.fcn, brcm_vnd_a2dp_pdata.pcmi2s_pinmux.pad_conf); - } - - if (status != BT_VND_OP_RESULT_SUCCESS) - brcm_vnd_a2dp_ssm_execute(BRCM_VND_A2DP_OFFLOAD_FAILED_ABORT, NULL); - - /* Free the RX event buffer */ - bt_vendor_cbacks->dealloc(p_evt_buf); -} - -void brcm_vnd_a2dp_init() -{ - if (!bt_vendor_cbacks) - return; - - ALOGD("%s ", __FUNCTION__); - brcm_vnd_a2dp_ssm_execute(BRCM_VND_A2DP_OFFLOAD_INIT_REQ, NULL); -} - -int brcm_vnd_a2dp_execute(bt_vendor_opcode_t opcode, void *ev_data) -{ - tBRCM_VND_A2DP_EVENT ssm_event = (opcode == BT_VND_OP_A2DP_OFFLOAD_START)? - BRCM_VND_A2DP_OFFLOAD_START_REQ:BRCM_VND_A2DP_OFFLOAD_STOP_REQ; - - ALOGD("%s opcode %d ", __FUNCTION__, opcode); - - return brcm_vnd_a2dp_ssm_execute(ssm_event, ev_data); -} - - -- cgit v1.2.3