diff options
| -rw-r--r-- | Android.mk | 17 | ||||
| -rw-r--r-- | include/bt_vendor_brcm_a2dp.h | 101 | ||||
| -rw-r--r-- | include/uipc_msg.h | 798 | ||||
| -rw-r--r-- | include/vnd_smelt.txt | 5 | ||||
| -rwxr-xr-x | src/bt_vendor_brcm.c | 10 | ||||
| -rw-r--r-- | src/bt_vendor_brcm_a2dp.c | 744 |
6 files changed, 1673 insertions, 2 deletions
@@ -4,6 +4,14 @@ ifneq ($(BOARD_HAVE_BLUETOOTH_BCM),) include $(CLEAR_VARS) +ifneq ($(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR),) + bdroid_C_INCLUDES := $(BOARD_BLUETOOTH_BDROID_BUILDCFG_INCLUDE_DIR) + bdroid_CFLAGS += -DHAS_BDROID_BUILDCFG +else + bdroid_C_INCLUDES := + bdroid_CFLAGS += -DHAS_NO_BDROID_BUILDCFG +endif + BDROID_DIR := $(TOP_DIR)system/bt ifeq ($(strip $(USE_BLUETOOTH_BCM4343)),true) @@ -12,6 +20,7 @@ endif LOCAL_SRC_FILES := \ src/bt_vendor_brcm.c \ + src/bt_vendor_brcm_a2dp.c \ src/hardware.c \ src/userial_vendor.c \ src/upio.c \ @@ -19,7 +28,13 @@ LOCAL_SRC_FILES := \ LOCAL_C_INCLUDES += \ $(LOCAL_PATH)/include \ - $(BDROID_DIR)/hci/include + $(BDROID_DIR)/hci/include \ + $(BDROID_DIR)/include \ + $(BDROID_DIR)/stack/include \ + $(BDROID_DIR)/gki/ulinux + +LOCAL_C_INCLUDES += $(bdroid_C_INCLUDES) +LOCAL_CFLAGS += $(bdroid_CFLAGS) LOCAL_SHARED_LIBRARIES := \ libcutils \ diff --git a/include/bt_vendor_brcm_a2dp.h b/include/bt_vendor_brcm_a2dp.h new file mode 100644 index 0000000..9601111 --- /dev/null +++ b/include/bt_vendor_brcm_a2dp.h @@ -0,0 +1,101 @@ +/****************************************************************************** + * + * 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. + * + ******************************************************************************/ + +/****************************************************************************** + * + * Filename: bt_vendor_brcm_a2dp.h + * + * Description: Contains definitions specific for interfacing with Broadcom + * Bluetooth chipsets for A2DP Offload implementation. + * + ******************************************************************************/ + +#ifndef BT_VENDOR_BRCM_A2DP_H +#define BT_VENDOR_BRCM_A2DP_H + +#include "bt_vendor_brcm.h" +#include "bt_target.h" +#include "uipc_msg.h" + +/****************************************************************************** +** Constants & Macros +******************************************************************************/ + +#define HCI_VSC_WRITE_PCM_PINS 0xFC61 +#define HCI_VSC_READ_PCM_PINS 0xFC62 +#define HCI_VSC_UIPC_OVER_HCI 0xFC8B + +/* pinmux for I2S pins */ +#define PCM_PIN_FCN_GPIO 0x00 +#define PCM_PIN_FCN_PCM 0x01 +#define PCM_PIN_FCN_I2S_MASTER 0x05 +#define PCM_PIN_FCN_I2S_SLAVE 0x07 +#define PCM_PIN_FCN_INVALID 0xFF + +/* PADCONF for I2S pins */ +/* From LSB, byte map to DIN, DOUT, WS, CLK */ +/* +bit 0: 0 OUTPUT, 1 INPUT +bit 1: 0 NO-PULL,1 PULL-UP +bit 2: 0 NO-PULL,1 PULL-DN +bit 3: 1 SHMITT Trigger Enable +bit 4-7: Drive Strength +*/ +/* Define standard Master & Slave I2S PADCONFs */ +#define PCM_PIN_PADCNF_I2S_SLAVE 0x19191819 +#define PCM_PIN_PADCNF_I2S_MASTER 0x18181819 + +#define HCI_EVT_CMD_CMPL_LEN 1 +#define HCI_EVT_CMD_CMPL_VSC 3 +#define HCI_CMD_PREAMBLE_SIZE 3 +#define HCI_CMD_MAX_LEN 258 + +#define UNUSED(x) (void)(x) + +#if (BRCM_A2DP_OFFLOAD != TRUE) +#define BRCM_A2DP_OFFLOAD FALSE +#endif + +/* A2DP offload parameters from vnd_<prod>.txt */ + +#ifndef BRCM_A2DP_OFFLOAD_SRC +#define BRCM_A2DP_OFFLOAD_SRC AUDIO_ROUTE_SRC_I2S +#endif + +#ifndef BRCM_A2DP_OFFLOAD_SRC_SF +#define BRCM_A2DP_OFFLOAD_SRC_SF AUDIO_ROUTE_SF_48K +#endif + +#ifndef BRCM_A2DP_OFFLOAD_PCM_PIN_FCN +#define BRCM_A2DP_OFFLOAD_PCM_PIN_FCN PCM_PIN_FCN_I2S_SLAVE +#endif + +#ifndef BRCM_A2DP_OFFLOAD_PCM_PIN_PADCNF +#if (BRCM_A2DP_OFFLOAD_PCM_PIN_FCN == PCM_PIN_FCN_I2S_MASTER) +#define BRCM_A2DP_OFFLOAD_PCM_PIN_PADCNF PCM_PIN_PADCNF_I2S_MASTER +#else +#define BRCM_A2DP_OFFLOAD_PCM_PIN_PADCNF PCM_PIN_PADCNF_I2S_SLAVE +#endif +#endif + +#define MULTI_BIT_SET(x) !!(x & (x - 1)) + +void brcm_vnd_a2dp_init(); +int brcm_vnd_a2dp_execute(bt_vendor_opcode_t, void *ev_data); + +#endif /*BT_VENDOR_BRCM_A2DP_H*/ diff --git a/include/uipc_msg.h b/include/uipc_msg.h new file mode 100644 index 0000000..a8f31c0 --- /dev/null +++ b/include/uipc_msg.h @@ -0,0 +1,798 @@ +/****************************************************************************** + * + * Copyright (C) 1999-2012 Broadcom 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 file contains sync message over UIPC + * + ******************************************************************************/ + +#ifndef UIPC_MSG_H +#define UIPC_MSG_H + +#include "bt_types.h" + +/****************************************************************************/ +/* UIPC version number: 1.0 */ +/****************************************************************************/ +#define UIPC_VERSION_MAJOR 0x0001 +#define UIPC_VERSION_MINOR 0x0000 + + +/******************************** + + UIPC Management Messages + +********************************/ + +/* tUIPC_STATUS codes*/ +enum +{ + UIPC_STATUS_SUCCESS, + UIPC_STATUS_FAIL +}; +typedef UINT8 tUIPC_STATUS; + +/* op_code */ +#define UIPC_OPEN_REQ 0x00 +#define UIPC_OPEN_RSP 0x01 +#define UIPC_CLOSE_REQ 0x02 +#define UIPC_CLOSE_RSP 0x03 + +#pragma pack(push) /* push current alignment to stack */ +#pragma pack(1) /* set alignment to 1 byte boundary to allow for offset mappings */ + +/* Structure of UIPC_OPEN_REQ message */ +typedef struct +{ + UINT8 opcode; /* UIPC_OPEN_REQ */ +} tUIPC_OPEN_REQ; +#define UIPC_OPEN_REQ_MSGLEN (1) + +/* Structure of UIPC_OPEN_RSP message */ +typedef struct +{ + UINT8 opcode; /* UIPC_OPEN_RESP */ + tUIPC_STATUS status; /* UIPC_STATUS */ + UINT16 version_major; /* UIPC_VERSION_MAJOR */ + UINT16 version_minor; /* UIPC_VERSION_MINOR */ + UINT8 num_streams; /* Number of simultaneous streams supported by the light stack */ +} tUIPC_OPEN_RSP; +#define UIPC_OPEN_RSP_MSGLEN (7) + +/* Structure of UIPC_CLOSE_REQ message */ +typedef struct t_uipc_close_req +{ + UINT8 opcode; /* UIPC_CLOSE_REQ */ +} tUIPC_CLOSE_REQ; +#define UIPC_CLOSE_REQ_MSGLEN (1) + +/* Structure of UIPC_CLOSE_RSP message, only for BTC, full stack may ignore it */ +typedef struct t_uipc_close_rsp +{ + UINT8 opcode; /* UIPC_CLOSE_RSP */ +} tUIPC_CLOSE_RSP; +#define UIPC_CLOSE_RSP_MSGLEN (1) + +/* UIPC management message structures */ +typedef union +{ + UINT8 opcode; + tUIPC_OPEN_REQ open_req; + tUIPC_OPEN_RSP open_resp; + tUIPC_CLOSE_REQ close_req; +} tUIPC_MSG; + +#define UIPC_MGMT_MSG_MAXLEN (sizeof(tUIPC_MSG)) + +#define IPC_LOG_MSG_LEN 100 +typedef struct t_uipc_log_msg +{ + UINT32 trace_set_mask; + UINT8 msg[IPC_LOG_MSG_LEN]; +} tUIPC_LOG_MSG; +#define UIPC_LOG_MSGLEN (IPC_LOG_MSG_LEN + 4) + +/******************************** + + H5 Sync Message + +********************************/ + +/* op_code */ +#define SLIP_SYNC_TO_LITE_REQ 0 +#define SLIP_SYNC_TO_LITE_RESP 1 +#define SLIP_SYNC_TO_FULL_REQ 2 +#define SLIP_SYNC_TO_FULL_RESP 3 +#define SLIP_SYNC_NOTIFY 4 + +/* status */ +#define SLIP_SYNC_SUCCESS 0 +#define SLIP_SYNC_FAILURE 1 + +typedef struct +{ + UINT8 op_code; + UINT8 status; + UINT16 acl_pkt_size; + UINT8 state; + UINT8 lp_state; /* Low Power state */ + UINT8 next_seqno; /* next send seq */ + UINT8 ack; /* next ack seq, expected seq from peer */ + UINT8 sent_ack; /* last sent ack */ + UINT8 sliding_window_size;/* window size */ + BOOLEAN oof_flow_control; /* Out of Frame SW Flow Control */ + BOOLEAN data_integrity_type;/* Level of Data Integrity Check */ + UINT8 rx_state; /* rx state for incoming packet processing */ +} tSLIP_SYNC_INFO; + +/******************************** + + L2CAP Sync Message + +********************************/ + +/* op_code */ +#define L2C_SYNC_TO_LITE_REQ 0 +#define L2C_SYNC_TO_LITE_RESP 1 +#define L2C_REMOVE_TO_LITE_REQ 2 +#define L2C_REMOVE_TO_LITE_RESP 3 +#define L2C_FLUSH_TO_FULL_IND 4 + +/* status */ +#define L2C_SYNC_SUCCESS 0 +#define L2C_SYNC_FAILURE 1 + +typedef struct t_l2c_stream_info +{ + UINT16 local_cid; /* Local CID */ + UINT16 remote_cid; /* Remote CID */ + UINT16 out_mtu; /* Max MTU we will send */ + UINT16 handle; /* The handle used with LM */ + UINT16 link_xmit_quota; /* Num outstanding pkts allowed */ + BOOLEAN is_flushable; /* TRUE if flushable channel */ +} tL2C_STREAM_INFO; + +typedef struct t_l2c_sync_to_lite_req +{ + UINT8 op_code; /* L2C_SYNC_TO_LITE_REQ */ + UINT16 light_xmit_quota; /* Total quota for light stack */ + UINT16 acl_data_size; /* Max ACL data size across HCI transport */ + UINT16 non_flushable_pbf; /* L2CAP_PKT_START_NON_FLUSHABLE if controller supports */ + /* Otherwise, L2CAP_PKT_START */ + UINT8 multi_av_data_cong_start; /* Multi-AV queue size to start congestion */ + UINT8 multi_av_data_cong_end; /* Multi-AV queue size to end congestion */ + UINT8 multi_av_data_cong_discard; /* Multi-AV queue size to discard */ + UINT8 num_stream; + tL2C_STREAM_INFO stream; +} tL2C_SYNC_TO_LITE_REQ; + +typedef struct t_l2c_sync_to_lite_resp_stream +{ + UINT16 lcid; + UINT8 status; +} tL2C_SYNC_TO_LITE_RESP_STREAM; + + +typedef struct t_l2c_sync_to_lite_resp +{ + UINT8 op_code; /* L2C_SYNC_TO_LITE_RESP */ + UINT16 light_xmit_unacked; /* unacked packet more than quota in light stack */ + UINT8 num_stream; + tL2C_SYNC_TO_LITE_RESP_STREAM stream; +} tL2C_SYNC_TO_LITE_RESP; + +typedef struct t_l2c_remove_to_lite_req +{ + UINT8 op_code; /* L2C_REMOVE_TO_LITE_REQ */ + UINT16 light_xmit_quota; /* Total quota for light stack */ + UINT8 num_stream; + UINT16 lcid; +} tL2C_REMOVE_TO_LITE_REQ; + +typedef tL2C_SYNC_TO_LITE_RESP tL2C_REMOVE_TO_LITE_RESP; +typedef tL2C_REMOVE_TO_LITE_REQ tL2C_FLUSH_TO_FULL_IND; + +typedef union t_l2c_sync_msg +{ + UINT8 op_code; + tL2C_SYNC_TO_LITE_REQ sync_req; + tL2C_SYNC_TO_LITE_RESP sync_resp; + tL2C_REMOVE_TO_LITE_REQ remove_req; + tL2C_REMOVE_TO_LITE_RESP remove_resp; + tL2C_FLUSH_TO_FULL_IND flush_ind; +} tL2C_SYNC_MSG; + +/******************************** + + AVDTP Sync Message + +********************************/ + +/* op_code */ +#define AVDT_SYNC_TO_LITE_REQ 0 +#define AVDT_SYNC_TO_LITE_RESP 1 +#define AVDT_RESYNC_TO_LITE_REQ 2 +#define AVDT_RESYNC_TO_LITE_RESP 3 +#define AVDT_SYNC_TO_FULL_REQ 4 +#define AVDT_SYNC_TO_FULL_RESP 5 +#define AVDT_REMOVE_TO_LITE_REQ 6 +#define AVDT_REMOVE_TO_LITE_RESP 7 +#define AVDT_SYNC_TO_BTC_LITE_REQ 8 +#define AVDT_SYNC_TO_BTC_LITE_RESP 9 + +/* status */ +#define AVDT_SYNC_SUCCESS 0 +#define AVDT_SYNC_FAILURE 1 + +typedef struct +{ + UINT16 lcid; + UINT32 ssrc; +} tAVDT_SYNC_TO_BTC_LITE_REQ_STREAM; + +typedef struct +{ + UINT8 opcode; /* AVDT_SYNC_TO_BTC_LITE_REQ */ + UINT8 num_stream; + tAVDT_SYNC_TO_BTC_LITE_REQ_STREAM stream; +} tAVDT_SYNC_TO_BTC_LITE_REQ; + +typedef struct +{ + UINT8 opcode; /* AVDT_SYNC_TO_BTC_LITE_RESP */ + UINT8 status; +} tAVDT_SYNC_TO_BTC_LITE_RESP; + +typedef struct t_avdt_scb_sync_info +{ + UINT8 handle; /* SCB handle */ + BD_ADDR peer_addr; /* BD address of peer */ + UINT16 local_cid; /* Local CID */ + UINT16 peer_mtu; /* L2CAP mtu of the peer device */ + UINT8 mux_tsid_media; /* TSID for media transport session */ + UINT16 media_seq; /* media packet sequence number */ +} tAVDT_SCB_SYNC_INFO; + +typedef struct t_avdt_sync_info +{ + UINT8 op_code; + UINT8 status; + + tAVDT_SCB_SYNC_INFO scb_info; + +} tAVDT_SYNC_INFO; + +typedef union t_avdt_sync_msg +{ + UINT8 op_code; + tAVDT_SYNC_INFO sync_info; + tAVDT_SYNC_TO_BTC_LITE_REQ btc_sync_req; + tAVDT_SYNC_TO_BTC_LITE_RESP btc_sync_resp; +} tAVDT_SYNC_MSG; + +/******************************** + + BTA AV Sync Message + +********************************/ + +/* op_code for MM light stack */ +#define BTA_AV_SYNC_TO_LITE_REQ 0 +#define BTA_AV_SYNC_TO_LITE_RESP 1 +#define BTA_AV_STR_START_TO_LITE_REQ 2 +#define BTA_AV_STR_START_TO_LITE_RESP 3 +#define BTA_AV_STR_STOP_TO_LITE_REQ 4 +#define BTA_AV_STR_STOP_TO_LITE_RESP 5 +#define BTA_AV_STR_CLEANUP_TO_LITE_REQ 6 +#define BTA_AV_STR_CLEANUP_TO_LITE_RESP 7 +#define BTA_AV_STR_SUSPEND_TO_LITE_REQ 8 +#define BTA_AV_STR_SUSPEND_TO_LITE_RESP 9 +#define BTA_AV_SYNC_ERROR_RESP 10 + +/* op_code for BTC light stack */ +#define A2DP_START_REQ 11 +#define A2DP_START_RESP 12 +#define A2DP_STOP_REQ 13 +#define A2DP_STOP_RESP 14 +#define A2DP_CLEANUP_REQ 15 +#define A2DP_CLEANUP_RESP 16 +#define A2DP_SUSPEND_REQ 17 +#define A2DP_SUSPEND_RESP 18 + +#define A2DP_JITTER_DONE_IND 41 /* For BTSNK */ + +#define AUDIO_CODEC_CONFIG_REQ 19 +#define AUDIO_CODEC_CONFIG_RESP 20 +#define AUDIO_CODEC_SET_BITRATE_REQ 21 +#define AUDIO_CODEC_FLUSH_REQ 22 +#define AUDIO_ROUTE_CONFIG_REQ 23 +#define AUDIO_ROUTE_CONFIG_RESP 24 +#define AUDIO_MIX_CONFIG_REQ 25 +#define AUDIO_MIX_CONFIG_RESP 26 +#define AUDIO_BURST_FRAMES_IND 27 +#define AUDIO_BURST_END_IND 28 +#define AUDIO_EQ_MODE_CONFIG_REQ 29 +#define AUDIO_SCALE_CONFIG_REQ 30 + +/* For TIVO, only applicable for I2S -> DAC */ +#define AUDIO_SUB_ROUTE_REQ 51 +#define AUDIO_SUB_ROUTE_RESP 52 + +typedef struct +{ + UINT8 opcode; /* A2DP_START_REQ */ + UINT16 lcid; + UINT16 curr_mtu; +}tA2DP_START_REQ; + +typedef struct +{ + UINT8 opcode; /* A2DP_STOP_REQ */ + UINT16 lcid; +}tA2DP_STOP_REQ; + +typedef struct +{ + UINT8 opcode; /* A2DP_SUSPEND_REQ */ + UINT16 lcid; +}tA2DP_SUSPEND_REQ; + +typedef struct +{ + UINT8 opcode; /* A2DP_CLEANUP_REQ */ + UINT16 lcid; + UINT16 curr_mtu; +} tA2DP_CLEANUP_REQ; + +typedef struct +{ + UINT8 opcode; /* A2DP_START_RESP, A2DP_STOP_RESP, A2DP_CLEANUP_RESP, A2DP_SUSPEND_RESP */ + UINT16 lcid; +}tA2DP_GENERIC_RESP; + +#define AUDIO_CODEC_NONE 0x0000 +#define AUDIO_CODEC_SBC_ENC 0x0001 +#define AUDIO_CODEC_SBC_DEC 0x0002 +#define AUDIO_CODEC_MP3_ENC 0x0004 +#define AUDIO_CODEC_MP3_DEC 0x0008 +#define AUDIO_CODEC_AAC_ENC 0x0010 +#define AUDIO_CODEC_AAC_DEC 0x0020 +#define AUDIO_CODEC_AAC_PLUS_ENC 0x0040 +#define AUDIO_CODEC_AAC_PLUS_DEC 0x0080 +#define AUDIO_CODEC_MP2_ENC 0x0100 +#define AUDIO_CODEC_MP2_DEC 0x0200 +#define AUDIO_CODEC_MP2_5_ENC 0x0400 +#define AUDIO_CODEC_MP2_5_DEC 0x0800 + +typedef UINT16 tAUDIO_CODEC_TYPE; + +/* SBC CODEC Parameters */ + +#define CODEC_INFO_SBC_SF_16K 0x00 +#define CODEC_INFO_SBC_SF_32K 0x01 +#define CODEC_INFO_SBC_SF_44K 0x02 +#define CODEC_INFO_SBC_SF_48K 0x03 + +#define CODEC_INFO_SBC_BLOCK_4 0x00 +#define CODEC_INFO_SBC_BLOCK_8 0x01 +#define CODEC_INFO_SBC_BLOCK_12 0x02 +#define CODEC_INFO_SBC_BLOCK_16 0x03 + +#define CODEC_INFO_SBC_CH_MONO 0x00 +#define CODEC_INFO_SBC_CH_DUAL 0x01 +#define CODEC_INFO_SBC_CH_STEREO 0x02 +#define CODEC_INFO_SBC_CH_JS 0x03 + +#define CODEC_INFO_SBC_ALLOC_LOUDNESS 0x00 +#define CODEC_INFO_SBC_ALLOC_SNR 0x01 + +#define CODEC_INFO_SBC_SUBBAND_4 0x00 +#define CODEC_INFO_SBC_SUBBAND_8 0x01 + +/* MPEG audio version ID */ +#define CODEC_INFO_MP25_ID 0x00 +#define CODEC_INFO_RESERVE 0x01 +#define CODEC_INFO_MP2_ID 0x02 +#define CODEC_INFO_MP3_ID 0x03 + +#define CODEC_INFO_MP3_PROTECTION_ON 0x00 +#define CODEC_INFO_MP3_PROTECTION_OFF 0x01 + +#define CODEC_INFO_MP3_BR_IDX_FREE 0x00 +#define CODEC_INFO_MP3_BR_IDX_32K 0x01 +#define CODEC_INFO_MP3_BR_IDX_40K 0x02 +#define CODEC_INFO_MP3_BR_IDX_48K 0x03 +#define CODEC_INFO_MP3_BR_IDX_56K 0x04 +#define CODEC_INFO_MP3_BR_IDX_64K 0x05 +#define CODEC_INFO_MP3_BR_IDX_80K 0x06 +#define CODEC_INFO_MP3_BR_IDX_96K 0x07 +#define CODEC_INFO_MP3_BR_IDX_112K 0x08 +#define CODEC_INFO_MP3_BR_IDX_128K 0x09 +#define CODEC_INFO_MP3_BR_IDX_160K 0x0A +#define CODEC_INFO_MP3_BR_IDX_192K 0x0B +#define CODEC_INFO_MP3_BR_IDX_224K 0x0C +#define CODEC_INFO_MP3_BR_IDX_256K 0x0D +#define CODEC_INFO_MP3_BR_IDX_320K 0x0E + +#define CODEC_INFO_MP3_SF_44K 0x00 +#define CODEC_INFO_MP3_SF_48K 0x01 +#define CODEC_INFO_MP3_SF_32K 0x02 + +#define CODEC_INFO_MP3_MODE_STEREO 0x00 +#define CODEC_INFO_MP3_MODE_JS 0x01 +#define CODEC_INFO_MP3_MODE_DUAL 0x02 +#define CODEC_INFO_MP3_MODE_SINGLE 0x03 + +/* layer 3, type of joint stereo coding method (intensity and ms) */ +#define CODEC_INFO_MP3_MODE_EXT_OFF_OFF 0x00 +#define CODEC_INFO_MP3_MODE_EXT_ON_OFF 0x01 +#define CODEC_INFO_MP3_MODE_EXT_OFF_ON 0x02 +#define CODEC_INFO_MP3_MODE_EXT_ON_ON 0x03 + + +#define CODEC_INFO_MP2_PROTECTION_ON 0x00 +#define CODEC_INFO_MP2_PROTECTION_OFF 0x01 + +#define CODEC_INFO_MP2_BR_IDX_FREE 0x00 +#define CODEC_INFO_MP2_BR_IDX_8K 0x01 +#define CODEC_INFO_MP2_BR_IDX_16K 0x02 +#define CODEC_INFO_MP2_BR_IDX_24K 0x03 +#define CODEC_INFO_MP2_BR_IDX_32K 0x04 +#define CODEC_INFO_MP2_BR_IDX_40K 0x05 +#define CODEC_INFO_MP2_BR_IDX_48K 0x06 +#define CODEC_INFO_MP2_BR_IDX_56K 0x07 +#define CODEC_INFO_MP2_BR_IDX_64K 0x08 +#define CODEC_INFO_MP2_BR_IDX_80K 0x09 +#define CODEC_INFO_MP2_BR_IDX_96K 0x0A +#define CODEC_INFO_MP2_BR_IDX_112K 0x0B +#define CODEC_INFO_MP2_BR_IDX_128K 0x0C +#define CODEC_INFO_MP2_BR_IDX_144K 0x0D +#define CODEC_INFO_MP2_BR_IDX_160K 0x0E + +#define CODEC_INFO_MP2_SF_22K 0x00 +#define CODEC_INFO_MP2_SF_24K 0x01 +#define CODEC_INFO_MP2_SF_16K 0x02 + +#define CODEC_INFO_MP2_MODE_STEREO 0x00 +#define CODEC_INFO_MP2_MODE_JS 0x01 +#define CODEC_INFO_MP2_MODE_DUAL 0x02 +#define CODEC_INFO_MP2_MODE_SINGLE 0x03 + +/* layer 3, type of joint stereo coding method (intensity and ms) */ +#define CODEC_INFO_MP2_MODE_EXT_OFF_OFF 0x00 +#define CODEC_INFO_MP2_MODE_EXT_ON_OFF 0x01 +#define CODEC_INFO_MP2_MODE_EXT_OFF_ON 0x02 +#define CODEC_INFO_MP2_MODE_EXT_ON_ON 0x03 + +#define CODEC_INFO_MP2_SAMPLE_PER_FRAME 576 + +/* mpeg 2.5 layer 3 decoder */ + +#define CODEC_INFO_MP25_PROTECTION_ON 0x00 +#define CODEC_INFO_MP25_PROTECTION_OFF 0x01 + +#define CODEC_INFO_MP25_BR_IDX_FREE 0x00 +#define CODEC_INFO_MP25_BR_IDX_8K 0x01 +#define CODEC_INFO_MP25_BR_IDX_16K 0x02 +#define CODEC_INFO_MP25_BR_IDX_24K 0x03 +#define CODEC_INFO_MP25_BR_IDX_32K 0x04 +#define CODEC_INFO_MP25_BR_IDX_40K 0x05 +#define CODEC_INFO_MP25_BR_IDX_48K 0x06 +#define CODEC_INFO_MP25_BR_IDX_56K 0x07 +#define CODEC_INFO_MP25_BR_IDX_64K 0x08 +#define CODEC_INFO_MP25_BR_IDX_80K 0x09 +#define CODEC_INFO_MP25_BR_IDX_96K 0x0A +#define CODEC_INFO_MP25_BR_IDX_112K 0x0B +#define CODEC_INFO_MP25_BR_IDX_128K 0x0C +#define CODEC_INFO_MP25_BR_IDX_144K 0x0D +#define CODEC_INFO_MP25_BR_IDX_160K 0x0E + +#define CODEC_INFO_MP25_SF_11K 0x00 +#define CODEC_INFO_MP25_SF_12K 0x01 +#define CODEC_INFO_MP25_SF_8K 0x02 + +#define CODEC_INFO_MP25_MODE_STEREO 0x00 +#define CODEC_INFO_MP25_MODE_JS 0x01 +#define CODEC_INFO_MP25_MODE_DUAL 0x02 +#define CODEC_INFO_MP25_MODE_SINGLE 0x03 + +/* layer 3, type of joint stereo coding method (intensity and ms) */ +#define CODEC_INFO_MP25_MODE_EXT_OFF_OFF 0x00 +#define CODEC_INFO_MP25_MODE_EXT_ON_OFF 0x01 +#define CODEC_INFO_MP25_MODE_EXT_OFF_ON 0x02 +#define CODEC_INFO_MP25_MODE_EXT_ON_ON 0x03 + +#define CODEC_INFO_MP25_SAMPLE_PER_FRAME 576 + +/* AAC/AAC+ CODEC Parameters */ +#define CODEC_INFO_AAC_SF_IDX_96K 0x0 +#define CODEC_INFO_AAC_SF_IDX_88K 0x1 +#define CODEC_INFO_AAC_SF_IDX_64K 0x2 +#define CODEC_INFO_AAC_SF_IDX_48K 0x3 +#define CODEC_INFO_AAC_SF_IDX_44K 0x4 +#define CODEC_INFO_AAC_SF_IDX_32K 0x5 +#define CODEC_INFO_AAC_SF_IDX_24K 0x6 +#define CODEC_INFO_AAC_SF_IDX_22K 0x7 +#define CODEC_INFO_AAC_SF_IDX_16K 0x8 +#define CODEC_INFO_AAC_SF_IDX_12K 0x9 +#define CODEC_INFO_AAC_SF_IDX_11K 0xA +#define CODEC_INFO_AAC_SF_IDX_08K 0xB +#define CODEC_INFO_AAC_SF_IDX_RESERVE 0xC + +#define CODEC_INFO_AAC_BR_RATE_48K 288000 +#define CODEC_INFO_AAC_BR_RATE_44K 264600 +#define CODEC_INFO_AAC_BR_RATE_32K 192000 + + +#define CODEC_INFO_AAC_1_CH 1 /*center front speaker */ +#define CODEC_INFO_AAC_2_CH 2 /*left, right front speaker */ +#define CODEC_INFO_AAC_3_CH 3 /*center front speaker, left right front speaker */ +#define CODEC_INFO_AAC_4_CH 4 /*center/rear front speaker, left/right front speaker */ +#define CODEC_INFO_AAC_5_CH 5 /*center, left, right front speaker, left/right surround */ +#define CODEC_INFO_AAC_6_CH 6 /*center, left, right front speaker, left/right surround, LFE */ +#define CODEC_INFO_AAC_7_CH 7 /*(left, right)center/left,right front speaker, left/right surround, LFE */ + + +typedef struct +{ + UINT8 sampling_freq; + UINT8 channel_mode; + UINT8 block_length; + UINT8 num_subbands; + UINT8 alloc_method; + UINT8 bitpool_size; /* 2 - 250 */ +} tCODEC_INFO_SBC; + +typedef struct +{ + UINT8 ch_mode; + UINT8 sampling_freq; + UINT8 bitrate_index; /* 0 - 14 */ +} tCODEC_INFO_MP3; + +typedef struct +{ + UINT8 ch_mode; + UINT8 sampling_freq; + UINT8 bitrate_index; /* 0 - 14 */ +} tCODEC_INFO_MP2; + + +typedef struct +{ + UINT8 ch_mode; + UINT8 sampling_freq; + UINT8 bitrate_index; /* 0 - 14 */ +} tCODEC_INFO_MP2_5; + +typedef struct +{ + UINT16 sampling_freq; + UINT8 channel_mode; /* 0x02:mono, 0x01:dual */ + UINT32 bitrate; /* 0 - 320K */ + UINT32 sbr_profile; /* 1: ON, 0: OFF */ +} tCODEC_INFO_AAC; + +typedef union +{ + tCODEC_INFO_SBC sbc; + tCODEC_INFO_MP3 mp3; + tCODEC_INFO_MP2 mp2; + tCODEC_INFO_MP2_5 mp2_5; + tCODEC_INFO_AAC aac; +} tCODEC_INFO; + +typedef struct +{ + UINT8 opcode; /* AUDIO_CODEC_CONFIG_REQ */ + tAUDIO_CODEC_TYPE codec_type; + tCODEC_INFO codec_info; +} tAUDIO_CODEC_CONFIG_REQ; + +#define AUDIO_CONFIG_SUCCESS 0x00 +#define AUDIO_CONFIG_NOT_SUPPORTED 0x01 +#define AUDIO_CONFIG_FAIL_OUT_OF_MEMORY 0x02 +#define AUDIO_CONFIG_FAIL_CODEC_USED 0x03 +#define AUDIO_CONFIG_FAIL_ROUTE 0x04 +typedef UINT8 tAUDIO_CONFIG_STATUS; + +typedef struct +{ + UINT8 opcode; /* AUDIO_CODEC_CONFIG_RESP */ + tAUDIO_CONFIG_STATUS status; +} tAUDIO_CODEC_CONFIG_RESP; + +typedef struct +{ + UINT8 opcode; /* AUDIO_CODEC_SET_BITRATE_REQ */ + tAUDIO_CODEC_TYPE codec_type; + union + { + UINT8 sbc; + UINT8 mp3; + UINT32 aac; + } codec_bitrate; +} tAUDIO_CODEC_SET_BITRATE_REQ; + +#define AUDIO_ROUTE_SRC_FMRX 0x00 +#define AUDIO_ROUTE_SRC_I2S 0x01 +#define AUDIO_ROUTE_SRC_ADC 0x02 +#define AUDIO_ROUTE_SRC_HOST 0x03 +#define AUDIO_ROUTE_SRC_PTU 0x04 +#define AUDIO_ROUTE_SRC_BTSNK 0x05 +#define AUDIO_ROUTE_SRC_NONE 0x80 +#define MAX_AUDIO_ROUTE_SRC 6 +typedef UINT8 tAUDIO_ROUTE_SRC; + +#define AUDIO_ROUTE_MIX_NONE 0x00 +#define AUDIO_ROUTE_MIX_HOST 0x01 +#define AUDIO_ROUTE_MIX_PCM 0x02 +#define AUDIO_ROUTE_MIX_CHIRP 0x03 +#define AUDIO_ROUTE_MIX_I2S 0x04 +#define AUDIO_ROUTE_MIX_ADC 0x05 +#define AUDIO_ROUTE_MIX_RESERVED 0x06 +#define MAX_AUDIO_ROUTE_MIX 7 +typedef UINT8 tAUDIO_ROUTE_MIX; + +#define AUDIO_ROUTE_OUT_NONE 0x0000 +#define AUDIO_ROUTE_OUT_BTA2DP 0x0001 +#define AUDIO_ROUTE_OUT_FMTX 0x0002 +#define AUDIO_ROUTE_OUT_BTSCO 0x0004 +#define AUDIO_ROUTE_OUT_HOST 0x0008 +#define AUDIO_ROUTE_OUT_DAC 0x0010 +#define AUDIO_ROUTE_OUT_I2S 0x0020 +#define AUDIO_ROUTE_OUT_BTA2DP_DAC 0x0040 +#define AUDIO_ROUTE_OUT_BTA2DP_I2S 0x0080 +#define AUDIO_ROUTE_OUT_BTSCO_DAC 0x0100 +#define AUDIO_ROUTE_OUT_BTSCO_I2S 0x0200 +#define AUDIO_ROUTE_OUT_HOST_BTA2DP 0x0400 +#define AUDIO_ROUTE_OUT_HOST_BTSCO 0x0800 +#define AUDIO_ROUTE_OUT_HOST_DAC 0x1000 +#define AUDIO_ROUTE_OUT_HOST_I2S 0x2000 +#define AUDIO_ROUTE_OUT_DAC_I2S 0x4000 +#define AUDIO_ROUTE_OUT_RESERVED_2 0x8000 + +#define MAX_AUDIO_SINGLE_ROUTE_OUT 6 +#define MAX_AUDIO_MULTI_ROUTE_OUT 16 +typedef UINT16 tAUDIO_MULTI_ROUTE_OUT; +typedef UINT8 tAUDIO_ROUTE_OUT; + +#define AUDIO_ROUTE_SF_8K 0x00 +#define AUDIO_ROUTE_SF_16K 0x01 +#define AUDIO_ROUTE_SF_32K 0x02 +#define AUDIO_ROUTE_SF_44_1K 0x03 +#define AUDIO_ROUTE_SF_48K 0x04 +#define AUDIO_ROUTE_SF_11K 0x05 +#define AUDIO_ROUTE_SF_12K 0x06 +#define AUDIO_ROUTE_SF_22K 0x07 +#define AUDIO_ROUTE_SF_24K 0x08 +#define AUDIO_ROUTE_SF_NA 0xFF +typedef UINT8 tAUDIO_ROUTE_SF; + +#define AUDIO_ROUTE_EQ_BASS_BOOST 0x00 +#define AUDIO_ROUTE_EQ_CLASSIC 0x01 +#define AUDIO_ROUTE_EQ_JAZZ 0x02 +#define AUDIO_ROUTE_EQ_LIVE 0x03 +#define AUDIO_ROUTE_EQ_NORMAL 0x04 +#define AUDIO_ROUTE_EQ_ROCK 0x05 +#define AUDIO_ROUTE_EQ_BYPASS 0x06 + +#define AUDIO_ROUTE_DIGITAL_VOLUME_CONTROL 0x07 + +#define AUDIO_ROUTE_EQ_CONFIG_GAIN 0xFF /* Custion Gain Config */ +typedef UINT8 tAUDIO_ROUTE_EQ; + +typedef struct +{ + UINT8 opcode; /* AUDIO_ROUTE_CONFIG_REQ */ + tAUDIO_ROUTE_SRC src; + tAUDIO_ROUTE_SF src_sf; + tAUDIO_ROUTE_OUT out; + tAUDIO_ROUTE_SF out_codec_sf; + tAUDIO_ROUTE_SF out_i2s_sf; + tAUDIO_ROUTE_EQ eq_mode; +} tAUDIO_ROUTE_CONFIG_REQ; + +typedef struct +{ + UINT8 opcode; /* AUDIO_ROUTE_CONFIG_RESP */ + tAUDIO_CONFIG_STATUS status; +} tAUDIO_ROUTE_CONFIG_RESP; + +typedef struct +{ + UINT16 amp[2]; /* left/right 15 bit amplitude value */ + UINT16 tone[2]; /* left/right 12 bit frequency 0 - 4096Hz */ + UINT16 mark[2]; /* left/right 16 bit mark time 0 - 65535ms */ + UINT16 space[2]; /* left/right 16 bit space time 0 - 65535ms */ +} tCHIRP_CONFIG; + +typedef struct +{ + UINT8 pri_l; /* Primary Left scale : 0 ~ 255 */ + UINT8 mix_l; /* Mixing Left scale : 0 ~ 255 */ + UINT8 pri_r; /* Primary Right scale : 0 ~ 255 */ + UINT8 mix_r; /* Mixing Right scale : 0 ~ 255 */ +} tMIX_SCALE_CONFIG; + +/* For custon equalizer gain configuration */ +typedef struct +{ + UINT32 audio_l_g0; /* IIR biquad filter left ch gain 0 */ + UINT32 audio_l_g1; /* IIR biquad filter left ch gain 1 */ + UINT32 audio_l_g2; /* IIR biquad filter left ch gain 2 */ + UINT32 audio_l_g3; /* IIR biquad filter left ch gain 3 */ + UINT32 audio_l_g4; /* IIR biquad filter left ch gain 4 */ + UINT32 audio_l_gl; /* IIR biquad filter left ch global gain */ + UINT32 audio_r_g0; /* IIR biquad filter left ch gain 0 */ + UINT32 audio_r_g1; /* IIR biquad filter left ch gain 1 */ + UINT32 audio_r_g2; /* IIR biquad filter left ch gain 2 */ + UINT32 audio_r_g3; /* IIR biquad filter left ch gain 3 */ + UINT32 audio_r_g4; /* IIR biquad filter left ch gain 4 */ + UINT32 audio_r_gl; /* IIR biquad filter left ch global gain */ +} tEQ_GAIN_CONFIG; + +typedef struct +{ + UINT8 opcode; /* AUDIO_MIX_CONFIG_REQ */ + tAUDIO_ROUTE_MIX mix_src; + tAUDIO_ROUTE_SF mix_src_sf; + tMIX_SCALE_CONFIG mix_scale; + tCHIRP_CONFIG chirp_config; +} tAUDIO_MIX_CONFIG_REQ; + +typedef struct +{ + UINT8 opcode; /* AUDIO_MIX_CONFIG_RESP */ + tAUDIO_CONFIG_STATUS status; +} tAUDIO_MIX_CONFIG_RESP; + + +typedef struct +{ + UINT8 opcode; /* AUDIO_BURST_FRAMES_IND */ + UINT32 burst_size; /* in bytes */ +} tAUDIO_BURST_FRAMES_IND; + +typedef struct +{ + UINT8 opcode; /* AUDIO_BURST_END_IND */ +} tAUDIO_BURST_END_IND; + +typedef struct +{ + UINT8 opcode; /* AUDIO_CODEC_FLUSH_REQ */ +} tAUDIO_CODEC_FLUSH_REQ; + +typedef struct +{ + UINT8 opcode; /* AUDIO_EQ_MODE_CONFIG_REQ */ + tAUDIO_ROUTE_EQ eq_mode; + tEQ_GAIN_CONFIG filter_gain; /* Valid only when eq_mode is 0xFF */ +} tAUDIO_EQ_MODE_CONFIG_REQ; + +typedef struct +{ + UINT8 opcode; /* AUDIO_SCALE_CONFIG_REQ */ + tMIX_SCALE_CONFIG mix_scale; +} tAUDIO_SCALE_CONFIG_REQ; + +#pragma pack(pop) /* pop saved alignment to stack */ + +#endif /* UIPC_MSG_H */ diff --git a/include/vnd_smelt.txt b/include/vnd_smelt.txt index 0a86aeb..7fe6a76 100644 --- a/include/vnd_smelt.txt +++ b/include/vnd_smelt.txt @@ -12,3 +12,8 @@ BTVND_DBG = FALSE BTHW_DBG = TRUE VNDUSERIAL_DBG = FALSE UPIO_DBG = FALSE +BRCM_A2DP_OFFLOAD = TRUE +BRCM_A2DP_OFFLOAD_SRC = AUDIO_ROUTE_SRC_I2S +BRCM_A2DP_OFFLOAD_SRC_SF = AUDIO_ROUTE_SF_48K +BRCM_A2DP_OFFLOAD_PCM_PIN_FCN = PCM_PIN_FCN_I2S_SLAVE +BTA2DP_DEBUG = FALSE 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 <string.h> +#include <pthread.h> +#include <utils/Log.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <signal.h> +#include <time.h> +#include <errno.h> +#include <fcntl.h> +#include <dirent.h> +#include <ctype.h> +#include <cutils/properties.h> +#include <stdlib.h> +#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); +} + + |
